n =len(A)next_higher, next_lower = [-1] * n, [-1] * nstack = []for i, a inenumerate(A):while stack and A[stack[-1]]<= A[i]: next_higher[stack.pop()]= i stack.append(i)stack = []for i, a inenumerate(A):while stack and A[stack[-1]]>= A[i]: next_lower[stack.pop()]= i stack.append(i)
可是我们需要求的是下一个最小的比其大(或等于)呀。一种简单的方法是先对 A 进行排序再使用单调栈。比如我们进行升序排序,接下来只要遍历一次排好序的数组,同时结合单调栈即可。 由于已经进行了排序,因此后面的数一定是不小于前面的数的,且对于任意相邻的数 a 和 b,a 的最小的大于等于它本身的数就是 b,前提是 a 和 b 对应排序之前的索引 i 和 j 满足 i < j。这提示我们排序的时候需要额外记录原始索引。
代码:
A =sorted([a, i] for i, a inenumerate(A))
这里有 1 个细节。即排序的时候如何处理相等情况,比如 a 和 b 相等,是保持之前的相对顺序还是逆序还是都可以?实际上,我们想希望的是保持之前的相对顺序,这样才不会错过相等的情况的解。因此我这里排序的是时候是以 [a, i] 形式保存的数据。
由于除了要处理跳高,我们仍然需要处理跳低。而最关键的是跳低也需要我们在 a 和 b 相等的情况下,保持之前的相对顺序。 因此就不能通过简单的排序一次处理。比如我们不能这么干:
classSolution:defoddEvenJumps(self,A): n =len(A) next_higher, next_lower = [0] * n, [0] * n A =sorted([a, i] for i, a inenumerate(A)) stack = []for _, i in A:# it means stack[-1]'s next bigger(or equal) is iwhile stack and stack[-1]< i: next_higher[stack.pop()]= i stack.append(i) stack = []for _, i in A[::-1]:# it means stack[-1]'s next smaller(or equal) is iwhile stack and stack[-1]< i: next_lower[stack.pop()]= i stack.append(i)# ...
解决这个问题的方法最简单的莫过于使用两次排序,具体见下方代码区。
现在已经有了两个数组,这两个数组可以帮助我们
快速找到下一个最小的比其大(或等于)的数。(奇数跳)
快速找到下一个最大的比其小(或等于)的数。(偶数跳)
数据已经预处理完毕。接下来,只需要从结果倒推即可。这提示我们从后往前遍历。
算法:
使用前面的方法预处理出 next_higher 和 next_lower
使用两个数组 higher 和 lower。higher[i] 表示是否可从 i 开始通过跳高的方式奇偶跳到达数组最后一项,lower 也是类似。
从后往前倒推遍历。如果 lower[next_higher[i]] 为 true 说明 i 是可以通过跳高的方式奇偶跳到达数组最后一项的。higher[next_lower[i]] 也是类似。
最后返回 higher 中 为 true 的个数。
代码
代码支持: Python3
Python Code:
classSolution:defoddEvenJumps(self,A): n =len(A) next_higher, next_lower = [0] * n, [0] * n stack = []for _, i insorted([a, i] for i, a inenumerate(A)):# it means stack[-1]'s next bigger(or equal) is iwhile stack and stack[-1]< i: next_higher[stack.pop()]= i stack.append(i) stack = []for _, i insorted([-a, i] for i, a inenumerate(A)):# it means stack[-1]'s next smaller(or equal) is iwhile stack and stack[-1]< i: next_lower[stack.pop()]= i stack.append(i) higher, lower = [False] * n, [False] * n higher[-1]= lower[-1]=True ans =1for i inrange(n -2, -1, -1): higher[i]= lower[next_higher[i]] lower[i]= higher[next_lower[i]] ans += higher[i]return ans
复杂度分析
令 N 为数组 A 的长度。
时间复杂度:$O(NlogN)$
空间复杂度:$O(N)$
有的同学好奇为什么不考虑 lower。类似:
ans =1for i inrange(n -2, -1, -1): higher[i]= lower[next_higher[i]] lower[i]= higher[next_lower[i]] ans += higher[i]or lower[i]return ans