题目链接
题目:
分析:
我们上次做的题目, 是找到所有字符的异位词, 和这道题有些类似, 使用记录有效字符的个数找到子字符, 此题无非是把字符变成了字符串题目回顾 有一下几方面不同, 我们以示例1为例:
1. 哈希表
上次我们使用的是哈希数组, 因为数组的下标可以是字符, 现在变成字符串, 所以我们可以使用hashMap<String,Integer>来映射字符串和出现次数的关系
2. 窗口大小
words数组的长度为2, 那么窗口大小就固定了是2, 但是每个元素是长度len为3的字符串, 所以真正的窗口大小应该是2*3 = 6
3. left和right移动距离
因为我们要找的是字符串, 所以left和right每次需要移动len个字符, 才能找到下一个字符串
4. 遍历次数
但是如果left和right从零开始, 每次移动len个字符, 不能够找到所有的长度为len子字符串, 所以我们需要重新遍历字符串, 此时从0的下一个位置开始, 每次移动len个字符, 如果我们想找到所有的长度为len字符串, 只需循环len次就可以, 每次都从下一个位置开始, 因为循环len+1次, 会和从0位置开始遍历的重复
思路:
- 使用hashMap<String,Integer>, 将words中的元素记录在hash1中
- 定义begin来记录遍历次数及每次遍历开始的位置
- 定义 left = begin, right = begin, 有效个数count = 0
- 定义hash2存放每次遍历的窗口(注意: 不能在循坏外定义hash2, 因为每次循环都应该重新new一个hash记录窗口情况)
- 进窗口 此时的条件应该是right+len<=s.length(), 因为我们要从right截取len大小的字符串, 如果像以前写成right<s.length(), 可能会导致越界, 截取子字符串使用substring()方法, 每次right移动len
- 进窗口后, 判断count的值是否需要变化
- 判断 如果窗口的大小 > words数组中的字符总长度, 则出窗口
- 出窗口前, 判断count的值是否需要变化
- 出窗口 每次left移动len
- 更新结果 如果count == 字符串的个数, 说明找到此子字符串, 记录left
代码:
class Solution {
public List<Integer> findSubstring(String s, String[] words) {
List<Integer> list = new ArrayList<>();
Map<String, Integer> hash1 = new HashMap<>();
for (int i = 0; i < words.length; i++) {
hash1.put(words[i], hash1.getOrDefault(words[i], 0) + 1);
}
int begin = 0;
int len = words[0].length();
while (begin < len) {
int left = begin;
int right = begin;
int count = 0;
Map<String, Integer> hash2 = new HashMap<>();
while (right + len <= s.length()) {
String in = s.substring(right, right + len);
hash2.put(in, hash2.getOrDefault(in, 0) + 1);
if (hash2.getOrDefault(in, 0) <= hash1.getOrDefault(in, 0))
count++;
if (right - left + 1 > words.length*len) {
String out = s.substring(left, left + len);
if (hash2.getOrDefault(out, 0) <= hash1.getOrDefault(out, 0))
count--;
hash2.put(out, hash2.get(out) - 1);
left += len;
}
if (count == words.length) {
list.add(left);
}
right += len;
}
begin++;
}
return list;
}
}