題目:定義棧的數據結構,請在該類型中實現一個能夠得到棧的最小元素的min函數。在該棧中,調用min,push及pop的時間複雜度都是O(1).
看到這個問題,我們的第一反應可能是每次壓入一個新元素進棧時,將棧裏的所有元素排序,讓最小的元素位於棧頂,這樣就能在O(1)時間得到最小元素了。但這種思路不能保證最後壓入的元素能夠最先出棧,因此這個數據結構已經不是棧了。
我們接着想到在棧裏添加一個成員變量存放最小的元素。每次壓入一個新元素進棧的時候,如果該元素比當前最小的元素還要小,則更新最小元素。面試官聽到這種思路之後就會問:如果當前最小的元素被彈出棧了,如何得到下一個最小的元素呢?
分析到這裏我們發現僅僅添加一個成員變量存放最小元素是不夠的,也就是說當最小元素彈出棧的時候,我們希望能夠得到次小元素。因此在壓入這個最小元素之前,我們要把次小元素保存起來。因此,在壓入這個最小元素之前,我們要把次小元素保存起來。因此我們可以把每次的最小元素都保存起來放到另一個輔助棧裏。
我們不妨舉幾個例子來分析一下把元素壓入或者彈出棧的過程。
從表4.1我們可以看出,如果每次都把最小元素壓入輔助棧,那麼就能保證輔助棧的棧頂一直都是最小元素。當最小元素從數據棧內彈出之後,同時彈出輔助棧的棧頂元素,此時輔助棧的新棧頂元素就是下一個最小值。
class ListNode<K>{
K data;
ListNode<K> nextNode;
}
public class MyStack<K> {
/**
* 定義棧的數據結構,請在該類型中實現一個能夠得到棧的最小元素的min函數
* 在該棧中,min、push、pop的時間複雜度都是O(1)
*/
public ListNode<K> head;
public int length;
public void push(K item){
ListNode<K> node = new ListNode<K>();
node.data = item;
node.nextNode = head;
head = node;
length++;
}
public K pop(){
if(head == null)
return null;
ListNode<K> temp = head;
head = head.nextNode;
length--;
return temp.data;
}
}
private MyStack<Integer> minStack = new MyStack<>();
private MyStack<Integer> dataStack = new MyStack<>();
public void push(Integer item){
dataStack.push(item);
if(minStack.length == 0 || item<=minStack.head.data){
minStack.push(item);
}else{
minStack.push(minStack.head.data);
}
}
public Integer pop(){
if(dataStack.length == 0 || minStack.length == 0){
return null;
}
minStack.pop();
return dataStack.pop();
}
public Integer min(){
if(minStack.length == 0){
return null;
}
return minStack.head.data;
}