Leetcode笔记-栈和队列

40 阅读3分钟

有效的括号

括号配对,栈的经典应用场景。左括号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字段。
  • 所有操作都需要判定是否可行。