leetcode
leetcode 3001 ~ 3050
守护太空城

守护太空城

难度:

标签:

题目描述

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

代码结果

运行时间: 50 ms, 内存: 16.1 MB


// 题目思路:
// 使用Java Stream可以简化对数组的处理。
// 我们仍然需要追踪每个舱室的屏障状态和能量消耗。

import java.util.Arrays;

public class MeteorShowerProtectionStream {

    public int minEnergy(int[] time, int[] position) {
        int n = time.length;
        int maxPosition = 101; // 最大舱室数
        int[] energy = new int[maxPosition];

        // 用Stream来简化对数组的遍历
        Arrays.stream(position).distinct().forEach(p -> {
            int maxTime = Arrays.stream(time).filter(t -> position[Arrays.binarySearch(position, p)] == p).max().orElse(0);
            energy[p] = maxTime;
        });

        int totalEnergy = Arrays.stream(energy).sum();
        return totalEnergy;
    }

    public static void main(String[] args) {
        MeteorShowerProtectionStream msp = new MeteorShowerProtectionStream();
        int[] time = {1, 2, 1};
        int[] position = {6, 3, 3};
        System.out.println(msp.minEnergy(time, position)); // 输出:5
    }
}

解释

方法:

这个问题可以通过使用动态规划来解决。首先,为了处理这些陨石的影响,我们需要知道每个位置在不同时间的状态。我们用一个位掩码来表示每个位置在各个时刻是否会受到陨石的影响。接着,我们定义两个动态规划数组,分别用来存储每个状态的最小能量消耗。具体来说,我们考虑每个位置的每个时间点,检查所有可能的前一个状态,计算从前一个状态转移到当前状态所需的最小能量,并更新当前状态的最小能量。这个过程涉及到位运算和状态压缩,是一个较为复杂的动态规划问题。

时间复杂度:

O(P * (2^T)^2)

空间复杂度:

O(2^T)

代码细节讲解

🦆
为什么在计算从前一个状态到当前状态的能量消耗时,使用了两个动态规划数组'states'和'states1'进行交替更新?
在这种动态规划问题中,使用两个数组'states'和'states1'进行交替更新是为了避免在更新过程中覆盖或混淆前一个时间点的状态值。在每一轮计算中,一个数组用于保存当前时间点的最小能量消耗值,而另一个数组保存上一个时间点的值。这样,我们可以保证在计算当前状态的最小能量时,有一个准确且未被修改的前一个状态参考,从而确保动态规划的正确性和效率。在每个时间点的计算完成后,两个数组的角色会交换,以准备下一个时间点的计算。
🦆
在处理状态转移时,代码中的'pre = (pre - 1) & m'这一行是如何工作的,它的逻辑和目的是什么?
这行代码用于生成当前状态掩码'm'的所有可能的子掩码,它是状态压缩动态规划中常见的技术,用于遍历所有子集。在这个特定的代码中,'pre'变量初始化为'm'的补码(即所有未被当前掩码覆盖的位都被设置为1),然后递减'pre'并与'm'进行按位与操作,这样可以确保只考虑'm'的有效位。这种操作可以生成'm'的所有子集,包括空集,从而允许我们在动态规划中考虑所有可能的前一个状态。每次循环生成的'pre'都是'm'的一个有效子集,直到'pre'变为0,即不包含任何有效位,循环结束。这种方法有效地利用位操作来遍历子集,从而提高状态转移的效率。

相关问题