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 problem is one of resource allocation. A ladder covers any height difference for the cost of one ladder, so a ladder is worth most on the largest climbs, and bricks should cover the smaller climbs. The complication is that we walk left to right and do not know which climbs are the largest until we have seen them all. We have to decide as we go while keeping the option to reassign resources later.
This is a greedy problem where we track past decisions and 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. An O(n^2) solution would be around 10^10 operations, which is too slow.0 <= bricks <= 10^9 → Bricks fit in a 32-bit signed int (max ~2.1 x 10^9), and we only ever subtract a single climb (at most 10^6) before checking the sign, so bricks cannot underflow far enough to wrap. Bricks can also be zero, meaning we may rely entirely on ladders.0 <= ladders <= heights.length → We could have a ladder for every climb, or none at all.At each climb, try using bricks, then try using a ladder, and take whichever choice reaches further. This is a depth-first search that branches into two paths at every uphill step.
The search explores every possible allocation and returns the maximum building index reached. It is correct but slow, since 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 without spending anything.diff > 0, try both options:diff bricks (if you have enough) and recurse from i+1.i+1.This is correct but exponentially slow. Since ladders should go to the largest climbs, we can make greedy decisions in a single pass and use a heap to reassign the smallest ladder-climb back to bricks whenever a bigger climb appears.
A ladder covers any height difference for a fixed cost of one ladder, while bricks cost is proportional to the climb height. The optimal strategy is to spend ladders on the largest climbs and bricks on the smallest ones. The difficulty is that we walk left to right and do not know which climbs are the biggest until the whole array is seen.
A min-heap of size ladders resolves this. Start as if ladders were unlimited: every time a climb appears, assign a ladder to it by pushing the climb height onto the heap. When the heap size exceeds ladders, more climbs are covered by ladders than we own, so pop the smallest climb from the heap and pay for it with bricks. This converts the cheapest ladder assignment so far into a brick payment.
After each step the heap holds the ladders largest climbs seen so far, and every other climb has been paid with bricks. That allocation minimizes brick spending at every step.
Among the climbs seen so far, total brick spending equals the sum of all climbs minus the climbs covered by ladders. With at most ladders ladders available, that sum is minimized by covering the ladders largest climbs, which is exactly the set the heap retains. Using a ladder on a climb of 100 saves 100 bricks, while using it on a climb of 2 saves only 2, so assigning ladders to the largest climbs maximizes brick savings. Returning the index as soon as bricks goes negative is also safe: brick spending only grows as we advance, so if the minimum spend up to building i+1 already exceeds the budget, no later allocation can recover.
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).