学习资料:代码随想录
42. 接雨水
暴力解法超时了,直接从双指针开始
双指大概思路为创立两个数组记录两侧的最大值,这里的最大值是真正的最大的值,而不是最近的那个比较大的值,即所谓的按列计算,后面单调栈方法找到的是上一个较大值和下一个较大值,是所谓的按行计算,这样这个凹槽可能身处更大的凹槽中,所以每次都要乘一个宽度,类似与按层往上摞
class Solution {
public:
int trap(vector<int>& height) {
vector<int> Rightmax(height.size(),0); //牺牲一点空间复杂度换时间复杂度
vector<int> Leftmax(height.size(),0);
int size=height.size();
Leftmax[0]=height[0];
Rightmax[size-1]=height[size-1];
for(int i=1;i<size;i++){
Leftmax[i]=max(Leftmax[i-1],height[i]);
}
for(int j=size-2;j>=0;j--){
Rightmax[j]=max(Rightmax[j+1],height[j]);
}
int sum = 0;
for(int i=1;i<size-1;i++){
int capacity=min(Leftmax[i],Rightmax[i])-height[i];
if(capacity>0) sum+=capacity;
}
return sum;
}
};
单调栈:遇到比栈顶小的值和等于的值就入栈,相当于等待那个大的出现,如次栈顶的下一个下标对应的值比它大,再遇到大的,正好栈顶元素的两边会比其大
要注意警惕对栈非空的判断,否则超时很难排查
class Solution {
public:
int trap(vector<int>& height) {
stack<int> st;
st.push(0);
int sum = 0;
for(int i=1;i<height.size();i++){
if(height[i]<height[st.top()]){
st.push(i);
}
else if(height[i]==height[st.top()]){
st.push(i);
}
else{
while(!st.empty()&&height[i]>height[st.top()]){
int cur = st.top();
st.pop();
if(!st.empty()){ //这里还要检查一下防止访问空
int h =min(height[i],height[st.top()])-height[cur];
int w=i-st.top()-1;
int capacity = h*w;
sum+=capacity;
}
}
st.push(i);
}
}
return sum;
}
};
84.柱状图中最大的矩形
先看单调栈的方法:首先要理解求这个面积的方法是当前的值为高,宽为左边比其小到右边比其小的这个距离,高乘宽为能勾勒的最大矩形的面积
这次是找两边的小值,逻辑上是接雨水变一下操作逻辑,当前大于等于栈顶的情况入栈,等那个小的,这样栈顶两侧都比其小
尾加一个0是为了数组最后是升序的情况下,让数组到最后能找到那个小的,进行计算逻辑。最后这个0会被放在栈里,不会影响结果
开头加一个0是为了在数组降序的情况下,能找到那个小的,能进行正常的计算逻辑
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int> st;
st.push(0);
heights.insert(heights.begin(),0);
heights.insert(heights.end(),0);
int result =0;
for(int i=1;i<heights.size();i++){
if(heights[i]>heights[st.top()]){ //找的是比栈中元素小的
st.push(i);
}
else if(heights[i]==heights[st.top()]){
st.push(i);
}
else{
while(!st.empty()&&heights[i]<heights[st.top()]){
int cur = st.top();
st.pop();
if(!st.empty()){
int left = st.top();
int right = i;
int h=heights[cur];
int width = i-st.top()-1;
result = max(result,h*width);
}
}
st.push(i);
}
}
return result;
}
};
这次双指针也是记录的下标了,而且和上一题不同的一个地方是,不是找两侧的最小的,而是找到第一个比其小的就停
// leftMinIndex[i]表示i处左边的较小高度柱子的高度的下标
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
vector<int> leftMinIndex(heights.size());
vector<int> rightMinIndex(heights.size());
int result =0;
leftMinIndex[0] = -1; //初始化防止死循环
for(int i=1;i<heights.size();i++){
int t=i-1;
while(t>=0&&heights[t]>=heights[i]){
t=leftMinIndex[t]; //有回溯的感觉了
}
leftMinIndex[i]=t;
}
rightMinIndex[heights.size()-1] = heights.size(); //初始化防止死循环
for(int j=heights.size()-2;j>=0;j--){
int t=j+1;
while(t<heights.size()&&heights[t]>=heights[j]){
t=rightMinIndex[t];
}
rightMinIndex[j]=t;
}
for(int i=0;i<heights.size();i++){
int area = heights[i]*(rightMinIndex[i]-leftMinIndex[i]-1);
result=max(area,result);
}
return result;
}
};