滑动窗口
滑动窗口三步走:
- 在一定条件下,移动尾指针;
- 尾指针无法向前时,移动头指针直到符合条件;
- 记录符合要求的结果。
难点在于如何建立哈希表,下面两题哈希表的键值是字符,存储元素出现的次数。
一、无重复字符的最长字串
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。
算法分析
经典的滑动窗口问题,此前做过一道类似的数字串的题目,这次做的字符串的题,使用数组也可过,但使用 unordered_map 应该更直观一点。做这道题的时候总是忘记左指针该怎么移动到重复元素的前面一个元素,需要记忆一下思路。
算法实现
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int x=0,y=0,cnt,res=0;
int h[50000]={0};
// unordered_map<char,int> h;
while(y<s.size()){
while(y<s.size()&&h[s[y]]==0) h[s[y]]++,y++;
h[s[y]]--;
cnt=y-x;
if(cnt>res) res=cnt;
while(h[s[x]]==1) h[s[x]]--,x++;
x++;
}
return res;
}
};
二、找到字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。异位词:指由相同字母重排列形成的字符串(包括相同的字符串)。
算法分析
如何表示异位词相同是本体的关键,一开始我想把p的每个字符存储到 unordered_set 里面,比较在 s 的滑动窗口中的元素是否出现过,但要输出起始索引不好处理。建立哈希表,使用 vector 或者数组直接存储 p 和滑动窗口的每个字母出现的次数,如果次数相同则是异位词,似乎更简洁一点。
算法实现
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> res;
if (s.size() < p.size()) return res; // 如果 s 的长度小于 p 的长度,直接返回空结果
int plen = p.size();
vector<int> vp(26, 0); // 存储 p 中每个字母出现的次数
vector<int> vtmp(26, 0); // 存储滑动窗口中每个字母出现的次数
for (auto x : p) vp[x - 'a']++;
for (int i = 0; i < s.size(); i++) {
if (i >= plen) // 如果超过 p 的长度,就要移动 head 指针
vtmp[s[i - plen] - 'a']--; // 释放 head 指向的字符
vtmp[s[i] - 'a']++; // 使用 tail 指向的字符
if (vtmp == vp) // 如果两个数组相等,说明找到了一个异位词
res.push_back(i - plen + 1); // 将 head 的值加入结果中
}
return res;
}
};