一、题目
二、分析
1、 暴力破解就不解释了
2 、单调栈:把循环数复制一份:
[2, 1, 3] -> [2, 1, 3, 2, 1]
n -> 2n-1
就变成了为 [2, 1, 3, 2, 1] 这个有重复数值的,非循环数组找下一个更大元素的问题。找完之后,只要截断n以后的数据即可。
那么新问题就是:有重复数据的数组,为其寻找下一个更大元素。
旧题变新题,你说神奇不神奇?
思路仍然是单调栈的思路,只不过,栈内要记录下标和数值的 pair。所以在此我选择使用 vector 代替之前的 unordered_map
。
3、官网解答:当然了,细心的朋友可能已经看出来了,记录下标,通过 nums 自然就能得到 nums[i]。这也就是官方解答。单调栈中存放数组下标。这个方法对于有重复数字的数组是通用的。此做法就是上述第二种做法的简化版,降低了存储开销,还省去了最后的拷贝过程,降低了时间开销。
三、代码
- 暴力
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> res;
bool isfound = false;
for(int i = 0, j = 0; i < nums.size(); i++){
isfound = false;
for(j = (i == nums.size()-1) ? 0 : i+1;
j != i; j = (j==nums.size()-1) ? 0 : j+1)
{ // 注意 j 的变化即可
if(nums[j] > nums[i]){
res.push_back(nums[j]);
isfound = true;
break;
}
}
if(!isfound) res.push_back(-1);
}
return res;
}
};
执行用时: 432 ms, 在所有 C++ 提交中击败了6.83%的用户
内存消耗: 22.9 MB, 在所有 C++ 提交中击败了41.18%的用户
- 单调栈
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n(nums.size());
if(n == 0) return vector<int>();
vector<pair<int, int>> numtwo(2*n-1);
stack<pair<int, int>> s2;
//栈不仅记录了数组值,还记录了下标,目的是存结果的 vector 中按 nums 下标有序存放。
s2.push(make_pair(0, nums[0]));
for (int i = 1; i < 2 * n - 1; i++)
{
// 虽然说是数组扩展到 2n-1,但是实际取数组值的时候,采用 i % n。
while (!s2.empty() && s2.top().second < nums[i % n])
{
// 栈中 pair 的 first 值为nums中的下标,second为此下标的数组值。
numtwo[s2.top().first] = make_pair(s2.top().second, nums[i % n]);
s2.pop();
}
s2.push(make_pair(i,nums[i % n]));
}
// 处理那些没有解的元素
while (!s2.empty())
{
numtwo[s2.top().first] = make_pair(s2.top().second, -1);
s2.pop();
}
vector<int> res;
// 拷贝到结果中,截断到n
for(int i = 0; i < n; i ++){
res.push_back(numtwo[i].second);
}
return res;
}
};
执行用时:48 ms, 在所有 C++ 提交中击败了64.89%的用户
内存消耗:25.2 MB, 在所有 C++ 提交中击败了5.04%的用户
- 官网的复现
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n(nums.size());
// if(n == 0) return vector<int>(); //不加这一句就40ms了!!!!!????
vector<int> numtwo(n,-1);
stack<int> s2;
for (int i = 0; i < 2 * n - 1; i++)
{
while (!s2.empty() && nums[s2.top()] < nums[i % n])
{
numtwo[s2.top()] = nums[i % n];
s2.pop();
}
s2.push(i % n);
}
return numtwo;
}
};
执行用时:40 ms, 在所有 C++ 提交中击败了81.25%的用户
内存消耗:22.4 MB, 在所有 C++ 提交中击败了90.86%的用户