目录
一、题目
给定两个字符串 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 的异位词。因为字符串 p 的异位词的长度一定与字符串 p 的长度相同,所以我们可以在字符串 s 中构造一个长度为与字符串 p 的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量;当窗口中每种字母的数量与字符串 p 中每种字母的数量相同时,则说明当前窗口为字符串 p 的异位词。
在算法的实现中,我们可以使用数组来存储字符串 p 和滑动窗口中每种字母的数量。
[i, i+p.length()-1]表示滑动窗口的下标,其中 0 <= i <= (s的长度-p的长度+1)。用数组统计完滑动窗口内的词频后,通过Arrays.equals方法与目标字符串 p 的词频做比较。如果相等,则 i 即为满足条件的下标。
窗口向后移动一位,新的窗口下标为[i+1 , i+p.length()]。统计新滑动窗口内的词频时,可以在上一步统计结果的基础上,加上新移入窗口的下标为 i+p.length()的字符,并去掉移出窗口的下标为 i 的字符,以此来降低时间复杂度。
三、答案
import java.util.Arrays;
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> indexList = new ArrayList<>();
// 统计目标字符串的词频
int[] target = new int[26];
for (int i = 0; i < p.length(); i++) {
target[p.charAt(i) - 'a']++;
}
// 统计滑动窗口字符串的词频
int[] window = new int[26];
for (int i = 0; i <= s.length() - p.length(); i++) {
// [i, i+p.length()-1]表示滑动窗口的下标
if (i == 0) {
for (int j = i; j < i + p.length(); j++) {
window[s.charAt(j) - 'a']++;
}
} else {
//更新词频:下标i - 1移出窗口,i + p.length() - 1移入窗口
window[s.charAt(i - 1) - 'a']--;
window[s.charAt(i + p.length() - 1) - 'a']++;
}
if (Arrays.equals(target, window)) {
indexList.add(i);
}
}
return indexList;
}
}
日日刷算法,老年痴呆远离我~