难度评级:中等
小扣当前位于魔塔游戏第一层,共有 N
个房间,编号为 0 ~ N-1
。每个房间的补血道具/怪物对于血量影响记于数组 nums
,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减少对应数值;0
表示房间对血量无影响。
小扣初始血量为 1,且无上限。假定小扣原计划按房间编号升序访问所有房间补血/打怪,为保证血量始终为正值,小扣需对房间访问顺序进行调整,每次仅能将一个怪物房间(负数的房间)调整至访问顺序末尾。请返回小扣最少需要调整几次,才能顺利访问所有房间。若调整顺序也无法访问完全部房间,请返回 -1。
输入:
nums = [100,100,100,-250,-60,-140,-50,-50,100,150]
输出:
1
解释:初始血量为 1。至少需要将 nums[3] 调整至访问顺序末尾以满足要求。
题解思路:优先队列与贪心算法
分为两种情况
第一种,无论如何调整位置都无法通过魔塔,即nums值总和小于等于0,直接遍历求和即可
第二种,通过调整房间位置可以通过魔塔,已知每次只能将某一房间调至末尾一次,所以采用边处理边调整的思路。
当小扣位于x房间时,当前血量无法通过,故需要回溯至前面某一房间,为了使调整次数最少,贪心思想告诉我们需要将最小的负数(绝对值最大的负数)移至最后,故为了方便调用,推荐使用小顶堆的优先队列对已通过的房间进行记录,优先队列里仅记录小于0的房间。
Ps:不会使用或忘记priority_queue的小伙伴可以看看基本使用文档.
题解代码如下
class Solution {
public:
long long life = 1; // 生命值
int total = 0; // 步数记录
priority_queue<int, vector<int>, greater<int>> que;
// 定义优先队列,构建小顶堆
int magicTower(vector<int>& nums) {
for (int i : nums) life += i;
if (life <= 0){
return -1; // 总和小于0无论如何都无法通过
}
life = 1;
for (int i = 0; i < nums.size(); i++){
if (nums[i] < 0){ // 记录已通过的房间
que.push(nums[i]);
}
life += nums[i];
if (life <= 0){
int temp = que.top(); // 记录队头最小的负数(绝对值最大)
que.pop();
nums.push_back(temp); // 放到vector队
life -= temp; // 恢复
total++; // 计数
}
}
return total;
}
};