LC.42.接雨水
方法好多,学习到了。
1.对每个柱子向左向右暴力枚举最大柱子,然后取较小的作为贡献。时间复杂度,会
2.由1可以想到,预处理一下向左,向右的最大值,即预处理前缀最大值,和后缀最大值即可。时间复杂度:
class Solution {
public:
int trap(vector<int>& h) {
if(h.empty()) return 0;
int n=h.size();
vector<int>pre(n,0);
vector<int>suf(n,0);
pre[0]=h[0];
int ans=0;
for(int i=1;i<n;i++)
pre[i]=max(pre[i-1],h[i]);
suf[n-1]=h[n-1];
for(int j=n-2;j>=0;j--)
suf[j]=max(suf[j+1],h[j]);
for(int i=1;i<n-1;i++){
ans+=min(pre[i],suf[i])-h[i];
}
return ans;
}
};
3.用单调递减栈维护一个前缀,然后枚举每个可能作为装水柱的右端柱子,如果比栈顶矮直接入栈,否则计算贡献。时间复杂度:。
class Solution {
public:
int trap(vector<int>& h) {
stack<int>s;
int ans=0;
int n=h.size();
for(int i=0;i<n;i++){
while(!s.empty()&&h[s.top()]<=h[i]){
int pos=s.top();
s.pop();
if(s.empty()) break;
int hm=min(h[i],h[s.top()])-h[pos];
ans+=hm*(i-s.top()-1);
}
s.push(i);
}
return ans;
}
};
4.双指针法,官方解法很妙,这里不多讲了。
class Solution {
public:
int trap(vector<int>& h) {
int l=0,r=h.size()-1;
int lmx=0,rmx=0;
int ans=0;
while(l<=r){
if(h[l]<h[r]){
lmx<=h[l]?lmx=h[l]:ans+=lmx-h[l];
l++;
}
else {
rmx<=h[r]?rmx=h[r]:ans+=rmx-h[r];
r--;
}
}
return ans;
}
};
5.填补法。
向左扫的有效矩形面积+向右扫的矩形面积-柱子的面积-整个矩形的面积就是答案,可以画图看下。
class Solution {
public:
int trap(vector<int>& h) {
int s1=0,s2=0,sum=0;
int n=h.size();
int lmx=0,rmx=0;
for(int i=0;i<n;i++){
lmx=max(lmx,h[i]);
rmx=max(rmx,h[n-1-i]);
s1+=lmx,s2+=rmx;
sum+=h[i];
}
return s1+s2-sum-max(lmx,rmx)*n;
}
};