算法训练Day59|● 503.下一个更大元素II ● 42. 接雨水

简介: 算法训练Day59|● 503.下一个更大元素II ● 42. 接雨水

LeetCode: 503.下一个更大元素II

503. 下一个更大元素 II - 力扣(LeetCode)

1.思路

暴力求解间接。

构建单调栈,栈中存放着数组元素对应的索引。单调栈通过取模操作在原数组的基础上实现循环遍历

2.代码实现

// 暴力求解:创建新数组是原数组的二倍,使得其能模拟循环一圈的场景。双层for循环遍历将符合条件的取模加入结果中。
class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int[] nums1 = new int[2 * nums.length];
        for (int i = 0; i < nums.length; i++) {
            nums1[i] = nums[i];
            nums1[i + nums.length] = nums[i];
        }
        int[] res = new int[nums.length];
        Arrays.fill(res, -1);
        for (int i = 0; i < nums1.length; i++) {
            for (int j = i + 1; j < nums1.length; j++) {
                if (nums1[j] > nums1[i]) {
                    res[i % nums.length] = nums1[j];
                    break;
                }
            }
        }
        return res;
    }
}
// 单调栈
class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int[] res = new int[nums.length];
        // 构建递增的单调栈,存储数组索引,方便对当前索引右侧更大的一个值进行记录
        Stack<Integer> stack = new Stack<>();
        Arrays.fill(res, -1);
        stack.add(0);
        // 遍历两倍数组大小,实现模拟循环的场景
        for (int i = 1; i < nums.length * 2; i++) {
            // 栈不为空且当前索引下数值大于栈顶索引数值
            while (!stack.isEmpty() && nums[i % nums.length] > nums[stack.peek()]) {
                res[stack.peek()] = nums[i % nums.length]; // 栈顶索引处的元素右侧存在更大的值为nums[i % nums.length]
                stack.pop(); // 栈顶索引弹出
            }
            stack.add(i % nums.length); // 否则将相应索引加入栈中
        } 
        return res;
    }
}

3.复杂度分析

时间复杂度:O(n).

空间复杂度:O(n).

LeetCode:42. 接雨水

42. 接雨水 - 力扣(LeetCode)

1.思路

基本思路:找到当前索引下左右雨柱最大高度中较小的那个,减去当前位置高度,得到当前索引下可盛放雨水的容量,将大于0的结果进行加和即可。后面双指针定义两个数组也是延续这种思路,单调栈也是在这个基础上建立的。

2.代码实现

// 方法一:暴力
class Solution {
    public int trap(int[] height) {
        int ans = 0; // 存储可接到的雨水结果
        int n = height.length; 
        for (int i = 0; i < n; i++) {
            int leftMax = 0; // 当前位置左侧最大值
            int rightMax = 0; // 当前位置右侧最大值
            // 遍历找到左侧最高的柱子
            for (int j = i; j >= 0; i--) {
                leftMax = Math.max(leftMax, height[j]);
            }
            // 遍历找到右侧最高的柱子
            for (int j = i; j < n; j++) {
                rightMax = Math.max(rightMax, height[j]);
            }
            // 计算当前位置能接到的雨水量
            int minMax = Math.min(leftMax, rightMax);
            ans += minMax - height[i];
        }
        return ans;
    }
}
// 方法二:双指针
class Solution {
    public int trap(int[] height) {
        int len = height.length;
        int[] maxLeft = new int[len];
        int[] maxRight = new int[len];
        // 记录每个柱子左边柱子最大高度
        maxLeft[0] = height[0];
        for (int i = 1; i < len; i++) {
            maxLeft[i] = Math.max(maxLeft[i - 1], height[i]);
        }
        // 记录每个柱子右边柱子最大高度
        maxRight[len - 1] = height[len - 1];
        for (int i = len - 2; i >= 0; i--) {
            maxRight[i] = Math.max(maxRight[i + 1], height[i]);
        }
        // 求和
        int sum = 0;
        for (int i = 0; i < len; i++) {
            int count = Math.min(maxLeft[i], maxRight[i]) - height[i];
            if (count > 0) sum += count;
        }
        return sum;
    }
}
// 单调栈
class Solution {
    public int trap(int[] height) {
        int sum = 0;
        Stack<Integer> stack = new Stack<>();
        stack.add(0);
        for (int i = 1; i < height.length; i++) {
            if (height[i] < height[stack.peek()]) {
                stack.add(i);
            } else if (height[i] == height[stack.peek()]) {
                stack.pop();
                stack.add(i);
            } else {
                int nowHeight = height[i]; // 当前索引下的高度
                while (!stack.isEmpty() && (height[i] > height[stack.peek()])) {
                    int mid = stack.pop();
                    if (!stack.isEmpty()) {
                        int left = stack.peek();
                        int h = Math.min(height[left], height[i]) - height[mid];
                        int w = i - left - 1;
                        int s = h * w;
                        if (s > 0) {
                            sum += s;
                        }
                    }
                }
                stack.add(i);
            }
        }
        return sum;
    }
}

3.复杂度分析

时间复杂度:O(n).

空间复杂度:O(n).

相关文章
|
6天前
|
算法 Java
[Java·算法·简单] LeetCode 27. 移除元素 详细解读
[Java·算法·简单] LeetCode 27. 移除元素 详细解读
27 1
|
6天前
|
设计模式 算法 Java
【数据结构和算法】删掉一个元素以后全为 1 的最长子数组
这是力扣的 1493 题,难度为中等,解题方案有很多种,本文讲解我认为最奇妙的一种。又又又是一道滑动窗口的典型例题,可以帮助我们巩固滑动窗口算法。这道题很活灵活现,需要加深对题意的变相理解。给你一个二进制数组nums,你需要从中删掉一个元素。 请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。 如果不存在这样的子数组,请返回 0 。
67 1
|
6天前
|
存储 算法
代码随想录算法训练营第五十九天 | LeetCode 739. 每日温度、496. 下一个更大元素 I
代码随想录算法训练营第五十九天 | LeetCode 739. 每日温度、496. 下一个更大元素 I
23 1
|
6天前
|
算法
代码随想录算法训练营第五十七天 | LeetCode 739. 每日温度、496. 下一个更大元素 I
代码随想录算法训练营第五十七天 | LeetCode 739. 每日温度、496. 下一个更大元素 I
18 3
|
6天前
|
算法 测试技术 Serverless
【二分查找】【C++算法】378. 有序矩阵中第 K 小的元素
【二分查找】【C++算法】378. 有序矩阵中第 K 小的元素
|
6天前
|
算法
常见算法题——203.移除链表元素
【2月更文挑战第9天】
26 0
|
6天前
|
搜索推荐 算法
在冒泡排序算法中,为什么每次比较相邻的元素时都要进行交换?
【2月更文挑战第8天】【2月更文挑战第21篇】在冒泡排序算法中,为什么每次比较相邻的元素时都要进行交换?
|
6天前
|
算法
|
6天前
|
搜索推荐 算法 测试技术
【排序算法】【二叉树】【滑动窗口】LeetCode220: 存在重复元素 III
【排序算法】【二叉树】【滑动窗口】LeetCode220: 存在重复元素 III
|
6天前
|
存储 算法
算法题解-二叉搜索树中第K小的元素
算法题解-二叉搜索树中第K小的元素