A company has limited resources, it can only finish at most k distinct projects before the IPO. Help the company to design the best way to maximize its total capital after finishing at most k distinct projects.
You are given n projects where the ith project has a pure profit profits[i] and a minimum capital of capital[i] is needed to start it. Initially, you have w capital. When you finish a project, you will obtain its pure profit and the profit will be added to your total capital.
Pick a list of at most k distinct projects from given projects to maximize your final capital, and return the final maximized capital.
The answer is guaranteed to fit in a 32-bit signed integer.
Example 1:
Input: k = 3, w = 0, profits = [1,4,2,3], capital = [0,3,1,1]
Output: 8Explanation : The order of indices to pick are [0,3,1] and final capital is (1 + 3 + 4) = 8.
Example 2:
Input: k = 4, w = 2, profit = [2,3,1,5,3], capital = [4,4,2,3,3]
Output: 14Explanation: The order of indices to pick are [2,3,4,1] and final capital is (2 + (1 + 5 + 3 + 3)) = 14.
Constraints:
n == profits.length == capital.length1 <= n, k <= 100,0000 <= w <= 1,000,000,0000 <= profits[i] <= 10,0000 <= capital[i] <= 1,000,000,000Before attempting this problem, you should be comfortable with:
To maximize capital after completing at most k projects, we should always pick the project with the highest profit among those we can currently afford. A min-heap ordered by capital lets us efficiently find all affordable projects as our capital grows. A max-heap ordered by profit then lets us pick the most profitable one. After completing a project, our capital increases, potentially unlocking more projects from the min-heap to consider.
k times:w into the max-heap.break.w.w.class Solution:
def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
maxProfit = [] # Max heap
minCapital = [(c, p) for c, p in zip(capital, profits)] # Min heap
heapq.heapify(minCapital)
for _ in range(k):
while minCapital and minCapital[0][0] <= w:
c, p = heapq.heappop(minCapital)
heapq.heappush(maxProfit, -p)
if not maxProfit:
break
w += -heapq.heappop(maxProfit)
return wThis approach improves on the previous one by storing only indices in the heaps rather than copying the actual capital and profit values. The heaps use custom comparators that reference the original arrays. This reduces memory overhead while maintaining the same greedy strategy: always select the most profitable project among those currently affordable.
capital[index].profits[index].k times:capital[index] <= w into the max-heap.break.index with maximum profit, add profits[index] to w.w.class Solution:
def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
class Node:
def __init__(self, idx):
self.idx = idx
def __lt__(self, other):
if capital[self.idx] != capital[other.idx]:
return capital[self.idx] < capital[other.idx]
return self.idx < other.idx
minCapital = []
maxProfit = []
for i in range(len(capital)):
heapq.heappush(minCapital, Node(i))
for _ in range(k):
while minCapital and capital[minCapital[0].idx] <= w:
idx = heapq.heappop(minCapital).idx
heapq.heappush(maxProfit, -profits[idx])
if not maxProfit:
break
w += -heapq.heappop(maxProfit)
return wInstead of using a min-heap for capital, we can simply sort the projects by their capital requirements upfront. A pointer then tracks which projects have become affordable. As capital grows, we advance this pointer and push newly affordable project profits into a max-heap. This avoids repeated heap operations on the capital side and is often faster in practice due to better cache performance from the sorted array traversal.
[0, 1, ..., n-1] and sort it by capital[index].idx = 0.k times:idx < n and capital[indices[idx]] <= w, push profits[indices[idx]] onto the max-heap and increment idx.break.w.w.class Solution:
def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:
n = len(profits)
indices = list(range(n))
indices.sort(key=lambda i: capital[i])
maxProfit, idx = [], 0
for _ in range(k):
while idx < n and capital[indices[idx]] <= w:
heapq.heappush(maxProfit, -profits[indices[idx]])
idx += 1
if not maxProfit:
break
w += -heapq.heappop(maxProfit)
return wA critical mistake is confusing which heap to use for which purpose. You need a min-heap ordered by capital (to efficiently find affordable projects) and a max-heap ordered by profit (to select the most profitable affordable project). Reversing these or using the wrong ordering will produce incorrect results.
After completing a project and gaining profit, your capital increases, which may unlock previously unaffordable projects. Forgetting to transfer newly affordable projects from the capital heap to the profit heap before selecting the next project means you might miss the most profitable option available to you.
If your current capital is insufficient to start any remaining projects, the max-heap for profits will be empty. Failing to check for this condition and break out of the loop will cause errors (such as attempting to pop from an empty heap) or infinite loops.
Some developers try to optimize by considering both profit and capital together (e.g., profit-to-capital ratio) or by looking ahead multiple projects. This overcomplicates the solution. The optimal greedy strategy is simple: always pick the highest-profit project among those currently affordable.
Remember that you can complete at most k projects, not exactly k. If there are fewer than k affordable projects total or if you run out of affordable projects before completing k, you should stop early rather than erroring or returning incorrect values.