文章目录
模版题1 纯模版
739. 每日温度
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
单调栈:用来寻找序列中一个元素左边/右边第一个比自身大/小的元素。
比如题目要寻找比自身大的第一个元素,栈底到顶由大到小。因为栈顶遇到一个 比自己大的元素就可以弹出,记录信息。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n=temperatures.size();
vector<int> res(n,0);
stack<int> s;
for(int i=0;i<n;i++){
if(s.empty()){
s.push(i);
continue;
}
if(temperatures[i]<=temperatures[s.top()]){
s.push(i);
}
else{
while(!s.empty()&&temperatures[i]>temperatures[s.top()]){
int k=s.top();
s.pop();
res[k]=i-k;
}
s.push(i);
}
}
return res;
}
};
496. 下一个更大元素 I
nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。
相比上一题多了个hash…
我的方法的大部分还是和上题保持一致,但是输出的时候要注意映射关系。
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size();
int m=nums2.size();
vector<int> t(m,-1);
vector<int> res(n,-1);
unordered_map<int,int> mp;
stack<int> s;
s.push(0);
for(int i=1;i<m;i++){
if(nums2[i]<=nums2[s.top()]){
s.push(i);
}
else{
while(!s.empty()&&nums2[i]>nums2[s.top()]){
// cout<<nums2[i]<<" "<<nums2[s.top()]<<endl;
t[s.top()]=i;
s.pop();
}
s.push(i);
}
}
for(int i=0;i<m;i++){
if(t[i]!=-1) mp[nums2[i]]=nums2[t[i]];
else mp[nums2[i]]=-1;
// cout<<nums2[i]<<t[i]<<endl;
}
for(int i=0;i<n;i++){
res[i]=mp[nums1[i]];
}
return res;
}
};
503. 下一个更大元素 II(循环数组 下标取模)
给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。
数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。
示例 1:
输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n=nums.size();
vector<int> res(n,-1);
stack<int> s;
s.push(0);
for(int i=1;i<2*n;i++){
if(nums[i%n]<=nums[s.top()]){
s.push(i%n);
}
else{
while(!s.empty()&&nums[i%n]>nums[s.top()]){
res[s.top()]=nums[i%n];
s.pop();
}
s.push(i%n);
}
}
return res;
}
};
模版题2 (找一个点两遍低的,两边高的)
42. 接雨水
法1:按列计算雨水
class Solution {
public:
int trap(vector<int>& height) {
//第一种方法,按列计算
int n=height.size();
vector<int> leftHeight(n,0);
vector<int> rightHeight(n,0);
int res=0;
for(int i=1;i<n;i++){
leftHeight[i]=max(leftHeight[i-1],height[i-1]);
}
for(int i=n-2;i>=0;i--){
rightHeight[i]=max(rightHeight[i+1],height[i+1]);
//cout<<rightHeight[i]<<" "<<endl;
}
for(int i=1;i<n-1;i++){
if(height[i]<leftHeight[i]&&height[i]<rightHeight[i]){
res+=min(leftHeight[i],rightHeight[i])-height[i];
}
}
return res;
}
};
法2:按行计算雨水(利用单调栈)
class Solution {
public:
int trap(vector<int>& height) {
int n=height.size();
stack<int> s;
int res=0;
s.push(0);
for(int i=1;i<n;i++){
if(height[i]<=height[s.top()]){
s.push(i);
}
else{
while(!s.empty()&&height[i]>height[s.top()]){
int mid=s.top();
s.pop();
if(!s.empty()){
int h=min(height[i],height[s.top()])-height[mid];
int w=i-s.top()-1;
res+=w*h;
}
}
s.push(i);
}
}
return res;
}
};
84. 柱状图中的最大矩形
关键在于找到三个变量:
mid=s.top()
s.pop()
left=s.top();
right=i;
然后计算要求的面积:w*h
注意:w,h是需要分析的点。
w=right-left-1
h=heigh[mid]
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
heights.insert(heights.begin(), 0); // 数组头部加入元素0
heights.push_back(0); // 数组尾部加入元素0
int n=heights.size();
int res=0;
stack<int> s;
s.push(0);
for(int i=1;i<n;i++){
if(heights[i]>=heights[s.top()]){
s.push(i);
}
else{
while(!s.empty()&&heights[i]<heights[s.top()]){
int mid=s.top();
s.pop();
if(!s.empty()){
int h=heights[mid];
int w=i-s.top()-1;
res=max(res,w*h);
}
}
s.push(i);
}
}
return res;
}
};