Sliding window
滑动窗口
滑动窗口作为对数组类算法题中惯用的方法,通常能通过对设置好的"窗口"移动可观察得到候选结果,当窗口从左临界点移动到右临界点时,即可得出最优结果.
举例:
剑指Offer 57题-II. 和为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
对于我来说,这道题上手的第一反应就是公差为1的等差数列求和…
那么利用这一点,因为是一个[1,2,3…n]的连续正整数序列,应用滑动窗口的思想,便可把窗口的范围设置出来,即:
- 若为奇数的话: 则窗口的右临界点为 target/2 +1
- 若为偶数的话: 则窗口的右临界点为 target/2
通常情况下,滑动窗口改变的点是左临界点即作为初始点,向右移动
一般可以将滑动窗口作为一个左闭右开的区间.
滑动窗口的重要性质是:窗口的左边界和右边界永远只能向右移动,而不能向左移动。这是为了保证滑动窗口的时间复杂度是 O(n)O(n)。如果左右边界向左移动的话,这叫做“回溯”,算法的时间复杂度就可能不止 O(n)O(n)。
对于此题:由于输入的值是滑动窗口需得出的结果,则可以把target当成滑动窗口中所有数的和. 当滑动窗口的右边界(设为right)向右移动一个位置,那么下一个窗口内的序列和就要加上right+1.同样的道理左边界向右移动,则要减去未移动前的左边界的值.
为了防止回溯,滑动窗口的左边界和右边界设定只能向右移动即向右临界点移动.从而保证时间复杂度为O(n)
对于数组,我们要考虑的是什么时候"扩大"窗口和"缩小窗口".
以示例2为例:
输入:target = 15 输出:[[1,2,3,4,5],[4,5,6],[7,8]]
"扩大窗口"即窗口内的和小于target时,就要考虑左边界或右边界的移动,但是因为之前提到为了防止回溯的原因,只能使有边界向右移动
同理,当窗口内的和