1、题目来源
438. 找到字符串中所有字母异位词 - 力扣(LeetCode)
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
仅包含小写字母
3、题解分享
// 方法一:
class Solution {
public List<Integer> findAnagrams(String s, String p) {
//思路:滑动窗口 + 固定窗口长度,每次移动都比较窗口内的字符是否是异位词
int sLen = s.length(),pLen = p.length();
if(sLen < pLen){
return new ArrayList<>();
}
// 存储每个字符串中的各个字符的个数
int[] sCount = new int[26];
int[] pCount = new int[26];
for(int i = 0;i<pLen;++i){
++pCount[p.charAt(i) - 'a'];
++sCount[s.charAt(i) - 'a'];
}
List<Integer> ans = new ArrayList<>();
if(Arrays.equals(sCount,pCount)){// 比较两个数组是否相同,下同
ans.add(0);
}
// 移动滑动窗口
for(int i = 0;i<sLen - pLen;++i){
--sCount[s.charAt(i) - 'a'];
++sCount[s.charAt(i+pLen) - 'a'];
if(Arrays.equals(sCount,pCount)){
ans.add(i+1);
}
}
return ans;
}
}
// 方法二
class Solution {
public List<Integer> findAnagrams(String s, String p) {
//思路:滑动窗口 + 固定窗口长度,每次移动都比较变量diff是否为0
(diff表示窗口内的字符与p的字符的差异(包括种类和数量))
int sLen = s.length(),pLen = p.length();
if(sLen < pLen){
return new ArrayList<>();
}
// 存储字符串中的各个字符的个数
int[] count = new int[26];
for(int i = 0;i<pLen;++i){
++count[p.charAt(i) - 'a'];
--count[s.charAt(i) - 'a'];
}
List<Integer> ans = new ArrayList<>();
int diff = 0;// 记录字符的差异
for(int i = 0;i<26;++i){
if(count[i] != 0){
++diff;
}
}
// 表示为异位词
if(diff == 0){
ans.add(0);
}
for(int i = 0;i<sLen - pLen;++i){
//该s.charAt(i)字符缺一个
if(count[s.charAt(i) - 'a'] == -1){
--diff;
}else if(count[s.charAt(i) - 'a'] == 0){//本来是刚好的, 现在多一个
++diff;
}
++count[s.charAt(i) - 'a'];
if(count[s.charAt(i+pLen) - 'a'] == 1){
--diff;
}else if(count[s.charAt(i+pLen) - 'a'] == 0){
++diff;
}
--count[s.charAt(i+pLen) - 'a'];
if(diff == 0){
ans.add(i+1);
}
}
return ans;
}
}
// 方法三:
class Solution {
public List<Integer> findAnagrams(String s, String p) {
//思路:滑动窗口 + 变长窗口长度,将p字符串中的每个字符变成消耗品
int sLen = s.length(),pLen = p.length();
if(sLen <pLen){
return new ArrayList<>();
}
// 记录p字符串中每个字符的个数
int[] count = new int[26];
for(char c: p.toCharArray()){
++count[c-'a'];
}
int left = 0,right = 0;
List<Integer> ans = new ArrayList<>();
while(right < sLen){
// 说明right指向的字符在p中含有 或者 left已经来到right指针处
if(count[s.charAt(right) - 'a'] > 0){
--count[s.charAt(right++) - 'a'];
if(right - left == pLen){
ans.add(left);
}
}else{///恢复消耗的字符
++count[s.charAt(left++) - 'a'];
}
}
return ans;
}
}