[力扣每日习题][LCP 30]. 魔塔游戏 2024.02.06

难度评级:中等

小扣当前位于魔塔游戏第一层,共有 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, greater> que;
    // 定义优先队列,构建小顶堆
    int magicTower(vector& 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;
    }
};

你可能感兴趣的:(leetcode,算法,c++)