标签 滑动窗口 下的文章

题目链接:最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

方法:滑动窗口

class Solution {
public:
    string minWindow(string s, string t) {
        if (s.empty() || t.empty() || t.size() > s.size()) {
            return "";
        }

        int need[128] = {0};
        for (char c : t) {
            need[(unsigned char)c]++;
        }

        int needCount = t.size();     // 还需要匹配多少字符
        int left = 0, right = 0;
        int minLen = INT_MAX;         // 当前找到的最短长度
        int start = 0;                // 最优区间的起始位置

        while (right < (int)s.size()) {
            char rc = s[right];
            if (need[(unsigned char)rc] > 0) {
                needCount--;          // 用掉一个需要的字符
            }
            need[(unsigned char)rc]--; // 窗口中多了一个 rc
            right++;

            // 当前窗口已经包含了所有需要的字符,开始尽量缩小左边界
            while (needCount == 0) {
                // 更新最小区间
                if (right - left < minLen) {
                    minLen = right - left;
                    start = left;
                }

                char lc = s[left];
                need[(unsigned char)lc]++; // 移出左边字符
                if (need[(unsigned char)lc] > 0) {
                    // 移出了一个“必须”的字符,窗口不再满足条件
                    needCount++;
                }
                left++;
            }
        }

        // 注意 substr 的第二个参数是长度,不是右边界
        return minLen == INT_MAX ? "" : s.substr(start, minLen);
    }
};

题目链接:滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

方法:单调队列

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if (nums.size() == 0 || k == 0) return {};
        deque<int> d;
        vector<int> res(nums.size()-k+1);
        for (int j = 0,i = 1-k; j < nums.size();i++,j++) {
            if (i > 0 && d.front() == nums[i-1]) {
                d.pop_front();
            }
            while (!d.empty() && d.back() < nums[j]) 
                d.pop_back();
            d.push_back(nums[j]);
            if (i >= 0) {
                res[i] = d.front();
            }

        }
        return res;
    }
};

题目链接:找到字符串中所有字母异位词

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

方法:滑动窗口

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int sl = s.size(),pl = p.size();
        if (sl < pl) {
            return vector<int>();
        }
        vector<int> ans;
        vector<int> sc(26);
        vector<int> pc(26);
        for (int i = 0;i < pl;i++) {
            ++sc[s[i]-'a'];
            ++pc[p[i]-'a'];
        }
        if (sc == pc) {
            ans.push_back(0);
        }
        for (int i = 0;i < sl-pl;i++) {
            --sc[s[i]-'a'];
            ++sc[s[i+pl]-'a'];
            if (sc == pc) {
                ans.push_back(i+1);
            }
        }
        return ans;
    }
};

题目链接:无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。

方法一:暴力?

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ans = 0;
        
        for (int i = 0;i < s.size();i++) {
            unordered_set<char> occ;
            int num = 1;
            occ.insert(s[i]);
            for (int j = i+1;j < s.size();j++) {
                if (!occ.count(s[j])) {
                    occ.insert(s[j]);
                    num++;
                }else break;
            }
            ans = max(ans,num);
        }
        return ans;
    }
};

方法二:滑动窗口

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_set<char> occ;
        int i = 0;
        int ans = 0;
        int n = s.size();
        for (int j = 0;j < n;j++) {
            while (i < j && occ.count(s[j]) != 0) {
                occ.erase(s[i++]);
            }
            occ.insert(s[j]);
            ans = max(ans,j-i+1);
        }
        return ans;
    }
};