42. 接雨水
文章讲解:代码随想录
思路:
以
height = [4,2,0,3,2,5]为例
先求每根柱子左右边第一个高的
得到
5 3 3 5 5 -1
-1 4 2 4 3 -1
左右两边都不为-1才能接住水
初始化ans 为0
左右两边都不为-1的置为1
对于1 里边都能盛水
所盛水是 1的左右两边柱子的最小值 然后再减去1的柱子里边原本的高度
然后统计所有的水 j
cpp
class Solution {
public:
int trap(vector<int>& height) {
vector<int>right(height.size(),-1);
vector<int>left(height.size(),-1);
stack<int>st;
st.push(0);
for(int i=1;i<height.size();i++){ //右边第一个大的
while(!st.empty()&&height[i]>height[st.top()]){
right[st.top()]=height[i];
st.pop();
}
st.push(i);
}
stack<int>lst;
lst.push(height.size()-1);
for(int i=height.size()-2;i>=0;i--){ //左边第一个大
while(!lst.empty()&&height[i]>height[lst.top()]){
left[lst.top()]=height[i];
lst.pop();
}
lst.push(i);
}
vector<int>ans(height.size(),1);
for(int i=0;i<height.size();i++){ //能盛水的单位
if(left[i]==-1||right[i]==-1){
ans[i]=0;
}
}
for(int i=0;i<height.size();i++){
if(ans[i]){
int l=i-1; //能盛水的区间
int r;
for(int j=i;j<height.size();j++){
if(ans[j]==0){
r=j;
break;
}
}
int num=min(height[l],height[r]);
for(int j=l+1;j<r;j++){ //能盛水的区间每个柱子能接的水
ans[j]=num-height[j];
}
i=r-1;
}
}
int result=0;
for(auto &x:ans){
result+=x;
}
return result;
}
};
解法2:
暴力解:
需要优化
cpp
class Solution {
public:
int trap(vector<int>& height) {
//暴力解法 求每根柱子能盛的水
vector<int>lmax(height.size(),0);
vector<int>rmax(height.size(),0);
vector<int>ans(height.size(),0);
int n=height.size();
// 计算每个柱子左边最高的柱子
for (int i = 1; i < n; ++i) {
lmax[i] = max(lmax[i - 1], height[i - 1]);
}
// 计算每个柱子右边最高的柱子
for (int i = n - 2; i >= 0; --i) {
rmax[i] = max(rmax[i + 1], height[i + 1]);
}
for(int i=1;i<height.size()-1;i++){
ans[i]=min(lmax[i],rmax[i])-height[i];
}
int result=0;
for(auto &x:ans){
if(x>=0) result+=x;
}
return result;
}
};
方法三:
单调栈
cpp
class Solution {
public:
int trap(vector<int>& height) {
int result=0;
stack<int>st;
st.push(0);
for(int i=1;i<height.size();i++){
if(!st.empty()&&height[i]<height[st.top()]){
st.push(i);
}else if(!st.empty()&&height[i]==height[st.top()]){
st.push(i);
}else{
while(!st.empty()&&height[i]>height[st.top()]){
int mid=st.top();
st.pop();
if (st.empty()) break; // ✅ 必须加这个判断
int h=min(height[st.top()],height[i]);
int w=i-st.top()-1;//水量计算
result+=w*(h-height[mid]);
}
st.push(i); //这一句放在循环外
}
}
return result;
}
};
84.柱状图中最大的矩形
题目链接: 84. 柱状图中最大的矩形 - 力扣(LeetCode)
文章讲解: 代码随想录
思路:
考虑每个柱子的高度为高,然后计算最大的宽度,再计算面积。
比较上述面积的最大值
宽度的计算在于 寻找当前柱子左右两边第一个比它小的 l和r
那么w=r-l-1
cpp
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int size=heights.size();
vector<int>leftMin(heights.size(),-1); //左边第一个小的
vector<int>rightMin(heights.size(),size); //右边第一个小的
stack<int>lst;
stack<int>rst;
rst.push(0);
for(int i=1;i<size;i++){
while(!rst.empty()&&heights[i]<heights[rst.top()]){
rightMin[rst.top()]=i;
rst.pop();
}
rst.push(i);
}
lst.push(size-1);
for(int i=size-2;i>=0;i--){
while(!lst.empty()&&heights[i]<heights[lst.top()]){
leftMin[lst.top()]=i;
lst.pop();
}
lst.push(i);
}
int result=0;
for(int i=0;i<size;i++){
int r=rightMin[i];
int l=leftMin[i];
int w=r-l-1;
int area=w*heights[i];
result=max(result,area);
}
return result;
}
};