30. 串联所有单词的子串 - LeetCode
30. 串联所有单词的子串
直接枚举所有子串
class Solution {
public List<Integer> findSubstring(String s, String[] words) {
int sLen = s.length();
int n = words.length;
int wordLen = words[0].length();
int sumLen = wordLen * n;
Map<String, Integer> map = new HashMap<>();
for(int i = 0; i < n; i++){
if(!map.containsKey(words[i]))
map.put(words[i], 1);
else map.put(words[i], map.get(words[i]) + 1);
}
List<Integer> list = new ArrayList<>();
for(int i = 0; i < sLen - sumLen + 1; i++){
boolean flag = true;
Map<String, Integer> mapTemp = new HashMap<>(map);
for(int j = i; j <= i + (n - 1) * wordLen; j += wordLen){
String str = s.substring(j, j + wordLen);
if(!mapTemp.containsKey(str) || mapTemp.get(str) == 0){
flag = false;
break;
} else mapTemp.put(str, mapTemp.get(str) - 1);
}
if(flag) list.add(i);
}
return list;
}
}
- 使用map记录每个单词的可用次数,枚举起始点,判断是否可行
- 时间复杂度为O(n2logn)
双指针滑动窗口
class Solution {
public List<Integer> findSubstring(String s, String[] words) {
int sLen = s.length();
int n = words.length;
int wordLen = words[0].length();
int sumLen = wordLen * n;
Map<String, Integer> map = new HashMap<>();
for(int i = 0; i < n; i++){
if(!map.containsKey(words[i]))
map.put(words[i], 1);
else map.put(words[i], map.get(words[i]) + 1);
}
List<Integer> list = new ArrayList<>();
for(int k = 0; k < wordLen; k++){
Map<String, Integer> mapTemp = new HashMap<>(map);
int i = 0;
for(int j = 0; k + (j + 1) * wordLen - 1 < sLen ; j++){
String strJ = s.substring(k + j * wordLen, k + (j + 1) * wordLen);
if(!mapTemp.containsKey(strJ)){
while(i < j){
String strI = s.substring(k + i * wordLen, k + (i + 1) * wordLen);
mapTemp.put(strI, mapTemp.get(strI) + 1);
i++;
}
i++;
} else if(mapTemp.get(strJ) == 0){
while(i < j){
String strI = s.substring(k + i * wordLen, k + (i + 1) * wordLen);
if(strI.equals(strJ)){
i++;
break;
}
mapTemp.put(strI, mapTemp.get(strI) + 1);
i++;
}
} else{
mapTemp.put(strJ, mapTemp.get(strJ) - 1);
if(j - i + 1 == n){
list.add(k + i * wordLen);
String strI = s.substring(k + i * wordLen, k + (i + 1) * wordLen);
mapTemp.put(strI, mapTemp.get(strI) + 1);
i++;
}
}
}
}
return list;
}
}
-
双指针分别表示当前子串的头尾,按顺序枚举尾指针,分为以下三种情况:
- 若尾指针所在子串不在单词中,将头指针移过来,清空当前子串
- 若尾指针所在子串的单词次数用完,则将头指针右移,直到该单词有可用次数
- 若尾指针所在子串的单词有可用次数少,就用掉一次
- 若此时所有单词都匹配,则加入list
-
注意:因为每次都是按单词长度移动窗口,所以需要考虑起始点的offset
-
时间复杂度为O(nlogn)

浙公网安备 33010602011771号