C++ day58 每日温度 下一个更大元素

2023-12-08 06:45

本文主要是介绍C++ day58 每日温度 下一个更大元素,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目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);//初始化为-1stack<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循环的iresult[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);//初始化为-1stack<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循环的iresult[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);//初始化为-1stack<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循环的iresult[index]=nums2[i];}st.pop();}st.push(i);}return result;}
};

这篇关于C++ day58 每日温度 下一个更大元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/468912

相关文章

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

详解C++中类的大小决定因数

《详解C++中类的大小决定因数》类的大小受多个因素影响,主要包括成员变量、对齐方式、继承关系、虚函数表等,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 非静态数据成员示例:2. 数据对齐(Padding)示例:3. 虚函数(vtable 指针)示例:4. 继承普通继承虚继承5.

C++中std::distance使用方法示例

《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示