问题描述
- Given a string s and a non-empty string p, find all the start indices of p’s anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter. - Example:
Input:
s: “cbaebabacd” p: “abc”
Output:
[0, 6]
Explanation:
The substring with start index = 0 is “cba”, which is an anagram of “abc”.
The substring with start index = 6 is “bac”, which is an anagram of “abc”.
Input:
s: “abab” p: “ab”
Output:
[0, 1, 2]
Explanation:
The substring with start index = 0 is “ab”, which is an anagram of “ab”.
The substring with start index = 1 is “ba”, which is an anagram of “ab”.
The substring with start index = 2 is “ab”, which is an anagram of “ab”.
问题分析
- 在s串中找出所有p的 Anagrams子串,用滑动窗口来做。
滑动窗口的大致流程为起初窗口为[left, right),然后将right处元素满足加入窗口。看加数发生了什么变化,根据变化决定缩小窗口,或者继续扩大窗口。比如该题,若加数后满足形成的子串满足既定的规则,则收集当前窗口的结果。满足一定规则后,right不能继续扩了,则通过右移left来缩小窗口,才能使当前窗口能够重新加数,得到新的子串。直到right遍历到数组末尾,结束。
经验教训
- 滑动窗口处理子串或者子数组的技巧
- 相应题目
代码实现
class Solution {
public List<Integer> findAnagrams(String s, String p) {
if (s == null || p == null) {
return new ArrayList<Integer>();
}
int sLen = s.length();
int pLen = p.length();
if (sLen == 0 || pLen == 0 || sLen < pLen) {
return new ArrayList<Integer>();
}
List<Integer> res = new ArrayList<>();
//map用来记录当前窗口离p串,每个字符相差的个数,若某一字符为负,说明该字符多余了
int[] map = new int[256];
//diff用来记录当前窗口离p串还差几个字符,因为初始化窗口不存在数字初始化为pLen,差pLen个字符
int diff = pLen;
//因为初始化窗口内不存在数字,那么p的每一个字符都差。
for (int i = 0; i < pLen; i++) {
++map[p.charAt(i)];
}
//初始化窗口左右边界,窗口左闭右开,[left, right)
int left = 0;
int right = 0;
while (right < sLen) {
//窗口加数,更新map
if (map[s.charAt(right)]-- > 0) {
//map[s.charAt(right)] > 0 说明待入窗字符属于p串,并且当前窗口内该字符还不满足达到P串的要求
//若加入该元素,则能改变diff,diff--
--diff;
}
if (diff == 0) {
//相差字符为0,说明当前窗口满足要求
res.add(left);
}
//如果[left,right)长度已经达到 pLen,说明窗口应该缩小,左侧减数
if (right - left == pLen) {
if (map[s.charAt(left)] >= 0){//如果欲出窗的数属于p串,并且并不多余
//不多余的元素,出窗一定会影响diff
++diff;
}
//更新map
++map[s.charAt(left)];
//出窗,缩小窗口
++left;
}
//右指针右移
++right;
}
return res;
}
}