一、题目
1、题目描述
你需要访问
n
个房间,房间从0
到n - 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、原题链接
二、解题报告
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];
}
};