LeetCode 1997. 访问完所有房间的第一天 思维动态规划

LeetCode 1997. 访问完所有房间的第一天

题目描述

你需要访问 n 个房间,房间从 0 到 n - 1 编号。同时,每一天都有一个日期编号,从 0 开始,依天数递增。你每天都会访问一个房间。

最开始的第 0 天,你访问 0 号房间。给你一个长度为 n 且 下标从 0 开始 的数组 nextVisit。在接下来的几天中,你访问房间的 次序 将根据下面的 规则 决定:

假设某一天,你访问 i 号房间。
如果算上本次访问,访问 i 号房间的次数为 奇数,那么 第二天 需要访问 nextVisit[i] 所指定的房间,其中 0 <= nextVisit[i] <= i。
如果算上本次访问,访问 i 号房间的次数为 偶数,那么 第二天 需要访问 (i + 1) mod n 号房间。
请返回你访问完所有房间的第一天的日期编号。题目数据保证总是存在这样的一天。由于答案可能很大,返回对 10^9 + 7 取余后的结果。

样例
输入:nextVisit = [0,0]
输出:2
解释:

  • 第 0 天,你访问房间 0。访问 0 号房间的总次数为 1,次数为奇数。
    下一天你需要访问房间的编号是 nextVisit[0] = 0
  • 第 1 天,你访问房间 0。访问 0 号房间的总次数为 2,次数为偶数。
    下一天你需要访问房间的编号是 (0 + 1) mod 2 = 1
  • 第 2 天,你访问房间 1。这是你第一次完成访问所有房间的那天。
    输入:nextVisit = [0,0,2]
    输出:6
    解释:
    你每天访问房间的次序是 [0,0,1,0,0,1,2,...]。
    第 6 天是你访问完所有房间的第一天。
    输入:nextVisit = [0,1,2,0]
    输出:6
    解释:
    你每天访问房间的次序是 [0,0,1,1,2,2,3,...]。
    第 6 天是你访问完所有房间的第一天。
    限制
    n == nextVisit.length
    2 <= n <= 10^5
    0 <= nextVisit[i] <= i

算法

(动态规划)

  1. 本题的重要条件0 <= nextVisit[i] <= i,说明 i只能由i - 1到达,且必须是偶数次访问i-1,且可以推断出必须经过两次i-1才能到达i。

  2. 状态表示:f(i)为第一次访问第i房间时的日期。

  3. 状态转移:f(i) = 第二次访问i-1房天数 + 1

    • 第一次到达第i - 1个房间的步数f(i - 1)

    • 第二次到达第i - 1个房间的步数,我们第一次到达了第i - 1个房间,下一步必然是走到t = nextVisit[i - 1]号房间,推断0~i-2房间访问的次数均为偶数(可视化0次)相当于从新开始,但是0到t可以忽略,f(i - 1) - t + 1,加的步骤。加 1是需要补上从是需要补上从i到到t的那一步。

      \[f(i - 1) - f(t) + 1 \]

    • 到达第i个房间的一步。

    • 答案汇总: f[i] = 2 * f[i - 1] - f[t] + 2

  4. 初始化:f(0)=0,可以理解为第一次访问第 0个房间仅需 0 天。

时间复杂度

  • 状态数为 \(O(n)\) ,转移时间为常数,故总时间复杂度为 \(O(n)\)

空间复杂度

  • 需要 \(O(n)\) 的额外空间存储状态。
class Solution {
public:
    int firstDayBeenInAllRooms(vector<int>& nextVisit) {
        const int mod = 1000000007;
        int n = nextVisit.size();
        vector<int> f(n);
        f[0] = 0;
        for(int i = 1; i < n; i++){
            int t = nextVisit[i - 1];
            f[i] = (2 * f[i - 1] - f[t] + 2) % mod;
            if(f[i] < 0) f[i] += mod;
        }
        return f[n - 1];
    }
};
posted @ 2021-11-05 11:16  pxlsdz  阅读(103)  评论(0编辑  收藏  举报