LeetCode-滑动窗口-找到字符串中所有字母异位词
LeetCode-滑动窗口-找到字符串中所有字母异位词
✏️ 关于专栏:专栏用于记录
prepare for the coding test
。
文章目录
- LeetCode-滑动窗口-找到字符串中所有字母异位词
- 📝 找到字符串中所有字母异位词
- 🎯题目描述
- 🔍 输入输出示例
- 🧩题目提示
- 🧪滑动窗口—定长
- 🧪滑动窗口—变长
- 🌟 总结
- 🔁 相似题目推荐(逐步进阶)
📝 找到字符串中所有字母异位词
🎯题目描述
给定两个字符串
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" 的异位词。
🧩题目提示
1 <= s.length, p.length <= 3 * 104
s
和p
仅包含小写字母
🧪滑动窗口—定长
本题适合使用 定长滑动窗口,即窗口长度固定为 p.size()
,从左往右滑动,每次滑动判断当前窗口是否是异位词。
我们用两个长度为 26 的数组来统计字母频次(因为仅包含小写字母),当两个数组相等时(array支持 = = == ==直接比较),说明当前窗口是 p
的异位词。
1.预处理字符串 p
的字符频率,用一个长度为 26 的数组 cnt_p
存储。
2.滑动窗口遍历 s
,维护当前窗口内的频率数组 cnt_s
。
3.若 cnt_s
与 cnt_p
相等,则窗口起始位置是一个异位词。
class Solution {
public:vector<int> findAnagrams(string s, string p) {vector<int> ans;array<int,26> cnt_s {};array<int,26> cnt_p {};for(char c : p){cnt_p[c - 'a']++;}for(int right = 0;right < s.size();right++){cnt_s[s[right] - 'a']++;int left = right - p.size() + 1;if(left >= 0){if(cnt_s == cnt_p){ans.push_back(left);}cnt_s[s[left]-'a']--;}else{continue;}}return ans;}
};
🧪滑动窗口—变长
相比固定窗口的方法,我们也可以用灵活窗口(变长)去尝试:
- 每次将右指针加入窗口,并对字符频率计数;
- 若某个字符频率多了,就不断移动左指针直到频率合法;
- 当窗口长度等于
p.size()
,说明找到一个异位词。
class Solution {
public:vector<int> findAnagrams(string s, string p) {vector<int> ans;array<int,26> cnt {};for(char c : p){cnt[c - 'a']++;}int left = 0;for(int right = 0;right < s.size();right++){int c = s[right] - 'a';cnt[c]--;while(cnt[c] < 0){cnt[s[left] - 'a']++;left++;}if(right - left + 1 == p.size()){ans.push_back(left);}}return ans;}
};
🌟 总结
-
使用字符频率数组作为滑动窗口核心;
-
左指针控制窗口合法性,右指针推动遍历;
-
比较频率数组是否一致,作为是否匹配的判断依据。
滑动窗口维度 | 技巧要点 |
---|---|
指针控制 | 一般使用 left 和 right 两个指针定义区间 [left, right] 或 [left, right) |
窗口内数据维护 | 统计频率、子串长度、计数器(如满足条件的字符个数)等 |
何时收缩窗口 | 取决于当前窗口是否满足题意或已经不合法 |
何时记录结果 | 当窗口满足题意时保存起始索引或其他信息 |
知识点 | 简要描述 |
---|---|
滑动窗口 | 一种通过左右指针控制子串区域的技巧,适合处理子串/子数组问题 |
字符频率匹配 | 通过数组或哈希表统计字符出现次数,判断是否为异位词 |
固定长度滑窗 | 每次窗口长度固定,对新字符加入、旧字符移出,保持频率平衡 |
数组比较 | std::array<int, 26> 支持 == 运算,效率高于 unordered_map |
🔁 相似题目推荐(逐步进阶)
难度 | 题目 | 题目编号 | 技巧 |
---|---|---|---|
🌱 简单 | 字符串的排列 | 567 | 判断是否包含某异位词 |
🌿 中等 | 本题 | 438 | 找出所有异位词起始位置 |
🌳 中等 | 最小覆盖子串 | 76 | 滑窗 + 字符要求计数器 |
🌲 困难 | 串联所有单词的子串 | 30 | 复杂频率统计、窗口倍增 |