962. 最大宽度坡

Difficulty
Medium
Tags
单调栈
前缀和
Star
给定一个整数数组 A是元组 (i, j),其中 i < jA[i] <= A[j]。这样的坡的宽度为 j - i
找出 A 中的坡的最大宽度,如果不存在,返回 0 。
示例 1:
输入:[6,0,8,2,1,5] 输出:4 解释: 最大宽度的坡为 (i, j) = (1, 5): A[1] = 0 且 A[5] = 5.
示例 2:
输入:[9,8,1,0,1,9,4,0,4,1] 输出:7 解释: 最大宽度的坡为 (i, j) = (2, 9): A[2] = 1 且 A[9] = 1.
提示:
  1. 2 <= A.length <= 50000
  1. 0 <= A[i] <= 50000
通过次数15,673提交次数34,873

法1 单调栈

思路
首先正序遍历数组 A,将以 A[0] 开始的递减序列的元素下标依次存入栈中。
为什么要存从 A[0] 开始的递减序列呢? 因为题中条件 A[i] <= A[j],所以要让 A[i] 的值尽可能的小,即从 A[0] 开始的一个递减序列。单调栈中记录的是从后往前每个大分段 “坡底” 所在的位置。
[6, 1, 8, 2, 0, 5] 为例,由于 (6, 1, 0) 是递减的,所以栈中存的元素应该为:(栈顶 -> (4, 1, 0) <- 栈底)。
其中 [2, 0, 5] 也是一个满足条件的坡并且宽度为 2,但是为什么在计算的时候没有算它呢? 因为该数组从 A[0] 开始的递减序列为 (6, 1, 0) 并没有元素 2,是因为在元素 2 的左边有比它还要小的元素 1。当计算最大宽度坡时 12 相比,不管是元素值还是元素的下标都更小,所以若以 2 为坡底能计算出某一坡的宽度时同样的以 1 为坡底也能计算出相应的坡的宽度并且宽度更大,所以就不需要计算以 2 为坡底的坡的宽度了。
此时栈 stack:(4(0), 1(1), 0(6)):然后逆序遍历数组 A,若以栈顶元素为下标的元素值 A[stack.peek()] 小于等于当前遍历的元素 A[i],即 A[stack.peek()] <= A[i]。此时就是一个满足条件的坡的宽度,并且这个宽度一定是栈顶这个坡底 i 能形成的最大宽度,将栈顶元素出栈并计算当前坡的宽度,保留最大值即可。
为什么找到一个右端点 j 之后,可以不断的将满足条件的栈顶元素弹出来呢? 因为我们的j是是从右向左遍历的,此时的宽度已经是i能匹配到的最大宽度了!也就是说,i的价值已经发挥了最大了。
题解
class Solution: def maxWidthRamp(self, nums: List[int]) -> int: if len(nums) <= 1: return len(num) # 保存 递减元素的下标 stack = [] for i in range(0, len(nums)): while len(stack) == 0 or nums[i] < nums[stack[-1]]: stack.append(i) res = 0 for i in range(len(nums)-1, -1, -1): while stack and nums[i] >= nums[stack[-1]]: res = max(res, i - stack[-1]) stack.pop() return res