Stack and queue 6: sliding window maximum

Posted by kidestranged on Mon, 08 Nov 2021 13:40:33 +0100

Problem Description:

Title Link:
Sliding window Max

Give you an integer array nums, with a sliding window of size k moving from the leftmost side of the array to the rightmost side of the array. You can only see k numbers in the sliding window. The sliding window moves only one bit to the right at a time.
Returns the maximum value in the sliding window.

Like the following (the picture comes from the force buckle)

What should I do?

Suppose there is such a queue.
The queues are ordered, and as the sliding window moves, the queues in the window are always orderly (decreasing).

Do we just need to return to the queue header element in the window after each sliding window move!!!

It's very comfortable.

So, the core question now is: how can we keep the queue in the window monotonous all the time?

When might the monotonicity of the queue change?

Obviously, when the sliding window moves, the most team head element goes out, and the team tail is supposed to add an element.

However, if this element is added to the tail, does it not decrease?

It's hard to say. However, we can define a new push() queue function to ensure that the queue decreases after joining the queue.

Let's look at the methods to join the queue and ensure the single reduction of the queue.

Principle of team push

If the value of the push is greater than the element value of the entry (tail of the queue),
Then directly pop up the value at the back end of the queue (at the end of the queue).
If it is always greater than, it will always play the tail element;
Until the value to be push ed is smaller than the value of the tail element.

(one is the largest and the other is the second largest)

Principle of outgoing pop()

Every time it pops up,
Check the size of the element value * * (that is, the leftmost element of the window) * * and the queue exit (queue head) element to be removed from the current window,
If both are equal (the element to pop up and the team head element)
So, pop up.

When you leave the team, you should note that elements do not pop up every time you move back. As for why, you can follow the following example to simulate it.

In fact, there is only one case that the following pop function will be used to get out of the team: that is, the team head element is also on the far left of the sliding window.

Because sometimes the maximum value is in the middle, the value on the left of the window may have been deleted when the middle maximum value enters the team, so there is no need to delete it at this time.

for instance:
For example, the window is indicated in parentheses, and the queue is indicated in parentheses;
[ , , (5,4)]
There are 4 elements in the above window, but there are only 2 elements in the queue. At this time, the window moves to the right and deletes the 5 on the left of the queue?
Obviously not.
Because when the window moves next time, the leftmost element of the window has popped up, so just move it directly.

However, you will be out of the team if:
[(5, 4), , ]

Language description makes people dizzy. Let's take an example to simulate it. Let's look at the above description after the simulation.

Simulation:

Array: nums = [1,3,-1,-3,5,3,6,7]
Sliding window: k = 3
Add elements from 0 elements in the sliding window cluster. The maximum value of the sliding window is calculated after there are 3 elements in the window.
Therefore, the first maximum value of the sliding window is 3 of the third line, and the first two lines are not counted.
The first two lines are just to simulate the flow of code execution.

Value to pushValue popped due to pushElements in the queue (left head and right tail)Left most value of sliding window
1nothing11
3131
-1nothing3,-1-1
-3nothing3,-1,-33
53,-1,-35-1
3nothing5,3-3
65,365
7673

As can be seen from the above simulation, the queue header element in the queue is always the maximum value of the sliding window

Difficulties:

Distinguish the elements in the sliding window
and
Relationship of elements in monotone queue

  • The elements of the monotone queue must be in the sliding window, but they are a subset of the sliding window
  • The sliding window only retains the largest elements, and will certainly retain the largest elements in the window. As for several other elements, it depends on the size of the newly added elements. Through the push function, all other elements in the team smaller than the newly added elements can be deleted.
    If the new element is big enough, he is obviously the only one left in the team, that is, the head of the team
  • When the queue moves to the right, it is also very critical
    • If the leftmost element of the sliding window happens to be the queue head element (i.e. the largest element of the queue), it must be deleted

In short, the push function ensures that the queue head of the monotone queue is the largest element in this sliding window
The pop function ensures that the sliding window moves normally
Combine the two swords to find the maximum value in the window

The following is the code implementation

#include <string>
#include <queue>
#include <iostream>

using namespace std;

class Solution {
private:
	class MyQueue{
	//Define a unique operation of a monotonic queue by yourself
	public:
			//Using deque to implement monotonic queues
			deque<int> que;
				
			/*1.pop(value)Pop up function:
			*Under what circumstances can it pop up?
			*When sliding the leftmost element of the window and
			*When the leftmost element of the monotonic queue (that is, the queue head element) is equal, it pops up.
			*Otherwise, no operation will be done and nothing will pop up.
			*Of course, when the click out queue is not empty, it can't pop up.
		    */
			void pop(int value) {
			//front() function: get the queue header element of the queue
				if (!que.empty() && value == que.front()) {		//Pop up queue header element
				 	que.pop_front();
				}
			}
				
			//2.push(value) element queue function
			/*When can I enter the queue?
			*What are the operations required to enter the queue in order to maintain the monotonous reduction of the queue?
			*If the element to be queued is larger than the current tail element,
			*Then pop_back(), bounce the last element of the team away.
			*Continue to judge until the last element at the end of the queue is larger than the element to be added, or the queue is empty.
			*In this way, we can ensure that there is the largest number in the team, and this number is at the head of the team, and the number on the right of the head of the team is also the second largest.
			*The monotonicity of monotone queue is guaranteed.
			 */
		    void push(int value) {
				while (!que.empty() && value > que.back()) {
					que.pop_back();
				}
				//After ejecting the smaller than value, put the value in the queue.
				que.push_back(value);
			}
				
			//Finally, the team head element, this element, is the largest one in the sliding window
			int front() {
				return que.front();
			}
	}
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
		MyQueue que;
		vector<int> result;
		for (int i = 0;i < k; i++) {
			que.qush(nums[i]);
		}

		//result record the maximum value of the first k element
		result.push_back(que.front());
		for (int i = k; i <nums.size(); i++) {
			//Note that the order of deleting elements and adding elements here cannot be reversed. Add pop pop-up elements first, and then push to add elements
			que.pop(nums[i - k]);//Slide the window to remove the front most element
			que.push(nums[i]);//Sliding window plus corresponding elements
			result.push_back(que.front());//Record the corresponding maximum value
		}		
		return result;
    }
};

Topics: C++ data structure queue