Skip to content

Commit 4d5f28e

Browse files
committed
feat: add solutions to lc problem: No.0030
No.0030.Substring with Concatenation of All Words
1 parent c290d32 commit 4d5f28e

File tree

8 files changed

+384
-284
lines changed

8 files changed

+384
-284
lines changed

solution/0000-0099/0030.Substring with Concatenation of All Words/README.md

+131-94
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接
6666

6767
**方法一:哈希表 + 滑动窗口**
6868

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+
6977
<!-- tabs:start -->
7078

7179
### **Python3**
@@ -76,16 +84,16 @@ s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接
7684
class Solution:
7785
def findSubstring(self, s: str, words: List[str]) -> List[int]:
7886
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])
8189
ans = []
82-
for i in range(sublen):
90+
for i in range(k):
8391
cnt1 = Counter()
8492
l = r = i
8593
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
8997
if w not in cnt:
9098
l = r
9199
cnt1.clear()
@@ -94,11 +102,11 @@ class Solution:
94102
cnt1[w] += 1
95103
t += 1
96104
while cnt1[w] > cnt[w]:
97-
remove = s[l : l + sublen]
98-
l += sublen
105+
remove = s[l: l + k]
106+
l += k
99107
cnt1[remove] -= 1
100108
t -= 1
101-
if m == t:
109+
if t == n:
102110
ans.append(l)
103111
return ans
104112
```
@@ -112,33 +120,33 @@ class Solution {
112120
public List<Integer> findSubstring(String s, String[] words) {
113121
Map<String, Integer> cnt = new HashMap<>();
114122
for (String w : words) {
115-
cnt.put(w, cnt.getOrDefault(w, 0) + 1);
123+
cnt.merge(w, 1, Integer::sum);
116124
}
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();
119127
List<Integer> ans = new ArrayList<>();
120-
for (int i = 0; i < subLen; ++i) {
128+
for (int i = 0; i < k; ++i) {
121129
Map<String, Integer> cnt1 = new HashMap<>();
122130
int l = i, r = i;
123131
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;
127135
if (!cnt.containsKey(w)) {
128-
l = r;
129136
cnt1.clear();
137+
l = r;
130138
t = 0;
131139
continue;
132140
}
133-
cnt1.put(w, cnt1.getOrDefault(w, 0) + 1);
141+
cnt1.merge(w, 1, Integer::sum);
134142
++t;
135143
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);
139147
--t;
140148
}
141-
if (m == t) {
149+
if (t == n) {
142150
ans.add(l);
143151
}
144152
}
@@ -155,32 +163,35 @@ class Solution {
155163
public:
156164
vector<int> findSubstring(string s, vector<string>& words) {
157165
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();
161170
vector<int> ans;
162-
for (int i = 0; i < subLen; ++i) {
171+
for (int i = 0; i < k; ++i) {
163172
unordered_map<string, int> cnt1;
164173
int l = i, r = i;
165174
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;
169178
if (!cnt.count(w)) {
179+
cnt1.clear();
170180
l = r;
171181
t = 0;
172-
cnt1.clear();
173182
continue;
174183
}
175-
cnt1[w]++;
176-
t++;
184+
++cnt1[w];
185+
++t;
177186
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];
181190
--t;
182191
}
183-
if (t == m) ans.push_back(l);
192+
if (t == n) {
193+
ans.push_back(l);
194+
}
184195
}
185196
}
186197
return ans;
@@ -219,41 +230,36 @@ public:
219230
### **Go**
220231

221232
```go
222-
func findSubstring(s string, words []string) []int {
233+
func findSubstring(s string, words []string) (ans []int) {
223234
cnt := map[string]int{}
224235
for _, w := range words {
225236
cnt[w]++
226237
}
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++ {
231240
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
237245
if _, ok := cnt[w]; !ok {
238-
l = r
239-
t = 0
246+
l, t = r, 0
240247
cnt1 = map[string]int{}
241248
continue
242249
}
243250
cnt1[w]++
244251
t++
245252
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
249255
t--
250256
}
251-
if t == m {
257+
if t == n {
252258
ans = append(ans, l)
253259
}
254260
}
255261
}
256-
return ans
262+
return
257263
}
258264
```
259265

@@ -262,56 +268,87 @@ func findSubstring(s string, words []string) []int {
262268
```cs
263269
public class Solution {
264270
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;
275275
}
276+
++cnt[w];
276277
}
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+
}
287305
}
288306
}
307+
return ans;
308+
}
309+
}
310+
```
289311

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;
306337
}
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);
310348
}
311349
}
312-
313-
return result;
314350
}
351+
return ans;
315352
}
316353
```
317354

0 commit comments

Comments
 (0)