AlgoMaster Logo

IPO

hardFrequency5 min readUpdated June 23, 2026

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.

A greedy rule solves this: at each step, among all projects we can currently afford, 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 returns the most profitable affordable project quickly.

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 non-negative, so completing more projects never decreases our capital. This is why running for the full k rounds (when projects remain affordable) is safe.

Approach 1: Brute Force (Greedy with Linear Scan)

Intuition

The greedy rule says: always pick the most profitable project we can afford. A direct implementation scans all projects each round, finds the one with the highest profit among those whose capital requirement is at most our current capital, completes it, and repeats up to k times.

Each project can only be completed once, so we track which projects have been used with a boolean array.

Algorithm

  1. Create a boolean array used of size n, initialized to false.
  2. Repeat up to k times:
    • Scan all n projects. Among those not yet used and whose capital[i] <= w, find the one with the maximum profits[i].
    • If no affordable project exists, stop early.
    • Mark that project as used and add its profit to w.
  3. 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 is correct but too slow for large inputs, because it re-scans every project on every round. The next approach removes the repeated scanning by sorting projects by capital and using a max-heap to retrieve the best affordable project in logarithmic time.

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

Intuition

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

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 (the previous round increased our capital, so more may have become reachable), then pop the top to get the most profitable one. The pointer never moves 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:
    • While idx < n and projects[idx].capital <= w, push projects[idx].profit into the max-heap and increment idx.
    • If the max-heap is empty, no more affordable projects exist. Stop early.
    • Pop the maximum profit from the heap and add it to w.
  4. 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