目录
1. LeetCode739. 每日温度
2. LeetCode496. 下一个更大元素 I
3. LeetCode503. 下一个更大元素 II
4. LeetCode42. 接雨水
5. LeetCode84. 柱状图中最大的矩形
在一维数组中,要寻找任一元素的右边或者左边第一个自己大或小的元素的位置,就可以想到用单调栈了。——代码随想录
思路:
1.创建辅助栈stk和结果数组answer
2.遍历温度数组,把第i天的温度temperatures[i]入栈,栈顶到栈底单调递减
3.如果当前温度大于栈顶温度,则不断出栈,并把相隔天数(i-stk.top())写入到结果集中class Solution {
public:vector dailyTemperatures(vector& temperatures) {//结果集,因为对于后续没有温度更高的,结果是0,所以默认都为0vectoranswer(temperatures.size());//辅助栈stackstk;//遍历数组for(int i=0;itemperatures[stk.top()]){answer[stk.top()]=i-stk.top();stk.pop();}stk.push(i);//存入下标,既能知道天数,又可以知道温度}return answer;}
};时间复杂度:O(n),对于每个温度数组的元素下标,只有入栈和出栈各一次操作;
空间复杂度:O(n),需要维护一个辅助栈
思路:
1.创建辅助栈stk,结果集ans,映射表存储nums1中各元素和下标的对应
2.初始化结果集为-1
3.建立好nums1的映射关系
4.遍历nums2,找到nums1中的元素在nums2右边第一个比自己大的值,放入结果集中卡点:因为nums1和nums2是元素方面的联系,所以可以通过哈希表来找到当前遍历元素在nums1中的对应下标class Solution {
public:vector nextGreaterElement(vector& nums1, vector& nums2) {//结果集,默认-1vectorans(nums1.size(),-1);//辅助栈stackstk;//栈底到栈顶:单调递减//映射表unordered_maprecorded;//建立映射关系for(int i=0;inums2[stk.top()]){if(recorded.count(nums2[stk.top()])>0){ans[recorded[nums2[stk.top()]]]=nums2[i];}stk.pop();}stk.push(i);}return ans;}
};
class Solution {
public:vector nextGreaterElements(vector& nums) {vectorans(nums.size(),-1);//结果集,默认-1stackstk;//辅助栈,栈底到栈顶:单调递减//当第二次遍历到最大值时,就可以结束循环了//第一次遍历到最大值:后面的元素还没遍历到,需要继续处理//第二次遍历到最大值时,最坏情况下,后面的所有元素右边比自己更大的数刚好就是最大值//由于所有位置的元素都有可能是最大值,所以把所有元素都遍历两次,nums的所有元素肯定都处理好了for(int i=0;inums[stk.top()]){ans[stk.top()]=nums[i%nums.size()];stk.pop();}stk.push(i%nums.size());}return ans;}
};
1.双指针:按列计算雨水面积
当前列的雨水面积=min(左边最大高度,右边最大高度)-当前列高度,因为宽度默认是1,取最小值是由于短板效应
因为我们只需要每一列柱子左边和右边的高度的最小值,所以可以用maxLeft和maxRight来记录,这样就避免了重复计算左右两边最大高度的操作
class Solution {
public:int trap(vector& height) {int res=0;//结果vectormaxLeft(height.size());//左边最大高度vectormaxRight(height.size());//右边最大高度//动态规划maxLeft[0]=height[0];for(int i=1;i=0;i--){maxRight[i]=max(maxRight[i+1],height[i]);}//计算雨水面积for(int i=1;i& height) {stackstk;//辅助栈int res=0;//结果stk.push(0);//先让0入栈,因为已进入循环就要和stk.top()比较,所以先让0入栈for(int i=1;iheight[stk.top()]){int mid=stk.top();stk.pop();if(!stk.empty()){int h=min(height[stk.top()],height[i])-height[mid];int w=i-stk.top()-1;res+=h*w;}}stk.push(i);}}return res;}
};简化代码:
等于和小于的操作类似,而等于的更新栈顶元素不影响计算。如果栈顶和栈顶的下一个元素相同,则在大于的操作中h=0,不影响结果。等到栈顶下一个相等高度的柱子做凹槽底部时,h是正常的,w也不受影响,因为w只和stk.top()有关,和弹出的柱子无关
class Solution {
public:int trap(vector& height) {stackstk;//辅助栈int res=0;//结果stk.push(0);for(int i=1;iheight[stk.top()]){int mid=stk.top();stk.pop();if(!stk.empty()){int h=min(height[stk.top()],height[i])-height[mid];int w=i-stk.top()-1;res+=h*w;}}stk.push(i);}return res;}
};卡点:没有考虑凹槽底部柱子高度,导致计算了很多多余的面积
1.双指针:
leftFirst[i]:0~i-1第一个比柱子i低的下标
rightFirst[i]:i+1~height.size()-1第一个比i低的下标
把leftFirst[0]初始化为-1,把rightFirst初始化为height.size(),能够最低的柱子计算出正确的矩形class Solution {
public:int largestRectangleArea(vector& heights) {int res=0;vectorleftFirst(heights.size());vectorrightFirst(heights.size());leftFirst[0]=-1;for(int i=1;i=0&&heights[i]<=heights[t])t=leftFirst[t];leftFirst[i]=t; }rightFirst[heights.size()-1]=heights.size();for(int i=heights.size()-2;i>=0;i--){int t=i+1;while(theight[stk.top()]:入栈
height[i]==height[stk.top()]:更新栈顶
height[i]& heights) {stackstk;int res=0;heights.insert(heights.begin(),0);heights.push_back(0);stk.push(0);for(int i=1;iheights[stk.top()])stk.push(i);else if(heights[i]==heights[stk.top()])stk.top()=i;else{while(!stk.empty()&&heights[i]& heights) {stackstk;int res=0;heights.insert(heights.begin(),0);heights.push_back(0);stk.push(0);for(int i=1;i