438. 找到字符串中所有字母异位词
1.题目介绍
给定两个字符串
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 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" 的异位词。
提示:
和 仅包含小写字母
2.题解
2.1 滑动窗口
思路
这里便是使用滑动窗口的一种典型情形,由于窗口大小固定为p.length();
所以可以直接使用数组来存储每个字母出现次数,并通过窗口不断向后移动进行一次次判断(这里==是向量vector重载后的符号,比较每一个元素)
注意这里最后一个窗口起始值是s.length()-p.length(),而不是s.length()-p.length()-1
因为s.length() = 下标A + 1, 下标B = 下标A -(回退p.length()-1 个单位)[自身+回退的p.length()-1 = p.length()];
即下标B = 下标A - p.length() + 1 = s.length() - 1 + p.length() +1 = s.length() - p.length();
代码
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
if (s.length() < p.length()) return vector<int>();
vector<int> ans;
vector<int> sCount(26);
vector<int> pCount(26);
for (int i = 0; i < p.length(); i++){
sCount[s[i]-'a']++;
pCount[p[i]-'a']++;
}
if (sCount == pCount) ans.push_back(0);
for (int i = 1; i <= s.length()-p.length(); i++){
--sCount[s[i-1] - 'a'];
++sCount[s[p.length()+i-1] - 'a'];
if (sCount == pCount) ans.push_back(i);
}
return ans;
}
};
复杂度分析
时间复杂度:O(m+(n−m)×Σ),其中 n 为字符串 s 的长度,m 为字符串 p 的长度,Σ 为所有可能的字符数。我们需要 O(m) 来统计字符串 p 中每种字母的数量;需要 O(m)来初始化滑动窗口;需要判断 n−m+1 个滑动窗口中每种字母的数量是否与字符串 p 中每种字母的数量相同,每次判断需要 O(Σ) 。因为 s 和 p 仅包含小写字母,所以 Σ=26。
2.2滑动窗口优化
思路
这里直接使用一个计数器 differ 来统计不同的字符数目,而不需要再遍历整个数组进行比较。
代码
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
if (s.length() < p.length()) return vector<int>();
vector<int> ans;
vector<int> count(26);
for (int i = 0; i < p.length(); i++){
count[s[i]-'a']++; //滑动窗口中多出的字母元素个数
count[p[i]-'a']--; //滑动窗口中少出的字母元素个数
}
int differ = 0;
for (int i = 0; i < 26; i++)
if(count[i] != 0) differ++;
if (differ == 0) ans.push_back(0);
for (int i = 0; i < s.length()-p.length(); i++){
// 首先是滑动窗口滑动排出的首个元素
if (count[s[i]-'a'] == 1) differ--; //排出的正好是多的那个,differ--
if (count[s[i]-'a'] == 0) differ++; //本来刚刚好,现在少了,differ++
count[s[i] -'a']--;
// 然后是滑动窗口滑进的新元素
if (count[s[i+p.length()]-'a'] == -1) differ--; //新增的刚好是少一个的哪个,differ--
if (count[s[i+p.length()]-'a'] == 0) differ++; //本来刚好,现在多一个了
count[s[i+p.length()]-'a'] ++;
if (differ == 0) ans.push_back(i+1);
}
return ans;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了