文章目录
- Day59
- 下一个更大元素II
- 题目
- 思路
- 代码
- 接雨水
- 题目
- 思路
- 代码
Day59
下一个更大元素II
503. 下一个更大元素 II - 力扣(LeetCode)
题目
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
- 输入: [1,2,1]
- 输出: [2,-1,2]
- 解释: 第一个 1 的下一个更大的数是 2;数字 2 找不到下一个更大的数;第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
提示:
- 1 <= nums.length <= 10^4
- -10^9 <= nums[i] <= 10^9
思路
本题要循环数组
查找元素右边最大值,使用单调递增栈(从栈口到栈底)
代码
class Solution {
public int[] nextGreaterElements(int[] nums) {
int len = nums.length;
int res[] = new int[len];
Arrays.fill(res, -1);
LinkedList<Integer> stack = new LinkedList<>();
stack.push(0);
for(int i = 1; i < len * 2; i++){
if(nums[stack.peek() % len] > nums[i % len]) stack.push(i);
else if(nums[stack.peek() % len] == nums[i % len]) stack.push(i);
else {
while(!stack.isEmpty() && nums[stack.peek() % len] < nums[i % len]){
res[stack.peek() % len] = nums[i % len];
stack.pop();
}
stack.push(i);
}
}
return res;
}
}
接雨水
42. 接雨水 - 力扣(LeetCode)
题目
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
- 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
- 输出:6
- 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
- 输入:height = [4,2,0,3,2,5]
- 输出:9
思路
只写了单调栈,其他方法(双指针,动态规划)看
代码随想录 (programmercarl.com)
准备工作
那么本题使用单调栈有如下几个问题:
- 首先单调栈是按照行方向来计算雨水
- 使用单调栈内元素的顺序
从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
因为一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子,栈头第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子。
- 遇到相同高度的柱子怎么办。
遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中。
因为我们要求宽度的时候 如果遇到相同高度的柱子,需要使用最右边的柱子来计算宽度。
- 栈里要保存什么数值
使用单调栈,也是通过 长 * 宽 来计算雨水面积的。
长就是通过柱子的高度来计算,宽是通过柱子之间的下标来计算,
那么栈里有没有必要存一个pair<int, int>类型的元素,保存柱子的高度和下标呢。
其实不用,栈里就存放下标就行,想要知道对应的高度,通过height[stack.top()] 就知道弹出的下标对应的高度了。
单调栈处理逻辑
以下逻辑主要就是三种情况
- 情况一:当前遍历的元素(柱子)高度小于栈顶元素的高度 height[i] < height[st.top()]
- 如果当前遍历的元素(柱子)高度小于栈顶元素的高度,就把这个元素加入栈中,因为栈里本来就要保持从小到大的顺序(从栈头到栈底)。
if(height[i] < height[stack.peek()]) stack.push(i)
- 情况二:当前遍历的元素(柱子)高度等于栈顶元素的高度 height[i] == height[st.top()]
- 如果当前遍历的元素(柱子)高度等于栈顶元素的高度,要跟更新栈顶元素,因为遇到相相同高度的柱子,需要使用最右边的柱子来计算宽度。
if(height[i] == height[stack.peek()]){
stack.pop();
stack.push(i);
}
- 情况三:当前遍历的元素(柱子)高度大于栈顶元素的高度 height[i] > height[st.top()]
- 如果当前遍历的元素(柱子)高度大于栈顶元素的高度,此时就出现凹槽了
那么雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度,代码为:int h = min(height[st.top()], height[i]) - height[mid];
雨水的宽度是 凹槽右边的下标 - 凹槽左边的下标 - 1(因为只求中间宽度),代码为:int w = i - st.top() - 1 ;
当前凹槽雨水的体积就是:h * w
。
while(!stack.isEmpty() && height[i] > height[stack.peek()]){
int mid = stack.peek();
stack.pop();
if(!stack.isEmpty()){
int h = Math.min(height[stack.peek()], height[i]) - height[mid];
int w = i - stack.peek() - 1; // 注意减一,只求中间宽度
sum += w * h;
}
}
stack.push(i);
代码
class Solution {
public int trap(int[] height) {
if (height.length <= 2) return 0;
int sum = 0;
LinkedList<Integer> stack = new LinkedList<>();
stack.push(0);
for(int i = 1; i < height.length; i++){
if(height[i] < height[stack.peek()]){
stack.push(i);
}else if(height[i] == height[stack.peek()]){
stack.pop();
stack.push(i);
}else {
while(!stack.isEmpty() && height[i] > height[stack.peek()]){
int mid = stack.peek();
stack.pop();
if(!stack.isEmpty()){
int h = Math.min(height[stack.peek()], height[i]) - height[mid];
int w = i - stack.peek() - 1; // 注意减一,只求中间宽度
sum += w * h;
}
}
stack.push(i);
}
}
return sum;
}
}