记忆化搜索&动态规划,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];
    }
};
相关推荐
NAGNIP3 小时前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试
NAGNIP3 小时前
一文搞懂激活函数!
算法·面试
董董灿是个攻城狮3 小时前
AI 视觉连载7:传统 CV 之高斯滤波实战
算法
爱理财的程序媛9 小时前
openclaw 盯盘实践
算法
MobotStone13 小时前
Google发布Nano Banana 2:更快更便宜,图片生成能力全面升级
算法
颜酱16 小时前
队列练习系列:从基础到进阶的完整实现
javascript·后端·算法
用户57573033462416 小时前
两数之和:从 JSON 对象到 Map,大厂面试官到底在考察什么?
算法
程序猿追16 小时前
“马”上行动:手把手教你基于灵珠平台打造春节“全能数字管家”
算法
ZPC82101 天前
docker 镜像备份
人工智能·算法·fpga开发·机器人