单调栈也是笔试面试的时候经常出现的考点,经典的题目如Leetcode739.每日温度 与 Leetcode42.接雨水,这两个题均是维护一个单调栈
注意:
1)题目一般给的是一个数组,那么栈中存放的可以是数组的下标,也可以是数组元素,这里要区分好。
2)根据题意看是要维护一个单调递增还是单调递减的栈,上述两题均是维护一个单调递减栈
伪代码: stack = [] # 创建一个栈,并维护其形成一个单调栈 ans = [0]*len(数组) or ans = 0 # 看结果需要返回的是一个数还是一个列表,这里以返回一个列表举例 for i in range(len(数组)): while stack and 数组[i] > 数组[stack[-1]]: # 如果栈非空并且栈顶元素小于数组索引i处元素 prev_index = stack.pop() # 将元素出栈 ans[pre_index] = i - pre_index stack.append(i) # 此时符合单调栈,将i索引值推入栈顶 print(ans)
Leetcode739.每日温度 题目链接
def dailyTemperatures(temperatures: List[int]) -> List[int]: # 单调栈:时间复杂度O(n),空间复杂度O(n) # 遍历每日温度,维护一个单调栈: # 若栈为空或者当日温度小于等于栈顶温度则直接入栈 # 反之,若当日温度大于栈顶温度,说明栈顶元素的升温日找到了,则将栈顶元素出栈,计算其与当日相差的天数即可。 length = len(temperatures) stack = [] # 栈 res = [0]*length # 存放结果 for i in range(length): temperature = temperatures[i] # 当日温度 while stack and temperature> temperatures[stack[-1]]: # 如果当日温度大于栈顶温度,说明找到该日的升温日了 preIndex = stack.pop() res[preIndex] = i-preIndex stack.append(i) return res
**Leetcode42.接雨水 **
解法一:单调栈
建议debug一下,会发现,单调栈解法中,code计算ans值是一层一层计算的,如下图所示
def trap(height: List[int]) -> int: # 设计一个单调栈,单调栈中存储的是下标,满足从栈底到栈顶的下标对应的数组height中的元素递减,单调递减栈 ans = 0 # 记录结果 stack = [] # 单调栈 for i,h in enumerate(height): # 同时获得下标和对应的高度 while stack and h> height[stack[-1]]:# 可以接到雨水的区域一定是高度先减后增的,在单调栈中,栈顶元素永远比它的前一个元素低 #此时的高度有比栈顶元素高,这样就是一个高低高的区域,故可以得到一个可以接雨水的区域 top = stack.pop() if not stack: # 栈为空,左边不存在最大值,无法接到雨水 break left = stack[-1] # left成为新的栈顶元素 currWidth = i-left-1 #获取接雨水区域的宽度 currHeight = min(height[left], height[i])- height[top] # 能接到雨水的高度 ans += currWidth*currHeight stack.append(i) # 在对下标i出计算能接的雨水量之后,将i入栈,继续遍历后面的下标 return ans
解法二:找到最高点二分计算左右区间面积
针对最高处左侧的区域,我们可以得出以下结论:能接到雨水的面积只与左边部分有关,如果左半部分比现在的位置高,那么一定能收集到雨水
针对最高处右侧的区域,我们可以得出以下结论:能接到雨水的面积只与右部分有关,如果右半部分比现在的位置高,那么一定能收集到雨水
def trap(height: List[int]) -> int: # 找到数组最大值及其下标,作为边界,将数组分为两份 max_value = max(height) max_index = height.index(max_value) # python 中 a.index(target) 可以返回某一个值的索引 # print(max_value,max_index) result = 0 # 处理左半部分 lst1 = height[0:max_index+1] # [0,1,0,2,1,0,1,3] for left in range(0,max_index): # 到不了max_index for i in range(left,max_index+1): # 到得了max_index if lst1[left]>lst1[i]: result+= lst1[left]-lst1[i] else: left = i break lst2 = height[max_index:] lst2 = lst2[::-1] # 将右半部分反转,这样和左半部分求解相同 for left in range(0,len(lst2)-1): # 到不了max_index for i in range(left,len(lst2)): # 到得了max_index if lst2[left]>lst2[i]: result+= lst2[left]-lst2[i] else: left = i break return result
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)