The sword refers to the maximum value of Offer59-I-sliding window

Problem Description

Given an array nums and the size of the sliding window k, please find the maximum value among all sliding windows.

Example:

输入: 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

Problem solving ideas

This problem can be solved by a brute force method, each time the sliding window moves to the maximum of the k numbers, then each time it takes O(k) time, a total of n steps, then O(nk) of
course can also be done with a monotonic queue Solving, the monotonic queue is similar to the monotonic stack problem, and the monotonic stack problem refers to the stack containing the min function (monotonic stack). The
Insert picture description here
monotonic queue is similar to the monotonic stack problem. We can observe whether there are some elements in the queue that are useless. We leave these without If you remove the used elements, see if you get monotonicity.
As the above figure is an example, suppose we find the minimum value in the sliding window every time . When -3 comes in, the first 3 is definitely useless. Every time we find the minimum value in the queue, -3 is less than 3,3. It is on the left of -3, so this 3 will be ejected first. In other words, as long as -3 is there, 3 will never be output as the minimum value, and if -3 is alive longer, it will The 3 will be moved out after it is moved out of the sliding window, so we can conclude that the previous 3 will not be output as an answer and can be removed. The same is true for -1.
Therefore, as long as the previous number in the queue is larger than the next number, the previous number is definitely useless, because the next number will be popped out later and is smaller. Therefore, as long as there is such a reversed pair, We can delete the big points, we delete all such numbers, and the entire queue will become a strictly monotonously increasing queue.
We require the minimum value in the queue, so the strictly monotonously rising queue is the head element, so every time you find the minimum value, you can directly find the head element.
Summary: For the problem of monotonic stacks and monotonic queues, we can first consider using stacks and queues to violently simulate the original problem, that is, conventional thinking, and then look at which elements in the stack and queue are useless in the conventional thinking, and then Delete again and see if the remaining elements are monotonic. If the remaining elements are monotonic, you can do some optimizations, such as taking extreme values ​​or dichotomy .

For this question:

Since what we need to ask for is the maximum value of the sliding window, if there are two subscripts i and j in the current sliding window, where i is on the left side of j (i <j), and the element corresponding to i is not greater than that corresponding to j The element of is (nums[i]<=nums[j]), so what will happen?

When the sliding window moves to the right, as long as i is still in the window, then j must also be in the window , which is guaranteed by i on the left side of j. Therefore, due to the existence of nums[j], nums[i] must not be the maximum value in the sliding window. We can permanently remove nums[i]

So we can use a queue to store all the subscripts that have not been removed. In the queue, these subscripts are stored in ascending order, and their corresponding values ​​in the array nums are strictly monotonically decreasing. Because if there are two adjacent subscripts in the queue, their corresponding values ​​are equal or increasing, then let the former be i and the latter be j, which corresponds to the situation mentioned above, that is, nums[i] will be removed , Which creates a contradiction.

When the sliding window moves to the right, we need to put a new element in the queue. In order to maintain the nature of the queue, we will constantly compare the new element with the element at the end of the queue. If the former is greater than or equal to the latter, then the element at the end of the queue can be permanently removed and we will pop it out of the queue. We need to continue this operation until the queue is empty or the new element is smaller than the element at the end of the queue.

**Since the element corresponding to the subscript in the queue is strictly monotonically decreasing, the element corresponding to the subscript at the head of the queue is the maximum value in the sliding window. **But the same as in Method 1, the maximum value at this time may be on the left side of the left border of the sliding window, and as the window moves to the right, it will never appear in the sliding window. Therefore, we also need to keep popping elements from the head of the team until the head element of the team is in the window.

In order to pop the first and last elements of the queue at the same time, we need to use a double-ended queue. A deque that satisfies this monotonicity is generally called a "monotonic queue" .

In Java, deque and its application can refer to Java deque and its application

class Solution {
    
    
    public int[] maxSlidingWindow(int[] nums, int k) {
    
    
        int len=nums.length;
        if(len<1){
    
    
            return nums;
        }
        //创建双端队列,使用LinkedList实现类
        //注意,双端队列存储的是元素的下标
        Deque<Integer> queue=new LinkedList<Integer>();
        List<Integer> list=new ArrayList<Integer>();        //用于保存最终结果
        int st=0,ed=k-1;        //st,ed分别指向滑动窗口的左右边界
        //我们先把初始情况下滑动窗口里面的元素都加入到单调队列中,这里隐含了k>=len的问题
        for(int i=st;i<=ed;i++){
    
        
            //当滑动窗口右移时,会不断判断当前元素是否大于或者等于队尾元素对应的值,如果满足条件的话,就移出队尾元素
            //一直到队列为空或者当前元素小于队尾元素对应的值为止
            //才把当前元素的下标加入到队尾,这样可以保持队列的单调递减的性质
            while(!queue.isEmpty() && nums[i]>=nums[queue.peekLast()]){
    
    
                int temp=queue.pollLast();
            } 
            queue.offerLast(i);
        }
        //把队头元素加入到结果集中,队头元素对应的值即滑动窗口的最大值
        list.add(nums[queue.peekFirst()]);
        while(ed<len-1){
    
    
            //滑动窗口后移一位
            st++;
            ed++;
            //当队列不为空,并且队头元素(下标)处在滑动窗口左端点的左边时,就需要把它移出队列
            if(!queue.isEmpty() && queue.peekFirst()<st){
    
    
                int temp=queue.pollFirst();
            }
            //当滑动窗口右移时,会不断判断当前元素是否大于或者等于队尾元素对应的值,如果满足条件的话,就移出队尾元素
            //一直到队列为空或者当前元素小于队尾元素对应的值为止
            //才把当前元素的下标加入到队尾,这样可以保持队列的单调递减的性质   
            while(!queue.isEmpty() && nums[ed]>=nums[queue.peekLast()]){
    
    
                int temp=queue.pollLast();
            }
            queue.offerLast(ed);
            list.add(nums[queue.peekFirst()]);
        }
        //把结果存入到数组中
        int size=list.size();
        int res[]=new int[size];
        for(int i=0;i<size;i++){
    
    
            res[i]=list.get(i);
        }
        return res;
    }
}

Guess you like

Origin blog.csdn.net/qq_39736597/article/details/113815879