Monotone stack
Is it time to use monotone stack
We must remember that the data structure must assist us in solving problems, and must be optimized in the way of violent solution (in fact, space for time)
The monotone stack must meet the first in first out feature when processing data, just as we must meet the first in first out feature when using priority queue
How to make good use of monotone stack
There are several problems to understand when using monotone stack well
- What is the specific meaning of stacking
- What is the specific meaning of out of stack
- When does it get into the stack
- When will it come out
- The order of entering the stack: remember that the stack is entering the stack, backward out of the stack, backward in the stack, and positive out of the stack
- How to set up sentry points
Template
vector<int> answer(vector<int>& nums) { vector<int> ans(nums.size()); stack<int> st; for(int i=nums.size()-1;i>=0;i--) { while(!st.empty() && st.top()<=nums[i]) { // The second condition here should be changed according to the actual situation st.pop(); } ans[i]=st.empty()? 0 : st.top(); st.push(nums[i]) } return ans; }
In fact, it can also be traversed, or sentinel points can be added to better solve the problem
That is, for() iterates back and forth. Because we use the stack structure, we are actually going out of the stack by going into the stack backwards
Examples
739. Daily temperature
Medium difficulty 817
According to the daily temperature list, please calculate how many days you need to wait for a higher temperature each day. If the temperature will not rise after that, please replace it with 0 in this position.
Example 1:
input: temperatures = [73,74,75,71,69,72,76,73] output: [1,1,4,2,1,1,0,0]
Example 2:
input: temperatures = [30,40,50,60] output: [1,1,1,0]
Example 3:
input: temperatures = [30,60,90] output: [1,1,0]
Tips:
- 1 <= temperatures.length <= 105
- 30 <= temperatures[i] <= 100
Don't panic when you get the problem. Conduct a wave of analysis first. Any problem has certain characteristics. When you get the problem, you must first think about how to solve it, and then find out the characteristics of the problem for optimization
Violent solution to the problem: Is that each number traverses back to find the time complexity is o(n*n) At this time, why do you look back every time, because you don't remember what values are bigger than him At this time, only 73 can know the solution of the problem-----No 73,74 And-------Yes, the answer at position 73 is 1, but you don't know the answer at position 74 This reflects a characteristic Visit the points first and then get the results. This is very consistent with the processing characteristics of the stack, so we use the monotonic stack to solve it
positive sequence
class Solution { public: vector<int> dailyTemperatures(vector<int>& temperatures) { // Positive order traversal problem solving vector<int> ans(temperatures.size(),0); stack<int> st; for(int i=0;i<temperatures.size();i++) { while(!st.empty() && temperatures[i]>temperatures[st.top()]) { ans[st.top()]=i-st.top(); st.pop(); } st.push(i); } return ans; } };
Reverse order + sentry
class Solution { public: vector<int> dailyTemperatures(vector<int>& temperatures) { // thinking /* This should be traversed from the back to the front, because the previous results depend on the back, and the latter results are easier to get After that, we can see that this is consistent with the processing method of the stack. We first traverse the data and then get the result */ vector<int> res(temperatures.size()+1); stack<int> st; temperatures.push_back(0); for(int i=temperatures.size()-1;i>=0;i--) { while(!st.empty() && temperatures[i]>=temperatures[st.top()]) { st.pop(); } res[i]=st.empty()? 0 : st.top()-i; st.push(i); } res.pop_back(); return res; } };
496. Next larger element I
Simple difficulty 452
Give you two arrays nums1 and nums2 without duplicate elements, where nums1 is a subset of nums2.
Please find out the next larger value of each element in nums1 in nums2.
The next larger element of the number x in nums1 refers to the first element larger than x to the right of the corresponding position in nums2. If it does not exist, the corresponding position outputs - 1.
Example 1:
input: nums1 = [4,1,2], nums2 = [1,3,4,2]. output: [-1,3,-1] explain: about num1 You can't find the next larger number in the second array, so output -1 . about num1 The number 1 in the second array, and the next larger number to the right of the number 1 in the second array is 3. about num1 The number 2 in the second array has no next larger number, so it is output -1 .
Example 2:
input: nums1 = [2,4], nums2 = [1,2,3,4]. output: [3,-1] explain: about num1 The number in the second array is 2, and the next larger number in the second array is 3. about num1 The number 4 in the second array has no next larger number, so it is output -1 .
Preorder traversal
class Solution { public: vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) { // Obviously, it is in line with the habit of first in and then out // Understand the meaning of the question. Nums1 is a subset of nums2, that is, the length of nums1 < = the length of nums2 // You can use the monotone stack to calculate the maximum value of each number of nums2, and there are no duplicate elements map<int,int> mp; // [number, subscript] for(int i=0;i<nums2.size();i++) { mp[nums2[i]]=i; } vector<int> ans(nums2.size(),-1); stack<int> st; for(int i=0;i<nums2.size();i++) { while(!st.empty() && nums2[st.top()]<nums2[i]) { ans[st.top()]=nums2[i]; st.pop(); } st.push(i); } vector<int> res(nums1.size()); for(int i=0;i<nums1.size();i++) { res[i]=ans[mp[nums1[i]]]; } return res; } };
Post traversal + sentry
class Solution { public: vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) { // Obviously, it is in line with the habit of first in and then out // Understand the meaning of the question. Nums1 is a subset of nums2, that is, the length of nums1 < = the length of nums2 // You can use the monotone stack to calculate the maximum value of each number of nums2, and there are no duplicate elements map<int,int> mp; // [number, subscript] for(int i=0;i<nums2.size();i++) { mp[nums2[i]]=i; } nums2.push_back(-1); vector<int> ans(nums2.size(),-1); stack<int> st; for(int i=nums2.size()-1;i>=0;i--) { while(!st.empty() && nums2[st.top()]<=nums2[i] ) { st.pop(); } // At this time, the top of the stack smaller than the number is removed, which is a non strict monotonic stack ans[i]=st.empty() ? -1: nums2[st.top()]; st.push(i); } ans.pop_back(); vector<int> res(nums1.size()); for(int i=0;i<nums1.size();i++) { res[i]=ans[mp[nums1[i]]]; } return res; } };