You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.
For example, given: S:
"barfoothefoobarman"
L:["foo", "bar"]
You should return the indices:
[0,9]
. (order does not matter).
题目地址:leetcode Substring with Concatenation of All Words
题目大意:给定一些单词words(可能重复,长度相同)和一个长字符串s,要求求出长字符串的所有起始位置,使得给定的所有单词在之后出现一次且仅一次
思路:
方法一
首先用对words中每个单词进行计数count_word(hash表),
枚举起始位置和终点位置,每次用cur_cnt计数,若单词存在且cur_cnt[word] <= count_word[word],总计数total_in+1, 如果rotal_in等于words的长度,放入答案ans
复杂度O(len(s) * len(words) * t), t为计算每个单词hash值的时间。
C++ 125ms
1 | class Solution { |
Python
1 | class Solution: |
方法二
我们可以用滑动窗口思想优化上面的过程。
设word_len为单词的长度,枚举可能的起点为[0, word_len],
然后枚举s中的单词,令start = i表示当前窗口的起点,令j = i表示当前枚举的字符串s的起点,每次枚举结束j+= word_len
在枚举s中单词的过程中保持一个合法的窗口 使得cur_cnt[word] <= count_word[word],若窗口不合法,则说明之前已经有单词存在,不断的令start对应的单词-=1,start+=word_len即可。
复杂度O(word_len * len(s) / word_len * 2)= O(len(s) * 2)
,乘上2是因为一次遍历中,每个单词最多两次。(PS:这个复杂度没有计算哈希的代价,假设为O(1))
C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ans;
if (s.empty() || words.empty()) return ans;
int word_len = words[0].size();
unordered_map<string, int> count_word;
for (const string &word : words)
++count_word[word];
for (int i = 0; i < word_len; ++i) {
int total_in = 0;
unordered_map<string, int> cur_cnt;
for (int j = i, start = i; j + word_len <= s.size(); j += word_len) {
string word = s.substr(j, word_len);
if (count_word.find(word) == count_word.end()) {
cur_cnt.clear();
total_in = 0;
start = j + word_len;
}
else {
++cur_cnt[word];
while (cur_cnt[word] > count_word[word]) {
--cur_cnt[s.substr(start, word_len)];
start += word_len;
--total_in;
}
if (++total_in == words.size()) {
ans.push_back(start);
}
}
}
}
return ans;
}
};
Python 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29class Solution(object):
def findSubstring(self, s, words):
"""
:type s: str
:type words: List[str]
:rtype: List[int]
"""
if not s or not words: return []
word_len = len(words[0])
word_total = (len(words) - 1) * word_len
ans = []
word_cnt = collections.Counter(words)
for i in range(word_len):
start = i
cur_cnt = collections.Counter()
for j in range(i, len(s) - word_len + 1, word_len):
word = s[j: j + word_len]
if word in word_cnt:
cur_cnt[word] += 1
while cur_cnt[word] > word_cnt[word]:
cur_cnt[s[start: start + word_len]] -= 1
start += word_len
else:
cur_cnt.clear()
start = j + word_len
if(start + word_total == j):
ans.append(start)
return ans
更多题解可以查看: https://www.hrwhisper.me/leetcode-algorithm-solution/