计包含min函数的栈

来源:互联网 发布:mpii数据集介绍 编辑:程序博客网 时间:2024/06/08 05:11

题目:

设计一个栈,使得PUSH、POP以及GetMin(获取栈中最小元素)能够在常数时间内完成。

转自:http://blog.csdn.net/sgbfblog/article/details/7752878

分析:

很刚开始很容易想到一个方法,那就是额外建立一个最小堆保存所有元素,这样每次获取最小元素只需要O(1)的时间。但是这样的话,PUSH和POP操作就需要O(lgn)的时间了(假定栈中元素个数为n),不符合题目的要求。

那么用1个辅助栈如何呢?


解法:

使用一个辅助栈来保存最小元素,这个解法简单不失优雅。设该辅助栈名字为minimum stack,其栈顶元素为当前栈中的最小元素。这意味着

  • 要获取当前栈中最小元素,只需要返回minimum stack的栈顶元素即可。
  • 每次执行push操作,检查push的元素是否小于或等于minimum stack栈顶元素。如果是,则也push该元素到minimum stack中。
  • 当执行pop操作的时候,检查pop的元素是否与当前最小值相等。如果相同,则需要将改元素从minimum stack中pop出去。
代码:
[cpp] view plaincopy
  1. struct StackGetMin {  
  2.   void push(int x) {  
  3.     elements.push(x);  
  4.     if (minStack.empty() || x <= minStack.top()) //push的元素小于当前minStack的最小元素,则push到minStack中  
  5.       minStack.push(x);  
  6.   }  
  7.   bool pop() {  
  8.     if (elements.empty()) return false;  
  9.     if (elements.top() == minStack.top()) //如果原始栈栈顶元素与minStack栈顶元素相同,则将该元素也从minStack中pop出去。  
  10.       minStack.pop();  
  11.     elements.pop();  
  12.     return true;  
  13.   }  
  14.   bool getMin(int &min) {  
  15.     if (minStack.empty()) {  
  16.       return false;  
  17.     } else {  
  18.       min = minStack.top();  
  19.       return true;  
  20.     }  
  21.   }  
  22.   stack<int> elements;  
  23.   stack<int> minStack;  
  24. };  

实例:
假定有元素3, 2, 5, 4, 2, 1依次入栈,则原始栈中元素为(1), 辅助栈中元素为(2)
 1                              
 2                              
 4                             1
 5                             2
 2                             2
 3                             3
(1)                  (2)
这样,第1次pop时,1从两个栈都pop出去;第2次pop时,2从两个栈都pop出去;第3次pop,元素4从原始栈pop出去,辅助栈不用pop;第4次pop,元素5从原始栈pop出去,辅助栈不需pop;第5次pop,元素2从两个栈pop出去;第6次pop,元素3从两个栈都pop出去。我们可以发现,每次push或者pop后,辅助栈的栈顶元素总是当前栈的最小元素。

 

另一解法(不用辅助栈)

另外一种解法利用存储差值而不需要辅助栈,方法比较巧妙。其中需要说明的几点:

push(int elem)函数在栈中压入当前元素与当前栈中最小元素的差值,然后通过比较当前元素与当前栈中最小元素大小,并将它们中间的较小值压入。

pop()函数执行的时候,先pop出栈顶的两个值,这两个值分别是当前栈中最小值min和最后压入的元素与栈中最小值的差值diff。如果diff<0,则表示最后压入栈的元素是最小的元素,因此只需将min-diff压入栈中,并将min值返回即可。min-diff就是当前元素弹出后,栈中剩下元素的最小值。而如果diff>=0且栈不为空,则表示当前值不是最小值,所以需要在栈中压入最小值min并将diff+min返回;如果栈为空,则表示已经是最后一个数字,直接返回min即可。

[cpp] view plaincopy
  1. stack<int> s;  
  2. void push(int elem)  
  3.  {  
  4.     if (s.empty()) {  
  5.         s.push(elem);  
  6.         s.push(elem);  
  7.     } else {  
  8.         int min = s.top();  
  9.         s.pop();  
  10.         s.push(elem - min);  
  11.         s.push(elem < min ? elem : min);  
  12.     }  
  13. }  
  14.   
  15. int pop()   
  16. {  
  17.     int min = s.top();  
  18.     s.pop();  
  19.     int diff = s.top();  
  20.     s.pop();  
  21.     if (diff < 0) {  
  22.         s.push(min - diff);  
  23.         return min;  
  24.     } else {  
  25.         if (!s.empty()) {  
  26.             s.push(min);  
  27.             return diff + min;  
  28.         }  
  29.         return min;  
  30.     }  
  31. }  
  32.   
  33. int min()   
  34. {  
  35.     int min = s.top();  
  36.     return min;  
  37. }  


一个实例如下:

clear(): [ ] 
push(3): [3 3] 
push(4): [3 1 3] 
push(2): [3 1 -1 2] 
push(5): [3 1 -1 3 2] 
push(1): [3 1 -1 3 -1 1] 
push(1): [3 1 -1 3 -1 0 1] 
push(6): [3 1 -1 3 -1 0 5 1] 
push(7): [3 1 -1 3 -1 0 5 6 1]

min() --> 1; pop() --> 7: [3 1 -1 3 -1 0 5 1] 
min() --> 1; pop() --> 6: [3 1 -1 3 -1 0 1] 
min() --> 1; pop() --> 1: [3 1 -1 3 -1 1] 
min() --> 1; pop() --> 1: [3 1 -1 3 2] 
min() --> 2; pop() --> 5: [3 1 -1 2] 
min() --> 2; pop() --> 2: [3 1 3] 
min() --> 3; pop() --> 4: [3 3] 
min() --> 4; pop() --> 3: [ ]


参考资料:

设计包含min的栈另解

0 0
原创粉丝点击