数组双指针【算法】

滑动窗口

框架

题型

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

题目: 给定一个字符串 s, 找出其中不含有重复字符的最长字串的长度.

示例:

输⼊:s = "abcabcbb"
输出:3 
解释:因为⽆重复字符的最⻓⼦串是 "abc",所以其⻓度为 3.

思路:

// 1. 利用双指针构建移动窗口.
// 2. 先右移窗口, window[c]++.
// 3. 当 window[c] > 1 时说明有元素重复了.
// 4. 再左移窗口, window[d]--;
// 5. 记录下当前的 len, 并更新最大 len.

代码:

class Solution {
    
    
public:
    int lengthOfLongestSubstring(string s) {
    
    
        unordered_map<char, int> window;
        int left = 0, right = 0;				// 1. 利用双指针构建移动窗口.
        int res = 0, n = s.size();
        while (right < n) {
    
    
            char c = s[right++];				// 2. 先右移窗口, window[c]++.
            window[c]++;
            while (window[c] > 1) {
    
    				// 3. 当 window[c] > 1 时说明有元素重复了.
                char d = s[left++];				// 4. 这时候左移窗口, window[d]--;
                window[d]--;
            }
            res = max(res, right - left);   	// 5. 记录下当前的 len, 并更新最大 len.
        }
        return res;
    }
};

0076. 最小覆盖子串

题目: 给定两个字符串 sp, 返回 s 中涵盖 p 的最小子串.

示例:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

思路:

// 1. 利用双指针构建移动窗口.
// 2. 先右移窗口, 如果当前字符在 p 中且数量相同, window[c]++, valid++.
// 3. 如果当前的 valid 达成了题目的条件, 则可以左移窗口.
// 4. 先更新当前res.
// 5. 再左移窗口, 如果当前字符在 p 中且数量相同, valid--, window[d]--.

代码:

class Solution {
    
    
public:
    string minWindow(string s, string p) {
    
    
        unordered_map<char, int> window, need;
        for (char c : p) {
    
    need[c]++;}
        int left = 0, right = 0;					// 1. 利用双指针构建移动窗口.
        int valid = 0, n = s.size(), m = p.size();
        int start = 0, len = INT_MAX;
        while (right < n) {
    
    
            char c = s[right++];					// 2. 先右移窗口, 如果当前字符在 p 中且数量相同, window[c]++, valid++.
            if (need.count(c)) {
    
    
                window[c]++;
                if (window[c] == need[c]) {
    
    
                    valid++;
                }
            }
            while (valid == need.size()) {
    
    			// 3. 如果当前的 valid 达成了题目的条件, 则可以左移窗口.
                if (right - left < len) {
    
    			// 4. 先更新当前res.
                    start = left;
                    len = right - left;
                }
                char d = s[left++];					// 5. 再左移窗口, 如果当前字符在 p 中且数量相同, valid--, window[d]--.
                if (need.count(d)) {
    
    
                    if (window[d] == need[d]) {
    
    
                        valid--;
                    }
                    window[d]--;
                }
            }
        }
        return len == INT_MAX ? "" : s.substr(start, len);
    }
};

0239. 滑动窗口的最大值

题目: 给定一个数组 nums, 有一个长为 k 的滑动窗口从最左侧移动到最右侧, 求滑动窗口中的最大值.

示例:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

思路:

这道题用到了单调队列的方法.
// 1. 定义一个单调队列 q, 先添加 k 个元素于其中, 保存 q.front 为最大值.
// 2. 从 k 处依次添加元素到单调队列中.
// 3. 若最大值索引 <= i - k, 则 q.pop_front, 并保存新的 q.front 为最大值.

代码:

class Solution {
    
    
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    
    
        deque<int> q;
        int n = nums.size();
        vector<int> res;
        // 1. 定义一个单调队列 q, 先添加 k 个元素于其中, 保存 q.front 为最大值.
        for (int i = 0; i < k; ++i) {
    
     							
            while (!q.empty() && nums[i] >= nums[q.back()]) {
    
    
                q.pop_back();
            }
            q.push_back(i);
        }
        res.push_back(nums[q.front()]);
        // 2. 从 k 处依次添加元素到单调队列中.
        for (int i = k; i < n; ++i) {
    
    
            while (!q.empty() && nums[i] >= nums[q.back()]) {
    
    
                q.pop_back();
            }
            q.push_back(i);
            // 3. 若最大值索引 <= i - k, 则 q.pop_front, 并保存新的 q.front 为最大值.
            if (q.front() <= i - k) {
    
    
                q.pop_front();
            }
            res.push_back(nums[q.front()]);
        }
        return res;
    }
};

0438. 找到字符串中的所有异位词 (0567)

题目: 给定两个字符串 sp, 找出 s 中所有 p 的异位词的字串, 返回子串的起始索引.

示例:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词.
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词.

思路:

// 1. 利用双指针构建移动窗口.
// 2. 先右移窗口, 如果当前字符在 p 中且数量相同, window[c]++, valid++.
// 3. 当窗口宽度 >= p 的宽度, 则该左移窗口.
// 4. 判断有没有达成 valid 的条件, 达成时更新 res.
// 5. 再左移窗口, 如果当前字符在 p 中且数量相同, valid--, window[d]--.

代码

class Solution {
    
    
public:
    vector<int> findAnagrams(string s, string p) {
    
    
        unordered_map<char, int> window, need;
        for (char c : p) {
    
    need[c]++;}
        int left = 0, right = 0;					// 1. 利用双指针构建移动窗口.
        int valid = 0, n = s.size(), m = p.size();
        vector<int> res;
        while (right < n) {
    
    
            char c = s[right++];					// 2. 先右移窗口, 如果当前字符在 p 中且数量相同, window[c]++, valid++.
            if (need.count(c)) {
    
    
                window[c]++;
                if (window[c] == need[c]) {
    
    
                    valid++;
                }
            }
            while (right - left >= m) {
    
    				// 3. 当窗口宽度 >= p 的宽度, 则该左移窗口.
                if (valid == need.size()) {
    
    			// 4. 先记录下有没有达成 valid 的条件.
                    res.push_back(left);
                }
                char d = s[left++];					// 5. 再左移窗口, 如果当前字符在 p 中且数量相同, valid--, window[d]--.
                if (need.count(d)) {
    
    
                    if (window[d] == need[d]) {
    
    
                        valid--;
                    }
                    window[d]--;
                }
            }
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_39547794/article/details/127804763