Skip to content

Commit 141af5c

Browse files
authored
feat: add solutions to lc problems: No.3046,0076 (#3895)
1 parent fb7ac1c commit 141af5c

File tree

13 files changed

+520
-313
lines changed

13 files changed

+520
-313
lines changed

solution/0000-0099/0076.Minimum Window Substring/README.md

+146-105
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,18 @@ tags:
7777

7878
### 方法一:计数 + 双指针
7979

80-
我们用一个哈希表或数组 $need$ 统计字符串 $t$ 中每个字符出现的次数,用另一个哈希表或数组 $window$ 统计滑动窗口中每个字符出现的次数。另外,定义两个指针 $j$ 和 $i$ 分别指向窗口的左右边界,变量 $cnt$ 表示窗口中已经包含了 $t$ 中的多少个字符,变量 $k$ 和 $mi$ 分别表示最小覆盖子串的起始位置和长度。
80+
我们用一个哈希表或数组 $\textit{need}$ 统计字符串 $t$ 中每个字符出现的次数,用另一个哈希表或数组 $\textit{window}$ 统计滑动窗口中每个字符出现的次数。另外,定义两个指针 $l$ 和 $r$ 分别指向窗口的左右边界,变量 $\textit{cnt}$ 表示窗口中已经包含了 $t$ 中的多少个字符,变量 $k$ 和 $\textit{mi}$ 分别表示最小覆盖子串的起始位置和长度。
8181

82-
我们从左到右遍历字符串 $s$,对于当前遍历到的字符 $s[i]$:
82+
我们从左到右遍历字符串 $s$,对于当前遍历到的字符 $s[r]$:
8383

84-
我们将其加入窗口中,即 $window[s[i]] = window[s[i]] + 1$,如果此时 $need[s[i]] \geq window[s[i]]$,则说明 $s[i]$ 是一个「必要的字符」,我们将 $cnt$ 加一。如果 $cnt$ 等于 $t$ 的长度,说明此时窗口中已经包含了 $t$ 中的所有字符,我们就可以尝试更新最小覆盖子串的起始位置和长度了。如果 $i - j + 1 \lt mi$,说明当前窗口表示的子串更短,我们就更新 $mi = i - j + 1$ 和 $k = j$。然后,我们尝试移动左边界 $j$,如果此时 $need[s[j]] \geq window[s[j]]$,则说明 $s[j]$ 是一个「必要的字符」,移动左边界时会把 $s[j]$ 这个字符从窗口中移除,因此我们需要将 $cnt$ 减一,然后更新 $window[s[j]] = window[s[j]] - 1$,并将 $j$ 右移一位。如果 $cnt$ 与 $t$ 的长度不相等,说明此时窗口中还没有包含 $t$ 中的所有字符,我们就不需要移动左边界了,直接将 $i$ 右移一位,继续遍历即可。
84+
- 我们将其加入窗口中,即 $\textit{window}[s[r]] = \textit{window}[s[r]] + 1$,如果此时 $\textit{need}[s[r]] \geq \textit{window}[s[r]]$,则说明 $s[r]$ 是一个「必要的字符」,我们将 $\textit{cnt}$ 加一。
85+
- 如果 $\textit{cnt}$ 等于 $t$ 的长度,说明此时窗口中已经包含了 $t$ 中的所有字符,我们就可以尝试更新最小覆盖子串的起始位置和长度了。如果 $r - l + 1 < \textit{mi}$,说明当前窗口表示的子串更短,我们就更新 $\textit{mi} = r - l + 1$ 和 $k = l$。
86+
- 然后,我们尝试移动左边界 $l$,如果此时 $\textit{need}[s[l]] \geq \textit{window}[s[l]]$,则说明 $s[l]$ 是一个「必要的字符」,移动左边界时会把 $s[l]$ 这个字符从窗口中移除,因此我们需要将 $\textit{cnt}$ 减一,然后更新 $\textit{window}[s[l]] = \textit{window}[s[l]] - 1$,并将 $l$ 右移一位。
87+
- 如果 $\textit{cnt}$ 与 $t$ 的长度不相等,说明此时窗口中还没有包含 $t$ 中的所有字符,我们就不需要移动左边界了,直接将 $r$ 右移一位,继续遍历即可。
8588

86-
遍历结束,如果没有找到最小覆盖子串,返回空字符串,否则返回 $s[k:k+mi]$ 即可。
89+
遍历结束,如果没有找到最小覆盖子串,返回空字符串,否则返回 $s[k:k+\textit{mi}]$ 即可。
8790

88-
时间复杂度 $O(m + n)$,空间复杂度 $O(C)$。其中 $m$ 和 $n$ 分别是字符串 $s$ 和 $t$ 的长度;而 $C$ 是字符集的大小,本题中 $C = 128$。
91+
时间复杂度 $O(m + n)$,空间复杂度 $O(|\Sigma|)$。其中 $m$ 和 $n$ 分别是字符串 $s$ 和 $t$ 的长度;而 $|\Sigma|$ 是字符集的大小,本题中 $|\Sigma| = 128$。
8992

9093
<!-- tabs:start -->
9194

@@ -96,20 +99,21 @@ class Solution:
9699
def minWindow(self, s: str, t: str) -> str:
97100
need = Counter(t)
98101
window = Counter()
99-
cnt, j, k, mi = 0, 0, -1, inf
100-
for i, c in enumerate(s):
102+
cnt = l = 0
103+
k, mi = -1, inf
104+
for r, c in enumerate(s):
101105
window[c] += 1
102106
if need[c] >= window[c]:
103107
cnt += 1
104108
while cnt == len(t):
105-
if i - j + 1 < mi:
106-
mi = i - j + 1
107-
k = j
108-
if need[s[j]] >= window[s[j]]:
109+
if r - l + 1 < mi:
110+
mi = r - l + 1
111+
k = l
112+
if need[s[l]] >= window[s[l]]:
109113
cnt -= 1
110-
window[s[j]] -= 1
111-
j += 1
112-
return '' if k < 0 else s[k : k + mi]
114+
window[s[l]] -= 1
115+
l += 1
116+
return "" if k < 0 else s[k : k + mi]
113117
```
114118

115119
#### Java
@@ -119,25 +123,27 @@ class Solution {
119123
public String minWindow(String s, String t) {
120124
int[] need = new int[128];
121125
int[] window = new int[128];
122-
int m = s.length(), n = t.length();
123-
for (int i = 0; i < n; ++i) {
124-
++need[t.charAt(i)];
126+
for (char c : t.toCharArray()) {
127+
++need[c];
125128
}
126-
int cnt = 0, j = 0, k = -1, mi = 1 << 30;
127-
for (int i = 0; i < m; ++i) {
128-
++window[s.charAt(i)];
129-
if (need[s.charAt(i)] >= window[s.charAt(i)]) {
129+
int m = s.length(), n = t.length();
130+
int k = -1, mi = m + 1, cnt = 0;
131+
for (int l = 0, r = 0; r < m; ++r) {
132+
char c = s.charAt(r);
133+
if (++window[c] <= need[c]) {
130134
++cnt;
131135
}
132136
while (cnt == n) {
133-
if (i - j + 1 < mi) {
134-
mi = i - j + 1;
135-
k = j;
137+
if (r - l + 1 < mi) {
138+
mi = r - l + 1;
139+
k = l;
136140
}
137-
if (need[s.charAt(j)] >= window[s.charAt(j)]) {
141+
c = s.charAt(l);
142+
if (window[c] <= need[c]) {
138143
--cnt;
139144
}
140-
--window[s.charAt(j++)];
145+
--window[c];
146+
++l;
141147
}
142148
}
143149
return k < 0 ? "" : s.substring(k, k + mi);
@@ -151,29 +157,36 @@ class Solution {
151157
class Solution {
152158
public:
153159
string minWindow(string s, string t) {
154-
int need[128]{};
155-
int window[128]{};
156-
int m = s.size(), n = t.size();
157-
for (char& c : t) {
160+
vector<int> need(128, 0);
161+
vector<int> window(128, 0);
162+
for (char c : t) {
158163
++need[c];
159164
}
160-
int cnt = 0, j = 0, k = -1, mi = 1 << 30;
161-
for (int i = 0; i < m; ++i) {
162-
++window[s[i]];
163-
if (need[s[i]] >= window[s[i]]) {
165+
166+
int m = s.length(), n = t.length();
167+
int k = -1, mi = m + 1, cnt = 0;
168+
169+
for (int l = 0, r = 0; r < m; ++r) {
170+
char c = s[r];
171+
if (++window[c] <= need[c]) {
164172
++cnt;
165173
}
174+
166175
while (cnt == n) {
167-
if (i - j + 1 < mi) {
168-
mi = i - j + 1;
169-
k = j;
176+
if (r - l + 1 < mi) {
177+
mi = r - l + 1;
178+
k = l;
170179
}
171-
if (need[s[j]] >= window[s[j]]) {
180+
181+
c = s[l];
182+
if (window[c] <= need[c]) {
172183
--cnt;
173184
}
174-
--window[s[j++]];
185+
--window[c];
186+
++l;
175187
}
176188
}
189+
177190
return k < 0 ? "" : s.substr(k, mi);
178191
}
179192
};
@@ -183,27 +196,32 @@ public:
183196

184197
```go
185198
func minWindow(s string, t string) string {
186-
need := [128]int{}
187-
window := [128]int{}
188-
for _, c := range t {
189-
need[c]++
199+
need := make([]int, 128)
200+
window := make([]int, 128)
201+
for i := 0; i < len(t); i++ {
202+
need[t[i]]++
190203
}
191-
cnt, j, k, mi := 0, 0, -1, 1<<30
192-
for i, c := range s {
193-
window[c]++
194-
if need[c] >= window[c] {
204+
205+
m, n := len(s), len(t)
206+
k, mi, cnt := -1, m+1, 0
207+
208+
for l, r := 0, 0; r < m; r++ {
209+
c := s[r]
210+
if window[c]++; window[c] <= need[c] {
195211
cnt++
196212
}
197-
for cnt == len(t) {
198-
if i-j+1 < mi {
199-
mi = i - j + 1
200-
k = j
213+
for cnt == n {
214+
if r-l+1 < mi {
215+
mi = r - l + 1
216+
k = l
201217
}
202-
if need[s[j]] >= window[s[j]] {
218+
219+
c = s[l]
220+
if window[c] <= need[c] {
203221
cnt--
204222
}
205-
window[s[j]]--
206-
j++
223+
window[c]--
224+
l++
207225
}
208226
}
209227
if k < 0 {
@@ -217,69 +235,80 @@ func minWindow(s string, t string) string {
217235

218236
```ts
219237
function minWindow(s: string, t: string): string {
220-
const need: number[] = new Array(128).fill(0);
221-
const window: number[] = new Array(128).fill(0);
222-
for (const c of t) {
223-
++need[c.charCodeAt(0)];
238+
const need: number[] = Array(128).fill(0);
239+
const window: number[] = Array(128).fill(0);
240+
for (let i = 0; i < t.length; i++) {
241+
need[t.charCodeAt(i)]++;
224242
}
225-
let cnt = 0;
226-
let j = 0;
227-
let k = -1;
228-
let mi = 1 << 30;
229-
for (let i = 0; i < s.length; ++i) {
230-
++window[s.charCodeAt(i)];
231-
if (need[s.charCodeAt(i)] >= window[s.charCodeAt(i)]) {
232-
++cnt;
243+
const [m, n] = [s.length, t.length];
244+
let [k, mi, cnt] = [-1, m + 1, 0];
245+
for (let l = 0, r = 0; r < m; r++) {
246+
let c = s.charCodeAt(r);
247+
if (++window[c] <= need[c]) {
248+
cnt++;
233249
}
234-
while (cnt === t.length) {
235-
if (i - j + 1 < mi) {
236-
mi = i - j + 1;
237-
k = j;
250+
while (cnt === n) {
251+
if (r - l + 1 < mi) {
252+
mi = r - l + 1;
253+
k = l;
238254
}
239-
if (need[s.charCodeAt(j)] >= window[s.charCodeAt(j)]) {
240-
--cnt;
255+
256+
c = s.charCodeAt(l);
257+
if (window[c] <= need[c]) {
258+
cnt--;
241259
}
242-
--window[s.charCodeAt(j++)];
260+
window[c]--;
261+
l++;
243262
}
244263
}
245-
return k < 0 ? '' : s.slice(k, k + mi);
264+
return k < 0 ? '' : s.substring(k, k + mi);
246265
}
247266
```
248267

249268
#### Rust
250269

251270
```rust
271+
use std::collections::HashMap;
272+
252273
impl Solution {
253274
pub fn min_window(s: String, t: String) -> String {
254-
let (mut need, mut window, mut cnt) = ([0; 256], [0; 256], 0);
275+
let mut need: HashMap<char, usize> = HashMap::new();
276+
let mut window: HashMap<char, usize> = HashMap::new();
255277
for c in t.chars() {
256-
need[c as usize] += 1;
278+
*need.entry(c).or_insert(0) += 1;
257279
}
258-
let (mut j, mut k, mut mi) = (0, -1, 1 << 31);
259-
for (i, c) in s.chars().enumerate() {
260-
window[c as usize] += 1;
261-
if need[c as usize] >= window[c as usize] {
280+
let m = s.len();
281+
let n = t.len();
282+
let mut k = -1;
283+
let mut mi = m + 1;
284+
let mut cnt = 0;
285+
286+
let s_bytes = s.as_bytes();
287+
let mut l = 0;
288+
for r in 0..m {
289+
let c = s_bytes[r] as char;
290+
*window.entry(c).or_insert(0) += 1;
291+
if window[&c] <= *need.get(&c).unwrap_or(&0) {
262292
cnt += 1;
263293
}
264-
265-
while cnt == t.len() {
266-
if i - j + 1 < mi {
267-
k = j as i32;
268-
mi = i - j + 1;
294+
while cnt == n {
295+
if r - l + 1 < mi {
296+
mi = r - l + 1;
297+
k = l as i32;
269298
}
270-
let l = s.chars().nth(j).unwrap() as usize;
271-
if need[l] >= window[l] {
299+
300+
let c = s_bytes[l] as char;
301+
if window[&c] <= *need.get(&c).unwrap_or(&0) {
272302
cnt -= 1;
273303
}
274-
window[l] -= 1;
275-
j += 1;
304+
*window.entry(c).or_insert(0) -= 1;
305+
l += 1;
276306
}
277307
}
278308
if k < 0 {
279-
return "".to_string();
309+
return String::new();
280310
}
281-
let k = k as usize;
282-
s[k..k + mi].to_string()
311+
s[k as usize..(k as usize + mi)].to_string()
283312
}
284313
}
285314
```
@@ -291,26 +320,38 @@ public class Solution {
291320
public string MinWindow(string s, string t) {
292321
int[] need = new int[128];
293322
int[] window = new int[128];
323+
294324
foreach (var c in t) {
295-
++need[c];
325+
need[c]++;
296326
}
297-
int cnt = 0, j = 0, k = -1, mi = 1 << 30;
298-
for (int i = 0; i < s.Length; ++i) {
299-
++window[s[i]];
300-
if (need[s[i]] >= window[s[i]]) {
301-
++cnt;
327+
328+
int m = s.Length, n = t.Length;
329+
int k = -1, mi = m + 1, cnt = 0;
330+
331+
int l = 0;
332+
for (int r = 0; r < m; r++) {
333+
char c = s[r];
334+
window[c]++;
335+
336+
if (window[c] <= need[c]) {
337+
cnt++;
302338
}
303-
while (cnt == t.Length) {
304-
if (i - j + 1 < mi) {
305-
mi = i - j + 1;
306-
k = j;
339+
340+
while (cnt == n) {
341+
if (r - l + 1 < mi) {
342+
mi = r - l + 1;
343+
k = l;
307344
}
308-
if (need[s[j]] >= window[s[j]]) {
309-
--cnt;
345+
346+
c = s[l];
347+
if (window[c] <= need[c]) {
348+
cnt--;
310349
}
311-
--window[s[j++]];
350+
window[c]--;
351+
l++;
312352
}
313353
}
354+
314355
return k < 0 ? "" : s.Substring(k, mi);
315356
}
316357
}

0 commit comments

Comments
 (0)