Skip to content

Commit 5b558c0

Browse files
committed
feat: add solutions for lc No.2657
1 parent b05530c commit 5b558c0

9 files changed

Lines changed: 207 additions & 25 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ package-lock.json
1414
!.cache/plugin/git-committers/
1515
!.cache/plugin/git-committers/page-authors.json
1616

17+
# Claude
18+
.claude/settings.local.json
19+
1720
# pnpm
1821
pnpm-lock.yaml
1922
.pnpm-store/

README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,6 @@
173173
- [找到最小生成树里的关键边和伪关键边](/solution/1400-1499/1489.Find%20Critical%20and%20Pseudo-Critical%20Edges%20in%20Minimum%20Spanning%20Tree/README.md) - `最小生成树``Kruskal 算法``并查集`
174174
- [判断二分图](/solution/0700-0799/0785.Is%20Graph%20Bipartite/README.md) - `染色法判定二分图``并查集`
175175

176-
<!-- 待补充
177-
### 7. 数学知识
178-
-->
179-
180176
## 加入我们
181177

182178
刷编程题的最大好处就是可以锻炼解决问题的思维能力。相信我,「如何去思考」​ 本身也是一项需要不断学习和练习的技能。非常感谢前微软工程师、现蚂蚁金服技术专家 [@kfstorm](https://github.com/kfstorm) 贡献了本项目的所有 [C# 题解](https://github.com/doocs/leetcode/pull/245)

README_EN.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,6 @@ https://leetcode.doocs.org/en
168168
- [Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree](/solution/1400-1499/1489.Find%20Critical%20and%20Pseudo-Critical%20Edges%20in%20Minimum%20Spanning%20Tree/README_EN.md) - `Minimum Spanning Tree`, `Kruskal's algorithm`, `Union find`
169169
- [Is Graph Bipartite?](/solution/0700-0799/0785.Is%20Graph%20Bipartite/README_EN.md) - `Graph coloring`, `Union find`
170170

171-
<!--
172-
### 7. Mathematical Knowledge
173-
-->
174-
175171
## Contributions
176172

177173
I'm looking for long-term contributors/partners to this repo! Send me [PRs](https://github.com/doocs/leetcode/pulls) if you're interested! See the following:

solution/2600-2699/2657.Find the Prefix Common Array of Two Arrays/README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,27 @@ function findThePrefixCommonArray(A: number[], B: number[]): number[] {
174174
}
175175
```
176176

177+
#### Rust
178+
179+
```rust
180+
impl Solution {
181+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
182+
let n = a.len();
183+
let mut ans = vec![0; n];
184+
let mut cnt1 = vec![0; n + 1];
185+
let mut cnt2 = vec![0; n + 1];
186+
for i in 0..n {
187+
cnt1[a[i] as usize] += 1;
188+
cnt2[b[i] as usize] += 1;
189+
for j in 1..=n {
190+
ans[i] += std::cmp::min(cnt1[j], cnt2[j]);
191+
}
192+
}
193+
ans
194+
}
195+
}
196+
```
197+
177198
<!-- tabs:end -->
178199

179200
<!-- solution:end -->
@@ -296,6 +317,27 @@ function findThePrefixCommonArray(A: number[], B: number[]): number[] {
296317
}
297318
```
298319

320+
#### Rust
321+
322+
```rust
323+
impl Solution {
324+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
325+
let n = a.len();
326+
let mut ans = vec![0; n];
327+
let mut vis = vec![1; n + 1];
328+
let mut s = 0;
329+
for i in 0..n {
330+
vis[a[i] as usize] ^= 1;
331+
s += vis[a[i] as usize];
332+
vis[b[i] as usize] ^= 1;
333+
s += vis[b[i] as usize];
334+
ans[i] = s;
335+
}
336+
ans
337+
}
338+
}
339+
```
340+
299341
<!-- tabs:end -->
300342

301343
<!-- solution:end -->
@@ -403,6 +445,23 @@ function bitCount64(i: bigint): number {
403445
}
404446
```
405447

448+
#### Rust
449+
450+
```rust
451+
impl Solution {
452+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
453+
let mut ans = Vec::with_capacity(a.len());
454+
let (mut x, mut y): (u64, u64) = (0, 0);
455+
for (&a_val, &b_val) in a.iter().zip(b.iter()) {
456+
x |= 1 << a_val;
457+
y |= 1 << b_val;
458+
ans.push((x & y).count_ones() as i32);
459+
}
460+
ans
461+
}
462+
}
463+
```
464+
406465
<!-- tabs:end -->
407466

408467
<!-- solution:end -->

solution/2600-2699/2657.Find the Prefix Common Array of Two Arrays/README_EN.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,27 @@ function findThePrefixCommonArray(A: number[], B: number[]): number[] {
174174
}
175175
```
176176

