双指针问题(二) 滑动窗口

概念

滑动窗口是在数组上通过双指针同向移动而解决问题的方法。这样的问题我们不必为它们专门命名一个名字,它们的解法其实是很自然的。

滑动窗口通常是暴力解法的优化,掌握这一类问题最好的办法就是练习,然后思考清楚为什么可以使用滑动窗口。

209. 长度最小的子数组

209. 长度最小的子数组

该题是最基本的滑动窗口问题,我们可以用两个指针 l l l r r r表示窗口的左右段,然后让指针 r r r持续向右移动,同时用一个变量 s u m sum sum记录 [ l , r ] [l,r] [l,r]的区间和,若 s u m sum sum满足条件,则记录 l l l r r r的差作为答案,并移动指针 l l l,代码如下

class Solution {
public:
    int minSubArrayLen(int target, vector<int> &nums) {
        int l = 0, r = 0, res = INT_MAX, sum = 0;
        while (r < nums.size()) {
            sum += nums[r];
            while (sum >= target) {
                res = min(res, r - l + 1);
                sum -= nums[l];
                l++;
            }
            r++;
        }
        return res == INT_MAX ? 0 : res;
    }
};

713. 乘积小于K的子数组

713. 乘积小于K的子数组

这道题的解法与上道题非常相似,但求的不再是区间长度而是连续子区间数量。

对于子区间数量,我们可以发现,若 [ l , r ] [l,r] [l,r]是一个符合条件的窗口,则 [ l + i , r ] , ( 0 < i ≤ r − l ) [l+i,r],(0<i≤r-l) [l+i,r],(0<irl)也必然是符合条件的窗口

即对于任何符合条件的区间 [ l , r ] [l,r] [l,r],以 r r r结尾的子集个数永远是 r − l + 1 r-l+1 rl+1,因此我们要在每次更新 r r r之前为答案加上 r − l + 1 r-l+1 rl+1,代码如下

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int> &nums, int k) {
        int l = 0, r = 0, sum = 1, ans = 0;
        if (k <= 1) return 0;
        while (r < nums.size()) {
            sum *= nums[r];
            while (sum >= k) {
                sum /= nums[l];
                l++;
            }
            ans += r - l + 1;
            r++;
        }
        return ans;
    }
};

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

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

与前面的连续子序列不同的是,这道题要求的是连续子串的长度,因此我们需要修改一下判定条件,若窗口区间内出现重复字符,则更新 l l l,代码如下

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int l = 0, r = 0, ans = 0;
        map<char, int> cnt;
        while (r < s.length()) {
            cnt[s[r]]++;
            while (cnt[s[r]] > 1) {
                cnt[s[l]]--;
                l++;
            }
            ans = max(ans, r - l + 1);
            r++;
        }
        return ans;
    }
};

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

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

这道题解法与上一题大同小异,是把字符的判据改为了字符串的比较。同时,该题的窗口长度始终保持不变,为 p p p的长度

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ans, target(26, 0), sum(26, 0);
        if (s.length() < p.length()) return ans;
        for (int i = 0; i < p.length(); i++) target[(int) (p[i] - 'a')]++, sum[(int) (s[i] - 'a')]++;
        if (sum == target) ans.push_back(0);

        int l = 0, r = p.length();
        while (r < s.length()) {
            sum[(int) (s[l++] - 'a')]--;
            sum[(int) (s[r++] - 'a')]++;
            if (sum == target)
                ans.push_back(l);
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值