日报
- 今天只有一题
题目
一、2327. 知道秘密的人数
链接: 2327. 知道秘密的人数
1. 题目描述
2. 思路分析
这题其实是斐波那契兔子的变种。
周赛时用的*O(n2)*的线性DP,思考起来比较复杂,具体可以参加我之前的[LeetCode周赛复盘] 第 300 场周赛20220703。
- 今天写一下*O(n)*的做法。
- 定义f[i]为第i天新知道秘密的人的人数,那么转移可以通过刷表法转移。
- 通常我们做dp都是针对dp[i],看它能从哪个子状态(如dp[i-1]…dp[j],j<i)转移而来,叫填表法;这里刷表法指的是,处理dp[i]时,看dp[i]能对哪个dp[k]产生贡献,去更新dp[k]的值。
- 刷表法的题目之前刚好做过一道: 871. 最低加油次数,当然这题可以贪心+优先队列做。
- 返回这题,刷表其实非常简单了,对于第i天新知道秘密的人数,他们会在第i+delay天开始产生新的人,一直到i+forget天结束(这里注意不要越界)。
- 最后一段会产生一个如果这帮人产生新人的时间越界了,且他们没遗忘,那他们要累计到答案里,用cnt_b储存(cnt_b代表知道秘密但不能分享的人);
- 这个算法依然是*O(n2)*的,我们发现内层循环有一个区间加的运算,因此可以差分数组优化。
3. 代码实现
MOD = 10**9+7
class Solution:
def peopleAwareOfSecret(self, n: int, delay: int, forget: int) -> int:
diff = [0] * n # 用差分数组储存 第i天知道秘密且能分享的人
cnt_b = 0
diff[0] = 1
diff[1] = -1
f = 0
for i,d in enumerate(diff):
f = (f+d)%MOD
if i+delay>=n:
cnt_b += f
else:
diff[i+delay] += f
if i+forget<n:
diff[i+forget] -= f
return (f + cnt_b)%MOD