@@ -66,6 +66,14 @@ s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接
66
66
67
67
** 方法一:哈希表 + 滑动窗口**
68
68
69
+ 我们用哈希表 $cnt$ 统计 $words$ 中每个单词出现的次数,用哈希表 $cnt1$ 统计当前滑动窗口中每个单词出现的次数。我们记字符串 $s$ 的长度为 $m$,字符串数组 $words$ 中单词的数量为 $n$,每个单词的长度为 $k$。
70
+
71
+ 我们可以枚举滑动窗口的起点 $i$,其中 $0 \lt i \lt k$。对于每个起点,我们维护一个滑动窗口,左边界为 $l$,右边界为 $r$,滑动窗口中的单词个数为 $t$,另外用一个哈希表 $cnt1$ 统计滑动窗口中每个单词出现的次数。
72
+
73
+ 每一次,我们提取字符串 $s[ r: r +k] $,如果 $s[ r: r +k] $ 不在哈希表 $cnt$ 中,说明当前滑动窗口中的单词不合法,我们将左边界 $l$ 更新为 $r$,同时将哈希表 $cnt1$ 清空,单词个数 $t$ 重置为 0。如果 $s[ r: r +k] $ 在哈希表 $cnt$ 中,说明当前滑动窗口中的单词合法,我们将单词个数 $t$ 加 1,将哈希表 $cnt1$ 中 $s[ r: r +k] $ 的次数加 1。如果 $cnt1[ s[ r: r +k]] $ 大于 $cnt[ s[ r: r +k]] $,说明当前滑动窗口中 $s[ r: r +k] $ 出现的次数过多,我们需要将左边界 $l$ 右移,直到 $cnt1[ s[ r: r +k]] = cnt[ s[ r: r +k]] $。如果 $t = n$,说明当前滑动窗口中的单词正好合法,我们将左边界 $l$ 加入答案数组。
74
+
75
+ 时间复杂度 $O(m \times k)$,空间复杂度 $O(n \times k)$。其中 $m$ 和 $n$ 分别是字符串 $s$ 和字符串数组 $words$ 的长度,而 $k$ 是字符串数组 $words$ 中单词的长度。
76
+
69
77
<!-- tabs:start -->
70
78
71
79
### ** Python3**
@@ -76,16 +84,16 @@ s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接
76
84
class Solution :
77
85
def findSubstring (self , s : str , words : List[str ]) -> List[int ]:
78
86
cnt = Counter(words)
79
- sublen = len (words[ 0 ] )
80
- n, m = len (s), len ( words)
87
+ m, n = len (s), len ( words)
88
+ k = len (words[ 0 ] )
81
89
ans = []
82
- for i in range (sublen ):
90
+ for i in range (k ):
83
91
cnt1 = Counter()
84
92
l = r = i
85
93
t = 0
86
- while r + sublen <= n :
87
- w = s[r : r + sublen ]
88
- r += sublen
94
+ while r + k <= m :
95
+ w = s[r: r + k ]
96
+ r += k
89
97
if w not in cnt:
90
98
l = r
91
99
cnt1.clear()
@@ -94,11 +102,11 @@ class Solution:
94
102
cnt1[w] += 1
95
103
t += 1
96
104
while cnt1[w] > cnt[w]:
97
- remove = s[l : l + sublen ]
98
- l += sublen
105
+ remove = s[l: l + k ]
106
+ l += k
99
107
cnt1[remove] -= 1
100
108
t -= 1
101
- if m == t :
109
+ if t == n :
102
110
ans.append(l)
103
111
return ans
104
112
```
@@ -112,33 +120,33 @@ class Solution {
112
120
public List<Integer > findSubstring (String s , String [] words ) {
113
121
Map<String , Integer > cnt = new HashMap<> ();
114
122
for (String w : words) {
115
- cnt. put (w, cnt . getOrDefault(w, 0 ) + 1 );
123
+ cnt. merge (w, 1 , Integer :: sum );
116
124
}
117
- int subLen = words[ 0 ] . length();
118
- int n = s . length(), m = words . length ;
125
+ int m = s . length(), n = words . length ;
126
+ int k = words[ 0 ] . length();
119
127
List<Integer > ans = new ArrayList<> ();
120
- for (int i = 0 ; i < subLen ; ++ i) {
128
+ for (int i = 0 ; i < k ; ++ i) {
121
129
Map<String , Integer > cnt1 = new HashMap<> ();
122
130
int l = i, r = i;
123
131
int t = 0 ;
124
- while (r + subLen <= n ) {
125
- String w = s. substring(r, r + subLen );
126
- r += subLen ;
132
+ while (r + k <= m ) {
133
+ String w = s. substring(r, r + k );
134
+ r += k ;
127
135
if (! cnt. containsKey(w)) {
128
- l = r;
129
136
cnt1. clear();
137
+ l = r;
130
138
t = 0 ;
131
139
continue ;
132
140
}
133
- cnt1. put (w, cnt1 . getOrDefault(w, 0 ) + 1 );
141
+ cnt1. merge (w, 1 , Integer :: sum );
134
142
++ t;
135
143
while (cnt1. get(w) > cnt. get(w)) {
136
- String remove = s. substring(l, l + subLen );
137
- l += subLen ;
138
- cnt1. put (remove, cnt1 . get(remove) - 1 );
144
+ String remove = s. substring(l, l + k );
145
+ l += k ;
146
+ cnt1. merge (remove, - 1 , Integer :: sum );
139
147
-- t;
140
148
}
141
- if (m == t ) {
149
+ if (t == n ) {
142
150
ans. add(l);
143
151
}
144
152
}
@@ -155,32 +163,35 @@ class Solution {
155
163
public:
156
164
vector<int > findSubstring(string s, vector<string >& words) {
157
165
unordered_map<string, int> cnt;
158
- for (auto& w : words) cnt[ w] ++;
159
- int subLen = words[ 0] .size();
160
- int n = s.size(), m = words.size();
166
+ for (auto& w : words) {
167
+ ++cnt[ w] ;
168
+ }
169
+ int m = s.size(), n = words.size(), k = words[ 0] .size();
161
170
vector<int > ans;
162
- for (int i = 0; i < subLen ; ++i) {
171
+ for (int i = 0; i < k ; ++i) {
163
172
unordered_map<string, int> cnt1;
164
173
int l = i, r = i;
165
174
int t = 0;
166
- while (r + subLen <= n ) {
167
- string w = s.substr(r, subLen );
168
- r += subLen ;
175
+ while (r + k <= m ) {
176
+ string w = s.substr(r, k );
177
+ r += k ;
169
178
if (!cnt.count(w)) {
179
+ cnt1.clear();
170
180
l = r;
171
181
t = 0;
172
- cnt1.clear();
173
182
continue;
174
183
}
175
- cnt1[ w] ++ ;
176
- t++ ;
184
+ ++ cnt1[ w] ;
185
+ ++t ;
177
186
while (cnt1[ w] > cnt[ w] ) {
178
- string remove = s.substr(l, subLen );
179
- l += subLen ;
180
- cnt1[ remove] -- ;
187
+ string remove = s.substr(l, k );
188
+ l += k ;
189
+ -- cnt1[ remove] ;
181
190
--t;
182
191
}
183
- if (t == m) ans.push_back(l);
192
+ if (t == n) {
193
+ ans.push_back(l);
194
+ }
184
195
}
185
196
}
186
197
return ans;
@@ -219,41 +230,36 @@ public:
219
230
### ** Go**
220
231
221
232
``` go
222
- func findSubstring (s string , words []string ) []int {
233
+ func findSubstring (s string , words []string ) ( ans []int ) {
223
234
cnt := map [string ]int {}
224
235
for _ , w := range words {
225
236
cnt[w]++
226
237
}
227
- subLen := len (words[0 ])
228
- n , m := len (s), len (words)
229
- var ans []int
230
- for i := 0 ; i < subLen; i++ {
238
+ m , n , k := len (s), len (words), len (words[0 ])
239
+ for i := 0 ; i < k; i++ {
231
240
cnt1 := map [string ]int {}
232
- l , r := i, i
233
- t := 0
234
- for r+subLen <= n {
235
- w := s[r : r+subLen]
236
- r += subLen
241
+ l , r , t := i, i, 0
242
+ for r+k <= m {
243
+ w := s[r : r+k]
244
+ r += k
237
245
if _ , ok := cnt[w]; !ok {
238
- l = r
239
- t = 0
246
+ l, t = r, 0
240
247
cnt1 = map [string ]int {}
241
248
continue
242
249
}
243
250
cnt1[w]++
244
251
t++
245
252
for cnt1[w] > cnt[w] {
246
- remove := s[l : l+subLen]
247
- l += subLen
248
- cnt1[remove]--
253
+ cnt1[s[l:l+k]]--
254
+ l += k
249
255
t--
250
256
}
251
- if t == m {
257
+ if t == n {
252
258
ans = append (ans, l)
253
259
}
254
260
}
255
261
}
256
- return ans
262
+ return
257
263
}
258
264
```
259
265
@@ -262,56 +268,87 @@ func findSubstring(s string, words []string) []int {
262
268
``` cs
263
269
public class Solution {
264
270
public IList <int > FindSubstring (string s , string [] words ) {
265
- var wordsDict = new Dictionary <string , int >();
266
- foreach (var word in words )
267
- {
268
- if (! wordsDict .ContainsKey (word ))
269
- {
270
- wordsDict .Add (word , 1 );
271
- }
272
- else
273
- {
274
- ++ wordsDict [word ];
271
+ var cnt = new Dictionary <string , int >();
272
+ foreach (var w in words ) {
273
+ if (! cnt .ContainsKey (w )) {
274
+ cnt [w ] = 0 ;
275
275
}
276
+ ++ cnt [w ];
276
277
}
277
-
278
- var wordOfS = new string [s .Length ];
279
- var wordLength = words [0 ].Length ;
280
- var wordCount = words .Length ;
281
- for (var i = 0 ; i <= s .Length - wordLength ; ++ i )
282
- {
283
- var substring = s .Substring (i , wordLength );
284
- if (wordsDict .ContainsKey (substring ))
285
- {
286
- wordOfS [i ] = substring ;
278
+ int m = s .Length , n = words .Length , k = words [0 ].Length ;
279
+ var ans = new List <int >();
280
+ for (int i = 0 ; i < k ; ++ i ) {
281
+ var cnt1 = new Dictionary <string , int >();
282
+ int l = i , r = i , t = 0 ;
283
+ while (r + k <= m ) {
284
+ var w = s .Substring (r , k );
285
+ r += k ;
286
+ if (! cnt .ContainsKey (w )) {
287
+ cnt1 .Clear ();
288
+ t = 0 ;
289
+ l = r ;
290
+ continue ;
291
+ }
292
+ if (! cnt1 .ContainsKey (w )) {
293
+ cnt1 [w ] = 0 ;
294
+ }
295
+ ++ cnt1 [w ];
296
+ ++ t ;
297
+ while (cnt1 [w ] > cnt [w ]) {
298
+ -- cnt1 [s .Substring (l , k )];
299
+ l += k ;
300
+ -- t ;
301
+ }
302
+ if (t == n ) {
303
+ ans .Add (l );
304
+ }
287
305
}
288
306
}
307
+ return ans ;
308
+ }
309
+ }
310
+ ```
289
311
290
- var result = new List <int >();
291
- for (var i = 0 ; i <= s .Length - wordLength * wordCount ; ++ i )
292
- {
293
- var tempDict = new Dictionary <string , int >(wordsDict );
294
- var tempCount = 0 ;
295
- for (var j = i ; j <= i + wordLength * (wordCount - 1 ); j += wordLength )
296
- {
297
- if (wordOfS [j ] != null && tempDict [wordOfS [j ]] > 0 )
298
- {
299
- -- tempDict [wordOfS [j ]];
300
- ++ tempCount ;
301
- }
302
- else
303
- {
304
- break ;
305
- }
312
+ ### ** TypeScript**
313
+
314
+ ``` ts
315
+ function findSubstring(s : string , words : string []): number [] {
316
+ const cnt: Map <string , number > = new Map ();
317
+ for (const w of words ) {
318
+ cnt .set (w , (cnt .get (w ) || 0 ) + 1 );
319
+ }
320
+ const m = s .length ;
321
+ const n = words .length ;
322
+ const k = words [0 ].length ;
323
+ const ans: number [] = [];
324
+ for (let i = 0 ; i < k ; ++ i ) {
325
+ const cnt1: Map <string , number > = new Map ();
326
+ let l = i ;
327
+ let r = i ;
328
+ let t = 0 ;
329
+ while (r + k <= m ) {
330
+ const w = s .slice (r , r + k );
331
+ r += k ;
332
+ if (! cnt .has (w )) {
333
+ cnt1 .clear ();
334
+ l = r ;
335
+ t = 0 ;
336
+ continue ;
306
337
}
307
- if (tempCount == wordCount )
308
- {
309
- result .Add (i );
338
+ cnt1 .set (w , (cnt1 .get (w ) || 0 ) + 1 );
339
+ ++ t ;
340
+ while (cnt1 .get (w )! - cnt .get (w )! > 0 ) {
341
+ const remove = s .slice (l , l + k );
342
+ cnt1 .set (remove , cnt1 .get (remove )! - 1 );
343
+ l += k ;
344
+ -- t ;
345
+ }
346
+ if (t === n ) {
347
+ ans .push (l );
310
348
}
311
349
}
312
-
313
- return result ;
314
350
}
351
+ return ans ;
315
352
}
316
353
```
317
354
0 commit comments