leetcode原题链接:找到字符串中所有字母异位词
上一篇:HOT8-无重复字符的最长子串
下一篇:HOT10-和为K的子数组
题目描述
给定两个字符串 s
和 p
,找到 s
中所有 p
的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
示例 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" 的异位词。
解题方法:滑动窗口。假设模式串p的长度为p_n,在主串s中维护一个长度为p_n的滑动窗口,窗口区间为[left, right],我们将p[left, right]和s分别映射到两个长度为26的数字字符串数组p1和p2中,该数组对应的每一位表示对应字母出现在字符串中出现的次数,p[left, right]和s互为异位词的条件是p1 = p2,通过滑动窗口动态改变p[left, right]中的left和right的值。
C++代码
#include <string>
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int s_n = s.size();
int p_n = p.size();
if (s_n < p_n) { //这里不能漏,否则下面访问的时候数组会越界
return {};
}
std::string s1(26, '0');//保存s当前滑动窗口的异位词各个字母出现的次数
std::string p1(26, '0');//保存目标p的各个字母出现的次数
std::vector<int> result;
for (int i = 0; i < p_n; i++) {
// 先生成p的异位词
char ch_p = p[i];
p1[ch_p - 'a']++;
// 判断当前s.substr(0, len)是否为异位词(生成一个长度为目标异位词长度的子串)
char ch_s = s[i];
s1[ch_s - 'a']++;
}
if (s1 == p1) { //判断当前的窗口是否匹配
result.emplace_back(0);
}
// start表示新滑动窗口的起点
for (int start = 1; start <= s_n - p_n; start++) {
char old_start_ch = s[start - 1];//旧滑动窗口起点
char new_end_ch = s[start + p_n - 1]; //新滑动窗口终点
s1[old_start_ch - 'a']--;//旧滑动窗口起点对应字母对应的次数少1
s1[new_end_ch - 'a']++;//新滑懂窗口终点对应的字母出现的次数加1
if (s1 == p1) {
result.emplace_back(start);
}
}
return result;
}
};