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. 接雨水
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).