leetcode:438. 找到字符串中所有字母异位词
题目
给定两个字符串 s
和 p
,找到 s
中所有 p
的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
解答 & 代码
滑动窗口,思路同:
[中等] 567. 字符串的排列
p 的字母异位词就是 p 的字母排列,一个意思。和上题唯一的区别是,在找到符合条件的窗口时,上题是直接返回 true,这里则是将左指针存入结果数组。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> needs;
unordered_map<char, int> window;
for(int i = 0; i < p.size(); ++i)
++needs[p[i]];
int left = 0; // 左指针
int right = 0; // 右指针
int validChCnt = 0;
vector<int> result;
while(right < s.size())
{
char ch = s[right];
++right;
// 进行窗口内数据的更新
if(needs.find(ch) != needs.end())
{
++window[ch];
if(window[ch] == needs[ch])
++validChCnt;
}
// cout << "window: [" << left << ", " << right << "]" << endl;
// 判断左侧窗口是否要收缩
while(right - left >= p.size())
{
// 当窗口符合条件时,将窗口起始下标加入结果数组
if(validChCnt == needs.size())
result.push_back(left);
char deleteC = s[left];
++left;
// 进行窗口内数据的更新
if(needs.find(deleteC) != needs.end())
{
if(window[deleteC] == needs[deleteC])
--validChCnt;
--window[deleteC];
}
// cout << "window: [" << left << ", " << right << "]" << endl;
}
}
return result;
}
};
复杂度分析:设字符串 s
长为 N,字符串p
包含 C 个不同的字符
- 时间复杂度 O(N):最坏情况下,字符串
s
的每个字符分别被左、右指针遍历一次 - 空间复杂度 O(C):两个哈希表的空间复杂度都取决于字符串
p
中不同字符的种数 C
执行结果:
执行结果:通过
执行用时:20 ms, 在所有 C++ 提交中击败了 28.20% 的用户
内存消耗:8.3 MB, 在所有 C++ 提交中击败了 92.82% 的用户