题目1:739 每日温度
题目链接:每日温度
对题目的理解
temperature[i]表示每天的温度,返回数组answer,answer[i]指对于第i天,下一个更高温度最近出现在几天后,如果气温在这之后都不会升高,用0来代替
暴力解法
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
vector<int> answer(temperatures.size(),0);
for(int i=0;i<temperatures.size();i++){
for(int j=i+1;j<temperatures.size();j++){
if(temperatures[j]>temperatures[i]){
answer[i]=j-i;
break;
}
}
}
return answer;
}
};
会报超时错误
单调栈
1)何时想到使用单调栈?
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了,时间复杂度为O(n)。
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
就是用一个栈来记录已经遍历过的元素
2)如何使用单调栈?
单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T[i]就可以获取。
只有递增的时候,栈里要加入一个元素i的时候,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i。
使用单调栈主要有三个判断条件。
- 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
- 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
- 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
整个流程
定义result数组的时候,就应该直接初始化为0,如果result没有更新,说明这个元素右面没有更大的了,也就是为0。
伪代码
代码
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
vector<int> result(temperatures.size(),0);
stack<int> st;
st.push(0);
for(int i=1;i<temperatures.size();i++){
if(temperatures[i]<temperatures[st.top()]) st.push(i);
else if(temperatures[i]==temperatures[st.top()]) st.push(i);
else {
while(!st.empty() && temperatures[i]>temperatures[st.top()]){
result[st.top()] = i-st.top();
st.pop();
}
st.push(i);
}
}
return result;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)
精简代码
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
vector<int> result(temperatures.size(),0);
stack<int> st;
st.push(0);
for(int i=1;i<temperatures.size();i++){
while(!st.empty() && temperatures[i]>temperatures[st.top()]){
result[st.top()]=i-st.top();
st.pop();
}
if(temperatures[i]<=temperatures[st.top()]) st.push(i);
}
return result;
}
};
上述代码会出现如下错误
原因是for循环中下面的if判断并没有限制st,若st可能出现空栈的情况
将代码改正如下:
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
vector<int> result(temperatures.size(),0);
stack<int> st;
st.push(0);
for(int i=1;i<temperatures.size();i++){
while(!st.empty() && temperatures[i]>temperatures[st.top()]){
result[st.top()]=i-st.top();
st.pop();
}
if(!st.empty() && temperatures[i]<=temperatures[st.top()]) st.push(i);
}
return result;
}
};
这个时候倒是不报执行错误了,又有新的错误产生了,案例错误
出现这种错误的原因是在while循环中,栈外元素大于栈顶元素的情况,在栈顶元素弹出之后并没有将新的元素放入堆栈,因此将代码修改如下
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
vector<int> result(temperatures.size(),0);
stack<int> st;
st.push(0);
for(int i=1;i<temperatures.size();i++){
while(!st.empty() && temperatures[i]>temperatures[st.top()]){
result[st.top()]=i-st.top();
st.pop();
st.push(i);
}
if(!st.empty() && temperatures[i]<=temperatures[st.top()]) st.push(i);
}
return result;
}
};
又有新的错误出现了
原因是while循环代表着,栈外元素一直比栈顶元素大,那么一直弹出栈顶元素,直到小于等于为止,这个过程不应该将栈外元素放入堆栈,将栈外元素放入堆栈的操作应在整个while循环都遍历完成后才进行,因此,可以将代码改为如下,因为栈外元素大于等于栈顶元素的时候,一定是要放入堆栈的,所以这两步操作可以合并起来,就是没有这个if限制条件了,只要不满足栈外元素大于栈顶元素了,就将栈外元素放入堆栈,这时代码才可以正常通过·
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
vector<int> result(temperatures.size(),0);
stack<int> st;
st.push(0);
for(int i=1;i<temperatures.size();i++){
while(!st.empty() && temperatures[i]>temperatures[st.top()]){
result[st.top()]=i-st.top();
st.pop();
}
st.push(i);
}
return result;
}
};
题目2:496 下一个更大元素Ⅰ
题目链接:下一个更大元素Ⅰ
对题目的理解
两个数组nums1和nums2无重复元素,nums1是nums2的子集,找满足nums1[i]==nums2[j]的下标j,(即在数组nums2中,找出与nums1中相同元素的下标),并在nums2确定nums2[j]的下一个更大元素,如果不存在,则返回1
nums1中x的下一个更大元素是指:x在nums2中对应位置右侧的第一个比x大的元素
nums1和nums2至少包含一个元素
常规思路
常规思路,求出nums1中的元素在nums2中相等的下标,然后根据这个下标数组遍历nums2进行查找,但是卡死了,一直报错误
代码(卡死了)
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> index(nums1.size(),0);
for(int i=0;i<nums1.size();i++){
for(int j=0;j<nums2.size();j++){
if(nums1[i]==nums2[j]) index.push_back(j);
}//使用index存储nums2中的下标4,7,8,9
}
vector<int> result(nums1.size(),-1);
stack<int> st;
for(int i=0;i<index.size();i++){
while(!st.empty() && nums2[index[i]]>nums2[st.top()]){
result[]=nums2[index[i]];
st.pop();
}
st.push(index[i]);
}
return result;
}
};
单调栈
注意题目中说是两个没有重复元素 的数组 nums1 和 nums2,没有重复元素,就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过,C++中,使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的
分析如下三种情况:
情况一:当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况,此时满足递增栈(栈头到栈底的顺序),所以直接入栈。
情况二:当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况,如果相等的话,依然直接入栈,求的是右边第一个比自己大的元素,而不是大于等于!
情况三:当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况,判断栈顶元素是否在nums1里出现过,(注意栈里的元素是nums2的元素),如果出现过,开始记录结果。
伪代码
代码(注意一定要是nums2[st.top()])
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> result(nums1.size(),-1);//初始化为-1
stack<int> st;
//定义一个哈希表,来映射nums1的元素与下标的关系
unordered_map<int,int> umap;
for(int i=0;i<nums1.size();i++){
umap[nums1[i]]=i;//元素 位置,后续nums2根据与nums1中相同的元素,找到该位置i,更新该处的数值
}
st.push(0);
for(int i=1;i<nums2.size();i++){
while(!st.empty() && nums2[i]>st.top()){//如果出现元素大于的情况
//如果这个元素在nums1中
if(umap.count(st.top())>0){
int index=umap[st.top()];//获取这个元素在的位置,最上面for循环的i
result[index]=nums2[i];
}
st.pop();
}
st.push(nums2[i]);
}
return result;
}
};
!!!注意st栈中放的是下标,是下标,是下标,重要的事情说三遍,使用的时候需要将该下标带入数组,,一定要是nums2[st.top()],将代码改为如下就OK
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> result(nums1.size(),-1);//初始化为-1
stack<int> st;
//定义一个哈希表,来映射nums1的元素与下标的关系
unordered_map<int,int> umap;
for(int i=0;i<nums1.size();i++){
umap[nums1[i]]=i;//元素 位置,后续nums2根据与nums1中相同的元素,找到该位置i,更新该处的数值
}
st.push(0);
for(int i=1;i<nums2.size();i++){
if(nums2[i]<nums2[st.top()]) st.push(i);
else if(nums2[i]==nums2[st.top()]) st.push(i);
else {
while(!st.empty() && nums2[i]>nums2[st.top()]){//如果出现元素大于的情况
//如果这个元素在nums1中
if(umap.count(nums2[st.top()])>0){
int index=umap[nums2[st.top()]];//获取这个元素在的位置,最上面for循环的i
result[index]=nums2[i];
}
st.pop();
}
st.push(i);
}
}
return result;
}
};
精简代码
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> result(nums1.size(),-1);//初始化为-1
stack<int> st;
//定义一个哈希表,来映射nums1的元素与下标的关系
unordered_map<int,int> umap;
for(int i=0;i<nums1.size();i++){
umap[nums1[i]]=i;//元素 位置,后续nums2根据与nums1中相同的元素,找到该位置i,更新该处的数值
}
st.push(0);
for(int i=1;i<nums2.size();i++){
while(!st.empty() && nums2[i]>nums2[st.top()]){//如果出现元素大于的情况
//如果这个元素在nums1中
if(umap.count(nums2[st.top()])>0){
int index=umap[nums2[st.top()]];//获取这个元素在的位置,最上面for循环的i
result[index]=nums2[i];
}
st.pop();
}
st.push(i);
}
return result;
}
};