AlgoMaster Logo

IPO

Last Updated: April 4, 2026

hard
3 min read

Understanding the Problem

We have a set of projects, each requiring some minimum capital to start and yielding a certain profit upon completion. We start with w capital and can complete at most k projects. After completing a project, its profit gets added to our capital, potentially unlocking more expensive projects. The goal is to maximize the final capital.

The greedy insight here is straightforward: at each step, among all projects we can currently afford, we should pick the one with the highest profit. That gives us the most capital for future rounds, which in turn unlocks the most options. The challenge is doing this efficiently. With up to 10^5 projects and 10^5 rounds, we need a data structure that quickly tells us the most profitable affordable project.

Key Constraints:

  • 1 <= k <= 10^5 and 1 <= n <= 10^5 → We might iterate up to k times, and each iteration needs to efficiently find the best project. A naive O(n) scan per iteration gives O(k * n) = O(10^10), which is too slow.
  • 0 <= w <= 10^9 and 0 <= capital[i] <= 10^9 → Capital values can be very large, so we can't use them as array indices. No bucket sort tricks.
  • 0 <= profits[i] <= 10^4 → Profits are bounded but this doesn't help much algorithmically.

Approach 1: Brute Force (Greedy with Linear Scan)

Intuition

The greedy strategy is clear: always pick the most profitable project you can afford. The simplest way to implement this is to scan all projects each round, find the one with the highest profit among those whose capital requirement is at most our current capital, complete it, and repeat up to k times.

We need to track which projects have been used since each project can only be completed once. A boolean array works for that.

Algorithm

  1. Create a boolean array used of size n, initialized to false.
  2. Repeat up to k times:

a. Scan all n projects. Among those not yet used and whose capital[i] <= w, find the one with the maximum profits[i].

b. If no affordable project exists, stop early.

c. Mark that project as used and add its profit to w.

  1. Return w.

Example Walkthrough

1Round 1: w=0. Scan all projects for best affordable profit.
0
1
scan
1
2
2
3
1/7

Code

This approach works correctly but is too slow for large inputs. What if we sorted projects by capital and used a max-heap to instantly retrieve the best affordable project?

Approach 2: Greedy with Sort + Max-Heap (Optimal)

Intuition

The key observation is that once a project becomes affordable, it stays affordable because our capital only increases. So instead of re-scanning every project each round, we can sort projects by their capital requirement and use a pointer to track which ones we have unlocked so far.

Here is the plan: sort all projects by capital. Maintain a max-heap of profits for all projects we can currently afford. Each round, push any newly affordable projects into the max-heap (since our capital just increased), then pop the top to get the most profitable one. The pointer never goes backward because capital only grows.

Algorithm

  1. Pair each project as (capital[i], profits[i]) and sort by capital ascending.
  2. Initialize a pointer idx = 0 and a max-heap (empty).
  3. Repeat k times:

a. While idx < n and projects[idx].capital <= w, push projects[idx].profit into the max-heap and increment idx.

b. If the max-heap is empty, no more affordable projects exist. Stop early.

c. Pop the maximum profit from the heap and add it to w.

  1. Return w.

Example Walkthrough

1Sorted by capital: [(0,1), (1,2), (1,3)]. idx=0, w=0
0
idx
(0,1)
1
(1,2)
2
(1,3)
1/6

Code