第六篇:单调栈
栈好像一个倒扣的杯子,栈底在上面,栈顶在下面。单调栈是从栈顶到栈底逐渐递增或递减的栈,用于解决【找下一个较大/小的元素】的问题。
在golang算法题中,用slice表示栈,如var stack []int,用append表示入栈,用stack[:len(stack)-1]表示出栈,用stack[0]表示栈底,用stack[len(stack)-1]表示栈顶。
力扣496、下一个更大元素。easy
思路:倒序遍历第二个数组,从栈顶开始,依次移除栈中所有小于当前元素的元素。移完之后,如果栈不为空,则栈顶元素即为下一个更大元素,否则下一个更大元素为-1。把对应关系用map存储,然后把当前元素放到栈中,继续下一次循环。遍历完第二个数组之后,再遍历第一个数组,依次从map中取值添加到结果集中就行。
力扣1475、商品折扣后的最终价格。easy
思路:倒序遍历数组,从栈顶开始,依次移除栈中所有大于当前元素的元素。移完之后,如果栈不为空,则栈顶元素即为当前商品的折扣,否则,没有折扣。把最终价格添加到结果集中,然后把当前元素放到栈中,继续下一次循环。
力扣316、去除重复字母。medium
思路:做完402题,再来看这个题更容易理解。假如给定字符串没有重复字符,那么如何实现去掉一个字符后,余下的字符串最小?答案还是从左往右找,找到第一个满足条件的arr[i]>arr[i+1],移除arr[i]后,余下的字符串最小。由于有重复字符,所以在出栈的时候要判断还有没有该字符没有遍历,如果有,才可以出栈,否则该字符及栈中该字符之后的字符均不能出栈。为什么该字符之后的字符也不能出栈?因为该字符之后的字符是小于该字符的,出栈了的话,栈中字符组成的字符串就变大了。题目还要求每个字符能且仅能出现一次,所以,还需要用一个额外的map来保存当前栈中是否有当前遍历到的字符,如果有,那么就不用拿当前字符和和栈顶元素做比较了,直接丢弃即可。没有的话,再比较、出栈。入栈和出栈时,都要维护此map。为什么如果栈中有,就直接丢弃?因为拿当前元素和栈中元素从栈顶开始比较,无非是想把当前元素往栈底方向放,现在已经在最佳位置了,所以倒是省事了。
力扣402、移掉K位数字。medium
思路:两个长度相同的正整数,从左往右比较,先遇到较小数字的整数较小。所以,如果是移除1位数字,那么只需从左往右找,找到第一个满足条件的arr[i]>arr[i+1],移除arr[i]即可。即找到前面数字比后面数字大的位置,删掉前面的数字。移除K位数字,只需在每次移除一个数字后,再从头开始找符合条件的位置,再移除前面的数字。。。。直到移除K个数字。剩下的数字组成的整数即为最小整数。
可以利用单调栈做优化,把时间复杂度由O(nk)降为O(n)。具体操作是从左往右遍历数字字符串,如果还需要移除,且栈不为空,就把栈中大于当前元素的元素出栈,出栈的过程就是移除数字的过程。
浙公网安备 33010602011771号