单调栈系列 单调栈系列

单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减)。

题目列表

1、496 Next Great Element

2、739 Daily Temperature

3、503 Next Greater Element II

496 Next Great Element

题目描述

单调栈系列
单调栈系列

这道题如果暴力解法的话很容易想到,直接遍历该数字后面的数,然后返回值即可。时间复杂度O(n1);

可以换一个方式思考,这里我们先上代码,方便解释;

 public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        Map<Integer,Integer> map =new HashMap<>();
        int n2 =nums2.length;
        Stack<Integer> s = new Stack<Integer>();
        for (int i = n2-1; i >= 0; i--) {
            while(!s.isEmpty() && s.peek()<=nums2[i]){
                s.pop();
            }
            map.put(nums2[i],s.isEmpty()? -1: s.peek());
            s.add(nums2[i]);
        }
        int n1 = nums1.length;
        int[] ans =new int[n1];
        for (int i = 0; i < n1; i++) {
            ans[i] = map.get(nums1[i]);
        }
        return ans;
    }

我们先求出nums2中每个数的next great element,然后存HashMap中,再遍历nums1在HashMap找到所求结果。

关键在于nums2中如何求得每一个数的next great element呢?

这里我们先创建栈,然后在栈中排出比当前nums2[i]小的值,如果栈S不为空,得到的s.peek()就是nums2[i]的next great element了。最后我们将nums2[i]添加进栈,就完成了单调栈的整个过程。

注意点:我们需要从后面向前遍历,这样我们才能够得到next great element,如果是从前向后遍历的话,得到就是 previous great number了。(想一想是不是这个道理)

虽然是for循环嵌套while,但是这个算法的时间复杂度为O(n);因为每个元素进栈一次,并且最多也只会被pop一次,所以时间复杂度为O(n)。

739 Daily Temperature

题目描述

单调栈系列
单调栈系列

这道题求的是隔了几天才会有更高的温度,我们只需要将元素的下标进栈即可。

public int[] dailyTemperatures(int[] temperatures) {
      int n = temperatures.length;
        int[] ans = new int[n];
        Stack<Integer> s = new Stack<>();
        for (int i = n - 1; i >= 0; i--) {
            while (!s.isEmpty() && temperatures[s.peek()] <= temperatures[i]) {
            s.pop();
            }
            ans[i] = s.isEmpty()? 0:s.peek()-i;
            s.add(i);
        }
        return ans;
    }

503 Next Greater Element II

单调栈系列
单调栈系列

注意到这里数组变成了环形数组,解决这一类问题的套路就是将数组的长度翻倍;

实际操作中也并不需要翻倍数组,而是将下标翻倍即可

public int[] nextGreaterElements(int[] nums) {
        int n = nums.length;
        int n2 = 2*n;
        int[] ans = new int[n];
        Stack<Integer> s = new Stack<Integer>();
        for (int i = n2-1; i >= 0; i--) {
            while(!s.isEmpty() && s.peek()<=nums[i%n]){
                s.pop();
            }
            if(i<=n-1){
                ans[i] = s.isEmpty()? -1:s.peek();
            }
            s.add(nums[i%n]);
        }
        return ans;
    }