【Leetcode】LCP 30. 魔塔游戏

文章目录

  • 题目
  • 思路
  • 代码
  • 结果

题目

题目链接
小扣当前位于魔塔游戏第一层,共有 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& nums)
    {
        priority_queue, greater> 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;
    }
};

结果

【Leetcode】LCP 30. 魔塔游戏_第1张图片

你可能感兴趣的:(练习题(记录做题想法),leetcode,游戏,算法)