栈——从入门到放弃
前言
基本线性数据结构分为栈、队列、列表等。真正的区别在于元素的添加及移除方式。作为书本(盘子)结构,栈的添加及移除操作只发生于同一端(顶端)。最新添加的元素会被最先移除,即LIFO(last-in first-out)。基础基本就这些,话不多说,直接上题手撕。
1. 最大宽度坡
由浅入深,首先看Leecode中等难度的一道题目:最大宽度坡。网址如下:
最大宽度坡
PS:大家可以看题目要求及其它语言的代码,本文主要分析python版本代码。
思路分析:
本题目标在于求解坡的最大宽度,更建模化讲就是寻找右端大于左端的最长子数组,我们称为目标子数组。因此我们只需要先从左到右找到一个单调递减的子数组,这个子数组中的元素是目标子数组的左端,因此起始为原数组第一个元素,后续比它大的肯定不可能是目标子数组的左端。然后从右到左遍历原数组,寻找目标子数组的右端。
解题基本思路如上,现在再具体分析一下代码思路。
首先维护一个单调递减子数组,第一个数肯定为数组A的起始值,逐步进行比较大小和添加,直到最后一个数为数组A的最小值。因为目标是求数组长度,因此维护的子数组存储A的索引而不是数值。
然后进行第二阶段,从右往左遍历数组A,当数值大于左端时,弹出计算长度并存储或舍弃(继续计算肯定长度肯定变小,因此可以停止)。同时因为计算最长的,因此当当前结果大于索引时已经可以停止了。
至此代码如下:
class Solution:
def maxWidthRamp(self, A: List[int]) -> int:
stack = []
nums = len(A)
for i in range(nums):
if not stack or A[stack[-1]] > A[i]:
stack.append(i)
res = 0
i = nums - 1
while i > res:
while stack and A[stack[-1]] <= A[i]:
res = max(res, i - stack[-1])
stack.pop()
i -= 1
return res
2. 表现良好的最长时间段
再来看一道进一步的题目:表现良好的最长时间段
思路分析:
这道题本质和上一道是一样的,只不过多了一部分的数据预处理。
以输入样例 hours = [9,9,6,0,6,6,9] 为例,大于8 小时的一天记为 1 ,小于等于 8 小时的一天记为 −1 ,生成一个新数组day。这时候关键来了,我们在生成一个新的数组,第一个数为0,此后每个数sum[i]为day前i个数的加和,这样的话sum[j]-sum[i]就成为了最大宽度坡,这个问题就转换为了上个问题。
至此代码如下:
class Solution:
def longestWPI(self, hours: List[int]) -> int:
nums = len(hours)
day = [-1 for i in range(nums)]
for i in range(nums):
if hours[i] > 8:
day[i] = 1
sum = [0 for i in range(nums+1)]
for i in range(1, nums+1):
sum[i] = sum[i-1] + day[i-1]
stack = []
for i in range(nums+1):
if not stack or sum[stack[-1]] > sum[i]:
stack.append(i)
res = 0
i = nums
while i > res:
while stack and sum[stack[-1]] < sum[i]:
res = max(res, i - stack[-1])
stack.pop()
i -= 1
return res
栈的刷题就先讲到这里啦,真正想特别熟练还是得多刷题,这里只是简单的刷题入门经典题目分享哈。又因为本人一向比较懒,各位看官觉得还可以就点赞评论,督促我写出下一篇,么~。