177+
#### Rust
178+
179+
```rust
180+
impl Solution {
181+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
182+
let n = a.len();
183+
let mut ans = vec![0; n];
184+
let mut cnt1 = vec![0; n + 1];
185+
let mut cnt2 = vec![0; n + 1];
186+
for i in 0..n {
187+
cnt1[a[i] as usize] += 1;
188+
cnt2[b[i] as usize] += 1;
189+
for j in 1..=n {
190+
ans[i] += std::cmp::min(cnt1[j], cnt2[j]);
191+
}
192+
}
193+
ans
194+
}
195+
}
196+
```
197+
177198
<!-- tabs:end -->
178199

179200
<!-- solution:end -->
@@ -296,6 +317,27 @@ function findThePrefixCommonArray(A: number[], B: number[]): number[] {
296317
}
297318
```
298319

320+
#### Rust
321+
322+
```rust
323+
impl Solution {
324+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
325+
let n = a.len();
326+
let mut ans = vec![0; n];
327+
let mut vis = vec![1; n + 1];
328+
let mut s = 0;
329+
for i in 0..n {
330+
vis[a[i] as usize] ^= 1;
331+
s += vis[a[i] as usize];
332+
vis[b[i] as usize] ^= 1;
333+
s += vis[b[i] as usize];
334+
ans[i] = s;
335+
}
336+
ans
337+
}
338+
}
339+
```
340+
299341
<!-- tabs:end -->
300342

301343
<!-- solution:end -->
@@ -403,6 +445,23 @@ function bitCount64(i: bigint): number {
403445
}
404446
```
405447

448+
#### Rust
449+
450+
```rust
451+
impl Solution {
452+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
453+
let mut ans = Vec::with_capacity(a.len());
454+
let (mut x, mut y): (u64, u64) = (0, 0);
455+
for (&a_val, &b_val) in a.iter().zip(b.iter()) {
456+
x |= 1 << a_val;
457+
y |= 1 << b_val;
458+
ans.push((x & y).count_ones() as i32);
459+
}
460+
ans
461+
}
462+
}
463+
```
464+
406465
<!-- tabs:end -->
407466

