This content originally appeared on DEV Community and was authored by seanpgallivan
This is part of a series of Leetcode solution explanations (index). If you liked this solution or found it useful, please like this post and/or upvote my solution post on Leetcode's forums.
Leetcode Problem #1642 (Medium): Furthest Building You Can Reach
Description:
(Jump to: Solution Idea || Code: JavaScript | Python | Java | C++)
You are given an integer array heights representing the heights of buildings, some bricks, and some ladders.
You start your journey from building 0 and move to the next building by possibly using bricks or ladders.
While moving from building i to building i+1 (0-indexed),
- If the current building's height is greater than or equal to the next building's height, you do not need a ladder or bricks.
- If the current building's height is less than the next building's height, you can either use one ladder or (h[i+1] - h[i]) bricks.
Return the furthest building index (0-indexed) you can reach if you use the given ladders and bricks optimally.
Examples:
Example 1: Input: heights = [4,2,7,6,9,14,12], bricks = 5, ladders = 1 Output: 4 Explanation: Starting at building 0, you can follow these steps:
- Go to building 1 without using ladders nor bricks since 4 >= 2.
- Go to building 2 using 5 bricks. You must use either bricks or ladders because 2 < 7.
- Go to building 3 without using ladders nor bricks since 7 >= 6.
- Go to building 4 using your only ladder. You must use either bricks or ladders because 6 < 9.
It is impossible to go beyond building 4 because you do not have any more bricks or ladders.Visual:
Example 2: Input: heights = [4,12,2,7,3,18,20,3,19], bricks = 10, ladders = 2 Output: 7
Example 3: Input: heights = [14,3,19,3], bricks = 17, ladders = 0 Output: 3
Constraints:
1 <= heights.length <= 10^5
1 <= heights[i] <= 10^6
0 <= bricks <= 10^9
0 <= ladders <= heights.length
Idea:
(Jump to: Problem Description || Code: JavaScript | Python | Java | C++)
The first realization should be that we always want to use our ladders to their best effect: where they would save us the most amount of bricks. Unfortunately, we can't just save the ladders for the largest gaps in the building heights, because we may not be able to reach them by using bricks.
Since we can't find out how far we can go until we figure out where to place the ladders, and we can't figure out where to put the ladders until we see how far we can go, we'll have to move the ladders around as we go in order to maintain their maximum effect.
To put this in terms of a coding solution, as we iterate through the building heights array (H), we'll want to continuously make sure that the largest L number of positive differences are occupied with ladders, allowing us the best use of our B number of bricks.
In general, this means that we should start iterating through H, ignoring any difference (diff) that is 0 or less, and place a ladder whenever we have a positive difference. Once we've used up all the ladders, then we can start using bricks. If we come across a diff that is larger than the smallest ladder that we're currently using, we should replace that ladder with bricks and move the ladder forwad to the current diff. Otherwise we should use bricks for the current diff.
The second big realization at this point is that we need a min-heap or min priority queue in order to keep track of the heights of the ladders in use, so that we can always take the smallest one, thus keeping the ladders always on the largest diff values.
If at any point we run out bricks, then we can't reach the next building and should return i. If we're able to reach the end of H without running out of bricks, we can return H.length - 1, signifying that we reached the last building.
- Time Complexity: O(N) where N is the length of H
- Space Complexity: O(L) to keep track of L number of ladder lengths
Implementation:
The Javascript MinPriorityQueue() npm package isn't as efficient as a min-heap, but it is much more succinct, so I've included both versions of code for comparison.
For C++, the priority_queue defaults to a max order, so we can just invert the sign on the diff values before insertion to effectively turn it into a min priority queue instead.
Javascript Code:
(Jump to: Problem Description || Solution Idea)
w/ MinPriorityQueue():
var furthestBuilding = function(H, B, L) {
let len = H.length - 1,
pq = new MinPriorityQueue({priority: x => x})
for (let i = 0; i < len; i++) {
let diff = H[i+1] - H[i]
if (diff > 0) {
if (L > 0) pq.enqueue(diff), L--
else if (pq.front() && diff > pq.front().element)
pq.enqueue(diff), B -= pq.dequeue().element
else B -= diff
if (B < 0) return i
}
}
return len
};
w/ Min-Heap:
var furthestBuilding = function(H, B, L) {
let len = H.length - 1, heap = [,]
const heapify = val => {
let i = heap.length, par = i >> 1, temp
heap.push(val)
while (heap[par] > heap[i]) {
temp = heap[par], heap[par] = heap[i], heap[i] = temp
i = par, par = i >> 1
}
}
const extract = () => {
if (heap.length === 1) return null
let top = heap[1], left, right, temp,
i = 1, child = heap[3] < heap[2] ? 3 : 2
if (heap.length > 2) heap[1] = heap.pop()
else heap.pop()
while (heap[i] > heap[child]) {
temp = heap[child], heap[child] = heap[i], heap[i] = temp
i = child, left = i << 1, right = left + 1
child = heap[right] < heap[left] ? right : left
}
return top
}
for (let i = 0; i < len; i++) {
let diff = H[i+1] - H[i]
if (diff > 0) {
if (L > 0) heapify(diff), L--
else if (heap.length > 1 && diff > heap[1])
heapify(diff), B -= extract()
else B -= diff
if (B < 0) return i
}
}
return len
};
Python Code:
(Jump to: Problem Description || Solution Idea)
class Solution:
def furthestBuilding(self, H: List[int], B: int, L: int) -> int:
heap = []
for i in range(len(H) - 1):
diff = H[i+1] - H[i]
if diff > 0:
if L > 0:
heappush(heap, diff)
L -= 1
elif heap and diff > heap[0]:
heappush(heap, diff)
B -= heappop(heap)
else: B -= diff
if B < 0: return i
return len(H) - 1
Java Code:
(Jump to: Problem Description || Solution Idea)
class Solution {
public int furthestBuilding(int[] H, int B, int L) {
int len = H.length - 1;
PriorityQueue<Integer> pq = new PriorityQueue<>();
for (int i = 0; i < len; i++) {
int diff = H[i+1] - H[i];
if (diff > 0) {
if (L > 0) {
pq.add(diff);
L--;
} else if (pq.size() > 0 && diff > pq.peek()) {
pq.add(diff);
B -= pq.poll();
} else B -= diff;
if (B < 0) return i;
}
}
return len;
}
}
C++ Code:
(Jump to: Problem Description || Solution Idea)
class Solution {
public:
int furthestBuilding(vector<int>& H, int B, int L) {
int len = H.size() - 1;
priority_queue<int> pq;
for (int i = 0; i < len; i++) {
int diff = H[i+1] - H[i];
if (diff > 0) {
if (L) pq.push(-diff), L--;
else if (!pq.empty() && diff > -pq.top())
pq.push(-diff), B += pq.top(), pq.pop();
else B -= diff;
if (B < 0) return i;
}
}
return len;
}
};
This content originally appeared on DEV Community and was authored by seanpgallivan
seanpgallivan | Sciencx (2021-04-26T09:33:43+00:00) Solution: Furthest Building You Can Reach. Retrieved from https://www.scien.cx/2021/04/26/solution-furthest-building-you-can-reach/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.