IPO
HardPrompt
Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Capital, LeetCode would like to work on some projects to increase its capital before the IPO. Since it has limited resources, it can only finish at most k distinct projects before the IPO. Help LeetCode 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 = 2, w = 0, profits = [1,2,3], capital = [0,1,1]
Output: 4
Explanation: Since your initial capital is 0, you can only start the project indexed 0.
After finishing it you will obtain profit 1 and your capital becomes 1.
With capital 1, you can either start the project indexed 1 or the project indexed 2.
Since you can choose at most 2 projects, you need to finish the project indexed 2 to get the maximum capital.
Therefore, output the final maximized capital, which is 0 + 1 + 3 = 4.Example 2:
Input: k = 3, w = 0, profits = [1,2,3], capital = [0,1,2]
Output: 6
Constraints:
1 <= k <= 1050 <= w <= 109n == profits.lengthn == capital.length1 <= n <= 1050 <= profits[i] <= 1040 <= capital[i] <= 109
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the process. For each of the k projects we can undertake, we iterate through all available projects to find the best one we can currently afford. The best project is defined as the one that is affordable (its capital requirement is less than or equal to our current capital) and offers the highest profit.
Algorithm
-
- Initialize a boolean array
usedof sizentofalseto track completed projects.
- Initialize a boolean array
-
- Loop from
i = 0tok-1.
- Loop from
-
- Inside the loop, initialize
bestProjectIndex = -1andmaxProfit = -1.
- Inside the loop, initialize
-
- Iterate through all projects from
j = 0ton-1.
- Iterate through all projects from
-
- If project
jis notusedandcapital[j] <= w:
- If project
-
- Check if
profits[j]is greater thanmaxProfit. If so, updatemaxProfit = profits[j]andbestProjectIndex = j.
- Check if
-
- After iterating through all projects, if
bestProjectIndexis still-1, it means no project is affordable. Break the outer loop.
- After iterating through all projects, if
-
- Otherwise, add
profits[bestProjectIndex]towand setused[bestProjectIndex]totrue.
- Otherwise, add
-
- After the outer loop finishes, return
w.
- After the outer loop finishes, return
Walkthrough
The algorithm iterates up to k times, representing the selection of at most k projects.
In each iteration, it searches for the most profitable project among all projects that have not yet been chosen and are affordable with the current capital w.
To do this, we loop through the profits and capital arrays. We maintain a variable to track the index of the best project found so far in the current iteration.
A project i is a candidate if capital[i] <= w and it hasn't been selected before. Among all candidates, we pick the one with the maximum profits[i].
To avoid re-selecting a project, we can use a boolean array visited or modify the project's data (e.g., set its profit to -1) after it's chosen.
If a suitable project is found, its profit is added to w, and it's marked as visited.
If no affordable project can be found in an iteration, it means we cannot proceed further, so we break the loop.
The final capital w is returned after the loop completes.
class Solution { public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) { int n = profits.length; boolean[] used = new boolean[n]; for (int i = 0; i < k; i++) { int bestProjectIndex = -1; int maxProfit = -1; // Find the most profitable affordable project for (int j = 0; j < n; j++) { if (!used[j] && capital[j] <= w) { if (profits[j] > maxProfit) { maxProfit = profits[j]; bestProjectIndex = j; } } } // If no affordable project is found, break if (bestProjectIndex == -1) { break; } // "Take" the project w += profits[bestProjectIndex]; used[bestProjectIndex] = true; } return w; }}Complexity
Time
O(k * n). The outer loop runs up to `k` times, and the inner loop runs `n` times to find the best project. In the worst case, this leads to `k * n` operations.
Space
O(n). We use a boolean array `used` of size `n` to keep track of the projects that have been completed.
Trade-offs
Pros
Simple to understand and implement.
Directly follows the problem's logic.
Cons
Inefficient for large inputs.
With
kandnup to 10^5,k * ncan be up to 10^10, which will result in a "Time Limit Exceeded" error.
This approach optimizes the selection process by using a greedy strategy combined with a max-heap and sorting. The core idea is that at any point, we should choose the most profitable project we can afford. To efficiently find this project, we first sort all projects by their capital requirement. Then, we use a max-heap to keep track of the profits of all projects that have become affordable.
Algorithm
-
- Create an array of
Projectobjects, each containing acapitalandprofit.
- Create an array of
-
- Sort the
projectsarray based oncapitalin ascending order.
- Sort the
-
- Initialize a max-heap (
PriorityQueuewith a reverse comparator) to store profits.
- Initialize a max-heap (
-
- Initialize a pointer
projectIndex = 0for the sortedprojectsarray.
- Initialize a pointer
-
- Loop
ktimes to select up tokprojects.
- Loop
-
- Inside the loop, add all newly affordable projects to the heap: while
projectIndex < nandprojects[projectIndex].capital <= w, addprojects[projectIndex].profitto themaxHeapand incrementprojectIndex.
- Inside the loop, add all newly affordable projects to the heap: while
-
- If the
maxHeapis empty, it means no more projects can be undertaken with the current capital. Break the loop.
- If the
-
- Otherwise, pop the maximum profit from the
maxHeapand add it tow.
- Otherwise, pop the maximum profit from the
-
- After the loop, return the final capital
w.
- After the loop, return the final capital
Walkthrough
The intuition is that as our capital w increases, the set of affordable projects only grows. Sorting by capital allows us to efficiently process projects as they become affordable.
First, we combine the profits and capital arrays into a single list of Project objects (or pairs), where each object stores the capital and profit for one project.
We sort this list of projects in ascending order based on their capital requirement.
We use a Max-Heap (implemented as a PriorityQueue in Java with a reverse order comparator) to store the profits of projects we can afford but haven't started yet.
We iterate k times. In each iteration:
- We add all newly affordable projects to the max-heap. We use a pointer to traverse the sorted projects list. As long as the project's capital is less than or equal to our current capital
w, we add its profit to the heap and advance the pointer. - If the heap is not empty, we extract the maximum profit (the root of the heap), add it to our capital
w, and effectively "complete" that project. - If the heap is empty, it means there are no affordable projects, so we can't continue. We break the loop.
After
kiterations or breaking early, the finalwis the maximized capital.
import java.util.Arrays;import java.util.Collections;import java.util.PriorityQueue; class Solution { private static class Project { int capital; int profit; Project(int capital, int profit) { this.capital = capital; this.profit = profit; } } public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) { int n = profits.length; Project[] projects = new Project[n]; for (int i = 0; i < n; i++) { projects[i] = new Project(capital[i], profits[i]); } // Sort projects by their capital requirement Arrays.sort(projects, (a, b) -> a.capital - b.capital); // Max-heap to store profits of affordable projects PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder()); int projectIndex = 0; for (int i = 0; i < k; i++) { // Add all affordable projects to the max-heap while (projectIndex < n && projects[projectIndex].capital <= w) { maxHeap.add(projects[projectIndex].profit); projectIndex++; } // If no projects can be started, break if (maxHeap.isEmpty()) { break; } // Greedily pick the most profitable project w += maxHeap.poll(); } return w; }}Complexity
Time
O(n log n + k log n). Sorting the projects takes O(n log n). The main loop runs `k` times. Each project is pushed onto the heap at most once (total O(n log n) for all pushes) and we perform at most `k` polls from the heap (total O(k log n) for all polls).
Space
O(n). We need O(n) space for the `projects` array and the max-heap can store up to `n` profits in the worst case.
Trade-offs
Pros
Much more efficient than the brute-force approach.
Correctly implements the optimal greedy strategy.
Passes the given constraints.
Cons
More complex to implement due to the use of sorting and a priority queue.
Requires extra space for storing projects and the heap.
Solutions
Solution
class Solution {public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) { int n = capital.length; PriorityQueue<int[]> q1 = new PriorityQueue<>((a, b)->a[0] - b[0]); for (int i = 0; i < n; ++i) { q1.offer(new int[]{capital[i], profits[i]}); } PriorityQueue<Integer> q2 = new PriorityQueue<>((a, b)->b - a); while (k-- > 0) { while (!q1.isEmpty() && q1.peek()[0] <= w) { q2.offer(q1.poll()[1]); } if (q2.isEmpty()) { break; } w += q2.poll(); } return w; }}using pii = pair < int , int > ; class Solution { public: int findMaximizedCapital ( int k , int w , vector < int >& profits , vector < int >& capital ) { priority_queue < pii , vector < pii > , greater < pii >> q1 ; int n = profits . size (); for ( int i = 0 ; i < n ; ++ i ) { q1 . push ({ capital [ i ], profits [ i ]}); } priority_queue < int > q2 ; while ( k -- ) { while ( ! q1 . empty () && q1 . top (). first <= w ) { q2 . push ( q1 . top (). second ); q1 . pop (); } if ( q2 . empty ()) { break ; } w += q2 . top (); q2 . pop (); } return w ; } };class Solution: def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int: h1 = [(c, p) for c, p in zip(capital, profits)] heapify(h1) h2 = [] while k: while h1 and h1[0][0] <= w: heappush(h2, - heappop(h1)[1]) if not h2: break w -= heappop(h2) k -= 1 return wVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.