滑动窗口

滑动窗口是一种想象出来的数据结构:

  1. 左边界l和右边界r
  2. 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;
	}

对于此题:

  1. 当前范围内若达标,则缩小范围必达标
  2. 若不达标,则扩大范围必不达标,可以及时break

遇到题,先看看问题本身和范围是否能够建立单调性,然后选择对应流程及流程中所要的信息

上一篇:mapbox.gl源码解析——基本架构与数据渲染流程


下一篇:LeetCode 134. Gas Station