文章目录
- 题目
- 思路
- 代码
- 结果
题目
题目链接
小扣当前位于魔塔游戏第一层,共有 N 个房间,编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于数组 nums,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减少对应数值;0 表示房间对血量无影响。
小扣初始血量为 1,且无上限。假定小扣原计划按房间编号升序访问所有房间补血/打怪,为保证血量始终为正值,小扣需对房间访问顺序进行调整,每次仅能将一个怪物房间(负数的房间)调整至访问顺序末尾。请返回小扣最少需要调整几次,才能顺利访问所有房间。若调整顺序也无法访问完全部房间,请返回 -1。
示例 1:
输入:nums = [100,100,100,-250,-60,-140,-50,-50,100,150]
输出:1
解释:初始血量为 1。至少需要将 nums[3] 调整至访问顺序末尾以满足要求。
示例 2:
输入:nums = [-200,-300,400,0]
输出:-1
解释:调整访问顺序也无法完成全部房间的访问。
提示:
- 1 <= nums.length <= 105
- -105 <= nums[i] <= 105
思路
在遍历每个房间的过程中,我们始终保持一个原则:尽可能减少调整房间顺序的次数,同时确保在每个房间结束时生命值都大于0。为了达到这个目标,我们采用了一种贪心的策略。
当我们访问到一个房间时,如果该房间的值是负数,我们并不立即处理它,而是将它放入一个小根堆(也就是优先队列,其中元素按照从小到大的顺序排列)中。这样做的原因是,我们希望在生命值不足时,能够找到一个最小的负数来“调整”,即将其放到最后,从而减少它对生命值的即时影响。
如果在某个房间结束时,生命值降到了0或以下,我们就从小根堆中取出最小的元素(也就是之前存储的某个负数房间的值),将它加到生命值上。这个操作相当于将那个房间调整到了最后,因为无论我们如何调整前面的房间顺序,总和是不变的,所以这种贪心选择是最优的。
遍历完所有房间后,我们还需要检查一件事:之前从小根堆中取出的所有元素的和(也就是那些被调整到最后的房间的总影响)需要重新加到生命值上。如果加上这些值后生命值还是小于或等于0,那么就说明无法通过调整房间顺序来保持生命值始终大于0,因此返回-1表示无解。
代码
class Solution {
public:int magicTower(vector<int>& nums){priority_queue<long long, vector<long long>, greater<long long>> q;long long ans = 0, hp = 1, delay = 0;for (int num : nums) {if (num < 0) {q.push(num);}hp += num;if (hp <= 0) {++ans;delay += q.top();hp -= q.top();q.pop();}}hp += delay;if(hp<0)return -1;return ans;}
};