代码随想录-2023/08/28

70 阅读1分钟

单调栈

503.下一个更大元素II

解题思路;

  1. 若一个元素是最大值, 则其一定没有下一个更大的元素, 所以该位置记录为-1
  2. 若一个元素不是最大值, 则一定可以找到下一个更大元素, 所以用取余运算找到下一个比其更大元素的位置

代码:

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int n = nums.length;
        int[] arr = new int[n];
        int max = Arrays.stream(nums).max().getAsInt();
        for(int i=0; i < n; i++){
            if(nums[i] != max){
                int j = i;
                // 非最大值一定能找到下一个比其大的值
                while(nums[(j + 1) % n] <= nums[i]) j++;
                arr[i] = nums[(j + 1) % n];
            }else arr[i] = -1;
        }
        return arr;
    }
}

42.接雨水

解题思路1---纵向求解

  1. 每个位置所能接的雨水的最大值为 Math.min(left_max, right_max)
  2. 前后缀数组找到当前位置的前边最大值和后边最大值, 求最小值即可
  3. 找到左边和右边最远的最大值

代码:

class Solution {
    // 每个木桶里面装的水取决于其左边高度最大值和其右边高度最大值的最小值-当前木桶高度
    public int trap(int[] height) {
         int n = height.length;

        // 1.构造一个前缀最大值数组
        int[] pre_max = new int[n];
        pre_max[0] = height[0];
        for(int i=1; i<n; i++){
            pre_max[i] = Math.max(pre_max[i-1], height[i]);
        }

        // 2.构造一个后缀最大值数组
        int[] suf_max = new int[n];
        suf_max[n-1] = height[n-1];
        for(int i=n-2; i>=0; i--){
            suf_max[i] = Math.max(suf_max[i+1], height[i]);
        }

        // 每个木桶能接的雨水 = Math.min(pre_max[i], suf_max[i]) - height[i]
        int ans = 0;
        for(int i=0; i<n; i++){
            ans += Math.min(pre_max[i], suf_max[i]) - height[i];
        }

        // 时间复杂度为O(n), 空间复杂度为O(n)
        return ans;
    }
}

解题思路2 --- 单调栈(横向求解)

  1. 维护一个单调递减栈, 每当有元素比栈顶元素大时, 代表栈内有元素可以接雨水
  2. 横向求解每个位置接的雨水量(若该位置能接雨水, 则其右边的横向的雨水都由其负责)
  3. 找到左边和右边最近的最大值

代码:

class Solution {
    public int trap(int[] height) {
        int n = height.length, ans = 0;
        // 前后缀最大值数组是纵向求解 --- 需要找到左边和右边最远的最大值
        // 维护一个单调递减栈横向求解 --- 需要找到左边和右边最近的最大值
        Deque<Integer> deque = new ArrayDeque<>();
        for(int i=0; i < n; i++){
            while(!deque.isEmpty() && height[i] > height[deque.peek()]){
                int cur = deque.pop();
                // 判断左边是否有元素, 若栈内只剩下一个元素(无法接雨水)
                if(deque.isEmpty()) break;
                // 弹出左边元素
                int l = deque.peek();
                // 计算当前位置能接的雨水
                ans += (Math.min(height[l], height[i]) - height[cur]) * (i - l - 1);
            }
            deque.push(i);
        }
        return ans;
    }
}