知道秘密的人数
前言
刷算法题(中等题以上)有两种境界,第一种就是秒算法题,这需要大量的知识积累,以及快速抓住核心问题并理解的能力;第二种是基本能力,就是需要做到见招拆招,大多数招是隐式的,所以需要通过认真分析才能看到背后的招式,利用自己积累的知识灵活解题。
一、知道秘密的人数
二、问题分析+时间流逝问题
package competition.single300;
import java.util.LinkedList;
import java.util.List;
public class PeopleAwareOfSecret {
/*
每个人每天能否传播,要看当天是不是在delay之后,forget之前,即[delay,forget)。
比如第i天,A知道了密码,设置delay = i + delay;forget = i + forget.
现在第j天,A能否传播秘密,当j >= delay && j < forget;
每一天传播的人为一组,他们有相同的delay和forget;前后两组的delay和forget都相差1.
每传播一次,就加一次知道秘密的人数。
*/
// 采用一次索引形式,减轻取余数的复杂书写。
final static int mod = (int) 1e9 + 7;
public int peopleAwareOfSecret(int n, int delay, int forget) {
List<int[]> que = new LinkedList<>();
// 第1天,该组只有一个人知到秘密,且它将来可以传播秘密。
// que的size维持在forget大小,毕竟过了就忘了,在这期间,大于等于delay后的才能传播秘密。
que.add(new int[]{1, 1 + delay, 1 + forget});// 第1天为第1天时知道秘密。
int ans = 1;
for (int i = 2; i <= n; i++) {
// 将忘记秘密的一组人移除队列。
while (!que.isEmpty() && que.get(0)[2] <= i) {
// 知道秘密的人流失。
ans -= que.get(0)[0];
ans = (ans + mod) % mod;
// 他已经不能传播秘密了。
que.remove(0);
}
// 取今天能传播多少人,并将其加到ans中。
int spreed = 0;
for (int j = 0; j < que.size(); j++) {
if (i >= que.get(j)[1]) {
spreed += que.get(j)[0];
spreed %= mod;
}
}
// 得到传播总人数,不断累计。
ans = (ans + spreed) % mod;
// 并将其加入队列。
que.add(new int[]{spreed, i + delay, i + forget});
}
return ans;//5 2 3
}
public static void main(String[] args) {
new PeopleAwareOfSecret().peopleAwareOfSecret(4, 1, 3);
}
}
总结
1)分析问题 -> 找到核心问题 -> 联系已有知识灵活应用。
2)平时负重前行,周赛才有可能灵活分析与应用知识点,取其上着得其中,多实践找找差距。
3)题目说取余,我一贯以为是最后结果很大,int存不下,所以需要最后取余,结果一直通不过。题意是中间每个结果都需要取余,否则会溢出。所以平时题感/经验刷少了。