有效的括号
括号配对,栈的经典应用场景。左括号push右括号pop和匹配即可,python list就是栈。
细节:
- pop前需要检查是否空列表,不能为空。
- 遍历完成需要检查是否空列表,必须为空。
本质上是一种构造测试case的思路,而非靠不断提交来排查边界条件。对本问题而言,需要构造的测试case包括三大类:
- 有效字符串:简单、复杂
- 无效字符串
- 括号数量对,顺序不匹配
- 括号数量不对,极端情况为全左或全右
- 全左:遍历完成,列表必须为空
- 全右:pop前,列表不能为空
- 空字符串:题目不允许为空,忽略
最小栈
相比常规栈,新增常数时间复杂度的getMin操作,显然一个栈无法实现,需要新增字段
思路一:用新的字段存储最小值,在push和pop时更新min,但pop的时间复杂度变成了O(n)。
思路二:用新的字段存储最小值的列表,即每次push时,新字段也push当前元素对应位置的最小值。
细节:注意处理list为空的情况。
验证栈序列
注意阅读题目提示,辅助算法设计:
- 无需验证空列表。
- 无需验证popped和pushed的长度和元素是否一致。
- 设计算法时,无需考虑元素重复的问题。
本质上是要模拟栈的push和pop操作,新建一个stack验证即可。
- 遍历每个popped的元素,验证是否在栈顶。如果不在,将pushed的元素继续入栈。如果在,pop stack。
- 如果某个popped的元素始终找不到对应栈顶元素,顺序错误。
每日温度
思路一:暴力解法,两层遍历,时间复杂度O(n2)。
- 外层:遍历列表。
- 内层:对每个元素i,从i+1遍历到n-1,寻找第一个大于i的温度。
思路二:暴力解法的问题,是在内层遍历里,有很多重复的遍历。直观的解决方案,是将外层的从左到右变为从右到左。
- 外层:从右到左遍历列表,记录每个元素的res。
- 内层:对每个元素i,从i+1开始遍历j,但要利用之前遍历的信息。
- 如果j的温度更大,返回j-i。
- 否则,直接跳到j后面比j大的第一个数,即j+res[j],而非j+1。
- 注意,如果res[j]=0,无需往后再找,i对应的res也是0。
思路三:在思路二中,如果j比i的温度低,则只需要前进到j的res对应的温度。换言之,j是可以去掉的。也即从右到左遍历,只需要保留比当前位置更大的数。因此,采用单调栈。时间复杂度变为O(n)。
- 由于需要index,栈内元素为tuple,包括温度与index。(进一步,其实不需要温度,下标即可,可以从原列表读取温度)
- 如果温度相等,仍需要pop。因为从右往左遍历,需要保留最左侧的结果。
- stack的pop操作前,永远记得先检验stack是否为空。
用栈实现队列
简单,一个in列表一个out列表即可实现。
注意,pop和peek操作的时间复杂度为均摊O(1),因为每个元素至多被操作入栈和出栈各两次。
设计循环双端队列
直观思路,也是python中deque的实现:双链表。整体思路比较简单,注意细节即可。
- head和tail都维护成哨兵节点,避免处理边界情况。
- 增删操作需要对应修改size字段。
- 所有操作都需要判定是否可行。