Skip to content

Commit c659aea

Browse files
committed
Add: Add 2025/9/9
1 parent 3e82d22 commit c659aea

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# 2327. Number of People Aware of a Secret
2+
3+
On day `1`, one person discovers a secret.
4+
5+
You are given an integer `delay`, which means that each person will share the secret with a new person every day, starting from `delay` days after discovering the secret.
6+
You are also given an integer `forget`, which means that each person will `forget` the secret forget days after discovering it.
7+
A person cannot share the secret on the same day they forgot it, or on any day afterwards.
8+
9+
Given an integer `n`, return the number of people who know the secret at the end of day `n`.
10+
Since the answer may be very large, return it modulo `10^9 + 7`.
11+
12+
**Constraints:**
13+
14+
- `2 <= n <= 1000`
15+
- `1 <= delay < forget <= n`
16+
17+
## 基礎思路
18+
19+
這題是在模擬「祕密傳播」的過程:第 1 天只有 1 個人知道祕密;每個人在知道祕密 **滿 `delay` 天後才開始每天各分享給 1 個新的人**,並在 **滿 `forget` 天時就遺忘**(當天起不可再分享)。
20+
若以第 `d` 天為基準,今天能分享的人,正是那些在區間 **\[`d - forget + 1`, `d - delay`]** 這些天「剛學到祕密的人」。因此,今天新增學到祕密的總數就是這個區間內「每日新學到的人數」之和。
21+
22+
直接每天做區間加總會是 $O(n^2)$;關鍵在於用**滑動視窗**把「可分享人數」視為上述區間的移動總和:
23+
24+
- 當天加入 `d - delay` 這一天的新學者(因為他們今天起可分享)。
25+
- 同步移除 `d - forget` 這一天的新學者(因為他們今天起遺忘,不可再分享)。
26+
同時維護「仍記得祕密的人數」作為答案,對上限取模即可。
27+
28+
## 解題步驟
29+
30+
### Step 1:初始化常數與每日新學者記錄
31+
32+
建立模數與一個長度 `n + 1` 的型別化陣列,記錄「每天新學到祕密的人數」。第 1 天有 1 人知道祕密。
33+
34+
```typescript
35+
const MOD = 1_000_000_007;
36+
37+
// 1. 初始化型別化陣列以記錄每天新學到祕密的人數
38+
const newLearners = new Int32Array(n + 1);
39+
newLearners[1] = 1;
40+
```
41+
42+
### Step 2:初始化追蹤變數
43+
44+
維護兩個量:
45+
46+
- 「今天可分享的人數」:代表當天會帶來的新學者數。
47+
- 「仍記得祕密的人數」:用來在最後回傳答案。
48+
49+
```typescript
50+
// 2. 追蹤變數
51+
let numberShareable = 0; // 今天有資格分享的人數
52+
let numberRemembering = 1; // 第 1 天結束時仍記得的人數
53+
```
54+
55+
### Step 3:主迴圈(第 2 天到第 n 天),用滑動視窗更新
56+
57+
對於每天 `day`
58+
59+
- 先讓「遺忘日 = day - forget」這批人從「仍記得」中移除;若也在可分享名單中,同步從可分享移除。
60+
- 再把「開始分享日 = day - delay」這批人加入「可分享」。
61+
- 當天新學者數就是目前「可分享」的人數;更新兩個統計量並做模數維護。
62+
63+
```typescript
64+
// 3. 從第 2 天處理到第 n 天
65+
for (let day = 2; day <= n; day++) {
66+
const indexToStartSharing = day - delay;
67+
const indexToForget = day - forget;
68+
69+
// 今天會遺忘的人(把其從仍記得的總數扣掉)
70+
if (indexToForget >= 1) {
71+
numberRemembering -= newLearners[indexToForget];
72+
if (numberRemembering < 0) {
73+
numberRemembering += MOD;
74+
}
75+
}
76+
77+
// 新增「今天開始可以分享」的人(delay 天前學到的人)
78+
if (indexToStartSharing >= 1) {
79+
numberShareable += newLearners[indexToStartSharing];
80+
if (numberShareable >= MOD) {
81+
numberShareable -= MOD;
82+
}
83+
}
84+
85+
// 從可分享名單中移除「今天剛遺忘」的人
86+
if (indexToForget >= 1) {
87+
numberShareable -= newLearners[indexToForget];
88+
if (numberShareable < 0) {
89+
numberShareable += MOD;
90+
}
91+
}
92+
93+
// 指派「今天的新學者數」= 目前可分享的人數
94+
const todaysNewLearners = numberShareable;
95+
newLearners[day] = todaysNewLearners;
96+
97+
// 更新仍記得的人數(加入今天的新學者),並取模
98+
numberRemembering += todaysNewLearners;
99+
if (numberRemembering >= MOD) {
100+
numberRemembering -= MOD;
101+
}
102+
}
103+
```
104+
105+
### Step 4:回傳答案
106+
107+
`n` 天結束時「仍記得祕密的人數」即為答案。
108+
109+
```typescript
110+
// 4. 最終答案為第 n 天結束時仍記得的人數
111+
return numberRemembering;
112+
```
113+
114+
## 時間複雜度
115+
116+
- 透過滑動視窗,每一天的更新皆為 $O(1)$,總共迭代 `n` 天。
117+
- 總時間複雜度為 $O(n)$。
118+
119+
> $O(n)$
120+
121+
## 空間複雜度
122+
123+
- 需要一個長度為 `n + 1` 的陣列記錄每天新學者數,額外只用到常數變數。
124+
- 總空間複雜度為 $O(n)$。
125+
126+
> $O(n)$
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
function peopleAwareOfSecret(n: number, delay: number, forget: number): number {
2+
const MOD = 1_000_000_007;
3+
4+
// 1. Initialize typed array to record new learners on each day
5+
const newLearners = new Int32Array(n + 1);
6+
newLearners[1] = 1;
7+
8+
// 2. Tracking variables
9+
let numberShareable = 0; // People eligible to share today
10+
let numberRemembering = 1; // People who still remember at the end of day 1
11+
12+
// 3. Process from day 2 to n
13+
for (let day = 2; day <= n; day++) {
14+
const indexToStartSharing = day - delay;
15+
const indexToForget = day - forget;
16+
17+
// People who forget today
18+
if (indexToForget >= 1) {
19+
numberRemembering -= newLearners[indexToForget];
20+
if (numberRemembering < 0) {
21+
numberRemembering += MOD;
22+
}
23+
}
24+
25+
// Add new sharers (delay days ago)
26+
if (indexToStartSharing >= 1) {
27+
numberShareable += newLearners[indexToStartSharing];
28+
if (numberShareable >= MOD) {
29+
numberShareable -= MOD;
30+
}
31+
}
32+
33+
// Remove people who just forgot from sharers
34+
if (indexToForget >= 1) {
35+
numberShareable -= newLearners[indexToForget];
36+
if (numberShareable < 0) {
37+
numberShareable += MOD;
38+
}
39+
}
40+
41+
// Assign today's new learners
42+
const todaysNewLearners = numberShareable;
43+
newLearners[day] = todaysNewLearners;
44+
45+
// Update remembering pool
46+
numberRemembering += todaysNewLearners;
47+
if (numberRemembering >= MOD) {
48+
numberRemembering -= MOD;
49+
}
50+
}
51+
52+
// 4. Final result is people still remembering on day n
53+
return numberRemembering;
54+
}

0 commit comments

Comments
 (0)