leetcode
leetcode 1751 ~ 1800
访问完所有房间的第一天

访问完所有房间的第一天

难度:

标签:

题目描述

代码结果

运行时间: 134 ms, 内存: 28.1 MB


/*
思路:
1. 使用Java Stream流的方式来解决该问题。
2. 使用一个数组来记录每个房间的访问次数,通过Stream处理来决定下一个房间。
*/

import java.util.stream.IntStream;

public class VisitRoomsStream {
    public int firstDayToVisitAllRooms(int[] nextVisit) {
        int n = nextVisit.length;
        int[] visitCount = new int[n];
        int[] current = new int[]{0}; // 当前位置初始化为房间0
        long[] currentDay = new long[]{0};
        boolean[] visited = new boolean[n];

        IntStream.iterate(0, i -> visited[i] ? -1 : current[0]).filter(i -> i != -1).forEach(i -> {
            if (visitCount[current[0]] == 0) {
                visited[current[0]] = true;
            }
            visitCount[current[0]]++;
            currentDay[0]++;

            if (visitCount[current[0]] % 2 == 1) {
                current[0] = nextVisit[current[0]];
            } else {
                current[0] = (current[0] + 1) % n;
            }
        });

        return (int) (currentDay[0] % (1e9 + 7));
    }

    public static void main(String[] args) {
        VisitRoomsStream vr = new VisitRoomsStream();
        int[] nextVisit = {0, 0, 2};
        System.out.println(vr.firstDayToVisitAllRooms(nextVisit)); // 输出 6
    }
}

解释

方法:

在这个题解中,使用了动态规划的方法。数组 dp 用来记录到达每个房间的第一天的日期编号。初始时,dp[0] = 0,表示第 0 天访问房间 0。对于每个房间 i (从 1 开始),根据题目中的访问规则,如果访问次数为奇数次,则访问 nextVisit[i],否则访问 (i + 1) % n。题解中,dp 的更新公式为 dp[i] = ((dp[i-1] << 1) + 2 - dp[nextVisit[i-1]]) % 1000000007,这个公式是基于之前房间的访问次数和规则计算得出。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在解题算法中,公式 `dp[i] = ((dp[i-1] << 1) + 2 - dp[nextVisit[i-1]]) % 1000000007` 是如何推导出来的?
该公式是基于访问房间的规则和动态规划的状态转移来推导的。从房间 i-1 到房间 i,如果访问次数是偶数次,我们访问房间 (i+1)%n,如果是奇数次,我们访问 nextVisit[i] 房间。考虑到每次访问房间 i 会再访问一次房间 i-1,因此从房间 i-1 到 i 至少需要 `dp[i-1] + 1` 天;再加上从房间 i-1 通过 nextVisit[i-1] 访问房间 i 的天数,即 `dp[nextVisit[i-1]] + 1`。综上,状态转移方程为 `dp[i] = dp[i-1] + 1 + (dp[i-1] + 1 - dp[nextVisit[i-1]])`,简化后得到 `dp[i] = 2 * dp[i-1] + 2 - dp[nextVisit[i-1]]`,最后取模以防止整数溢出。
🦆
为什么在初始化动态规划数组 `dp` 时只设置 `dp[0] = 0`,而没有为其他房间设置初始值?
在动态规划中,通常只需要初始化起点的状态,其他的状态值将通过状态转移方程逐步计算出来。在这个问题中,dp[0] = 0 表示第0天开始访问房间0,这是一个明确的初始条件。其他房间的访问天数依赖于前一房间的结果和状态转移方程,因此,在开始之前不需要为它们设置初始值。
🦆
题解中提到移除数组 `v` 的最后一个元素,这样做的具体原因是什么?是否对算法的正确性和最终结果有影响?
在题解中移除数组 `v` 的最后一个元素是为了简化计算过程,因为最后一个房间可以直接通过前一个房间的状态来计算它的状态,而不需要依赖于 nextVisit 的最后一个元素。这种处理方式简化了代码的复杂性,但不会影响算法的正确性或最终结果,因为最后一个房间的状态仍然会被计算和返回。
🦆
动态规划解法中使用的模数 `1000000007` 有什么特别的原因吗,还是只是为了防止整数溢出?
使用模数 `1000000007` 主要是为了防止整数溢出,并保持计算结果在可控的范围内。`1000000007` 是一个大的质数,常用于计算中以防止结果因为过大而溢出,并且在模运算中具有良好的性质,如简化冲突和分布均匀等。在各种编程竞赛和算法实现中,这个数经常被使用。

相关问题