【LeetCode刷题笔记】栈和队列

 456. 132 模式

解题思路:

  • 1. 单调递减栈,栈中存放的值当作 k 值,从右往左遍历数组,对于遇到的每一个元素 j 找最大的 k,遇到 nums[j] > 栈顶 时,就一直弹栈,并记录每次弹栈的 k 值,最后一次弹出的栈顶即maxK,此时 nums[j] > maxK,再往 j 的前面看一眼元素 i,如果 nums[i] < maxK,则找到一组解:nums[i] < maxK < nums[j]。否则将nums[j]压栈继续遍历。

  • 关键点1:从右往左遍历能保证栈中已保存的值下标都会比当前遇到的 大,即满足 j < k

  • 关键点2:遇到 nums[j] > 栈顶 时,往 j 的前面位置看一眼 i,保证了下标关系满足 i < j 

  • 关键点3:遇到 nums[j] > 栈顶 时,一直弹栈,这样找到的是满足这个关系的最大的  k 值,此时再到 j 的前面找小于这个 k 值的会更加容易(有一点贪心在里面)

 

 

注意:maxK 的初始化需要放在 for 循环的外面,这是因为总是要记录上一次的已弹出的最大的 k 值,即便当前遍历的 j 没有发生弹栈操作,仍然要和曾经记录的最大的 k 值比较,一旦 j 前一个位置的值比曾经记录的最大 k 值小,就存在解,因为这时即便 k 不是当前操作栈顶弹出的,但至少栈中会存在比曾经的 k 还大的值,因此必然会存在解。(对比下面第二种情况,这时的解是由 当前 j 前一个位置 i 上的值、maxK、栈中比 maxK 大的值组成)

解题思路: 

  • 2. 单调递减栈 + 最小值前缀数组,先求一个最小值前缀数组 minPrefixminPrefix[i] 表示[0..i] 中 ≤ nums[i] 的最小值

  • 然后从右往左遍历数组,如果 nums[j] > minPrefix[j] 时判断,如果 minPrefix[j] ≥ 栈顶 k,就一直弹栈,直到 minPrefix[j] < 栈顶 k。此时看一下若  栈顶 k < nums[j],则存在一组解:minPrefix[j] < 栈顶 k < nums[j]。(minPrefix[j] 就是 nums[i]

  • 否则压栈nums[j],栈中存放的是大于minPrefix[j]的可能的k值。

151. 颠倒字符串中的单词

 

解题思路:

  • 1. ,先提前去除前后空格,然后循环处理取出每个单词压栈,最后直接按出栈顺序弹出拼接即可。

解题思路: 

  • 2. 双端队列,每次从队首添加(offerFirst),最后按顺序出队即可。(或者按正常从队尾入队,取的时候也从队尾出队pollLast即可)其实跟方法1是一样的。

224. 基本计算器

解题思路:

  • 1. 遍历字符数组,使用一个保存遇到的每个字符,栈中保存String类型,当遇到右括号出栈计算结果,直到遇到左括号停止,然后将计算结果重新压栈。遍历结束后,如果栈中只有一个值,转成整型输出即可,如果有多个值,进行计算后输出。

注意:

  • 1)这种做法可能需要在遍历过程中计算结果时,处理一些特殊case,如 -(-2)  +(-2) 这种

  • 2)不允许使用内置函数,字符串转整数需要写一个函数来实现,另外为了避免计算结果压栈后面取出来反复计算,可以考虑使用map缓存结果

  • 3)遇到连续数字字符时,如 1+234-56,需要截取连续字符作为一个String压栈

  • 4)遍历过程中注意跳过空格 

解题思路: 

  • 2. 方法1代码写起来非常麻烦,因为存在一些特殊case,如 -(-2) 这种,可以换一种方式,遍历每个字符:

  • ① 遇到正负号时,就记录一下符号(用1或-1表示);(在遇到数字计算res时会使用到)

  • ② 遇到数字时,把当前数字(及它后面可能出现的连续数字)的值计算出来,累加到结果res中;

  • ③ 遇到左括号时,将当前结果res符号一并压栈(同时重置res和符号为初始状态);

  • ④ 遇到右括号时,出栈取出上一次的res符号,和当前的res进行结算并更新res

  • 最后遍历结束直接返回res即可。

 

注意,sign 表示的是每个数字前面的符号,当遇到连续数字计算结果时,需要将得到的 num 乘以该符号值,当遇到右括号时,取出的栈顶元素中的 sign 表示的是上次压栈时,左括号前面的符号,因此需要用上次的符号乘以这次 (...) 之间计算的结果,再累加上次结果。

这个代码相比方法1就简单多了,方法1实在太麻烦了,扣半天也不一定能扣出来。 

解题思路:  

  • 3. DFS递归,定义一个递归函数dfs(s, index,N),它表示计算s[index....N-1]的值,当遇到右括号或者字符串结尾停止并返回,递归函数的返回值为int[],包含当前的计算结果当前计算到了哪个位置下标

  • 在递归函数中,遍历字符数组的[index....N-1]的每个字符进行处理:

  • ① 遇到正负号时,就记录一下符号(1或-1) 遇到数字时,就使用记录的符号计算当前数字的结果,并累加到结果res中;

  • ② 遇到左括号时,递归调用dfs(s, i + 1,N)的计算结果, 并累加到当前结果res中,并将当前遍历的下标 i 移动到返回位置的下一个位置继续处理;

  • ③ 遇到右括号时,返回当前记录的res和位置 i

  • 最后遍历结束,说明遇到了字符串结尾返回当前记录的res和位置 i

  • 主调用函数中只需要返回 dfs(s, 0, N)[0] 即可。

注意:之所以递归函数的返回结果中还要包含当前计算的位置下标,是因为在递归调用返回之后,调用者要知道继续遍历处理的下一个位置从哪里开始。

上面代码中递归调用方法里的主要逻辑跟方法2差不多,相当于把方法2中压栈的地方改成了递归调用,弹栈的地方改成了返回结果。

227. 基本计算器 II

解题思路:  

  • ,栈中只需保存整型结果,这题相比224要简单一些,没有括号,只有加减乘除符号,顺序扫描字符:

  • ① 当遇到运算符时,就记录符号,

  • ② 当遇到数字时,把当前数字(及它后面可能出现的连续数字)的值计算出来,然后根据之前记录的符号判断(也就是位于当前数字前面的符号),是直接压栈还是需要跟之前的值计算后再压栈,

  • a. 如果之前记录的符号正负号,就直接压栈当前计算得到的num-num

  • b. 如果之前记录的符号乘除号弹出栈顶值(即上一次的结果,乘除号前面的数字),跟当前计算得到num进行乘除计算之后的结果,再压栈

  • 最后遍历结束后把栈里的数字都累加即可。

  • 注意:遇到空格时跳过,这题仍然包含空格。

 

772. 基本计算器 III

解题思路:  

  • 递归 + 栈,定义一个递归函数dfs(s, i,N),表示计算s[i...N-1]的结果,当遇到右括号str结尾位置就停止,递归函数的返回值为int[],包含当前的计算结果当前计算到了哪个位置下标

  • 在递归函数中,遍历字符数组的[i...N-1]的每个字符进行处理:

  • ① 当遇到数字运算符时,处理逻辑和227题一样;

  • ② 当遇到左括号时,递归调用dfs(s, i + 1,N)的计算结果,并将返回结果压栈并将当前遍历的下标 i 移动到返回位置的下一个位置继续处理;

  • ③ 当遇到右括号时,计算累加栈中的数<

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值