01 | 数据结构——单调栈问题
概述
解决问题:Next (Greater/Smaller) Element
构建单调递增/递减的栈,寻找下一个符合要求得元素
单调递增/递减
单调递增栈:s.peek()为栈中最小的元素,越往里越大
单调递减栈:s.peek()为栈中最大的元素,越往里越小
Next Greater:由于是寻找下一个更大的元素,需要有位置信息,以及最小的上边界,因此需要单调递增栈

Leetcode
496. Next Greater Element I
You are given two integer arrays nums1 and nums2 both of unique elements, where nums1 is a subset of nums2.
Find all the next greater numbers for nums1's elements in the corresponding places of nums2.
The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, return -1 for this number.
Example 1:
Input: nums1 = [4,1,2], nums2 = [1,3,4,2]
Output: [-1,3,-1]
Explanation:
For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
For number 1 in the first array, the next greater number for it in the second array is 3.
For number 2 in the first array, there is no next greater number for it in the second array, so output -1.
解析
(1)遍历nums2,利用单调s,构建map<val,next_val>
注:由于需要next greater element ,所以nums2应该从右往左遍历
栈顶元素3是栈中最小的元素,同时是与1距离最近的元素,所以后续循环出栈与1作比较:
- 大于1:就是该栈顶元素
- 小于等于1:说明此时栈顶元素还不够大,继续找大的
循环变不变量:
- 栈的top元素是距离
i最近,且最小的元素 - 遍历栈直到遇到比它大的元素
(2)根据nums1的值和map定位next_val,得到output
Solution
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
if(n1 == 0 || n2 == 0){
return new int[0];
}
// Get next map nums2
Map<Integer,Integer> map = new HashMap<>();
Stack<Integer> s = new Stack<>();
for(int i=n2-1; i>=0; i--){
while(!s.isEmpty() && nums2[i] >= s.peek()){
s.pop();
}
map.put(nums2[i], s.isEmpty() ? -1 : s.peek());
s.push(nums2[i]);
}
// Get result num1
int[] res = new int[n1];
for(int i = 0; i < n1; i++){
res[i] = map.get(nums1[i]);
}
return res;
}
}
739. Daily Temperatures
Given a list of daily temperatures T, return a list such that, for each day in the input, tells you how many days you would have to wait until a warmer temperature. If there is no future day for which this is possible, put 0 instead.
For example, given the list of temperatures T = [73, 74, 75, 71, 69, 72, 76, 73], your output should be [1, 1, 4, 2, 1, 1, 0, 0].
Note: The length of temperatures will be in the range [1, 30000]. Each temperature will be an integer in the range [30, 100].
解析
💌next greater number问题,单调递增栈
栈中存放数组T索引
从后至前遍历,循环不变量:
- 栈的top元素是距离
i最近,且最小的元素 - 遍历栈直到遇到比它大的元素
- 得到该元素的索引与
i的间距,放入结果数组next中
Solution
class Solution {
public int[] dailyTemperatures(int[] T) {
int n = T.length;
int[] next = new int[n];
// stack<index>
Stack<Integer> s = new Stack<>();
for(int i = n-1; i >= 0; i --){
while(!s.isEmpty() && T[i] >= T[s.peek()]){
s.pop();
}
next[i] = s.isEmpty() ? 0 : s.peek()-i;
s.push(i);
}
return next;
}
}
503. Next Greater Element II
Given a circular integer array nums (i.e., the next element of nums[nums.length - 1] is nums[0]), return the next greater number for every element in nums.
The next greater number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, return -1 for this number.
Example 1:
Input: nums = [1,2,1]
Output: [2,-1,2]
Explanation: The first 1's next greater number is 2;
The number 2 can't find next greater number.
The second 1's next greater number needs to search circularly, which is also 2.
解析
circular integer array问题,有两种解决策略:
-
复制数组,模仿环形数组遍历
-
循环上扩充,利用模模仿环形数组遍历
Solution
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
if(n == 0){
return new int[0];
}
int[] next = new int[n];
Stack<Integer> s = new Stack<>();
for(int i=2*n-1; i>=0; i--){
while(!s.isEmpty() && nums[i % n] >= s.peek()){
s.pop();
}
next[i % n] = s.isEmpty() ? -1 : s.peek();
s.push(nums[i % n]);
}
return next;
}
}
556. Next Greater Element III
Given a positive integer n, find the smallest integer which has exactly the same digits existing in the integer n and is greater in value than n. If no such positive integer exists, return -1.
Note that the returned integer should fit in 32-bit integer, if there is a valid answer but it does not fit in 32-bit integer, return -1.
Example 1:
Input: n = 12
Output: 21
解析
逆序数 7654321 :输出为-1
顺序数 1234567 : 输出为,后两位的交换1234576
乱序数59876:
- 生成数组
arr = [5,9,8,7,6] - 从后向前遍历,找到第一个比后边小的数5,位置为0
- 在
arr [1,4]中找到第一个比5大的数6 - 交换5和6的位置
Solution
class Solution {
public int nextGreaterElement(int n) {
if(n < 10){
return -1;
}
char[] cn = (n + "").toCharArray();
int i,j;
// cn[i-1] >= cn[i] 59876
for(i = cn.length-1; i>=1; i--){
if (cn[i-1] < cn[i]){
break;
}
}
if(i == 0){
return -1;
}
// find the smallest char in [i,cn.length-1] that greater than x
// for(j = cn.length-1; j >= i; j--){
// if(cn[j] > x){
// break;
// }
// }
j = binarySearch(cn,i-1);
// swap i-1 j
char temp = cn[j];
cn[j] = cn[i-1];
cn[i-1] = temp;
// reverse
reverse(cn, i, cn.length-1);
// ack whether val fit in 32-bit integer
long val = Long.parseLong(new String(cn));
return val <= Integer.MAX_VALUE ? (int)val : -1;
}
private void reverse(char[] cn, int i, int j){
while(i < j){
char temp = cn[i];
cn[i] = cn[j];
cn[j] = temp;
i++;
j--;
}
}
private int binarySearch(char[] cn, int index){
int right = cn.length ;
int left = index + 1;
// [left,right)
char target = cn[index];
while(left < right){
int mid = left + (right - left) / 2;
if(cn[mid] > target){
left = mid+1;
}else{
// cn[mid] <= target
right = mid;
}
}
return right - 1;
}
}

浙公网安备 33010602011771号