记忆化搜索&动态规划,LeetCode 1997. 访问完所有房间的第一天

一、题目

1、题目描述

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

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

  • 假设某一天,你访问 i 号房间。
  • 如果算上本次访问,访问 i 号房间的次数为 奇数 ,那么 第二天 需要访问 nextVisit[i] 所指定的房间,其中 0 <= nextVisit[i] <= i
  • 如果算上本次访问,访问 i 号房间的次数为 偶数 ,那么 第二天 需要访问 (i + 1) mod n 号房间。

请返回你访问完所有房间的第一天的日期编号。题目数据保证总是存在这样的一天。由于答案可能很大,返回对 109 + 7 取余后的结果。

2、接口描述

​python3
python 复制代码
class Solution:
    def firstDayBeenInAllRooms(self, nextVisit: List[int]) -> int:
cpp
cpp 复制代码
class Solution {
public:
    int firstDayBeenInAllRooms(vector<int>& nextVisit) {

    }
};

3、原题链接

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


二、解题报告

1、思路分析

要求什么?

访问完所有房间的第一天

由于根据题目要求,第一次访问第n个房间的前提是第n - 1个房间被访问两次,访问第n - 1个房间两次的前提是第n - 2个房间访问4次......

因而访问完所有房间的第一天就是第一次访问第n个房间的天数

和子问题的关系?

第一次访问第n个房间 <=> 第二次访问第n - 1个房间 + 1

<=> 第一次访问第n - 1个房间 + 从奇数次访问nextVisit[n - 1]到第二次访问第n - 1个房间 + 1 + 1

而从奇数次访问nextVisit[n - 1]到第二次访问第n - 1个房间等价为第一次访问第n - 1个房间的天数减去第一次访问第nextVisit[n - 1]个房间

设f(i)为第一次访问i号房间的天数

那么f(i) = f(i - 1) * 2 + f(nextVisit[i - 1]) + 2

我们可以用记忆化搜索来实现,也可以递推实现

2、复杂度

时间复杂度: O(n) 空间复杂度:O(n)

3、代码详解

​F1 记忆化搜索

python3

python 复制代码
class Solution:
    def firstDayBeenInAllRooms(self, nextVisit: List[int]) -> int:
        n, mod = len(nextVisit), 1000000007
        @cache
        def f(x: int) -> int:
            if not x:
                return 0
            return (2 + f(x - 1) * 2 - f(nextVisit[x - 1]) + mod) % mod
        return f(n - 1)

cpp

cpp 复制代码
class Solution {
public:
    int mem[100005];
    static constexpr int mod = 1e9 + 7;
    int f(int x, vector<int>& nextVisit){
        if(~mem[x]) return mem[x];
        return mem[x] = (2 + 2LL * f(x - 1, nextVisit) - f(nextVisit[x - 1], nextVisit) + mod) % mod;
    }
    int firstDayBeenInAllRooms(vector<int>& nextVisit) {
        int n = nextVisit.size();
        memset(mem, -1, sizeof mem);
        mem[0] = 0;
        return f(n - 1, nextVisit);
    }
};
F2 递推

python

python 复制代码
class Solution:
    def firstDayBeenInAllRooms(self, nextVisit: List[int]) -> int:
        n, mod = len(nextVisit), 1_000_000_007
        f = [0] * n
        for i in range(1, n):
            f[i] = (2 + f[i - 1] * 2 - f[nextVisit[i - 1]] + mod) % mod
        return f[n - 1]

cpp

cpp 复制代码
class Solution {
public:
static constexpr int mod = 1'000'000'007;
    int firstDayBeenInAllRooms(vector<int>& nextVisit) {
        int n = nextVisit.size();
        vector<int> f(n, 0);
        for(int i = 1; i < n; i++)
            f[i] = (2LL + 2LL * f[i - 1] - f[nextVisit[i - 1]] + mod) % mod;
        return f[n - 1];
    }
};
相关推荐
im_AMBER5 分钟前
算法笔记 16 二分搜索算法
c++·笔记·学习·算法
高洁017 分钟前
【无标具身智能-多任务与元学习】
神经网络·算法·aigc·transformer·知识图谱
leoufung11 分钟前
逆波兰表达式 LeetCode 题解及相关思路笔记
linux·笔记·leetcode
识醉沉香29 分钟前
广度优先遍历
算法·宽度优先
中國龍在廣州35 分钟前
现在人工智能的研究路径可能走反了
人工智能·算法·搜索引擎·chatgpt·机器人
快手技术36 分钟前
NeurIPS 2025 | 可灵团队提出 Flow-GRPO, 首次将在线强化学习引入流匹配生成模型
算法
星释1 小时前
Rust 练习册 67:自定义集合与数据结构实现
数据结构·算法·rust
前端小L2 小时前
图论专题(十九):DAG上的“关键路径”——极限规划「并行课程 III」
算法·矩阵·深度优先·图论·宽度优先
scx201310042 小时前
20251116 树状DP总结
算法·深度优先·图论
Aspect of twilight2 小时前
LeetCode华为大模型岗刷题
python·leetcode·华为·力扣·算法题