LeetCode/知道秘密的人数

发布时间 2023-07-09 17:55:03作者: 失控D大白兔

在第 1 天,有一个人发现了一个秘密。
给你一个整数 delay ,表示每个人会在发现秘密后的 delay 天之后,每天 给一个新的人分享秘密。
同时给你一个整数 forget ,表示每个人在发现秘密 forget 天之后会 忘记 这个秘密。一个人不能在忘记秘密那一天及之后的日子里分享秘密。

1. 刷表法

提前计算出后面增加的人数

class Solution {
    const int MOD = 1e9 + 7;
public:
    int peopleAwareOfSecret(int n, int delay, int forget) {
        int f[n]; memset(f, 0, sizeof(f)); //初始化为0,记录当天新增的人数
        f[0] = 1; //初始有一个人发现秘密
        for (int i = 0; i < n ; ++i) { //遍历每一天
            for (int j = i + delay; j < min(i + forget, n); ++j)//遍历作用范围区间
                f[j] = (f[j] + f[i]) % MOD; //预计新增人数
        }
        //把结束那一天还没有遗忘的人数加起来
        int res = 0;
        for(int i = n - forget; i < n; i++)
            res = (res + f[i])% MOD;
        return res;
    }
};

2. 差分数组

一段区间的元素都加上同一个数的操作
使用差分数组实现,差分数组只修改边界
使对连续数组的同一修改时间复杂度减少为常数

class Solution {
    const int MOD = 1e9 + 7;
public:
    int peopleAwareOfSecret(int n, int delay, int forget) {
        int diff[n]; memset(diff, 0, sizeof(diff));
        diff[0] = 1; // f[0] = 1,相当于 diff[0] = 1, diff[1] = -1
        diff[1] = MOD - 1; //第一次操作,将dp[0]修改为1,表现在差分数组中,就是diff[0]=1,diff[1]=-1
        int f = 0, cnt_b = 0;
        for (int i = 0; i < n; ++i) { //遍历所有数
            f = (f + diff[i]) % MOD;//将数组压缩成一维,因为f[i]都为0,所以只用从前面转移
            if (i  >= n - forget) cnt_b = (cnt_b + f) % MOD; //计算
            if(i + delay < n)   diff[i + delay] = (diff[i + delay] + f) % MOD;//左边界增加
            if (i + forget < n) diff[i + forget] = (diff[i + forget] - f + MOD) % MOD; // 右边界减少
        }
        return cnt_b % MOD;
    }
};