503. 下一个更大元素 II
给定一个循环数组 nums
( nums[nums.length - 1]
的下一个元素是 nums[0]
),返回 nums
中每个元素的 下一个更大元素 。
数字 x
的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1
。
示例 1:
输入: nums = [1,2,1] 输出: [2,-1,2] 解释: 第一个 1 的下一个更大的数是 2; 数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
示例 2:
输入: nums = [1,2,3,4,3] 输出: [2,3,4,-1,4]
提示:
1 <= nums.length <= 104
-109 <= nums[i] <= 109
思路:
方法一:将两个nums数组拼接在一起,使用单调栈计算出每一个元素的下一个最大值,最后再把结果集即result数组resize到原数组大小就可以了。单调栈在这篇文章有讲
Day61:单调栈 739. 每日温度 496.下一个更大元素 I-CSDN博客
class Solution {
public int[] nextGreaterElements(int[] nums) {
if(nums.length<=1){
return new int[]{-1};
}
int size=nums.length;
//初始化
int[] result=new int[size];
Arrays.fill(result,-1);
List<Integer> list=new LinkedList<>();
for(int i=0;i<2*size;i++){
while(list.size()>0&&nums[list.get(list.size()-1)]<nums[i%size]){
//取栈顶元素(坐标)
int num=list.get(list.size()-1);
result[num]=nums[i%size];
list.remove(list.size()-1);
}
list.add(i%size);
}
return result;
}
}
42. 接雨水
给定 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
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
思路:
方法一:
按列计算:每列的雨水面积=min(左边最高高度,右边最高高度)-当前列的高度
注意:左边最高高度>当前列的高度,右边最高高度>当前列的高度
代码参考:
class Solution {
public int trap(int[] height) {
int length = height.length;
if (length <= 2) return 0;
int[] maxLeft = new int[length];
int[] maxRight = new int[length];
// 记录每个柱子左边柱子最大高度
/*
为什么给左边最大高度的初值是当前高度,
为了防止Math.min(maxLeft[i], maxRight[i]) - height[i]等于负数,
所以每个柱子最左最右的最大高度至少大于等于当前高度
(参考:最高的那个柱子的雨水量为0)
*/
maxLeft[0] = height[0];
for (int i = 1; i< length; i++)
maxLeft[i] = Math.max(height[i], maxLeft[i-1]);
// 记录每个柱子右边柱子最大高度
maxRight[length - 1] = height[length - 1];
for(int i = length - 2; i >= 0; i--)
maxRight[i] = Math.max(height[i], maxRight[i+1]);
// 求和
int sum = 0;
for (int i = 0; i < length; i++) {
int count = Math.min(maxLeft[i], maxRight[i]) - height[i];
if (count > 0) sum += count;
}
return sum;
}
}
方法二:
单调栈:
1.首先单调栈是按照行方向来计算雨水量
2.使用单调栈内元素的顺序
从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
因为一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子
3.遇到相同高度的柱子怎么办?
遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中。
4.栈里要保存什么数值
使用单调栈,也是通过 长 * 宽 来计算雨水面积的。
长就是通过柱子的高度来计算,宽是通过柱子之间的下标来计算,
存着下标,计算的时候用下标对应的柱子高度
5.处理逻辑
- 情况一:当前遍历的元素(柱子)高度小于栈顶元素的高度
如果当前遍历的元素(柱子)高度小于栈顶元素的高度,就把这个元素加入栈中,因为栈里本来就要保持从小到大的顺序(从栈头到栈底)。
- 情况二:当前遍历的元素(柱子)高度等于栈顶元素的高度
如果当前遍历的元素(柱子)高度等于栈顶元素的高度,要跟更新栈顶元素,因为遇到相相同高度的柱子,需要使用最右边的柱子来计算宽度。
- 情况三:当前遍历的元素(柱子)高度大于栈顶元素的高度
如果当前遍历的元素(柱子)高度大于栈顶元素的高度,此时就出现凹槽了
取栈顶元素,将栈顶元素弹出,这个就是凹槽的底部,也就是中间位置,下标记为mid,对应的高度为height[mid]
此时的栈顶元素,就是凹槽的左边位置,下标为left,对应的高度为height[left]
当前遍历的元素index,就是凹槽右边的位置,下标为iindex,对应的高度为height[index]
那么雨水高度是 min(凹槽左边高度, 凹槽右边高度) - 凹槽底部高度,代码为:int h = min(height[left], height[index]) - height[mid];
遇见高度一样的
遇见更高的
代码参考:
class Solution {
public int trap(int[] height) {
int sums=0;
if(height.length<=2){
return 0;
}
List<Integer> list=new LinkedList<>();
list.add(0);
for(int index=1;index<height.length;index++){
if(height[index]<height[list.get(list.size()-1)]){
list.add(index);
}else if(height[index]==height[list.get(list.size()-1)]){
list.remove(list.size()-1);
list.add(index);
}else{
while(list.size()>0&&height[index]>height[list.get(list.size()-1)]){
int mid=list.get(list.size()-1);
list.remove(list.size()-1);
if(list.size()>0){
int left=list.get(list.size()-1);
int h=Math.min(height[left],height[index])-height[mid];
int w=index-left-1;
int hold=h*w;
if(hold>0) sums+=hold;
}
}
list.add(index);
}
}
return sums;
}
}