题目大意
给你一个整数数组 heights ,表示建筑物的高度。另有一些砖块 bricks 和梯子 ladders 。
你从建筑物 0 开始旅程,不断向后面的建筑物移动,期间可能会用到砖块或梯子。
当从建筑物 i 移动到建筑物 i+1(下标 从 0 开始 )时:
如果当前建筑物的高度 大于或等于 下一建筑物的高度,则不需要梯子或砖块
如果当前建筑的高度 小于 下一个建筑的高度,您可以使用 一架梯子 或 (h[i+1] - h[i]) 个砖块
如果以最佳方式使用给定的梯子和砖块,返回你可以到达的最远建筑物的下标(下标 从 0 开始 )。
题目用例就去看原题吧…
解题思路
如果后面的建筑物更高,则有两种选择:用一个梯子;用高度差数量的砖块;
分析题目可知,无论高度差有多少,一个梯子总是可以爬上去,因此:应该在高度差大的地方用梯子,高度差小的地方用砖头;
用小根堆(大小为梯子数量)表示用梯子时的最小高度差。则若当前高度差为x,小根堆的堆顶元素为y:
- x<=0:表示不需要梯子或者砖块就可以到达,结果直接+1即可;
- 若x<=y:则x高度差的位置应该用砖头(这样可以将砖头的使用数量降到最低,保留更多砖头):(1)如果当前砖头的数量不足了,则无法再进行下去了,返回结果;(2)否则将砖头数量扣除高度差;
- 若x>y:表示这里的高度差更高,高度差为y的地方使用砖头,同样根据上面的条件进行判断即可;
class Solution{
public:
int furthestBuilding(vector<int> & heights, int bricks, int ladders){
// 没有梯子的情况,直接算一遍就行了
if (ladders == 0){
return zeroLadder(heights, bricks);
}
// 如果梯子足够多,则全都可以走完
if (heights.size() <= ladders){
return heights.size() - 1;
}
// 创建梯子数量的小根堆,表示用梯子的高度差
priority_queue<int, vector<int>, greater<int>> myqueue;
int ans = 0, i = 1, diff = 0;
// 初始化的时候这里可能存入了负值,后面需要判断堆顶元素的正负
for (; i < heights.size() && myqueue.size() < ladders; ++i){
myqueue.push(heights[i] - heights[i - 1]);
}
for (; i < heights.size(); ++i){
// 当前高度差
diff = heights[i] - heights[i - 1];
// 大于堆顶元素,在堆顶位置应该考虑用砖头
if (diff >= myqueue.top()){
int curNeed = myqueue.top();
// 如果砖头不够了,则结束
if (curNeed > bricks){
break;
}
myqueue.pop();
// 如果高度差为正,则扣除一部分砖头
if (curNeed > 0){
bricks -= curNeed;
}
++ans;
// 将现在的高度差加入堆中
myqueue.push(diff);
}
// 当前位置考虑用砖头
else{
if (diff > bricks){
break;
}
if (diff > 0){
bricks -= diff;
}
ans++;
}
}
return ans + ladders;
}
int zeroLadder(vector<int> & heights, int bricks){
int ans = 0;
for(int i = 1; i < heights.size(); ++i){
if (heights[i] - heights[i - 1] <= 0){
++ans;
continue;
}
if (heights[i] - heights[i - 1] > bricks){
break;
}
++ans;
bricks -= (heights[i] - heights[i -1]);
}
return ans;
}
};