每日温度
代码随想录 (programmercarl.com)
暴力求法
内外两层遍历数组,外层i表示返回的数组的下标,内层表示比当前i大的温度数组的下标。具体代码如下,会超时。
class Solution {
public:vector<int> dailyTemperatures(vector<int>& temperatures) {// 初始化一个和 temperatures 大小相同的向量 ans,所有值初始为0vector<int> ans(temperatures.size(), 0);// 遍历 temperatures 数组for (int i = 0; i < temperatures.size(); i++) {// 初始化 next 为0,用于记录需要等待的天数int next = 0;// 从当前元素之后开始遍历,寻找更高的温度for (int j = i + 1; j < temperatures.size(); j++) {// 每遍历一个元素,等待的天数加一next++;// 如果找到了一个更高的温度if (temperatures[j] > temperatures[i]) {// 将等待的天数赋值给 ans 在当前位置的元素ans[i] = next;// 找到了更高的温度,跳出内层循环break;}}}// 返回计算出的等待天数数组return ans;}
};
算法时间复杂度为O(n^2),空间复杂度为O(n)。
单调栈
想要更好了解单调栈,可以考虑看看下面的博客
算法数据结构——关于单调栈(Monotone Stack)的详细讲解及应用案例-CSDN博客
关于本题的单调栈解法
单调栈,你该了解的,这里都讲了!LeetCode:739.每日温度_哔哩哔哩_bilibili
单调栈记录遍历过的元素的下标
建议从左到右遍历元素
查找比当前元素大的元素使用单调递增栈,查找比当前元素小的元素使用单调递减栈
从左侧查找看插入栈的栈顶元素,从右侧查找就看弹出栈时即将插入的元素。
本题查找下一个更大的元素,使用单调递增栈,创建一个ans数组。遍历数组元素时,比较栈顶索引和当前数组遍历索引的大小,若当前栈顶索引在数组中元素大于等于当前遍历的元素,将栈顶元素值i在ans数组中的值变为遍历的元素索引减去i.
ans[i] = current - i;
当栈非空时且栈顶索引的元素大于当前遍历元素时,继续,否则将当前遍历的索引下标current传入单调栈中。
当当前栈顶索引在数组中元素小于当前遍历的元素时,直接入栈即可。
具体代码如下。
class Solution {
public:// dailyTemperatures 函数计算每个温度之后更高温度需要等待的天数vector<int> dailyTemperatures(vector<int>& temperatures) {// 初始化一个栈,用于存储温度数组中的索引stack<int> stack;// 将第一个元素的索引推入栈中stack.push(0);// 初始化一个和 temperatures 大小相同的向量 ans,所有值初始为0vector<int> ans(temperatures.size(), 0);// 遍历 temperatures 数组,从索引1开始for (int i = 1; i < temperatures.size(); i++) {// 如果当前温度小于等于栈顶索引对应的温度if (temperatures[i] <= temperatures[stack.top()]) {// 将当前索引推入栈中stack.push(i);} else if (temperatures[i] > temperatures[stack.top()] && !stack.empty()) {// 如果当前温度大于栈顶索引对应的温度,且栈不为空// 循环直到栈为空或者当前温度不再大于栈顶索引对应的温度while (!stack.empty() && temperatures[i] > temperatures[stack.top()]) {// 弹出栈顶元素int pop = stack.top();// 计算等待天数,并赋值给 ans 在栈顶索引位置的元素ans[pop] = i - pop;// 弹出栈顶元素stack.pop();}// 将当前索引推入栈中stack.push(i);}}// 返回计算出的等待天数数组return ans;}
};
算法的时间复杂度和空间复杂度均为O(n)。
下一个更大元素I
496. 下一个更大元素 I - 力扣(LeetCode)
本题和上题类似,注意两点,一是求的下一个大于当前元素的元素,二考虑到元素各不相同且为了便于查找,考虑使用哈希表。具体代码如下。
class Solution {
public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {// 初始化一个哈希表,用于存储nums2中每个元素的下一个更大元素unordered_map<int, int> hashmap;// 初始化一个和 nums1 大小相同的向量 ans,所有值初始为-1vector<int> ans(nums1.size(), -1);// 初始化一个栈,用于存储nums2的索引stack<int> stack;stack.push(0);// 遍历 nums2 数组for (int i = 0; i < nums2.size(); i++) {// 如果当前元素小于等于栈顶索引对应的元素if (nums2[i] <= nums2[stack.top()]) {// 将当前索引推入栈中stack.push(i);} else {// 如果当前元素大于栈顶索引对应的元素while (!stack.empty() && nums2[i] > nums2[stack.top()]) {// 弹出栈顶元素int pop = stack.top();// 将当前元素作为栈顶元素的下一个更大元素存储在哈希表中hashmap[nums2[pop]] = nums2[i];// 弹出栈顶元素stack.pop();}// 将当前索引推入栈中stack.push(i);}}// 清空栈,将剩余元素的下一个更大元素设置为-1while (!stack.empty()) {int pop = stack.top();hashmap[nums2[pop]] = -1;stack.pop();}// 遍历 nums1 数组,根据哈希表构建答案for (int i = 0; i < nums1.size(); i++) {ans[i] = hashmap[nums1[i]];}// 返回计算出的下一个更大元素的数组return ans;}
};
算法的时间复杂度为O(m+n),m、n分别为两个数组的长度,空间复杂度为O(m+n),组成分别为哈希表n、ans数组m和栈n。
下一个更大元素II
. - 力扣(LeetCode)
和第一题思路类似,但由于是可以循环查找,有三个点需要注意,
首先是遍历数组从0-2*nums.size()-1,其次对下标采取取模的操作进行栈的插入等操作,最后是本题求的是下一个大于当前元素的元素,所以不是ans数组中的不是下标,而是元素。
class Solution {
public:// nextGreaterElements 函数找到每个元素右边第一个比它大的元素vector<int> nextGreaterElements(vector<int>& nums) {// 获取数组的大小int n = nums.size();// 初始化一个和 nums 大小相同的向量 ans,所有值初始为-1vector<int> ans(nums.size(), -1);// 初始化一个栈,用于存储数组索引stack<int> st;// 将0推入栈中st.push(0);// 遍历 nums 数组,循环两次数组长度减一,模拟循环数组for (int i = 1; i < 2 * nums.size() - 1; i++) {// 计算循环数组的索引int index = i % n;// 如果当前元素小于等于栈顶索引对应的元素if (nums[index] <= nums[st.top()]) {// 将当前索引推入栈中st.push(index);} else {// 如果当前元素大于栈顶索引对应的元素while (!st.empty() && nums[index] > nums[st.top()]) {// 弹出栈顶元素int pop = st.top();// 将当前元素赋值给 ans 在栈顶索引位置的元素ans[pop] = nums[index];// 弹出栈顶元素st.pop();}// 将当前索引推入栈中st.push(index);}}// 返回计算出的下一个更大元素的数组return ans;}
};
算法的时间复杂度为O(n),空间复杂度也是O(n)。