Skip to content

Commit 8731833

Browse files
committed
feat: add solutions to lc problem: No.0076
No.0076.Minimum Window Substring
1 parent 4d5f28e commit 8731833

File tree

8 files changed

+392
-493
lines changed

8 files changed

+392
-493
lines changed

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

Lines changed: 143 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,20 @@
5959

6060
## 解法
6161

62-
滑动窗口
63-
6462
<!-- 这里可写通用的实现逻辑 -->
6563

64+
**方法一:计数 + 双指针**
65+
66+
我们用一个哈希表或数组 $need$ 统计字符串 $t$ 中每个字符出现的次数,用另一个哈希表或数组 $window$ 统计滑动窗口中每个字符出现的次数。另外,定义两个指针 $j$ 和 $i$ 分别指向窗口的左右边界,变量 $cnt$ 表示窗口中已经包含了 $t$ 中的多少个字符,变量 $k$ 和 $mi$ 分别表示最小覆盖子串的起始位置和长度。
67+
68+
我们从左到右遍历字符串 $s$,对于当前遍历到的字符 $s[i]$:
69+
70+
我们将其加入窗口中,即 $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$ 右移一位,继续遍历即可。
71+
72+
遍历结束,如果没有找到最小覆盖子串,返回空字符串,否则返回 $s[k:k+mi]$ 即可。
73+
74+
时间复杂度 $O(m + n)$,空间复杂度 $O(C)$。其中 $m$ 和 $n$ 分别是字符串 $s$ 和 $t$ 的长度;而 $C$ 是字符集的大小,本题中 $C = 128$。
75+
6676
<!-- tabs:start -->
6777

6878
### **Python3**
@@ -72,27 +82,22 @@
7282
```python
7383
class Solution:
7484
def minWindow(self, s: str, t: str) -> str:
75-
ans = ''
76-
m, n = len(s), len(t)
77-
if m < n:
78-
return ans
7985
need = Counter(t)
8086
window = Counter()
81-
i, cnt, mi = 0, 0, inf
82-
for j, c in enumerate(s):
87+
cnt, j, k, mi = 0, 0, -1, inf
88+
for i, c in enumerate(s):
8389
window[c] += 1
8490
if need[c] >= window[c]:
8591
cnt += 1
86-
while cnt == n:
87-
if j - i + 1 < mi:
88-
mi = j - i + 1
89-
ans = s[i : j + 1]
90-
c = s[i]
91-
if need[c] >= window[c]:
92+
while cnt == len(t):
93+
if i - j + 1 < mi:
94+
mi = i - j + 1
95+
k = j
96+
if need[s[j]] >= window[s[j]]:
9297
cnt -= 1
93-
window[c] -= 1
94-
i += 1
95-
return ans
98+
window[s[j]] -= 1
99+
j += 1
100+
return '' if k < 0 else s[k: k + mi]
96101
```
97102

