package Leetcode;

import java.util.LinkedList;
/**
 * 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。(时间复杂度限制)
 */
public class test239 {
    public static void main(String[] args) {
        int []nums={1,3,-1,-3,5,3,6,7};
        int k=3;
        int []result=maxSlidingWindow(nums, k);  
        int x=0;
    }
    //双向链表存储最大值index位置
    ///遍历数组,将 数 存放在双向队列中,并用 L,R 来标记窗口的左边界和右边界。队列中保存的并不是真的 数,而是该数值对应的数组下标位置,
    // 并且数组中的数要从大到小排序。如果当前遍历的数比队尾的值大,则需要弹出队尾值,直到队列重新满足从大到小的要求。刚开始遍历时,
    // L 和 R 都为 0,有一个形成窗口的过程,此过程没有最大值,L 不动,R 向右移。当窗口大小形成时,L 和 R 一起向右移,每次移动时,
    // 判断队首的值的数组下标是否在 [L,R] 中,如果不在则需要弹出队首的值,当前窗口的最大值即为队首的数。
    // R=i,L=k-R。由于队列中的值是从大到小排序的,所以每次窗口变动时,只需要判断队首的值是否还在窗口中就行了。
    // 解释一下为什么队列中要存放数组下标的值而不是直接存储数值,因为要判断队首的值是否在窗口范围内,由数组下标取值很方便,而由值取数组下标不是很方便。

    public static int[] maxSlidingWindow(int[] nums, int k) {
        if(nums==null||nums.length<2){
            return nums;
        }
        LinkedList<Integer> queue=new LinkedList<>();
        int []result=new int[nums.length-k+1];
        for(int i=0;i<nums.length;i++){
            while(!queue.isEmpty()&&nums[queue.peekLast()]<=nums[i]){
                queue.pollLast();
            }
            queue.add(i);
            if(queue.peek()<=i-k){
                queue.poll();
            }
            if(i+1>=k){
                result[i+1-k]=nums[queue.peek()];
            }
        }
        return result;
    }

    
}