一题目链接
二题目描述

三解法(滑动窗口 + 哈希表)
3.1算法思路:
◦ 因为字符串 p 的异位词的长度一定与字符串 p 的长度相同,所以我们可以在字符串 s 中构
造一个长度为与字符串 p 的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量;
◦ 当窗口中每种字母的数量与字符串 p 中每种字母的数量相同时,则说明当前窗口为字符串 p
的异位词;
◦ 因此可以用两个大小为 26 的数组来模拟哈希表,一个来保存 s 中的子串每个字符出现的个
数,另一个来保存 p 中每一个字符出现的个数。这样就能判断两个串是否是异位词。
3.2C++ 算法代码:
cpp
class Solution
{
public:
vector<int> findAnagrams(string s, string p)
{
vector<int> ret;
int hash1[26] = { 0 }; // 统计字符串 p 中每个字符出现的个数
for(auto ch : p) hash1[ch - 'a']++;
int hash2[26] = { 0 }; // 统计窗口里面的每一个字符出现的个数
int m = p.size();
for(int left = 0, right = 0, count = 0; right < s.size(); right++)
{
char in = s[right];
// 进窗口 + 维护 count
if(++hash2[in - 'a'] <= hash1[in - 'a']) count++;
if(right - left + 1 > m) // 判断
{
char out = s[left++];
// 出窗口 + 维护 count
if(hash2[out - 'a']-- <= hash1[out - 'a']) count--;
}
// 更新结果
if(count == m) ret.push_back(left);
}
return ret;
}
};
3.2.1C++结果
3.3Java 算法代码:
java
class Solution
{
public List<Integer> findAnagrams(String ss, String pp)
{
List<Integer> ret = new ArrayList<Integer>();
char[] s = ss.toCharArray();
char[] p = pp.toCharArray();
int[] hash1 = new int[26]; // 统计字符串 p 中每一个字符出现的个数
for(char ch : p) hash1[ch - 'a']++;
int[] hash2 = new int[26]; // 统计窗口中每一个字符出现的个数
int m = p.length;
for(int left = 0, right = 0, count = 0; right < s.length; right++)
{
char in = s[right];
// 进窗口 + 维护 count
if(++hash2[in - 'a'] <= hash1[in - 'a']) count++;
if(right - left + 1 > m) // 判断
{
char out = s[left++];
// 出窗口 + 维护 count
if(hash2[out - 'a']-- <= hash1[out - 'a']) count--;
}
// 更新结果
if(count == m) ret.add(left);
}
return ret;
}
}
3.3.2Java结果
四细节与避坑
- 边界处理 :如果
p.size() > s.size(),直接返回空数组,避免越界。 - 数组对比 :用
memcmp直接对比两个 26 元素的数组,比循环判断更高效。 - 窗口滑动逻辑 :
- 左边界索引:
i - n2 - 新窗口起始索引:
i - n2 + 1
- 左边界索引:
- 内存优化:全程不用创建子串,只用两个 26 大小的数组,空间复杂度 O (1),不会超内存。

