6109. 知道秘密的人数
在第 1 天,有一个人发现了一个秘密。
给你一个整数 delay ,表示每个人会在发现秘密后的 delay 天之后,每天 给一个新的人 分享 秘密。同时给你一个整数 forget ,表示每个人在发现秘密 forget 天之后会 忘记 这个秘密。一个人 不能 在忘记秘密那一天及之后的日子里分享秘密。
给你一个整数 n ,请你返回在第 n 天结束时,知道秘密的人数。由于答案可能会很大,请你将结果对 109 + 7 取余 后返回。
示例 1:
输入:n = 6, delay = 2, forget = 4
输出:5
解释:
第 1 天:假设第一个人叫 A 。(一个人知道秘密)
第 2 天:A 是唯一一个知道秘密的人。(一个人知道秘密)
第 3 天:A 把秘密分享给 B 。(两个人知道秘密)
第 4 天:A 把秘密分享给一个新的人 C 。(三个人知道秘密)
第 5 天:A 忘记了秘密,B 把秘密分享给一个新的人 D 。(三个人知道秘密)
第 6 天:B 把秘密分享给 E,C 把秘密分享给 F 。(五个人知道秘密)
示例 2:
输入:n = 4, delay = 1, forget = 3
输出:6
解释:
第 1 天:第一个知道秘密的人为 A 。(一个人知道秘密)
第 2 天:A 把秘密分享给 B 。(两个人知道秘密)
第 3 天:A 和 B 把秘密分享给 2 个新的人 C 和 D 。(四个人知道秘密)
第 4 天:A 忘记了秘密,B、C、D 分别分享给 3 个新的人。(六个人知道秘密)
提示:
2 <= n <= 1000
1 <= delay < forget <= n
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-people-aware-of-a-secret
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
方法一:使用hash表的实现
思路:
使用hash表存放第i天知道的人数,然后当到达第i天的时候,减去当天遗忘的人数,再加上当天新增的人数,最后再用hash表存放当天新增的人数,当到达第n+1天的时候退出循环。
代码如下:
class Solution {
public:
int peopleAwareOfSecret(int n, int delay, int forget)
{
long mod = 1e9 + 7;
std::unordered_map<long, long> m; // key==>第几天,value==>这天有几个人知道
m[1] = 1;
long i = 1; // 第几天
long total = 1;
while (i <= n)
{
if (i > forget)// 当天遗忘的人数
{
if (m.find(i - forget) != m.end())
{
long v = m[i - forget];
if (total < v)
{
total += mod;
}
total -= v;
m.erase(i - forget);
}
}
if (i > delay)
{
long today = 0;// 当天新增的人数
for (long k = i; k >= i - forget; --k)
{
if (i - k < delay)
{
continue;
}
if (m.find(k) == m.end())
{
continue;
}
today += m[k];
}
if (today > 0)
{
today %= mod;
total = (total + today) % mod;
m[i] = today;
}
}
i++;
}
return total % mod;
}
};
方法二:动态规划解法
思路:
- 定义dp[i]为第i天新增的知道秘密的人数
- 初始化:dp[0] = 0,dp[1] = 1
- 状态转移方程:dp[i] = accumulate(dp+(i-forget+1),dp+(i-delay)) - dp[i-forget],也就是第i天新增的人数等于在[i-forget+1,i-delay]区间之和,再减dp[i-forget](表示这一天要遗忘这么多人)
- 返回值:使用一个整形累加每天新增人数以及减去每天遗忘人数
代码从略,有兴趣可以看其他的人解法~~