0
点赞
收藏
分享

微信扫一扫

Java 第 36 课 Next Greater Number



第 36 课

  • ★Next Greater Number



「栈」:「后进先出」 的线性数据结构,只对一端(栈顶)进行操作。

「单调栈」 栈内元素满足单调性的栈结构。分为单调递增与单调递减。

**「单调递增栈」**保持栈内元素单调递增,假设当前元素为 x ,若栈顶元素 ≤ x,则将 x 入栈,否则不断弹出栈顶元素,直至栈顶元素 ≤ x。
例 [3, 1, 4, 5, 2, 7] ,其「单调递增栈」入栈结束后,栈中仅保留了 [1, 2, 7],其中 3 比 1 大、4 与 5 比 2 大被弹出,「栈顶元素被弹出,当且仅当栈顶元素 > 当前元素」。

「栈中维护单调性的用途」
以 2 为当前元素,栈顶元素为 5,比 2 大,若将 2 放入栈内,则不满足单调递增,因此将 5 弹出。2 (当前) 和 5 (栈顶) 之间到底有什么更深层的关系呢?

栈顶元素的作用:1、需要后面的事情加以确认;2、为前面的事情提供依据。
2 是 5 右边第一个比 5 小的数。2 弹出 5 后,栈顶变为 4 ,此时 4 仍比 2 大,因此 4 也被弹出,这时可确定 2 是 4 右边第一个比它小的数。4 被弹出后,栈顶变为 1,1 ≤ 2,因此 2 被放入栈。

1 是 2 左边第一个小于等于它的数,当一个数字被放入单调递增栈时,其栈内左边的数是它在原始序列中,左边第一个小于等于它的数。

单调栈的本质在于「每一个数字在原始序列中左 / 右边第一个大于 / 小于它自身的数字」,并且由于每一个数字只会入栈一次且最多出栈一次,因此总的时间复杂度为 O(n)。

「单调递增栈」,我们在一遍扫描中求得每个数字左边第一个小于等于它的数,以及右边第一个小于它的数。另外,若想求得每个数字左边第一个小于它的数,则需要从右往左再扫描一遍数组。而对于「单调递减栈」,只需将上述的「小于」改为「大于」即可。
「单调栈」本质就是「在栈内维护元素单调性」,而其作用则为「O(n) 时间复杂度内求取每个数字在整个数组中左 / 右第一个大于 / 小于它的数」。

★Next Greater Number

给你一个数组,返回一个等长的数组,对应索引存储着下一个更大的元素,如果没有更大的元素,就存 -1。

例如:数组 [2, 1, 2, 4, 3],返回数组 [4, 2, 4, -1, -1]。对每一个元素从左向右看,第一个比他大的元素。

Java 第 36 课 Next Greater Number_数组


需要注意的关键点:

1、遍历顺序,正序先保存后处理,栈内是待处理元素,当前元素 是处理 栈顶元素 的依据,栈内保存的一般是下标。逆序即时处理当前元素,栈顶元素是依据,栈内保存的一般是元素。

2、是否是严格单调递增(递减)

3、保存的是元素还是下标

from typing import List
class Solution:
    def nextGreaterElement(self, nums: List[int]) -> List[int]:
        n, q = len(nums), []
        ans = [-1] * n # 初始化为 -1  

        for i, x in enumerate(nums): # 正序遍历 确定的是栈顶元素的状态
            while q and x > nums[q[-1]]: # x 是栈顶 top 右边第一个比 top大的数 
                ans[q.pop()] = x # 循环内处理栈内元素,栈内为非严格单调递减
            q.append(i)   # 下标  因为栈内元素需要下标确定 
            # print([nums[i] for i in q])
        
        # for i in range(n - 1, -1, -1): # 逆序遍历 确定的是当前元素的状态
        #     while q and q[-1] <= nums[i]: q.pop() # 维护严格单调递减栈
        #     if q: ans[i] = q[-1] # 栈顶元素为当前元素右边下一个更大的数
        #     q.append(nums[i]) # 元素
        #     # print(q)

        return ans
    
nums = [2, 1, 2, 4, 3]
s = Solution()
s.nextGreaterElement(nums)
# [4, 2, 4, -1, -1]

class Solution {
    public int[] nextGreaterElement(int[] nums) {
    	int n = nums.length;
		Deque<Integer> stack = new ArrayDeque<>();
		int[] ans = new int[n];
		for (int i = n - 1; i >= 0; i--){ // 逆序 维护单调递减栈
			while (!stack.isEmpty() && stack.peek() <= nums[i]){
				stack.pop();
			} 
			ans[i] = stack.isEmpty() ? -1 : stack.peek();
			stack.push(nums[i]);
		}
		return ans;
    }
}


举报

相关推荐

0 条评论