leetcode
leetcode 2901 ~ 2950
魔塔游戏

魔塔游戏

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 58 ms, 内存: 30.1 MB


/**
 * 思路:
 * 1. 先计算所有房间血量变化的总和。
 * 2. 如果总和加上初始血量小于1,返回-1。
 * 3. 否则,使用Stream API计算当前最小血量,并使用优先队列记录负数房间。
 * 4. 最后返回调整次数。
 */

import java.util.Arrays;
import java.util.PriorityQueue;

public class MagicTowerStream {
    public int magicTower(int[] nums) {
        long totalHealth = Arrays.stream(nums).sum();
        if (totalHealth < 0) return -1;

        long currentHealth = 1;
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        int adjustments = 0;

        for (int num : nums) {
            currentHealth += num;
            if (num < 0) {
                pq.add(num);
            }
            if (currentHealth < 1) {
                currentHealth -= pq.poll();
                adjustments++;
            }
        }

        return adjustments;
    }
}

解释

方法:

为了确保小扣在游戏中始终保持正的血量,题解使用贪心策略和优先队列(最小堆)来解决问题。整个思路是在遍历房间时,记录所有遇到的怪物(负数)。如果小扣的血量在任何点变为非正数,将最大的负数(即堆顶元素,因为是最小堆,存负数时绝对值最大的会在堆顶)移至房间数组的末尾,即延迟与这个怪物的战斗,并从总血量中减去这个数值。这个操作可视为将最危险的怪物延后处理,以便小扣在之前的房间中可能获得更多的血量。最后,如果经过所有调整后小扣的血量仍然不是正数,则返回-1,表示无法通过所有房间,否则返回调整次数。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在使用优先队列(最小堆)存储怪物时,为什么选择存储怪物而不是补血道具,这种选择对算法的效果有何影响?
选择存储怪物而非补血道具是因为在游戏中,保持生存比增加血量更为重要。怪物房间的负数值直接关系到是否能存活下去,因此需要优先处理。使用优先队列(最小堆)存储怪物可以快速地获取并调整对小扣威胁最大的负面影响(即绝对值最大的负数)。这种策略使得可以优先重新安排那些对当前血量影响最深刻的怪物,以最大程度地减少其对小扣的危害,从而提高整体的生存概率。
🦆
堆中存储负数的方式能确保每次移出的是绝对值最大的怪物吗?如何通过负数的存储实现这一点?
是的,堆中存储负数的方式能确保每次移出的是绝对值最大的怪物。在最小堆中,堆顶总是最小的元素,所以当我们将怪物的伤害值(负数)存入堆中时,最大的负数(即绝对值最大的负数)会被视为最小元素并置于堆顶。这样,每当需要减轻血量损失最大的怪物影响时,直接从堆顶移除该元素即可,这保证了我们总是优先处理最危险的怪物。
🦆
在代码中,`hp += num` 后紧接着检查 `hp <= 0` 来决定是否需要调整。这种检查方式是否可能遗漏某些情况,从而影响到调整策略的正确性?
这种检查方式理论上不会遗漏情况,因为它直接根据当前房间的影响后的血量来决策是否需要调整。每次小扣进入一个房间后,都会立即更新血量,并检查是否存活(即血量是否大于0)。如果血量非正,就意味着在不进行调整的情况下小扣无法继续前进。因此,这种方法能及时响应任何可能导致游戏失败的情况,并采取措施(如调整怪物房间顺序)以保持游戏可以继续进行。

相关问题