題目
設計一個支持 push ,pop ,top 操作,並能在常數時間內檢索到最小元素的棧。
push(x) —— 將元素 x 推入棧中。 pop() —— 刪除棧頂的元素。 top() —— 獲取棧頂元素。 getMin() ——
檢索棧中的最小元素。示例:
輸入: [“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]輸出: [null,null,null,null,-3,null,0,-2]
解釋: MinStack minStack = new MinStack(); minStack.push(-2);
minStack.push(0); minStack.push(-3); minStack.getMin(); --> 返回 -3.
minStack.pop(); minStack.top(); --> 返回 0. minStack.getMin();
–> 返回 -2.提示:
pop、top 和 getMin 操作總是在 非空棧 上調用。
來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/min-stack
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
分析
要做出這道題目,首先要理解棧結構先進後出的性質。
對於棧來說,如果一個元素 a 在入棧時,棧裏有其它的元素 b, c, d,那麼無論這個棧在之後經歷了什麼操作,只要 a 在棧中,b, c, d 就一定在棧中,因爲在 a 被彈出之前,b, c, d 不會被彈出。
因此,在操作過程中的任意一個時刻,只要棧頂的元素是 a,那麼我們就可以確定棧裏面現在的元素一定是 a, b, c, d。
那麼,我們可以在每個元素 a 入棧時把當前棧的最小值 m 存儲起來。在這之後無論何時,如果棧頂元素是 a,我們就可以直接返回存儲的最小值 m。
按照上面的思路,我們只需要設計一個數據結構,使得每個元素 a 與其相應的最小值 m 時刻保持一一對應。因此我們可以使用一個輔助棧,與元素棧同步插入與刪除,用於存儲與每個元素對應的最小值。
當一個元素要入棧時,我們取當前輔助棧的棧頂存儲的最小值,與當前元素比較得出最小值,將這個最小值插入輔助棧中;
- 當一個元素要出棧時,我們把輔助棧的棧頂元素也一併彈出;
- 在任意一個時刻,棧內元素的最小值就存儲在輔助棧的棧頂元素中。
代碼
#define STACK_MAX 1000
typedef struct {
int top;
int data[STACK_MAX];
} MyStack;
typedef struct {
MyStack stackAll;
MyStack stackMin;
} MinStack;
MinStack *minStackCreate() {
MinStack *stack = malloc(sizeof(MinStack));
stack->stackAll.top = -1;
stack->stackMin.top = -1;
return stack;
}
void minStackPush(MinStack *obj, int x) {
//只判斷stackAll即可,stackMin的數據小於等於stackAll
if (obj->stackAll.top == (STACK_MAX - 1))
return;
//stackAll保存所有數據,都要入棧
obj->stackAll.data[++obj->stackAll.top] = x;
//stackMin保存最小數據,入棧前需要判斷棧頂值
if (-1 == obj->stackMin.top || x <= obj->stackMin.data[obj->stackMin.top]) {
obj->stackMin.data[++obj->stackMin.top] = x;
}
}
void minStackPop(MinStack *obj) {
if (obj->stackAll.top == -1)
return;
if (obj->stackAll.data[obj->stackAll.top] == obj->stackMin.data[obj->stackMin.top]) {
obj->stackMin.top--;
}
obj->stackAll.top--;
}
int minStackTop(MinStack *obj) {
return obj->stackAll.data[obj->stackAll.top];
}
int minStackGetMin(MinStack *obj) {
return obj->stackMin.data[obj->stackMin.top];
}
void minStackFree(MinStack *obj) {
free(obj);
}
結果
效果勉強湊活。還有沒有其他方法呢?
分析
上面的解法用了兩個棧,輔助棧的操作比較有限。所以其實一個棧就可以實現兩個棧的作用效果,當push時入棧兩個元素,分別是當前命令需要入棧的元素和棧中所有元素的最小值;出棧的時候同時出兩個元素,丟棄最小值元素,返回所需要的元素;獲取最小值時就需要返回棧中第二個元素。
還有一種是我在棧中記錄最小值,當元素進棧時判斷是否更新最小值,當元素出棧的時候,若出棧元素等於最小值,則進行更新最小值。
這兩種方法中,我感覺後者明顯更優秀,但是後者更新最小值的時候需要遍歷一遍棧中所有元素。代碼如下:
代碼2
typedef struct {
int val[10000];
int min;
int len;
int count;
} MinStack;
/** initialize your data structure here. */
MinStack* minStackCreate() {
MinStack* obj= (MinStack*)calloc(1,sizeof(MinStack));
obj->count = 0;
obj->len = 10000;
obj->min = INT_MAX;
return obj;
}
void minStackPush(MinStack* obj, int x) {
if(obj->count<obj->len){
obj->val[obj->count++] = x;
if(obj->min>x)
obj->min = x;
}
}
void minStackPop(MinStack* obj) {
if(obj->count>0){
obj->count--;
}
int x = INT_MAX;
for(int i = 0;i<obj->count;i++) {
if(obj->val[i]<x)
x = obj->val[i];
}
obj->min = x;
}
int minStackTop(MinStack* obj) {
if(obj->count>0)
return obj->val[obj->count-1];
return 0;
}
int minStackGetMin(MinStack* obj) {
if(obj->count>0)
return obj->min;
return 0;
}
void minStackFree(MinStack* obj) {
obj->count = 0;
obj->min = INT_MIN;
}
運行結果
效果還可以吧。