98103
### **Java**
@@ -102,87 +107,31 @@ class Solution:
102107
```java
103108
class Solution {
104109
public String minWindow(String s, String t) {
105-
Map<Character, Integer> mp = new HashMap<>();
106-
int begin = 0, end = 0, counter = t.length(), minLen = Integer.MAX_VALUE, minStart = 0,
107-
size = s.length();
108-
109-
for (char c : s.toCharArray()) mp.put(c, 0);
110-
for (char c : t.toCharArray()) {
111-
if (mp.containsKey(c))
112-
mp.put(c, mp.get(c) + 1);
113-
else
114-
return "";
110+
int[] need = new int[128];
111+
int[] window = new int[128];
112+
int m = s.length(), n = t.length();
113+
for (int i = 0; i < n; ++i) {
114+
++need[t.charAt(i)];
115115
}
116-
117-
while (end < size) {
118-
if (mp.get(s.charAt(end)) > 0) counter--;
119-
120-
mp.put(s.charAt(end), mp.get(s.charAt(end)) - 1);
121-
122-
end++;
123-
124-
while (counter == 0) {
125-
if (end - begin < minLen) {
126-
minStart = begin;
127-
minLen = end - begin;
116+
int cnt = 0, j = 0, k = -1, mi = 1 << 30;
117+
for (int i = 0; i < m; ++i) {
118+
++window[s.charAt(i)];
119+
if (need[s.charAt(i)] >= window[s.charAt(i)]) {
120+
++cnt;
121+
}
122+
while (cnt == n) {
123+
if (i - j + 1 < mi) {
124+
mi = i - j + 1;
125+
k = j;
128126
}
129-
mp.put(s.charAt(begin), mp.get(s.charAt(begin)) + 1);
130-
131-
if (mp.get(s.charAt(begin)) > 0) {
132-
counter++;
127+
if (need[s.charAt(j)] >= window[s.charAt(j)]) {
128+
--cnt;
133129
}
134-
135-
begin++;
136-
}
137-
}
138-
139-
if (minLen != Integer.MAX_VALUE) {
140-
return s.substring(minStart, minStart + minLen);
141-
}
142-
return "";
143-
}
144-
}
145-
```
146-
147-
### **TypeScript**
148-
149-
```ts
150-
function minWindow(s: string, t: string): string {
151-
let n1 = s.length,
152-
n2 = t.length;
153-
if (n1 < n2) return '';
154-
let need = new Array(128).fill(0);
155-
let window = new Array(128).fill(0);
156-
for (let i = 0; i < n2; ++i) {
157-
++need[t.charCodeAt(i)];
158-
}
159-
160-
let left = 0,
161-
right = 0;
162-
let res = '';
163-
let count = 0;
164-
let min = n1 + 1;
165-
while (right < n1) {
166-
let cur = s.charCodeAt(right);
167-
++window[cur];
168-
if (need[cur] > 0 && need[cur] >= window[cur]) {
169-
++count;
170-
}
171-
while (count == n2) {
172-
cur = s.charCodeAt(left);
173-
if (need[cur] > 0 && need[cur] >= window[cur]) {
174-
--count;
175-
}
176-
if (right - left + 1 < min) {
177-
min = right - left + 1;
178-
res = s.slice(left, right + 1);
130+
--window[s.charAt(j++)];
179131
}
180-
--window[cur];
181-
++left;
182132
}
183-
++right;
133+
return k < 0 ? "" : s.substring(k, k + mi);
184134
}
185-
return res;
186135
}
187136
```
188137

