滑动窗口是一种想象出来的数据结构:
- 左边界
l
和右边界r
-
l
往右滑意味着一个样本出了窗口,r
往右滑意味着一个样本进了窗口,l和r都只能往右滑
滑动内最大值和最小值的更新结构
窗口不管l
还是r
滑动之后,都会让窗口呈现新状况,如何能够更快的得到窗口当前状况下的最大值和最小值?最好平均下来复杂度能做到O(1)
利用单调双端队列
窗口本质:哪些数会依次成为最大数的优先级
剑指 Offer 59 - I. 滑动窗口的最大值
给定一个数组 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
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums == null || k < 1 || nums.length < k) {
return new int[0];
}
LinkedList<Integer> qmax = new LinkedList<Integer>();
int[] res = new int[nums.length-k+1];
int index = 0;
for (int i = 0; i < nums.length; i++) {
while(!qmax.isEmpty() && nums[qmax.peekLast()]<=nums[i]) {
qmax.pollLast();
}
qmax.addLast(i);
if(qmax.peekFirst() == i-k) {
qmax.pollFirst();
}
if(i >= k-1) {
res[index++] = nums[qmax.peekFirst()];
}
}
return res;
}
}
求达标子数组的数量
给定一个整型数组arr
,和一个整数num
某个arr
中的子数组sub
,如果想达标,必须满足:
sub
中最大值 – sub
中最小值 <= num
,
返回arr
中达标子数组的数量
public static int subArrayNum(int[] arr, int num) {
if(arr == null || num < 0 || arr.length == 0) {
return 0;
}
LinkedList<Integer> qmin = new LinkedList<Integer>();
LinkedList<Integer> qmax = new LinkedList<Integer>();
int l = 0;
int r = 0;
//[l...r) -> [0,0) 窗口内无数
int res = 0;
while(l < arr.length) {
while(r < arr.length) {
while(!qmin.isEmpty() && arr[qmin.peekLast()] >= arr[r]) {
qmin.pollLast();
}
qmin.addLast(r);
while(!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[r]) {
qmax.pollLast();
}
qmax.addLast(r);
if(arr[qmax.getFirst()] - arr[qmin.getFirst()] > num) {
break;
}
r++;
}
res += r -l;
if(qmin.peekFirst() == l) {
qmin.pollFirst();
}
if(qmax.peekFirst() == l) {
qmax.pollFirst();
}
l++;
}
return res;
}
对于此题:
- 当前范围内若达标,则缩小范围必达标
- 若不达标,则扩大范围必不达标,可以及时break
遇到题,先看看问题本身和范围是否能够建立单调性,然后选择对应流程及流程中所要的信息