串联所有单词的⼦串(hard)
- 题⽬描述:
- 解法⼀(暴⼒解法):
- 算法思路:
- C++ 算法代码:
- Java 算法代码:
题⽬链接:30. 串联所有单词的⼦串
题⽬描述:
给定⼀个字符串 s 和⼀个字符串数组 words。 words 中所有字符串 ⻓度相同。
s 中的 串联⼦串 是指⼀个包含 words 中所有字符串以任意顺序排列连接起来的⼦串。
◦ 例如,如果 words = [“ab”,“cd”,“ef”], 那么"abcdef",“abefcd”,“cdabef”,“cdefab”,“efabcd”, 和 “efcdab” 都是串联⼦串。 “acdbef” 不是串联⼦串,因为他不是任何 words 排列的连接。
返回所有串联字串在 s 中的开始索引。你可以以 任意顺序 返回答案。
⽰例 1:
输⼊:s = “barfoothefoobarman”, words = [“foo”,“bar”]
输出:[0,9]
解释:因为 words.length = = 2 同时 words[i].length = = 3,连接的⼦字符串的⻓度必须为 6。
⼦串 “barfoo” 开始位置是 0。它是 words 中以 [“bar”,“foo”] 顺序排列的连接。
⼦串 “foobar” 开始位置是 9。它是 words 中以 [“foo”,“bar”] 顺序排列的连接。
输出顺序⽆关紧要。返回 [9,0] 也是可以的。
⽰例 2:
输⼊:s = “wordgoodgoodgoodbestword”, words = [“word”,“good”,“best”,“word”]
输出:[]
解释:因为 words.length = = 4 并且 words[i].length = = 4,所以串联⼦串的⻓度必须为 16。
s 中没有⼦串⻓度为 16 并且等于 words 的任何顺序排列的连接。
所以我们返回⼀个空数组。
⽰例 3:
输⼊:s = “barfoofoobarthefoobarman”, words = [“bar”,“foo”,“the”]
输出:[6,9,12]
解释:因为 words.length = = 3 并且 words[i].length = = 3,所以串联⼦串的⻓度必须为 9。
⼦串 “foobarthe” 开始位置是 6。它是 words 中以 [“foo”,“bar”,“the”] 顺序排列的连接。
⼦串 “barthefoo” 开始位置是 9。它是 words 中以 [“bar”,“the”,“foo”] 顺序排列的连接。
⼦串 “thefoobar” 开始位置是 12。它是 words 中以 [“the”,“foo”,“bar”] 顺序排列的连接。
提⽰:
1 <= s.length <= 104
1 <= words.length <= 5000
1 <= words[i].length <= 30
words[i] 和 s 由⼩写英⽂字⺟组成
解法⼀(暴⼒解法):
算法思路:
如果我们把每⼀个单词看成⼀个⼀个字⺟,问题就变成了找到「字符串中所有的字⺟异位词」。⽆⾮就是之前处理的对象是⼀个⼀个的字符,我们这⾥处理的对象是⼀个⼀个的单词。
C++ 算法代码:
class Solution{
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ret;
unordered_map<string, int> hash1; // 保存 words ⾥⾯所有单词的频次
for(auto& s : words) hash1[s]++;
int len = words[0].size(), m = words.size();
for(int i = 0; i < len; i++) { // 执⾏ len 次
unordered_map<string, int> hash2; // 维护窗⼝内单词的频次
for(int left = i, right = i, count = 0; right + len <= s.size();
right += len){
// 进窗⼝ + 维护 count
string in = s.substr(right, len);
hash2[in]++;
if(hash1.count(in) && hash2[in] <= hash1[in]) count++;
// 判断
if(right - left + 1 > len * m){
// 出窗⼝ + 维护 count
string out = s.substr(left, len);
if(hash1.count(out) && hash2[out] <= hash1[out]) count--;
hash2[out]--;
left += len;
}
// 更新结果
if(count == m) ret.push_back(left);
}
}
return ret;
}
}
Java 算法代码:
class Solution{
public List<Integer> findSubstring(String s, String[] words){
List<Integer> ret = new ArrayList<Integer>();
// 保存字典中所有单词的频次
Map<String, Integer> hash1 = new HashMap<String, Integer>();
for(String str : words) hash1.put(str, hash1.getOrDefault(str, 0) + 1);
int len = words[0].length(), m = words.length;
for(int i = 0; i < len; i++) { // 执⾏次数
// 保存窗⼝内所有单词的频次
Map<String, Integer> hash2 = new HashMap<String, Integer>();
for(int left = i, right = i, count = 0; right + len <= s.length();
right += len){
// 进窗⼝ + 维护 count
String in = s.substring(right, right + len);
hash2.put(in, hash2.getOrDefault(in, 0) + 1);
if(hash2.get(in) <= hash1.getOrDefault(in, 0)) count++;
// 判断
if(right - left + 1 > len * m){
// 出窗⼝ + 维护 count
String out = s.substring(left, left + len);
if(hash2.get(out) <= hash1.getOrDefault(out, 0)) count--;
hash2.put(out, hash2.get(out) - 1);
left += len;
}
// 更新结果
if(count == m) ret.add(left);
}
}
return ret;
}
}