串联所有单词的子串
题目描述:
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
// original idea :TimeOut
class Solution {
private List<String> combination = new ArrayList<String>();
private int[] index; // 每次保存的下标
private String[] words;
private int len;
private boolean[] used;
public List<Integer> findSubstring(String s, String[] words) {
// 初始化实例变量
this.words = words;
this.len = words.length;
index = new int[len];
used = new boolean[len];
List<Integer> result = new ArrayList<Integer>();
// 利用DFS算法求所有可能的组合
DFS(0);
for(int i = 0 ; i<s.length()-len*words[0].length()+1 && i<s.length(); i++){
boolean flag = false; // 提前结束标记
for(int j = 0 ; j<combination.size() ;j++){ // 遍历所有组合
for(int k = 0 ; k< combination.get(j).length() ;k++){
if(s.charAt(i+k) == combination.get(j).charAt(k)){
if(k == combination.get(j).length()-1){
result.add(i);
flag = true;
}
}else break;
if(flag) break;
}
}
}
return result;
}
public void DFS(int count){
if(count == this.len){ // 边界条件
StringBuffer sb = new StringBuffer();
for(int i = 0 ; i<count; i++){
sb.append(words[index[i]]);
}
combination.add(sb.toString()); // 保存结果
}
for(int i = 0 ; i<this.len ; i++){ // 遍历接下来的所有组合
if(!used[i]){ // 找到接下来的可行方案
used[i] = true;
index[count] = i;
DFS(count+1);
used[i] = false;
}
}
}
}
// 别人的思路
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if (s.empty() || words.empty()) return {};
int n = words.size();
int m = words[0].size();
int j = 0;
if (s.length() < m * n) return {};
vector<int> res;
unordered_map<string, int> mp, tmp;
for (auto str : words) {
++mp[str];
}
string str = "";
for (int i = 0; i + m * n <= s.size(); ++i) {
for (j = i; j < i + m * n; j += m) {
str = s.substr(j, m);
if (mp.find(str) == mp.end()) break;
++tmp[str];
}
if (j == i + m * n && tmp == mp) res.push_back(i);
tmp.clear();
}
return res;
}
};
首先利用深度优先算法找出所有的组合方式,然后一个for循环遍历s字符串,然后再比较是否相等。