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

相关文章

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元