LeetCode 503.下一个更大元素 Ⅱ

题目

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

1
2
3
4
5
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

思路

我的解法

每个元素都要找到下一个更大元素,故需要一层循环对每个元素都进行遍历。若当前的位置为i,之后从下一个数i+1开始,如果找到了更大的元素,将其赋值到结果数组中,进行下一个寻找;此时分为两种情况:(1)到数组结尾前找到了;(2)到数组结尾未找到则需要回到数组开头再进行寻找,找到i的前一个即可。其中如果未找到需要赋值-1,这个可以初始化的时候就赋好值,之后操作的时候了就该值,找不到不变即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> res(n, -1);
for(int i = 0; i < n; i++)
{
int j = -1;
for(j = i; j < n; j++)
{
if (nums[i] < nums[j])
{
res[i] = nums[j];
break;
}
}
if (j == n)
{
for(j = 0; j < i; j++)
{
if (nums[i] < nums[j])
{
res[i] = nums[j];
break;
}
}
}
}
return res;
}
};

官方解法

方法一:单调栈 + 循环数组

思路及算法

我们可以使用单调栈解决本题。单调栈中保存的是下标,从栈底到栈顶的下标在数组 nums中对应的值是单调不升的。

每次我们移动到数组中的一个新的位置 i,我们就将当前单调栈中所有对应值小于 nums[i]的下标弹出单调栈,这些值的下一个更大元素即为 nums[i](证明很简单:如果有更靠前的更大元素,那么这些位置将被提前弹出栈)。随后我们将位置 i入栈。

但是注意到只遍历一次序列是不够的,例如序列 [ 2, 3, 1 ],最后单调栈中将剩余 [ 3, 1 ],其中元素 [ 1 ]的下一个更大元素还是不知道的。

一个朴素的思想是,我们可以把这个循环数组「拉直」,即复制该序列的前n−1个元素拼接在原序列的后面。这样我们就可以将这个新序列当作普通序列,用上文的方法来处理。

而在本题中,我们不需要显性地将该循环数组「拉直」,而只需要在处理时对下标取模即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> ret(n, -1);
stack<int> stk;
for (int i = 0; i < n * 2 - 1; i++) {
while (!stk.empty() && nums[stk.top()] < nums[i % n]) {
ret[stk.top()] = nums[i % n];
stk.pop();
}
stk.push(i % n);
}
return ret;
}
};

时间复杂度分析

时间复杂度: O(n),其中 n 是序列的长度。我们需要遍历该数组中每个元素最多 2 次,每个元素出栈与入栈的总次数也不超过 4 次。

空间复杂度: O(n),其中 n 是序列的长度。空间复杂度主要取决于栈的大小,栈的大小至多为 2n−1

关于单调栈

单调栈即满足单调性的栈结构,存放的元素有序。单调栈又分为单调递增栈与单调递减栈。

  • 单调递增栈:单调递增栈就是从栈底到栈顶数据是从大到小
  • 单调递减栈:单调递减栈就是从栈底到栈顶数据是从小到大

单调栈的插入 > 模拟实现一个递增单调栈:

现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。 * 10入栈时,栈为空,直接入栈,栈内元素为10。 * 3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。 * 7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。 * 4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。 * 12入栈时,栈顶元素4比12小,4出栈,此时栈顶元素为7,仍比12小,栈顶元素7继续出栈,此时栈顶元素为10,仍比12小,10出栈,此时栈为空,12入栈,栈内元素为12。

伪码描述:

1
2
3
4
insert x
while !sta.empty() && sta.top()<x
sta.pop()
sta.push(x)

使用

自然就是从栈顶读出来一个元素,该元素满足单调性的某一端。

参考文章: [数据结构]——单调栈 单调栈


LeetCode 503.下一个更大元素 Ⅱ
https://excelius.xyz/leetcode-503-下一个更大元素-ⅱ/
作者
Ther
发布于
2021年3月6日
许可协议