代码随想录算法训练营第六十一天| 503.下一个更大元素II 、42. 接雨水
503.下一个更大元素II
题目链接:503. 下一个更大元素 II - 力扣(LeetCode)
题目描述:
给定一个循环数组 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 <= 10^4
-109 <= nums[i] <= 10^9
class Solution {
public:
std::vector<int> nextGreaterElements(std::vector<int>& nums) {
int lens = nums.size();
if(lens==0) return {};
std::stack<int> stack;
std::vector<int> arr(lens,-1);
stack.push(0);
for(int i = 1;i<lens*2;i++){
if(nums[i%lens] < nums[stack.top()]) stack.push(i%lens);
else if(nums[i%lens]==nums[stack.top()]) stack.push(i%lens);
else{
while(!stack.empty() && nums[i%lens] > nums[stack.top()]){
arr[stack.top()] = nums[i%lens];
stack.pop();
}
stack.push(i%lens);
}
}
return arr;
}
};
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 * 10^4
0 <= height[i] <= 10^5
双数组法:
将每一列看作是一个木桶,两个数组分别记录左边的最大值和右边的最大值
第 i i i个桶所能装的最大容量就是 s t d : : m i n ( l e f t [ i ] , r i g h t [ i ] ) − h e i g h t s [ i ] std::min(left[i],right[i]) - heights[i] std::min(left[i],right[i])−heights[i] 。
那么将每个桶的接水量加和就是 a n s ans ans 。
时间复杂度和空间复杂度都是 O ( n ) O(n) O(n)
class Solution {
public:
int trap(std::vector<int>& height) {
int lens = height.size();
std::vector<int> left(lens);
std::vector<int> right(lens);
int ans = 0;
int k = 0;
for(int i = 0;i<lens;i++){
k = std::max(k,height[i]);
left[i] = k;
}
k = 0;
for(int i = lens-1;i>=0;i--){
k = std::max(k,height[i]);
right[i] = k;
}
for(int i = 0;i<lens;i++){
ans += std::min(left[i],right[i])-height[i];
}
return ans;
}
};
双指针法:
class Solution {
public:
int trap(std::vector<int>& height) {
int left = 0,right = height.size()-1;// 左右指针
int lmax = 0,rmax = 0; // 记录左右两边的最大值
int ans = 0;
while(left<=right){
lmax = std::max(lmax,height[left]);
rmax = std::max(rmax,height[right]);
if(lmax<rmax){// 找到了此时左侧桶的最大雨水
ans += lmax - height[left];
left++;
}else{
ans += rmax - height[right];
right--;
}
}
return ans;
}
};
单调栈:
class Solution {
public:
int trap(std::vector<int>& height) {
std::stack<int> stack;// 单减栈
int ans = 0;
for(int i = 0;i<height.size();i++){
while(!stack.empty() && height[i]>height[stack.top()]){
int low = stack.top();
stack.pop();
if(!stack.empty()){
int g = std::min(height[i],height[stack.top()])- height[low];
int width = i - stack.top()-1;
ans += g*width;
}
}
stack.push(i);
}
return ans;
}
};