Last Updated: April 4, 2026
We need to travel across buildings from left to right. Going downhill or staying level costs nothing. Going uphill costs either bricks (equal to the height difference) or one ladder (regardless of the height difference). The question is: how far can we get if we allocate bricks and ladders optimally?
The crux of the problem is resource allocation. Ladders are best used for the largest climbs (since a ladder covers any height difference for free), and bricks should cover the smaller climbs. But here's the catch: we don't know which climbs are "the largest" until we've seen them all. So the real challenge is making decisions as we go, while keeping the option to retroactively reassign resources.
This is a greedy problem where we need to keep track of past decisions and potentially swap a previous brick allocation for a ladder when a bigger climb appears.
1 <= heights.length <= 10^5 → With n up to 100,000, we need O(n log n) or better. O(n^2) would be 10^10 operations, which is too slow.1 <= heights[i] <= 10^6 → Heights can be large, so height differences can be up to 10^6. Combined with up to 10^5 buildings, total brick usage could overflow 32-bit integers, but bricks is capped at 10^9 which fits in a 32-bit int.0 <= bricks <= 10^9 → Bricks can be zero, meaning we might rely entirely on ladders.0 <= ladders <= heights.length → We could have enough ladders for every single climb, or zero ladders.The most natural first thought: at each climb, try using bricks, then try using a ladder, and take whichever choice lets you get further. This is essentially a depth-first search where at each uphill step, you branch into two paths.
This approach explores all possible allocations and returns the maximum building index reached. It's correct but extremely slow because the number of paths doubles with each climb.
i, compute the climb to building i+1: diff = heights[i+1] - heights[i].diff <= 0, move to i+1 for free.diff > 0, try both options:diff bricks (if you have enough) and recurse from i+1.i+1.This approach is correct but exponentially slow. The key observation is that ladders should always go to the largest climbs. What if we made greedy decisions and used a heap to retroactively reassign the smallest ladder-climb to bricks?
Here's the key insight that makes this problem elegant. Ladders are most valuable for big climbs because a ladder covers any height difference at a fixed cost of one ladder. Bricks, on the other hand, are proportional to the climb height. So the optimal strategy is: use ladders for the largest climbs and bricks for the smallest ones.
But we're walking left to right. We don't know which climbs will be the biggest until we've seen them all. So how do we make optimal decisions on the fly?
The trick is to use a min-heap of size ladders. Think of it this way: assume you have unlimited ladders at first. Every time you hit a climb, throw a ladder at it (push the climb height onto the heap). When the heap size exceeds ladders, it means you've used more ladders than you actually have. Pop the smallest climb from the heap and pay for it with bricks instead. This retroactively converts your worst ladder usage into a brick payment.
This way, the heap always contains the ladders largest climbs you've seen so far, and everything else gets paid with bricks. That's the optimal allocation at every step.
The min-heap maintains an invariant: it always contains the ladders largest climbs encountered so far. Every time a new climb is added, the heap might overflow. When it does, the smallest climb gets evicted and paid with bricks. This means ladders are always assigned to the biggest climbs, which is provably optimal.
Why? Because ladders have a fixed cost (one ladder per climb, regardless of height), while bricks have a variable cost proportional to the climb. Using a ladder on a climb of 100 saves 100 bricks, while using it on a climb of 2 saves only 2. So maximizing the "brick savings" from ladders means assigning them to the largest climbs.
0 to n-2.diff = heights[i+1] - heights[i].diff <= 0, skip (no resources needed).diff > 0, push diff onto the min-heap (assign a ladder to this climb).ladders, pop the smallest value and subtract it from bricks (convert the smallest ladder-climb to bricks).bricks < 0, return i (we can't afford this step).n - 1 (we reached the last building).