LeetCode/知道秘密的人数
在第 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;
}
};