给定两个字符串
s和p,找到s中所有p的 **异位词 **的子串,返回这些子串的起始索引。不考虑答案输出的顺序。字母异位词
字母异位词是通过重新排列不同单词或短语的字母而形成的单词或短语,并使用所有原字母一次。
样例
Example
示例 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 * 10^4s和p仅包含小写字母
思路
- 滑动窗口一:对当前窗口的字母计数,判断其和字符串p的各字符个数是否一致。
- 滑动窗口二:判断当前窗口中和目标字符个数不一致的字符个数,当字符数变为一致时-1,当字符数不再一致时+1,为0时表示为异位词。
答案
Java
// 滑动窗口一
class Solution {
public List<Integer> findAnagrams(String s, String p) {
if(s.length() < p.length()){
return List.of();
}
int[] cnt1 = new int[128], cnt2 = new int[128];
for (int i = 0; i < p.length(); i++) {
cnt1[s.charAt(i)]++;
cnt2[p.charAt(i)]++;
}
List<Integer> ans = new ArrayList<>();
if (check(cnt1, cnt2)) {
ans.add(0);
}
for (int r = p.length(); r < s.length(); r++) {
cnt1[s.charAt(r - p.length())]--;
cnt1[s.charAt(r)]++;
if (check(cnt1, cnt2)) {
ans.add(r - p.length() + 1);
}
}
return ans;
}
public boolean check(int[] cnt1, int[] cnt2) {
for (char ch = 'a'; ch <= 'z'; ch++) {
if (cnt1[ch] != cnt2[ch]) {
return false;
}
}
return true;
}
}
// 滑动窗口二
class Solution {
public List<Integer> findAnagrams(String s, String p) {
if (s.length() < p.length()) {
return List.of();
}
int differ = 0;
int[] cnt1 = new int[128], cnt2 = new int[128];
for (int i = 0; i < p.length(); i++) {
cnt1[s.charAt(i)]++;
cnt2[p.charAt(i)]++;
}
for (char ch = 'a'; ch <= 'z'; ch++) {
if (cnt1[ch] != cnt2[ch]) {
differ++;
}
}
List<Integer> ans = new ArrayList<>();
if (differ == 0) {
ans.add(0);
}
for (int r = p.length(); r < s.length(); r++) {
int d = cnt2[s.charAt(r - p.length())] - --cnt1[s.charAt(r - p.length())];
if (d == 0) {
differ--;
} else if (d == 1) {
differ++;
}
d = cnt2[s.charAt(r)] - ++cnt1[s.charAt(r)];
if (d == 0) {
differ--;
} else if (d == -1) {
differ++;
}
if (differ == 0) {
ans.add(r - p.length() + 1);
}
}
return ans;
}
}