滑动窗口例题讲解

题目

题目链接:

剑指Offer 57-Ⅱ.和为s的连续正数序列

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

示例 1:

输入:target = 9
输出:[[2,3,4],[4,5]]

示例 2:

输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]

限制:

  • 1 <= target <= 10^5

解题思路

熟悉这类题的人第一反应应该是滑动窗口。简单说一下什么是滑动窗口?

顾名思义,滑动窗口就是可以滑动的窗口,在代码里就是用双指针代表可以滑动的窗口,在两个指针间是一个窗口,指针的范围是一个大的窗户框架。通过两个指针的移动可以取到可移动范围内的任何值和任何小范围。如下图:

在这里插入图片描述

现在来看这一题,我们可以通过滑动窗口的方式寻找我们想要的范围,那么如何寻找?

窗口范围

从样例可以看出,随着窗口越往后移,窗口的大小(范围)越来越小。当右指针等于目标数target的一半时,左右指针指向同一个位置(目标数为偶数时),此时窗口不能继续向后移动了,所以这个值就是窗口能到达的最大值。窗口的范围确定了,接下来就是如何移动窗口。

移动窗口

窗口的移动是控制左右指针的左右移动完成的,所以首先应该让左右指针指向最开始的位置1。由于窗口内的值是在变化的,所以我们需要一个变量res存储窗口值的大小,反应窗口的变化和判断窗口需要移动方向,res的初始值为1(左右指针的初始位置)。

由于窗口整体是一直向后移动的,所以应该规定右指针r的范围不能超过target/2 + 1,这里就可以用一个循环表示。在循环内,窗口的移动不是随意的或固定的,需要根据窗口的值restarget的大小确定。这里就有了三种情况:

  • restarget相等时,直接把窗口的值放入数组中,然后将窗口平行向后移动一格
  • res大于target时,说明此时窗口的值需要减去一些值,将左指针向后移动一格
  • res小于target时,说明此时窗口的值需要加上一些值,将右指针向后移动一格

注意:当左右指针移动时,表示窗口的值rse也需要变化

伪代码:

while (右指针 <= target / 2 + 1) {
	if (窗口值等于target) {
		将窗口的值放入数组
		窗口平行向后移动
	}
	if (窗口值大于target) {
		窗口值减去左指针所指的值
		左指针向后移动
	}
	if (窗口值小于target) {
		右指针向后移动
		窗口值加上右指针所指值
	}
}

基本的思路就是以上,下面是代码实现:

代码(C++)

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        int l = 1, r = 1, res = 1;
        vector<vector<int>> nums;
        vector<int> num;
        while (r <= target / 2 + 1) {
            if (res == target) {
                num.clear();
                for (int i = l; i <= r; ++ i) {
                    num.push_back(i);
                }
                nums.push_back(num);
                r ++;
                res += r;
                res -= l;
                l ++;
            }
            if (res > target) {
                res -= l;
                l ++;
            }
            if (res < target) {
                r ++;
                res += r;
            }
        }
        return nums;
    }
};

总结

滑动窗口理解起来并不难,这种算法的题型大都可以一眼看出需要用到滑动窗口。在解题时,需要注意的是左右指针的范围和一些边界值的处理。

评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聆听逝去的流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值