题目描述:
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 1:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是"abc" 的异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。
示例 2:
输入: s = “abab”, p = “ab”
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 “ab”, 它是 "ab"的异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的异位词。
起始索引等于 2 的子串是 “ab”, 它是 "ab"的异位词。
提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
思路:
最简单的思路是用数组下标存起来,然后用s一个个去比较p。如下
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int a[] = new int[26];
int t[] = new int[26];
List<Integer> result = new LinkedList<>();
for(int i = 0 ; i < p.length() ; i++)a[p.charAt(i) - 'a']++;
for(int i = 0; i < s.length() ; i++)
{
if(a[s.charAt(i)-'a'] > 0 && (i+p.length()) <= s.length())//先看有没有这个字符,然后长度会不会越界
{
int flag = 0;
int j,k;
Arrays.fill(t, 0);
for(j = i,k=i+p.length()-1; k>=j; j++,k--)
{
t[s.charAt(j)-'a']++;
t[s.charAt(k)-'a']++;
if(k==j)t[s.charAt(j)-'a']--;
if(t[s.charAt(j)-'a'] > a[s.charAt(j)-'a'] || t[s.charAt(k)-'a'] > a[s.charAt(k)-'a'])break;
}
for(j = 0 ; j < 26 ; j++)
{
if(a[j] != t[j])
{
flag = 1;
break;
}
}
if(flag == 0) result.add(i);
}
}
return result;
}
}
什么情况下会想到滑动窗口法:
任何题目如果没有思路其实都可以想一下暴力解法。这道题暴力解法思路简单:
遍历任意i,j,使得i和j之间的子串长度,等于p串的长度。该子串称之为x。该步复杂度为O(n)。
判断x是否与p是异位词。是的话,则把i加入答案中。该步复杂度为O(n)。
暴力法的复杂度为O(n^2)。显然不高效。
可以发现第二步其实做了很多不必要的操作,例如[i, j]和[i+1, j+1]两个子串在暴力法第二步中,需要各遍历一次,完全没必要。其实[i+1, j+1]完全可以在[i, j]的基础上做判断,也就是去掉头部的字符(i位置),加上尾部的字符(j+1位置)。这样第一步的复杂度可以降到O(1)。整体复杂度降到O(n)。已经得到信息不重复使用就浪费了,没必要重新搜集近乎相同的信息。这就是滑动窗口法。
滑动窗口法的特点是,一连串元素的信息,可以用常数时间推断出,该串整体移位后,新串信息。
所有滑动窗口问题,如果能从暴力法优化的角度思考,都不难想到,代码如下:
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int n = s.length(), m = p.length();
List<Integer> res = new ArrayList<>();
if(n < m) return res;
int[] pCnt = new int[26];
int[] sCnt = new int[26];
for(int i = 0; i < m; i++){
pCnt[p.charAt(i) - 'a']++;
sCnt[s.charAt(i) - 'a']++;
}
if(Arrays.equals(sCnt, pCnt)){
res.add(0);
}
for(int i = m; i < n; i++){
sCnt[s.charAt(i - m) - 'a']--;
sCnt[s.charAt(i) - 'a']++;
if(Arrays.equals(sCnt, pCnt)){
res.add(i - m + 1);
}
}
return res;
}
}