Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 141af5c

Browse files
feat: add solutions to lc problems: No.3046,0076 (doocs#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‎

Lines changed: 146 additions & 105 deletions
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[] = newArray(128).fill(0);
221-
const window: number[] = newArray(128).fill(0);
222-
for (const c oft) {
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[casusize] += 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)

AltStyle によって変換されたページ (->オリジナル) /