Solution1: Mono Stack + Binary Search
class Solution:
def maxWidthRamp(self, A: List[int]) -> int:
""" tc O(NlgN) sc O(1)
1. build decreasing mono stack :
(1)if current val is smaller than stack top || stack is empty, push into stack
(2) otherwise, for current value A[j], find the first number that smaller than A[j]
(3) update result
3. return res after loop ends
note, why we build strictly decresing instead of non-increasing? we want to get max diff so if value is the same, we only keep the one appears first
"""
res = 0
n = len(A)
st = []
for j in range(n):
if not st or st[-1][0] > A[j]:
st.append([A[j],j])
else:
left, right = 0, len(st)
while left < right:
mid = left + (right-left)//2
if st[mid][0] > A[j]:
left = mid + 1
else:
right = mid
i = st[left][1]
res = max(res,j-i)
return res
############################################or #####################
res = 0
n = len(A)
st = []
for i in range(n)[::-1]: # range(n-1,-1,-1)
if not st or st[-1][0] < A[i]: # from end to start to get a mono increasing stack, cache index so its index is not changed
st.append([A[i],i])
else:
j = st[bisect.bisect(st,[A[i],i])][1]
res = max(res,j-i)
return res
Optimization Solution2: Mono Stack
class Solution:
def maxWidthRamp(self, A: List[int]) -> int:
""" tc O(N) sc O(1)
1. build strictly decreasing mono stack
2. start from idex n-1 to 0, if stack top st[-1]<= A[i], (1)update the result (2) pop off stack
3. return res after loop ends
note, why we build strictly decresing instead of non-increasing? we want to get max diff so if value is the same, we only keep the one appears first
"""
n = len(A)
st = []
for i in range(n):
if not st or A[st[-1]] > A[i]:
st.append(i)
res = 0
for j in range(n-1,-1,-1):
while st and A[st[-1]] <= A[j]:
res = max(res, j-st[-1])
st.pop()
return res
Solution3: Sort + Two pointer
class Solution:
def maxWidthRamp(self, A: List[int]) -> int:
""" tc O(NlgN) sc O(1)
main idea: greedy - create (value,index) tuple, sort by value, two pointer to track strictly increasing idx of A[left] and A[right], otherwise, jump left ptr to right, move right one step more
"""
n = len(A)
val_i = [(v,i) for i, v in enumerate(A)]
val_i = sorted(val_i)
#print(val_i)
res = 0
st = []
left = 0
right = 1
while right < n:
while right < n and val_i[right][1] > val_i[left][1]:
res = max(res,val_i[right][1]- val_i[left][1])
right += 1
if right < n :
left = right
right = right + 1
return res