力扣 5865. 访问完所有房间的第一天 dp 前缀和优化

129 篇文章 2 订阅
3 篇文章 0 订阅

https://leetcode-cn.com/problems/first-day-where-you-have-been-in-all-the-rooms/
在这里插入图片描述
思路:经典读错题+想歪。分析后不难发现,第一次到达房间 i i i,下一次必定要回到 < = i <=i <=i的房间 j j j(不妨把这个操作叫做回访),且此时 < i <i <i的房间都到达了偶数次,那么对于 [ j , i ) [j,i) [j,i)的每个房间,我们都需要再次回访,如果用 d p i dp_i dpi表示在位置 i i i进行回访操作后再重新回到位置 i i i所需要的天数,那么有:
d p i = i − j + 1 + ∑ k = j i − 1 d p k dp_i=i-j+1+\sum_{k=j}^{i-1}dp_k dpi=ij+1+k=ji1dpk
显然最终结果就等于 ∑ i = 0 n − 2 d p i + n − 1 \sum_{i=0}^{n-2}dp_i+n-1 i=0n2dpi+n1。但是这样转移复杂度是 O ( n 2 ) O(n^2) O(n2)的。那么考虑记录 d p dp dp的前缀和 s s s,则转移方程转换为:
s i = s i − 1 + d p i = s i − 1 + s i − 1 − s j − 1 + i − j + 1 s_i=s_{i-1}+dp_i=s_{i-1}+s_{i-1}-s_{j-1}+i-j+1 si=si1+dpi=si1+si1sj1+ij+1
最终结果等于 s n − 2 + n − 1 s_{n-2}+n-1 sn2+n1,这样复杂度就优化到了 O ( n ) O(n) O(n)

class Solution {
public:
    int firstDayBeenInAllRooms(vector<int>& nextVisit) {
        int n=nextVisit.size();
        using ll=long long;
        const int mod=1e9+7;
        vector<ll> sum(n-1);
        sum[0]=1;
        for(int i=1;i<n-1;i++)
        {
            ll val=0;
            if(nextVisit[i]>0)
                val=sum[nextVisit[i]-1];
            sum[i]=(sum[i-1]+sum[i-1]-val+i-nextVisit[i]+1+mod)%mod;
        }
        return (sum[n-2]+n-1)%mod;
    }
};

等价的代码:

class Solution {
public:
    int firstDayBeenInAllRooms(vector<int>& nextVisit) {
        int n=nextVisit.size();
        using ll=long long;
        const int mod=1e9+7;
        vector<ll> sum(n);
        for(int i=0;i<n-1;i++)
            sum[i+1]=(sum[i]+sum[i]-sum[nextVisit[i]]+i-nextVisit[i]+1+mod)%mod;
        return (sum[n-1]+n-1)%mod;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值