大家好!我是曾续缘💚
今天是《LeetCode 热题 100》系列
发车第 9 天
滑动窗口第 2 题
❤️点赞 👍 收藏 ⭐再看,养成习惯
给定两个字符串
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
都是小写字母, 我们可以使用cnt[26]
来给字符串p
的每个字符计数。
s
中p
的异位词子串长度肯定等于字符串p
的长度, 因此我们可以判断s
中每个长度为p
字符串长度的字符串的字符计数,即使用定长窗口, 如果和字符串p
的字符计数相同, 说明找到了一个。
我们使用l
,r
来表示窗口的左右端点, 初始l = r = 0
, 到达p
字符串长度后, l
,r
每次都向前移动一个字符, 即增加r
位置字符, 减去l
位置字符。
为了充分利用cnt[26]
数组, 我们使用相消的策略, 即用s
的字符计数在cnt
数组中减去, 符合异位词子串的条件是cnt[26]
都为0
。
为了更容易判断cnt[26]
都为0
而不是通过遍历cnt
来判断, 我们使用diff
记录cnt
中的值不为0
的个数, 如果diff
为0
了, 就说明了cnt[26]
都为0
。
Code
查看代码
java
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int n = s.length(), m = p.length();
List<Integer>ans = new ArrayList<Integer>();
int[] cnt = new int[26];
for(int i = 0; i < m; i++){
cnt[p.charAt(i) - 'a']++;
}
int diff = 0;
for(int i = 0; i < 26; i++){
if(cnt[i] != 0) diff++;
}
for(int l = 0, r = 0; r < n; r++){
if(--cnt[s.charAt(r) - 'a'] == 0){
diff--;
}
if(r - l + 1 > m && ++cnt[s.charAt(l++) - 'a'] == 1){
diff++;
}
if(diff == 0){
ans.add(l);
}
}
return ans;
}
}