题目链接
题目:
分析:
我们上次做的题目, 是找到所有字符的异位词, 和这道题有些类似, 使用记录有效字符的个数找到子字符, 此题无非是把字符变成了字符串题目回顾 有一下几方面不同, 我们以示例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;}
}