算法训练营day59_单调栈(3.24提前打)
503.下一个更大元素II
两个数组拼接到一起;(vector用insert插入,不能直接赋值,因为大小规定了,会越界,要是数组的话,提前开够了空间,不会越界)
从后往前走一遍单调栈;
class Solution {
public:
int stk[10010],top;
vector<int> nextGreaterElements(vector<int>& nums) {
memset(stk,0,sizeof stk);
top=0;
int n=nums.size();
vector<int> t(nums.begin(),nums.end());
nums.insert(nums.end(),t.begin(),t.end());
vector<int> ans(n,-1);
for(int i=n*2-1;i>=0;i--){
while(top&&nums[i]>=stk[top]) top--;
if(i<n){
if(top) ans[i]=stk[top];
}
stk[++top]=nums[i];
}
return ans;
}
};
42.接雨水
dp预处理
没用单调栈的思路,没想出来;
这道题就是对于每个柱子,找出左边最大的与右边最大的,取小值,再减去当前柱子高度就是当前柱子的贡献值;
需要注意的是,左边与右边都包括自己,这样的话就算找不到比自己大的,也会自己-自己,贡献值为0;
一个小dp预处理出来i左边最大值的数组,i右边最大的数组;然后直接遍历累加贡献值;
class Solution {
public:
int lh[20010],rh[20010];
int trap(vector<int>& height) {
memset(lh,0,sizeof lh);
memset(rh,0,sizeof rh);
int n=height.size();
for(int i=1;i<=n;i++){
lh[i]=max(height[i-1],lh[i-1]);
}
for(int i=n;i>=1;i--){
rh[i]=max(height[i-1],rh[i+1]);
}
int ans=0;
for(int i=0;i<n;i++){
ans+=min(lh[i+1],rh[i+1])-height[i];
}
return ans;
}
};
单调栈
凹槽才会存水,如果是连着递减,那么不会存水,遇到了一个大的,往前依次清算;所以用到了单调栈;
维护一个单调递减的单调栈,遇到一个大的,往前看;
当前栈顶是凹的部分,当前栈顶左边右边都比它大,计算(min(左右高度)-当前高度)*(距离),这个计算的就是当前高度上面能存的雨水;
与动归遍历一下子加一列不同,这里一下子加几排;
要注意的是,最后栈里只有一个元素的时候,就不能算了,因为它没有左边的,不是凹槽,存不了水;
class Solution {
public:
int stk[20010],cnt;
int trap(vector<int>& height) {
memset(stk,0,sizeof stk);
cnt=0;
int ans=0;
int n=height.size();
for(int i=0;i<n;i++){
while(cnt&&height[i]>height[stk[cnt]]){
int cur=stk[cnt];
cnt--;
if(!cnt) break;
int l=stk[cnt];
int h=min(height[l],height[i])-height[cur];
int k=(i-l-1);
ans+=h*k;
}
stk[++cnt]=i;
}
return ans;
}
};