Pick at most k projects to maximize your capital, where each project needs a minimum capital to start and pays a profit on completion. Sort projects by their capital requirement, sweep a pointer to unlock everything you can currently afford into a max-heap of profits, and greedily bank the richest affordable project each round.
You start with capital w and may complete at most k of the given projects. To start project i you must already hold at least capital[i]; finishing it pays profits[i], which is added to your capital (you never spend the requirement — it's only a gate). Maximize the capital you end with. Example: k=2, w=0, profits=[1,2,3], capital=[0,1,1]. With w=0 only project 0 (needs 0) is affordable → take it, profit 1, now w=1. Now projects needing 1 are affordable → take the richer one (profit 3) → w=4. Answer: 4.
O(log n), and a pointer over projects sorted by capital feeds the heap as your capital rises.[capital, profit] and sort ascending by capital — this is the order in which projects become affordable as w climbs.i forward, pushing every project with capital ≤ w into a max-heap of profits. The pointer never resets — once unlocked, always unlocked.w. Repeat for up to k rounds.Sorting is O(n log n). Across the whole run each project is pushed at most once and popped at most once, so heap work is O((n + k) log n). Space is O(n) for the paired/sorted projects and the heap. The brute-force O(k·n) scan is fine for small inputs but degrades when both k and n are large.
$profit over c{capital}). Starting capital w = $0, budget of k = 2 projects.1function findMaximizedCapital(2 k: number,3 w: number,4 profits: number[],5 capital: number[],6): number {7 const n = profits.length;89 // Pair each project as [capital, profit], sorted by capital ascending.10▶ const projects = Array.from({ length: n }, (_, i) => [capital[i], profits[i]]);11▶ projects.sort((a, b) => a[0] - b[0]);1213 // Max-heap of the profits of every project we can currently afford.14 const affordable = new MaxHeap();15 let i = 0;1617 for (let round = 0; round < k; round++) {18 // Unlock every project whose capital requirement is within reach.19 while (i < n && projects[i][0] <= w) {20 affordable.push(projects[i][1]);21 i++;22 }23 // Nothing affordable now → nothing ever will be. Stop early.24 if (affordable.size === 0) break;25 // Greedily bank the most profitable affordable project.26 w += affordable.pop();27 }2829 return w;30}
function findMaximizedCapital(
k: number,
w: number,
profits: number[],
capital: number[],
): number {
const n = profits.length;
// Pair each project as [capital, profit], sorted by capital ascending.
const projects = Array.from({ length: n }, (_, i) => [capital[i], profits[i]]);
projects.sort((a, b) => a[0] - b[0]);
// Max-heap of the profits of every project we can currently afford.
const affordable = new MaxHeap();
let i = 0;
for (let round = 0; round < k; round++) {
// Unlock every project whose capital requirement is within reach.
while (i < n && projects[i][0] <= w) {
affordable.push(projects[i][1]);
i++;
}
// Nothing affordable now → nothing ever will be. Stop early.
if (affordable.size === 0) break;
// Greedily bank the most profitable affordable project.
w += affordable.pop();
}
return w;
}[capital, profit] and sorted ascending on capital. Because capital only ever rises, this is exactly the order projects unlock in, so a single forward pointer suffices.affordable holds the profits of every project we can currently start, with the largest on top. The pointer imarks how far into the sorted list we've unlocked.i while projects[i].capital ≤ w, pushing those profits into the heap. The pointer never moves backward — a project affordable at capital w is still affordable at any higher capital.w; since capital can't grow without doing a project, nothing will ever become affordable — break.w. That single pick is provably optimal for this round (any deferred project stays available), and the larger w may unlock more projects next round. After up to k rounds, w is the answer.O(n log n); each project is pushed/popped at most once and there are at most k pops → total O((n + k) log n) time, O(n) space.n projects, so the loop naturally stops when the heap empties; effectively you bank every project, largest-profit first.capital ≤ w. Same O((n + k) log n), no explicit sort.function findMaximizedCapital(
k: number,
w: number,
profits: number[],
capital: number[],
): number {
const n = profits.length;
// Pair each project as [capital, profit], sorted by capital ascending.
const projects = Array.from({ length: n }, (_, i) => [capital[i], profits[i]]);
projects.sort((a, b) => a[0] - b[0]);
// Max-heap of the profits of every project we can currently afford.
const affordable = new MaxHeap();
let i = 0;
for (let round = 0; round < k; round++) {
// Unlock every project whose capital requirement is within reach.
while (i < n && projects[i][0] <= w) {
affordable.push(projects[i][1]);
i++;
}
// Nothing affordable now → nothing ever will be. Stop early.
if (affordable.size === 0) break;
// Greedily bank the most profitable affordable project.
w += affordable.pop();
}
return w;
}O(n log n); each project is pushed/popped at most once and there are at most k pops → total O((n + k) log n) time, O(n) space.No heap: each round, linearly scan every not-yet-done project for the most profitable one you can currently afford.
function findMaximizedCapital(
k: number,
w: number,
profits: number[],
capital: number[],
): number {
const n = profits.length;
const done = new Array<boolean>(n).fill(false);
for (let round = 0; round < k; round++) {
// Find the affordable, unfinished project with the highest profit.
let best = -1;
for (let i = 0; i < n; i++) {
if (!done[i] && capital[i] <= w && (best === -1 || profits[i] > profits[best])) {
best = i;
}
}
// Nothing affordable → capital can't grow, so stop.
if (best === -1) break;
done[best] = true;
w += profits[best];
}
return w;
}n projects → O(k·n). Fine for small inputs; the heap version wins once k and n are both large.Avoid sorting: keep locked projects in a min-heap keyed on capital, draining their tops into a profit max-heap as capital rises.
function findMaximizedCapital(
k: number,
w: number,
profits: number[],
capital: number[],
): number {
const n = profits.length;
// Locked: min-heap on capital required. Affordable: max-heap on profit.
const locked = new MinHeap<[number, number]>((a, b) => a[0] - b[0]); // [capital, profit]
const affordable = new MaxHeap<number>();
for (let i = 0; i < n; i++) locked.push([capital[i], profits[i]]);
for (let round = 0; round < k; round++) {
// Move every now-affordable project from locked into affordable.
while (locked.size > 0 && locked.peek()[0] <= w) {
affordable.push(locked.pop()[1]);
}
if (affordable.size === 0) break;
w += affordable.pop();
}
return w;
}O(n)), and it streams projects in instead of sorting up front — handy if projects arrive online. Slightly more bookkeeping with two heaps.| pick k items, each gated by a threshold | sort by threshold + max-heap on value |
| resource only grows after each pick | greedy: take the best currently eligible |
| eligibility expands as a value rises | forward pointer feeds a heap (never reset) |
| nothing affordable | empty heap → break early |
// projects sorted by capital; affordable = max-heap on profit
projects.sort((a, b) => a.cap - b.cap);
let i = 0;
for (let t = 0; t < k; t++) {
while (i < n && projects[i].cap <= w) { // unlock
affordable.push(projects[i].profit); i++;
}
if (affordable.size === 0) break; // can't afford anything
w += affordable.pop(); // take richest
}
return w;