503. 下一个更大元素 II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
题目的两个重点:如何求下一个更大的元素和如何实现循环数组
思路:
就是入栈前先排个序。如果当前元素比栈顶元素小,正常入栈。如果当前元素比栈顶元素大,那么关键点就来了,说明当前元素至少是栈顶元素的下一个更大元素,将栈顶元素出栈,当前元素再和接下来的栈顶元素比较,小->入栈,大->继续栈顶出栈,出栈的这些就算是找到下一个更大元素了,更新即可。这个单调栈保存的其实是数组下标。
单调栈
单调栈是说栈里面的元素从栈底到栈顶是单调递增或者单调递减的(类似于汉诺塔)。
本题应该用「单调递减栈」来实现。单调栈中保存的是下标,从栈底到栈顶的下标在数组nums 中对应的值是单调不升的。
对于「找最近一个比当前值大/小」的问题,都可以使用单调栈来解决。
求下一个更大的元素
实现循环数组
循环数组?就是说数组的最后一个元素的下一个元素是数组的第一个元素,形状类似于「环」。
一种实现方式是,把数组复制一份到数组末尾,这样虽然不是严格的循环数组,但是对于本题已经足够了,因为本题对数组最多遍历两次。
另一个常见的实现方式是,使用取模运算可以把下标 i 映射到数组 nums 长度的 0 −N 内
代码
栈里面需要保存元素在数组中的下标,而不是具体的数字。因为需要根据下标修改结果数组 res。
class Solution(object):
def nextGreaterElements(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
N = len(nums)
res = [-1] * N
stack = []
for i in range(N * 2):
while stack and nums[stack[-1]] < nums[i % N]:
res[stack.pop()] = nums[i % N]
stack.append(i % N)
return res
另一种:
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
N=len(nums)
mnt_stack=[] # 存储未更新的下标
res=[-1]*N # 存储结果
for i in range(2*N-1):
while len(mnt_stack)>0 and nums[i%N]>nums[mnt_stack[-1]%N]:
res[(mnt_stack.pop(-1))%N]=nums[i%N]
mnt_stack.append(i) #把当前最大元素对应索引入栈
return res
注意:
循环两次:因为是根据更大元素这个“结论”反推前面更小元素的赋值,第一次循环中的元素要在第二次循环中才能寻找完一遍数组,做到“首尾相顾”。