Stack

Last in First Out list就是一个天然的stack,不需要单独定义class。

push

pop

top

从左到右linear scan,需要不断回头看过去的元素时,使用stack

常见题型:

  1. Deduplication and Repeatedly deduplication, Leetcode 71, simplify path

  2. 作为辅助实现更高级的data structure: two stack -> queue, min stack; max stack

  3. 表达式计算、decode

  4. 单调栈 eg. Histogram中找到最大的长方形

括号匹配

或者我们用dict吧...

{: brace-bracket/curly-bracket

[: square bracket

(: parenthesis

简易计算器(+-)

本质是遇到‘)‘后把之前存的数字和operator拿出来做个计算,push回stack,直到stack空为止

逆波兰表达式

Decode

遇到【时把之前的内容暂存起来,保护现场,遇到】时把stack的内容释放出来,恢复现场。

四个变量,cnt, string,cnt_stack, str_stack

遇到 [ : push cnt, string to stack, 重置cnt, string

遇到 ] : pop from stack

O(n2)O(n^2)

946 Validate Stack Sequences (with distinct values)

input: pushed=[1,2,3,4,5], popped = [4,5,3,2,1] output: True

Implement a queue using 2 stacks

两个array,s1用来进元素,s2用来出元素,如果在s2是空的时候还要继续出元素,就把s1的倒进s2里再pop 可以把它想象成底端对底端,中间有一个隐形的墙 --> 6 5 ][4 3 2 1 -->

stack1: to store new elements coming in (enqueue) - stack1.push() stack2: to help with dequeue - case 1: if stack2 is NOT empty: stack2.pop() - case 2: if stack2 is empty: - move all elements from stack1 to stack2 one by one - stack2.pop()

Enqueue: Time O(1)

Dequeue: Time worst case O(n), amortized O(1)

amortized time vs average time:

amortized: amortize all operations within input (不管是什么样的input) average: average over all possible inputs (和输入输出有关系 不能保证某一种情况)

Implement a stack using 2 queues

only 2 APIs available: enqueue, dequeue enqueue(): dequeue(): - if the queue is not empty, return the first element - if the queue is empty, return null stack [ 1 2 3 4 Q1 <-- <-- Q2 <-- <-- 如果Q1没空,就把Q1塞到Q2,如果空了,返回最后的那个

Implement a stack using 1 queue

如果此时多了一个size()的API stack [ 1 2 3 4 Q <-- <--

做size-1次:拿出来再从尾部塞回去

Implement a stack with Max API

Solution 1: Brute Force, O(n), iterate each element in the stack to find the max

Solution 2: Trade space for time

Current top of stack (x, x_max)

New value y:

push: if y>x_max, store (y, y) else, store (y, x_max)

pop: tmp=lst.pop(), return tmp[0]

Time: O(1)

Space: O(n)

同理,也可以实现getmin

Min Stack

两个stack

stack1 (input) 3 1 4 0 stack2 (min) 3 1 1 0

Push x: stack.append(x)

Case 1: x<getMin(): minStack.append(x)

Case2: x>=getMin(): minStack.append(getMin())

Pop x: stack.pop(), minStack.pop()

Time O(1) Space O(n)

优化 如果有很多duplicate

CART 如果有size就可以用tuple

加counter <1, 100> 代表有100个1

第一次出现它时里面有几个元素 <1,2> 出现1的时候是第二个位置

也可以用3个stack,不是存tuple而是又加一个stack来存位置

Follow up: duplicate element

优化,可以只有数值有变时再存min

Push x: stack.append(x)

Case 1: x<=getMin(): minStack.append(x)

Case2: x>getMin(): Do nothing

Pop x:

if stack[-1]==getMin()

minStack.pop()

stack.pop()

Implement a deque with multiple stacks

left XXXXXXXXXXXXXXXXXXXXXXXXX right l.add() r.add() l.remove() r.remove()

2 stacks

]s1 s2[ s1: simulate the left end of the deque s2: simulate the right end of the deque left.add(): s1.push() O(1) right.add(): s2.push() O(1) left.remove(): - if s1 is not empty, just stack1.pop() O(1) - if s2 is empty, - move all elements from s2 to s1 O(n) worst - stack1.pop() right.remove(): similar

 L. remove ()2n+1 R.remove() 2(n1)+1 L. remove() 2(n2)+1 R.remove() 2(n3)+1 L. remove()  R.remove()  L. remove()  R.remove() \begin{array}{ll}{\text { L. remove }()} & {-2 n+1} \\ {\text { R.remove() }} & {-2(n-1)+1} \\ {\text { L. remove() }} & {-2(n-2)+1} \\ {\text { R.remove() }} & {-2(n-3)+1} \\ {\text { L. remove() }} & {-} \\ {\text { R.remove() }} & {-} \\ {\text { L. remove() }} & {-} \\ {\text { R.remove() }} & {-\cdots}\end{array}
 Amortized time =2(n+(n1)+(n2)++1)+nn=n(n1)+nn=(n1)+1=n\text { Amortized time }=\frac{2^{*}(n+(n-1)+(n-2)+\ldots+1)+n}{n}=\frac{n^{*}(n-1)+n}{n}=(n-1)+1=n

How to speed up the remove() operation?

3 stacks

4 3 2 1 ]s1 s2[ s3 buffer [ 8 7 6 5 两个stack的时候腹背受敌,只要一边空了,这个操作就非常expensive。如果能只挪一半的元素,不管left.remove还是right.remove就都不怕了。借助s3这个buffer,让左右两边均等。

8 7 6 5 ]s1 s2[ 4 3 2 1 s3 buffer [

 1st call Right. remove(): n/2 stack 1. pop () n/2 stack 3. push() n/2 stack 1. push() - n/2 stack 1. push()  - n/2 stack 3. pop()  - n/2 stack 1. push()  - n/2 stack 1. push()  - stack 2. pop()  total 3 n+1 stack operations \begin{array}{l}{\text { 1st call Right. remove(): }} \\ {-\quad n / 2 \text { stack 1. pop }()} \\ {\quad- \text { n/2 stack 3. push()}} \\ {-\quad \text { n/2 stack 1. push()}} \\ {\text { - n/2 stack 1. push() }} \\ {\text { - n/2 stack 3. pop() }} \\ {\text { - n/2 stack 1. push() }} \\ {\text { - n/2 stack 1. push() }} \\ {\text { - stack 2. pop() }} \\ {\text { total 3 } n+1 \text { stack operations }}\end{array}
 Amortized time =(3n+1)+1(n/21)n/2=3.5n0.5n=7=O(1)\text { Amortized time }=\frac{(3 n+1)+1 *(n / 2-1)}{n / 2}=\frac{3.5^{*} n}{0.5 * n}=7=O(1)

Sort Numbers with 2/3 Stacks

3 stacks:

s1 input [ 1 3 2 4 s2 buffer [ global_min s3 output [

one sentence: use selection sort to sort data structure: record globalmin when buffering elements from s1 to s2; when s1 is empty, put the global_min in s3, put all but s2 back to s1. algorithm (high level--detail):

2 stacks:

s1 input [ 1 3 2 4 s2 left, output| right, buffer [ global_min

output: put global_min back buffer:

过去得到的 global_min一定小于当前轮的 global_min

方法一:while stack2.size()>stack2.initial_size_before_this_iteration 方法二:while stack2.top()>=global_min keep popping back to s1

Follow Up: duplicate element: add a counter

s1 input [ 1 3 2 4 s2 left, output| right, buffer [ global_min counter

3 stacks 实现merge sort

Leetcode 1003 合法字符串

和括号匹配的问题一样,遇到c时匹配并清空

Time: O(n)

Space: O(n)

Leetcode 856 表达式求值

()has score 1

AB has score A+B

(A) has score 2*A

Last updated