算法最小栈
Posted 有顶天の甲子园
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法最小栈相关的知识,希望对你有一定的参考价值。
实现一个栈,带有出栈(pop)、入栈(push)、取最小元素(getMin)三个方法,且时间复杂度均为O(1)。
初始想法:
- 创建 int min = -1,记录栈中最小元素的下标;
- 第一个元素进栈时,min = 0;
- 每当新元素进栈,让新元素与 min 下标位置的元素比较大小,min = 较小元素的下标;
- 调用 getMin 直接返回 min 的值。
这种方式进栈没有问题,而出栈时,若当前最小元素在栈顶并出栈了,用剩下哪个元素的下标顶替当前 min 就不得而知了。所以一旦最小元素的下标出栈,需要次小元素的下标作为备胎顶替,后几轮若次小元素的下标出栈,也需要一个备胎。。。
因此用一个额外的栈存储所有曾经的最小值的下标即可:
- 原有栈叫栈A,创建一个额外的栈B;
- 第一个元素进入栈A,这个唯一的元素是栈A的当前最小值,其下标就进入栈B;
- 每当新元素进入栈A,让新元素与栈B栈顶下标对应的栈A的当前最小值比较,若小于A的当前最小值,则新元素的下标进入栈B;
- 每当栈A有元素出栈,若出栈元素的下标 == 栈B的栈顶元素,则B的栈顶也出栈。此时栈B余下的栈顶元素所指向的,是栈A中原本的次小元素,这个第二小的元素就代替了刚出栈的最小元素成为了栈A当前的最小元素;
- 调用 getMin 方法直接返回栈B的栈顶元素即可。
这种方法最坏条件的空间复杂度是O(n)。
这种额外创建一个栈不断地存储“备胎”,并让“备胎”不断“转正”的思路,让我想到了做 Valid Parentheses 这题时最开始想到的死办法的解决方法。
原理:
top 表示当前栈顶,从0开始向后扫;i 表示即将入栈的元素,从1开始向后扫;创建额外栈 stack 存储所有上一次的栈顶位置,初始为 -1。这里需要注意的是,若上一次栈顶是 -1,那么 top 下面要到 i + 1 的位置继续扫;若不是 -1,则 top 退到上一次栈顶的位置即可。一开始我没想到用栈存储上一个栈顶下标,仅仅用一个变量存储,结果这种方法没有实现。看到了最小栈后,灵光一现想到了这样实现,时间和空间复杂度和原来的做法一样,都为O(n),不过没有那种做法直观,但也不失为一种思路。
1 bool isValid(string s) { 2 stack<int> stack; 3 int top = 0, i = 1; 4 stack.push(-1); 5 while (i < s.size()) { 6 if ((s[top] == \'(\' && s[i] == \')\') || (s[top] == \'[\' && s[i] == \']\') || (s[top] == \'{\' && s[i] == \'}\')) { 7 if (stack.top() == -1) { 8 top = i + 1; 9 i = top + 1; 10 } else { 11 top = stack.top(); 12 stack.pop(); 13 i++; 14 } 15 } else { 16 stack.push(top); 17 top = i++; 18 } 19 } 20 return stack.top() == -1 && top == s.size(); 21 }
以上是关于算法最小栈的主要内容,如果未能解决你的问题,请参考以下文章