408467
<!-- solution:end -->
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
impl Solution {
2+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
3+
let n = a.len();
4+
let mut ans = vec![0; n];
5+
let mut cnt1 = vec![0; n + 1];
6+
let mut cnt2 = vec![0; n + 1];
7+
for i in 0..n {
8+
cnt1[a[i] as usize] += 1;
9+
cnt2[b[i] as usize] += 1;
10+
for j in 1..=n {
11+
ans[i] += std::cmp::min(cnt1[j], cnt2[j]);
12+
}
13+
}
14+
ans
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
impl Solution {
2+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
3+
let n = a.len();
4+
let mut ans = vec![0; n];
5+
let mut vis = vec![1; n + 1];
6+
let mut s = 0;
7+
for i in 0..n {
8+
vis[a[i] as usize] ^= 1;
9+
s += vis[a[i] as usize];
10+
vis[b[i] as usize] ^= 1;
11+
s += vis[b[i] as usize];
12+
ans[i] = s;
13+
}
14+
ans
15+
}
16+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
impl Solution {
2+
pub fn find_the_prefix_common_array(a: Vec<i32>, b: Vec<i32>) -> Vec<i32> {
3+
let mut ans = Vec::with_capacity(a.len());
4+
let (mut x, mut y): (u64, u64) = (0, 0);
5+
for (&a_val, &b_val) in a.iter().zip(b.iter()) {
6+
x |= 1 << a_val;
7+
y |= 1 << b_val;
8+
ans.push((x & y).count_ones() as i32);
9+
}
10+
ans
11+
}
12+
}

solution/3400-3499/3430.Maximum and Minimum Sums of at Most Size K Subarrays/README.md

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,11 @@ tags:
165165
<!-- solution:start -->
166166

167167
### 方法一:双 Deque 维护窗口最大值与最小值
168+
168169
本题要求计算所有长度不超过 $k$ 的子数组中:
169-
* 子数组最大值之和
170-
* 子数组最小值之和
170+
171+
- 子数组最大值之和
172+
- 子数组最小值之和
171173

172174
并返回两者之和。
173175

@@ -188,23 +190,28 @@ $$
188190
表示所有以索引 $i$ 结尾的合法子数组,它们各自最小值的总和。
189191

190192
接下来,我们维护两个单调队列:
191-
* `max_stack`:维护当前窗口内所有子数组可能的最大值。
192-
* `min_stack`:维护当前窗口内所有子数组可能的最小值。
193+
194+
- `max_stack`:维护当前窗口内所有子数组可能的最大值。
195+
- `min_stack`:维护当前窗口内所有子数组可能的最小值。
193196

194197
虽然底层数据结构为 `deque`,但由于绝大多数操作都发生在右侧,因此其本质仍然是单调栈。
195198

196199
队列中的每个元素格式为:
200+
197201
```text
198202
(index, value, shares)
199203
```
200204

201205
其中:
202-
* `index`:元素索引
203-
* `value`:元素值
204-
* `shares`:该元素在当前窗口内,作为子数组最大值 / 最小值的贡献次数
206+
207+
- `index`:元素索引
208+
- `value`:元素值
209+
- `shares`:该元素在当前窗口内,作为子数组最大值 / 最小值的贡献次数
205210

206211
---
212+
207213
#### Step 1. 边界管理
214+
208215
当遍历到当前元素 `nums[i]` 时,我们首先需要确保窗口长度不超过 $k$。
209216

210217
窗口左边界为:
@@ -216,34 +223,41 @@ $$
216223
若某元素索引已经小于该边界,说明其已经离开窗口,不再属于任何合法子数组。
217224

218225
因此:
219-
* `max_stack` 栈头元素若已越界,则弹出
220-
* `min_stack` 栈头元素若已越界,则弹出
226+
227+
- `max_stack` 栈头元素若已越界,则弹出
228+
- `min_stack` 栈头元素若已越界,则弹出
221229

222230
同时,需要从:
223-
* `subarrays_max_sum`
224-
* `subarrays_min_sum`
231+
232+
- `subarrays_max_sum`
233+
- `subarrays_min_sum`
225234

226235
中扣除这些元素对应的贡献。
227236

228237
---
238+
229239
#### Step 2. 更新单调栈
240+
230241
对于当前元素 `nums[i]`
231242

232243
`max_stack` 栈尾元素的值小于等于 `nums[i]`
233244

234245
说明这些元素已经不可能继续成为后续子数组的最大值。
235246

236247
因此:
248+
237249
1. 持续弹出这些元素
238250
2. 将它们的贡献次数 `shares` 转移给 `nums[i]`
239251
3. 更新 `subarrays_max_sum`
240252

241253
若弹出的元素为:
254+
242255
```text
243256
(prev_idx, prev_num, prev_shares)
244257
```
245258

246259
则会对:
260+
247261
```text
248262
subarrays_max_sum
249263
```
@@ -259,43 +273,54 @@ $$
259273
随后,再加上当前元素自身形成的新子数组贡献。
260274

261275
最后,将:
276+
262277
```text
263278
(i, nums[i], shares)
264279
```
280+
265281
压入 `max_stack`
266282

267283
---
284+
268285
`min_stack` 的操作方式完全相同。区别仅在于:
269-
* `max_stack` 维护单调递减性质
270-
* `min_stack` 维护单调递增性质
286+
287+
- `max_stack` 维护单调递减性质
288+
- `min_stack` 维护单调递增性质
271289

272290
因此比较条件需要反转:
291+
273292
```text
274293
max_stack: top_value <= nums[i]
275294
min_stack: top_value >= nums[i]
276295
```
277296

278297
---
298+
279299
#### Step 3. 累加答案
300+
280301
当索引 $i$ 处理完成后:
281302

282-
* `subarrays_max_sum`
303+
- `subarrays_max_sum`
283304
表示所有以 $i$ 结尾的合法子数组最大值总和
284-
* `subarrays_min_sum`
305+
- `subarrays_min_sum`
285306
表示所有以 $i$ 结尾的合法子数组最小值总和
286307

287308
因此我们将两者加入最终答案:
309+
288310
```text
289311
subarrays_max_min_sum
290312
```
313+
291314
最终返回该结果即可。
292315

293316
---
317+
294318
时间复杂度为 $O(n)$,空间复杂度为 $O(n)$。
295319

296320
这是因为:
297-
* 每个元素至多进入并离开 `max_stack` 各一次
298-
* 每个元素至多进入并离开 `min_stack` 各一次
321+
322+
- 每个元素至多进入并离开 `max_stack` 各一次
323+
- 每个元素至多进入并离开 `min_stack` 各一次
299324

300325
因此每个元素总操作次数不超过四次,整体时间复杂度为严格线性时间复杂度。
301326

0 commit comments

Comments
 (0)