2012-09-28 64 views
1

如何維護堆棧,以便每當從堆棧彈出時知道堆棧中的最小元素?該算法應該有一個恆定的複雜性在java中維護堆棧的算法

在此先感謝

+3

Errmm,[你嘗試過什麼??](http://mattgemmell.com/2008/12/08/what-have-你試過/) – Sujay

+3

這聽起來像是一個面試問題。 (特別是,這是我申請加入Google時的面試問題。)您嘗試過什麼?這裏的背景是什麼? –

+1

此外,只是添加@JonSkeet提到的,顯然,一點點「谷歌」 - 給你很多提示,以解決這個問題,以及:) – Sujay

回答

3

好吧,這裏就是你需要做的..

你需要保持一定的data structure包含插入關於每個元素的信息,究竟是什麼minimum並在當你插入的元素時second minimum值..

所以,你想擁有的信息是這樣的: -

每個元素推 - 插入後>

  • 最小值插入前
  • 最小值

將需要此信息時,您pop從堆棧中的元素。所以,你就知道不管你是否是popping最小值或不是。如果是的話,那麼你可以在推送這個元素之前用minimum value替換當前的minimum值。如果沒有,那麼在minimum中將沒有變化當時價值..

對於如: -

假設目前你有以下元素堆棧: -

[3, 5, 7, 9, 2, 4] 
  • 你推值8 ..然後你有兩個值來維護。 (在推入8之前的最小值,即2,以及在插入8 之後的最小值,即2): -

    min_value_before_push = min(stack) 
    push 8 
    min_value_after_push = min(stack) 
    
  • 如果你把一個值1,則minimum_before_insertion是2, 和minimum_after_insertion爲1: -

    min_value_before_push = 2 
    min_value_after_push = 1 
    

現在你的籌碼是: -

[1, 8, 3, 5, 7, 9, 2, 4] 

現在,如果你pop,你會看到,value 1: -

min_value_before_push = 2 
    min_value_after_push = 1 

所以,啪會改變的最小值,所以在您更改爲1 minimum_value_before_push目前的最低值。所以,你又是最低2 ..

您當前的堆棧變爲: -

[8, 3, 5, 7, 9, 2, 4] 

現在,讓我們檢查這個算法是否適用於duplicate元素: -

假設你想再次推value 2 ..

min_value_before_push = 2 
min_value_after_push = 2 

然後你繼續和pop,你看到value 2min_value_after_push是2,所以這意味着它突然出現將改變最小值。所以你替換min_value_before_push這個值,這也是2 ..這是我們想要的東西..

注意: - 一個好處這種算法是,你不需要做太多比較..只是一個current_minimum_value同時推動。而比較current_minimum_value比較,當你pop ..

您可以嘗試進行作何感想data structure能你有..

+0

你是否彈出這裏的最小元素 – Jayy

+2

@KaipaMSarma ..OP問題並沒有說我們需要彈出最小元素..它說,我們需要找到什麼是我彈出後的最小元素元素從堆棧..我認爲這是非常明確的問題.. –

+0

我喜歡O(1)插入。聰明的stackploitation。 –

1

使用其他例如minStack,當按下一個元素val時,檢查是否val < minStack.peek(),如果是,則將val也推到minStack;當從stack彈出時,檢查彈出的值,如pop_val,如果pop_val == minStack.peek()minStack.pop()

現在我們有一個minStack在特定的時間點保持所有的local-min-element(直到下一次按minStack時),我們可以通過檢查堆棧的頂端是local-min-element,已經在上面介紹過了。

但是,只有當所有的元素都是唯一的時候,這個方法才能正常工作,否則,這樣做會更困難,提示,使用計數器:)。

2

聲明:禁止使用null值(就像ArrayDeque一樣),並且不經過嚴格測試。

import java.util.ArrayDeque; 

public class PessimisticStack<T extends Comparable<? super T>> { 

    private class Entry { 
     private Entry(T t, T minNow) { 
      this.t = t; 
      this.minNow = minNow; 
     } 
     private final T t; 
     private final T minNow; 
    } 

    private final ArrayDeque<Entry> deque; 

    public PessimisticStack() { 
     deque = new ArrayDeque<Entry>(); 
    } 

    public PessimisticStack(int initialCapacity) { 
     deque = new ArrayDeque<Entry>(initialCapacity); 
    } 

    public void push(T t) { 
     if (t == null) throw new NullPointerException(); 
     Entry entry = null; 
     if (deque.isEmpty()) { 
      entry = new Entry(t, t); 
     } 
     else { 
      T prevMinimum = deque.peek().minNow; 
      T newMinimum = null; 
      if (t.compareTo(prevMinimum) < 0) { 
       newMinimum = t; 
      } 
      else { 
       newMinimum = prevMinimum; 
      } 
      entry = new Entry(t, newMinimum); 
     } 
     deque.push(entry); 
    } 

    public T pop() { 
     return deque.pop().t; 
    } 

    public T getMinimum() { 
     Entry entry = deque.peek(); 
     return (entry == null ? null : entry.minNow); 
    } 
} 

使用示例

PessimisticStack<String> stack = new PessimisticStack<String>(); 

stack.push("Zebra"); 
stack.push("Elephant"); 
stack.push("Bryan"); 
stack.push("Adam"); 
stack.push("Calvin"); 

String calvin = stack.pop(); 

// "Adam" 
System.err.println(stack.getMinimum()); 

stack.push("Aaron"); 

// "Aaron" 
System.err.println(stack.getMinimum()); 

String aaron = stack.pop(); 

// "Adam" 
System.err.println(stack.getMinimum()); 

String adam = stack.pop(); 

// "Bryan" 
System.err.println(stack.getMinimum()); 
+0

我沒有排序堆棧。我維護一個單獨的排序LinkedList。堆棧順序始終保留,不會影響LinkedList排序,它完全基於Comparable行爲,並且根本不按推送順序執行...運行示例:) –

+0

@Joe ..是的,您是對的..剛剛看到你正在維護包含你的'Inner'類'Entry'實例的堆棧..這有點不同.. +1 .. –

+0

@Rohit你的插入具有更好的時間複雜性,巧妙地利用堆棧行爲,所以我更新了我的代碼因此(有一個小的差異,我不跟蹤以前的最低限度;我從頭偷看得到它) –