30. 串联所有单词的子串
如果我们把单词看成一个整体,就变成了类似【字符串中找最长不重复的字符子串】,为了能使得我们得到完整的遍历空间。
假设数组长度*单词长度=k,要遍历所有可能,需要[0~n-k]单词作为起点来判断是否可能。
实际上我们需要考虑的是没我们以单词长度为单位来移动,分别以第一个单词的每个字符作为起点,就可以找到等价上面的所有所有的可能性。
于是就可以进行具体建模:
定义left和right,并保证[left,right)区间内的都处于合法状态(每一单词在单词数组里面,且数量不超过),只要这样延伸到满足每一单词都数量相等,即为答案。
找到答案后,需再找答案空间,就是将left右移一个单位。
public List<Integer> findSubstring(String s, String[] words) {
List<Integer> ans = new ArrayList<>();
if (words == null || words.length == 0) return ans;
HashMap<String, Integer> set = new HashMap<>();
for (String i : words) set.put(i, set.getOrDefault(i, 0) + 1);
int len = words[0].length();
for (int i = 0; i < len; i++) {
HashMap<String, Integer> judge = new HashMap<>();
int left = i, right = i;
for (; right <= s.length() - len; right += len) {
String t = s.substring(right, right + len);
if (!set.containsKey(t)) {
for (; left < right; left += len) {
String tt = s.substring(left, left + len);
judge.put(tt, judge.getOrDefault(tt, 1) - 1);
}
left += len;
continue;
}
else if (judge.getOrDefault(t,0)>=set.get(t)){
for (; judge.get(t)>=set.get(t); left += len) {
String tt = s.substring(left, left + len);
judge.put(tt, judge.getOrDefault(tt, 1) - 1);
}
}
if (set.containsKey(t)) judge.put(t, judge.getOrDefault(t, 0) + 1);
if (set.size() == judge.size()) {
boolean isChecked = true;
for (Map.Entry<String, Integer> entry : set.entrySet()) {
if (!judge.getOrDefault(entry.getKey(), 0).equals(entry.getValue())) {
isChecked = false;
break;
}
}
if (isChecked) {
ans.add(left);
String tt = s.substring(left, left + len);
judge.put(tt, judge.getOrDefault(tt, 1) - 1);
left += len;
}
}
}
}
return ans;
}