題目描述
- 實現一個特殊的棧,在實現棧基本功能的基礎上,再實現返回棧中最小元素的操作。
- 要求push,pop,getmin的操作時間複雜度都是 1。
- 設計的棧類型可以使用現成的棧結構。
解題嘗試
- 自己最初的設想是在棧中增加一個成員變量min,用來記錄最小值,每入棧一個元素就把這個元素和min比較,如果小於min就更新min的值。
- 但是如果值爲min的那個最小元素出棧了,那麼就無法判斷當前棧中哪個元素最小,所以不可行。
解題方法1
- 除了實現基本功能的棧stack1之外,我們再定義一個棧stack2,用它來記錄每一步的最小值。
- 當stack1入棧了一個元素x,我們比較x與stack2的棧頂元素top的大小,如果x<=top,將x入棧到stack2,否則不進行處理。
- 當stack1出棧一個元素(棧頂)x,我們比較x與stack2的棧頂元素top的大小,如果x==top,將stack2也出棧,否則不進行處理。
- 這樣stack2的棧頂始終保存着stack1的最小值,實現getmin方法只需要返回stack2棧頂即可。
- 實現代碼
class stack{
private Stack<Integer> stack1;
private Stack<Integer> stack2;
stack(){
this.stack1 = new Stack<>();
this.stack2 = new Stack<>();
}
public void push(int x){
this.stack1.push(x);
if(this.stack2.empty() || x<=this.stack2.peek()){
this.stack2.push(x);
}
}
public Integer pop(){
if(this.stack1.empty()){
throw new RuntimeException("stack empty");
}
int e = this.stack1.pop();
if(e == this.stack2.peek()){
this.stack2.pop();
}
return e;
}
public Integer getmin(){
if(this.stack2.empty()){
throw new RuntimeException("stack empty");
}
return this.stack2.peek();
}
}
解題方法2
- 可以發現解題方法1中棧stack2中的元素數量少於stack1中元素數量,這樣每次出棧的時候都要將stack1的棧頂與stack2的棧頂比較一下。
- 我們也可以這樣實現,在stack1入棧的時候,如果入棧元素x大於stack2的棧頂,就將stack2的棧頂再次入棧到stack2。這樣可以使得stack2的元素數量與stack1是同步的,出棧的時候直接兩個棧都進行出棧就好了。
- 代碼如下:
class stack{
private Stack<Integer> stack1;
private Stack<Integer> stack2;
stack(){
this.stack1 = new Stack<>();
this.stack2 = new Stack<>();
}
public void push(int x){
this.stack1.push(x);
if(this.stack2.empty() || x<=this.stack2.peek()){
this.stack2.push(x);
}
if(x>this.stack2.peek()){
this.stack2.push(this.stack2.peek());
}
}
public Integer pop(){
if(this.stack1.empty()){
throw new RuntimeException("stack empty");
}
int e = this.stack1.pop();
this.stack2.pop();
return e;
}
public Integer getmin(){
if(this.stack2.empty()){
throw new RuntimeException("stack empty");
}
return this.stack2.peek();
}
}
- 兩個方法的基本思路是一樣的,都是使用stack2記錄stack1每一步的最小值,兩個方法的時間複雜度都爲1,空間複雜度都爲n。
- 唯一的區別是,方法1中stack2入棧時稍省空間,出棧時稍費時間。方法2中stack2入棧時稍費空間,入棧時稍省時間。