描述
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。
示例 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" 的字母异位词。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/
求解
class Solution {
public:
// 方法一,暴力解法,以每个字符起点开始判断, 时间复杂度O(m * n),需要额外的空间复杂度
// 低效率通过, 1300ms
vector<int> findAnagrams_1e(string s, string p) {
const int n = s.size();
const int m = p.size();
vector<int> res;
for (int i = 0; i <= n - m; ++i) {
if (isAnagrams(p, s, i, i + m)) {
res.emplace_back(i);
}
}
return res;
}
// 方法二,暴力解法优化,以每个字符起点开始判断, 时间复杂度O(m * n),需要额外的空间复杂度
// 低效率通过, 850ms
vector<int> findAnagrams_2e(string s, string p) {
const int n = s.size();
const int m = p.size();
vector<int> res;
bool preIsAnagrams = false;
for (int i = 0; i <= n - m; ++i) {
if (preIsAnagrams && s[i - 1] == s[i + m - 1]) {
// 如果发现前一个满足条件,即s[i-1....i-1+m)符合条件
// 则只需要判断s[i-1] 是否等于 s[i+m-1],即递增中去掉的那个字符和新加入的字符是否一致,一致则同样满足条件
res.emplace_back(i);
preIsAnagrams = true;
continue;
}
if (isAnagrams(p, s, i, i + m)) {
res.emplace_back(i);
preIsAnagrams = true;
continue;
}
preIsAnagrams = false;
}
return res;
}
// 方法三,双指针滑动窗口
vector<int> findAnagrams(string s, string p) {
const int n = s.size();
const int m = p.size();
int record[126]{0};
for (char &c : p) {
++record[c];
}
int l = 0, r = 0, num = 0;
vector<int> res;
while (r < n) {
if (record[s[r]] > 0) {
++num;
}
--record[s[r]];
++r;
while (num == m) {
if (r - l == m) {
res.emplace_back(l);
}
if (record[s[l]] == 0) {
--num;
}
++record[s[l]];
++l;
}
}
return res;
}
private:
/*!
*
* @param p 被匹配字符串
* @param s 待匹配字符串
* @param is 起点,相当于begin
* @param ie 终点, 相等于end
* @return 返回是否是异位匹配
*/
bool isAnagrams(const std::string_view p, const std::string_view s, int is, int ie) {
int pattern[26]{0};
for (const auto &c : p) {
++pattern[c - 'a'];
}
for (int i = is; i < ie; ++i) {
--pattern[s[i] - 'a'];
}
for (const int &num : pattern) {
if (num != 0) {
return false;
}
}
return true;
}
};