滑动窗口C++

题目列表

    • 3. 无重复字符的最长子串
    • 72. 最小覆盖子串
    • 567. 字符串的排列
    • 438. 找到字符串中所有字母异位词

3. 无重复字符的最长子串

原题链接

示例

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

思路

  • 设立左指针left和右指针right

  • 右指针向右移动

    • 判断右指针对应的字符在窗口内是否出现过
    • 如果出现过,左指针移动到右指针对应相同字符的下一个。
    • 更新子串长度。
  • 循环移动右指针

      本质上,就是遍历每一个s[right]结尾的,没有重复字符的最长子串,从中找到最长的。
    

代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int left = 0, right = 0, res = 0;
        unordered_map<char, int>window;
        
        while(right < s.size()){  
            char c1 = s[right++];
            // s[left, right)
            window[c1]++;
            while(window[c1] > 1){
                char c2 = s[left];
                window[c2]--;
                left++;
            }
            res = max(res, right - left);
        }
        return res;
    }
};

72. 最小覆盖子串

题目链接
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"

思路
原字符串s使用窗口[left, right),不断移动右指针,每当满足包含子串,就开始移动左指针,缩小窗口,一旦左指针移动到不满足包含子串,继续移动右指针,找下一个符合条件的窗口。

	问题一:如何判断窗口是否包含子串
  • 使用哈希表need,统计每个字符串需要的数量,使用vaild变量统计窗口中满足need中字符串需要的数量,当vaild == need.size(), 表示窗口已经包含子串。
    代码
class Solution {
public:
    string minWindow(string s, string t) {
        int left = 0, right = 0;
        unordered_map<char, int> need;
        unordered_map<char, int>window;
        for(char c: t)need[c]++;
        int valid = 0, start = 0, len = INT_MAX;
        while(right < s.size()){
            char c1= s[right++];
            
            if(need.count(c1)){
                window[c1]++;
                if(window[c1] == need[c1])
                    valid++;
            }
            while(valid == need.size()){
                
                if(len > right - left){
                    
                    len = right - left;
                    start = left;
                }
                char c2 = s[left++];
            
                if(need.count(c2)){
                    if(window[c2] == need[c2])valid--;            
                    window[c2]--;
                }
                
            }
        }
        return len == INT_MAX? "":s.substr(start, len);
    }
};

567. 字符串的排列

题目链接
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").

思路
和上一题的框架相同,只需要实现包含子串而且不包含其他的串。
如果valid == need而且 window == s1.size() 即为条件。

代码

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        unordered_map<char, int>need, window;
        int left = 0, right = 0, valid = 0;
        for(char c : s1) need[c]++;
        while(right < s2.size()){
            char c1 = s2[right++];
            if(need.count(c1)){
                window[c1]++;
                if(window[c1] == need[c1])valid++;
            }
            
            while(valid == need.size()){              
                //改变就在这里,实现包含子串而且只有子串没有其他元素
                if(right - left == s1.size())return true;
                char c2 = s2[left++];
                if(need.count(c2)){
                    if(need[c2] == window[c2])valid--;
                    window[c2]--;

                }
            }
        }
        return false;
    }
};

438. 找到字符串中所有字母异位词

题目链接

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序

示例

输入:
s: "cbaebabacd" p: "abc"

输出:
[0, 6]

解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。

代码

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        unordered_map<char, int> need, window;
        vector<int> res;
        int left = 0, right = 0, valid = 0;
        for(char c: p) need[c]++;
        while(right < s.size()){
            char c1 = s[right++];
            if(need.count(c1)){
                window[c1]++;
                if(window[c1] == need[c1]){
                    valid++;
                }
            }
            
            while(valid == need.size()){

                if(right - left == p.size()) res.push_back(left);
                char c2 = s[left++];
                if(need.count(c2)){
                    if(window[c2] == need[c2])valid--;
                    window[c2]--;
                }
            }
            
        }
        return res;
    }
};

你可能感兴趣的:(算法)