算法训练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).

相关文章
|
2月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
56 3
|
4月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
2月前
|
存储 机器学习/深度学习 算法
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
蓝桥杯Python编程练习题的集合,涵盖了从基础到提高的多个算法题目及其解答。
127 3
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
|
1月前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
2月前
|
存储 算法 Java
Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性
Java Set因其“无重复”特性在集合框架中独树一帜。本文解析了Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性,并提供了最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的hashCode()与equals()方法。
45 4
|
2月前
|
机器学习/深度学习 算法 决策智能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
|
2月前
|
算法 Java C++
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
|
2月前
|
算法 C++
蓝桥 算法训练 共线(C++)
蓝桥 算法训练 共线(C++)
|
5月前
knn增强数据训练
【7月更文挑战第27天】
46 10
|
5月前
knn增强数据训练
【7月更文挑战第28天】
51 2