滑动窗口的最大值

题目链接:https://www.acwing.com/problem/content/75/

参考链接:https://www.cnblogs.com/baccano-acmer/p/9997514.html

单调队列,即单调递减或单调递增的队列。使用频率不高,但在有些程序中会有非同寻常的作用

单调队列的舞台

由于单调队列的队头每次一定最小值,故查询为O(1)。
进队出队稍微复杂点:
进队时,将进队的元素为e,从队尾往前扫描,直到找到一个不大于e的元素d,将e放在d之后,舍弃e之后的所有元素;如果没有找到这样一个d,则将e放在队头(此时队列里只有这一个元素)。保证队列是单调增加的。
出队时,对于单调队列,只需判断队头是否已经超出滑动窗口范围,若超出,则从队头退队。
分析单调队列的时间复杂度,每个元素最多入队1次、出队1次,且出入队都是O(1)的,因此这是一个总时间O(n)的算法。
Java版本算法模板:
import java.util.LinkedList;
import java.util.Scanner;

public class Main1 {
	static class node{
		int num;
		int id;
		public int getNum() {
			return num;
		}
		public void setNum(int num) {
			this.num = num;
		}
		public int getId() {
			return id;
		}
		public void setId(int id) {
			this.id = id;
		}
		public node(int num, int id) {
			this.num = num;
			this.id = id;
		}
		public node() {
		}


	}
	public static void main(String[] args) {
		LinkedList<node> q1=new LinkedList<node>();
		LinkedList<node> q2=new LinkedList<node>();
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int k=sc.nextInt();
		int a[]=new int[n+2];
		for (int i = 1; i <=n; i++) {
			a[i]=sc.nextInt();
		}
		for(int i=1;i<=n+1;i++)
		{
			if(!q1.isEmpty())
			{
				if(q1.peek().id+k<i)
					q1.removeLast();
				if(i>=1+k)
					System.out.print(q1.peek().num+"  ");
			}
			while(!q1.isEmpty()&&q1.peekLast().num>=a[i]&&i<=n)
				q1.removeLast();
			q1.add(new node(a[i],i));
		}
		System.out.println();
		for(int i=1;i<=n+1;i++)
		{
			if(!q2.isEmpty())
			{
				if(q2.peek().id+k<i)//队列首的元素是否已经过期
					q2.removeFirst();
				if(i>=1+k)//至少滑动k个单位才需要输出
					System.out.print(q2.peek().num+"  ");
			}
			while(!q2.isEmpty()&&q2.peekLast().num<=a[i]&&i<=n)
				q2.removeLast();
			q2.add(new node(a[i],i));
		}

	}

}

以上的算法模板分别是求滑动窗口的最小值和最大值。

对于oj上的题目的算法应用是:

class Solution {
    static class node{
		int num;
		int id;
		public int getNum() {
			return num;
		}
		public void setNum(int num) {
			this.num = num;
		}
		public int getId() {
			return id;
		}
		public void setId(int id) {
			this.id = id;
		}
		public node(int num, int id) {
			this.num = num;
			this.id = id;
		}
		public node() {
		}


	}
    public int[] maxInWindows(int[] nums, int k) {
		ArrayList<Integer> res=new ArrayList<Integer>();
		LinkedList<node> q2=new LinkedList<node>();
		int n=nums.length;
		int a[]=new int[n+2];
		for (int i = 1; i <=n; i++) {
			a[i]=nums[i-1];
		}
		for(int i=1;i<=n+1;i++)
		{
			if(!q2.isEmpty())
			{
				if(q2.peek().id+k<i)//队列首的元素是否已经过期
					q2.removeFirst();
				if(i>=1+k)//至少滑动k个单位才需要输出
					//System.out.print(q2.peek().num+"  ");
					res.add(q2.peek().num);
			}
			while(!q2.isEmpty()&&q2.peekLast().num<=a[i]&&i<=n)
				q2.removeLast();
			q2.add(new node(a[i],i));
		}
		int arr[]=new int[res.size()];
		for (int i = 0; i < arr.length; i++) {
			arr[i]=res.get(i);
		}
		return arr;
	}
}

单调队列一般是使用在动态规划中。

加油啦!加油鸭,冲鸭!!!
原文地址:https://www.cnblogs.com/clarencezzh/p/10568210.html