59
59
60
60
## 解法
61
61
62
- 滑动窗口
63
-
64
62
<!-- 这里可写通用的实现逻辑 -->
65
63
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
+
66
76
<!-- tabs:start -->
67
77
68
78
### ** Python3**
72
82
``` python
73
83
class Solution :
74
84
def minWindow (self , s : str , t : str ) -> str :
75
- ans = ' '
76
- m, n = len (s), len (t)
77
- if m < n:
78
- return ans
79
85
need = Counter(t)
80
86
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):
83
89
window[c] += 1
84
90
if need[c] >= window[c]:
85
91
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]]:
92
97
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]
96
101
```
97
102
98
103
### ** Java**
@@ -102,87 +107,31 @@ class Solution:
102
107
``` java
103
108
class Solution {
104
109
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)];
115
115
}
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;
128
126
}
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;
133
129
}
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++ )];
179
131
}
180
- -- window [cur ];
181
- ++ left ;
182
132
}
183
- ++ right ;
133
+ return k < 0 ? " " : s . substring(k, k + mi) ;
184
134
}
185
- return res ;
186
135
}
187
136
```
188
137
@@ -192,37 +141,30 @@ function minWindow(s: string, t: string): string {
192
141
class Solution {
193
142
public:
194
143
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;
212
160
}
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++]] ;
219
165
}
220
166
}
221
-
222
- if (minlen != INT_MAX) {
223
- return s.substr(minStart, minlen);
224
- }
225
- return "";
167
+ return k < 0 ? "" : s.substr(k, mi);
226
168
}
227
169
};
228
170
```
@@ -231,36 +173,98 @@ public:
231
173
232
174
```go
233
175
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{}
240
178
for _, c := range t {
241
- need[c] += 1
179
+ need[c]++
242
180
}
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 {
246
183
window[c]++
247
184
if need[c] >= window[c] {
248
185
cnt++
249
186
}
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
254
191
}
255
- c = rune (s[i])
256
- if need[c] >= window[c] {
192
+ if need[s[j]] >= window[s[j]] {
257
193
cnt--
258
194
}
259
- window[c ]--
260
- i ++
195
+ window[s[j] ]--
196
+ j ++
261
197
}
262
198
}
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
+ }
264
268
}
265
269
```
266
270
0 commit comments