演算法學習,演算法學習網站
最小棧
最小棧其實和棧沒有什麼區別的,唯一的區別在於最小棧是可以在O(1)時間內得到當前的棧空間裡,最小的值是多少。
最小棧的操作
最小棧的操作和普通棧的操作沒有太大區別,唯一多了一個方法就是getMin()方法,這個方法是用來擷取當前棧內的最小值。其他方法就是Push(), Pop(), Top()...等
在O(n)時間內找到新的最小值
這裡就厲害了,先說普通的O(n)的方法~得到棧內最小值。是不是只要維護一個Min的變數就可以呢?不僅僅是!下面舉例說明。
我們發現Min值是在第一次插入1的時候為1,第4次插入-1的時候變為-1,這個時候我們是不是覺得很簡單,只用維護一個Min就可以了?不是的!假設我們進行操作:Pop(),Pop()操作。我們來看看堆棧裡剩下了什麼。
stack 1 2 3
那麼Min呢?還是-1,但其實-1已經被Pop()掉了。假如我們發現最小值被Pop()之後,我們如何更新Min呢?只能從頭遍曆,那麼就需要O(n)的時間。
O(1)的辦法
這裡說下如何O(1)時間內就找到,維護的變數沒有變化,但是我們在堆棧記憶體放的元素需要與Min值產生關聯。
例子:
我們進行同樣的5次Push操作,壓棧順序為1 2 3 -1 4。
- 第一次棧存放0, Min為1.
- 第二次棧存放2-Min=1, Min<2 所以繼續為1.
- 第三次棧存放3-Min=2, Min<3 所以繼續為1.
- 第四次棧存放-1-Min=-2, Min>-1 所以Min = -1.
- 第五次棧存放4-Min=5, Min<5 所以繼續為-1.
大家看明白沒?我們存放的數為x-Min.
這是Push的操作,當我們進行Pop()的時候怎麼做呢,進行兩次Pop()?
第一次棧頂元素5, 5>0, 彈出,返回 5+Min=4.
第二次棧頂元素-2, -2<0,彈出,返回Min. 並更新Min=Min-(-2).
那Top呢?
假如棧頂元素為5, 5>0 返回5+Min.
假如棧頂元素為-2, -2<0 返回Min.
大家發現沒?實際上我們壓棧的時候,壓入的元素就是X-Min,那麼只要壓入的元素大於Min,那麼存放的都是正數,而當X小於Min的時候,壓入的元素(X-Min)就是負數。
所以彈棧的時候:
遇到正數,直接彈出棧頂元素(X-Min)和Min的和(X-Min+Min)就可以了。
遇到負數,說明在壓入這個元素的時候Min值有更新,那個時候的Min值被更新為新插入的X. 例如Min=1,插入-1的時候,棧存放-1-Min=-2,而Min更新為新的X值(-1).則彈的時候就直接彈出Min就可以了。那麼我們同時也把最小值彈出了,要更新Min,更新為當前Min-(X-下一個Min)此處比較繞,多用例子理解。
代碼實現
我實現了4個版本,其中前兩個版本是O(1)層級的,後兩個是O(n)層級的。第2個版本可能有些瑕疵,假如你們看到代碼哪裡錯誤請評論,多謝。
1號容器實現
自己寫的結構體。
//// main.cpp// MinStack2//// Created by Alps on 14/12/3.// Copyright (c) 2014年 chen. All rights reserved.//#include <iostream>#include <vector>using namespace std;class MinStack {public: vector<int> stack; int min; void push(int x) { if (stack.empty()) { stack.push_back(0); min = x; }else{ stack.push_back(x-min); if (x < min) { min = x; } } } void pop() { if (stack.empty()) { return; }else{ if (stack.back() < 0) { min = min - stack.back(); } stack.pop_back(); } } int top() { if (stack.empty()) { return NULL; } if (stack.back() > 0) { return stack.back()+min; }else{ return min; } } int getMin() { if (stack.empty()) { return NULL; } return min; }};int main(int argc, const char * argv[]) { // insert code here... std::cout << "Hello, World!\n"; return 0;}
2號STL的stack實現
在邊緣測試的時候,我的編譯器沒出錯,但是OJ上報WA了。
//// main.cpp// MinStack4_leetcode//// Created by Alps on 14/12/3.// Copyright (c) 2014年 chen. All rights reserved.//#include <iostream>#include <stack>using namespace std;class MinStack{public: stack<long> s; long min; void push(int x){ if (s.empty()) { s.push(0); min = x; }else{ s.push(x-min); if (x < min) { min = x; } } } void pop(){ if (s.empty()) { return; }else{ if (s.top() < 0) { min = min - s.top(); } s.pop(); } } int top(){ if (s.empty()) { return NULL; }else{ if (s.top() > 0) { return (int)(min+s.top()); }else{ return (int)min; } } } int getMin(){ if (s.empty()) { return NULL; }else{ return (int)min; } } };int main(int argc, const char * argv[]) { int a = -2147483648; MinStack M; M.push(2147483646); M.push(2147483646); M.push(2147483647); printf("%d\n",M.top()); M.pop(); printf("%d\n",M.getMin()); M.pop(); printf("%d\n",M.getMin()); M.pop(); M.push(2147483647); printf("%d\n",M.top()); printf("%d\n",M.getMin()); M.push(a); printf("%d\n",M.top()); printf("%d\n",M.getMin()); M.pop(); printf("%d\n",M.getMin()); return 0;}
3號鏈表實現
自己寫的鏈表結構體。
//// main.cpp// MinStack3_leetcode//// Created by Alps on 14/12/3.// Copyright (c) 2014年 chen. All rights reserved.//#include <iostream>using namespace std;class MinStack {public: struct StackNode{ int num; StackNode *next; }; typedef StackNode* stack; stack s; MinStack(){ s = (stack)malloc(sizeof(struct StackNode)); s->next = NULL; } int min; void push(int x) { if (s->next == NULL) { stack node = (stack)malloc(sizeof(struct StackNode)); node->num = x; node->next = s->next; s->next = node; min = x; }else{ stack node = (stack)malloc(sizeof(struct StackNode)); node->num = x; node->next = s->next; s->next = node; if (x < min) { min = x; } } } void pop() { if (s->next == NULL) { return; }else{ stack temp = s->next; if (min == s->next->num && s->next->next != NULL) { s->next = s->next->next; free(temp); min = s->next->num; for (stack loop = s->next; loop != NULL; loop = loop->next) { if (min > loop->num) { min = loop->num; } } }else{ s->next = s->next->next; free(temp); } } } int top() { if (s->next == NULL) { return NULL; } return s->next->num; } int getMin() { if (s->next == NULL) { return NULL; } return min; }};int main(int argc, const char * argv[]) { MinStack MinS; MinS.push(-1); MinS.push(0); MinS.push(2); MinS.push(-2); printf("%d\n",MinS.top()); MinS.pop(); MinS.pop(); MinS.pop(); printf("%d\n",MinS.getMin()); return 0;}
4號容器實現
最古老的版本。
//// main.cpp// MinStack_leetcode//// Created by Alps on 14/12/2.// Copyright (c) 2014年 chen. All rights reserved.//#include <iostream>#include "vector"using namespace std;class MinStack {public: struct StackNode{ int num; int min; }; vector<StackNode> stack; void push(int x) { if (stack.empty()) { StackNode S = {x,x}; stack.push_back(S); }else{ if (x < stack.back().min) { StackNode S = {x,x}; stack.push_back(S); }else{ StackNode S = {x,stack.back().min}; stack.push_back(S); } } } void pop() { if (stack.empty()) { }else{ stack.pop_back(); } } int top() { if (stack.empty()) { return NULL; } return stack.back().num; } int getMin() { if (stack.empty()) { return NULL; } return stack.back().min; }};int main(int argc, const char * argv[]) { MinStack minstack; minstack.push(-1); minstack.push(1); printf("%d %d\n",minstack.top(), minstack.getMin()); return 0;}