一. 一般需要用到双指针, 还有特殊的需要用到特定数据结构sorted_map.
二. 这类题目脱离不开主串(主数组)和子串(子数组)的关系, 短的在长的中满足一定的条件.要求时间O(n),空间O(1).
三. 双指针确定一个窗口.
四. 思路是每次保证右指针往前移动一格, 每次移动会有新的元素进入窗口. 条件可能发生改变, 根据这个决定左指针是否移动.
五. 例题
1. leetcode76_最小覆盖子串
2. 暴力法: 列举出S所有的子串, 并且判断子串是否包含有T全部字母,最后选出长度最小的子串
3. 我们的做法是, 先找到可行解,即right指针先走,直到包含所有的T字母, 然后再优化可行解, 移动left指针, 窗口不断向右滑动, 最终找到最优解.
4. 假设needs 和 window 相当于计数器,分别记录 T 中字符出现次数和窗口中的相应字符的出现次数。用两个哈希表来解决.
class Solution {
public:
string minWindow(string s, string t) {
//初始情况
if(t.length()==0 || s.length() need;
map window;
//设置没有匹配的字符串的情况
int start=0, minLength=INT_MAX;
//首先哈希表列出t的字符个数情况.
for(int i=0;i
5. 算法时间复杂度O(M+N). 两个while循环最多执行2M次, 因为while的次数就是left和right走的路程, 因为滑动窗口, left和right都是++,即都是前进,因此走的路程最多是2M, 即两个s字符串的长度.
二. leetcode438_找到字符串中所有字母异位词.
1. 和上一题思路一样, 套用模板, 先找到s中包含所有字母的字符串, 然后再去验证长度是否相同, 再添加进最终的结果.
class Solution {
public:
vector findAnagrams(string s, string p) {
vector res;
if(s.length()==0 || s.length() < p.length()) return res;
int left=0, right=0;
map need;
map window;
int match = 0;
for(int i=0; i
2. 时间同样为O(N+M).
三. leetcode3_无重复字符的最长子串.
1. 思路没变,但是代码结构有些变化.
2. 遇到子串问题, 首先想到的就是滑动窗口技巧.
3. 先移动right, 等出现重复字符的时候, 再向左移动left, 如此往复.
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//初始条件
if(s.length()==0) return 0;
int left = 0, right = 0;
map window;
int match = 0;
int res = INT_MIN;
//当满足没有重复字符的时候,right指针一直向右移动,
//并且只有字符个数为1时才match++
while(right < s.length()) {
window[s[right]]++;
if(window[s[right]]==1) match++;
right++;
//当不满足无重复子串时,需要移动左指针
while(right-left!=match) {
//如果不等于,则说明移动会使无重复子串的长度减1.
if(s[left]!=s[right-1]) {
match--;
}
window[s[left]]--;
left++;
}
//找到最长的子串
res = max(res, match);
}
return res;
}
};