@@ -192,37 +141,30 @@ function minWindow(s: string, t: string): string {
192141
class Solution {
193142
public:
194143
string minWindow(string s, string t) {
195-
unordered_map<char, int> m;
196-
int begin = 0, end = 0, minlen = INT_MAX, minStart = 0, size = s.size(), counter = t.size();
197-
for (auto c : t)
198-
m[c]++;
199-
200-
while (end < size) {
201-
if (m[s[end]] > 0)
202-
counter--;
203-
204-
m[s[end]]--;
205-
206-
end++;
207-
208-
while (counter == 0) {
209-
if (end - begin < minlen) {
210-
minStart = begin;
211-
minlen = end - begin;
144+
int need[128]{};
145+
int window[128]{};
146+
int m = s.size(), n = t.size();
147+
for (char& c : t) {
148+
++need[c];
149+
}
150+
int cnt = 0, j = 0, k = -1, mi = 1 << 30;
151+
for (int i = 0; i < m; ++i) {
152+
++window[s[i]];
153+
if (need[s[i]] >= window[s[i]]) {
154+
++cnt;
155+
}
156+
while (cnt == n) {
157+
if (i - j + 1 < mi) {
158+
mi = i - j + 1;
159+
k = j;
212160
}
213-
214-
m[s[begin]]++;
215-
if (m[s[begin]] > 0)
216-
counter++;
217-
218-
begin++;
161+
if (need[s[j]] >= window[s[j]]) {
162+
--cnt;
163+
}
164+
--window[s[j++]];
219165
}
220166
}
221-
222-
if (minlen != INT_MAX) {
223-
return s.substr(minStart, minlen);
224-
}
225-
return "";
167+
return k < 0 ? "" : s.substr(k, mi);
226168
}
227169
};
228170
```
@@ -231,36 +173,98 @@ public:
231173
232174
```go
233175
func minWindow(s string, t string) string {
234-
ans := ""
235-
m, n := len(s), len(t)
236-
if m < n {
237-
return ans
238-
}
239-
need := make([]int, 128)
176+
need := [128]int{}
177+
window := [128]int{}
240178
for _, c := range t {
241-
need[c] += 1
179+
need[c]++
242180
}
243-
window := make([]int, 128)
244-
i, cnt, mi := 0, 0, m+1
245-
for j, c := range s {
181+
cnt, j, k, mi := 0, 0, -1, 1<<30
182+
for i, c := range s {
246183
window[c]++
247184
if need[c] >= window[c] {
248185
cnt++
249186
}
250-
for cnt == n {
251-
if j-i+1 < mi {
252-
mi = j - i + 1
253-
ans = s[i : j+1]
187+
for cnt == len(t) {
188+
if i-j+1 < mi {
189+
mi = i - j + 1
190+
k = j
254191
}
255-
c = rune(s[i])
256-
if need[c] >= window[c] {
192+
if need[s[j]] >= window[s[j]] {
257193
cnt--
258194
}
259-
window[c]--
260-
i++
195+
window[s[j]]--
196+
j++
261197
}
262198
}
263-
return ans
199+
if k < 0 {
200+
return ""
201+
}
202+
return s[k : k+mi]
203+
}
204+
```
205+
206+
### **TypeScript**
207+
208+
```ts
209+
function minWindow(s: string, t: string): string {
210+
const need: number[] = new Array(128).fill(0);
211+
const window: number[] = new Array(128).fill(0);
212+
for (const c of t) {
213+
++need[c.charCodeAt(0)];
214+
}
215+
let cnt = 0;
216+
let j = 0;
217+
let k = -1;
218+
let mi = 1 << 30;
219+
for (let i = 0; i < s.length; ++i) {
220+
++window[s.charCodeAt(i)];
221+
if (need[s.charCodeAt(i)] >= window[s.charCodeAt(i)]) {
222+
++cnt;
223+
}
224+
while (cnt === t.length) {
225+
if (i - j + 1 < mi) {
226+
mi = i - j + 1;
227+
k = j;
228+
}
229+
if (need[s.charCodeAt(j)] >= window[s.charCodeAt(j)]) {
230+
--cnt;
231+
}
232+
--window[s.charCodeAt(j++)];
233+
}
234+
}
235+
return k < 0 ? '' : s.slice(k, k + mi);
236+
}
237+
```
238+
239+
### **C#**
240+
241+
```cs
242+
public class Solution {
243+
public string MinWindow(string s, string t) {
244+
int[] need = new int[128];
245+
int[] window = new int[128];
246+
foreach (var c in t) {
247+
++need[c];
248+
}
249+
int cnt = 0, j = 0, k = -1, mi = 1 << 30;
250+
for (int i = 0; i < s.Length; ++i) {
251+
++window[s[i]];
252+
if (need[s[i]] >= window[s[i]]) {
253+
++cnt;
254+
}
255+
while (cnt == t.Length) {
256+
if (i - j + 1 < mi) {
257+
mi = i - j + 1;
258+
k = j;
259+
}
260+
if (need[s[j]] >= window[s[j]]) {
261+
--cnt;
262+
}
263+
--window[s[j++]];
264+
}
265+
}
266+
return k < 0 ? "" : s.Substring(k, mi);
267+
}
264268
}
265269
```
266270

0 commit comments

Comments
 (0)