每日温度
暴力求法
内外两层遍历数组,外层i表示返回的数组的下标,内层表示比当前i大的温度数组的下标。具体代码如下,会超时。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
// 初始化一个和 temperatures 大小相同的向量 ans,所有值初始为0
vector<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,所有值初始为0
vector<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
本题和上题类似,注意两点,一是求的下一个大于当前元素的元素,二考虑到元素各不相同且为了便于查找,考虑使用哈希表。具体代码如下。
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
// 初始化一个哈希表,用于存储nums2中每个元素的下一个更大元素
unordered_map<int, int> hashmap;
// 初始化一个和 nums1 大小相同的向量 ans,所有值初始为-1
vector<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);
}
}
// 清空栈,将剩余元素的下一个更大元素设置为-1
while (!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
和第一题思路类似,但由于是可以循环查找,有三个点需要注意,
首先是遍历数组从0-2*nums.size()-1,其次对下标采取取模的操作进行栈的插入等操作,最后是本题求的是下一个大于当前元素的元素,所以不是ans数组中的不是下标,而是元素。
class Solution {
public:
// nextGreaterElements 函数找到每个元素右边第一个比它大的元素
vector<int> nextGreaterElements(vector<int>& nums) {
// 获取数组的大小
int n = nums.size();
// 初始化一个和 nums 大小相同的向量 ans,所有值初始为-1
vector<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)。