面試 16:棧的壓入壓出隊列(劍指 Offer 第 22 題)

咱們今天繼續來看看週五留下的習題:java

面試題:輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷二個序列是否爲該棧的彈出順序。假設壓入棧的全部數字均不相等。例如:壓入序列爲{1,2,3,4,5},那{4,5,3,2,1} 就是該棧的彈出順序,而{4,3,5,1,2} 明顯就不符合要求;面試

這道題仍是比較容易想到思路,很直觀的想法就是創建一個輔助棧,把輸入的第一個序列中的數字依次壓入該輔助棧,並按照第二個序列的順序依次從該棧中彈出數字。數組

提早想好測試用例

同樣是老方法,咱們先準備測試用例:學習

  • 傳入兩個 null,或者 1 個 null,或者空數組,此時應該不符合要求;
  • 傳入兩個不相等的數組,應該直接不符合要求;
  • 分別傳入題乾的示意值,他們應該分別知足和不知足要求;
  • 傳入單個數字,選擇一組知足要求的和一組不知足要求的;

思考程序邏輯

判斷一個序列是否是棧的彈出序列的規律:若是下一個彈出的數字恰好是棧頂數字,那麼直接彈出。若是下一個彈出的數字不在棧頂,咱們把壓棧序列中尚未入棧的數字壓入輔助棧,直到把下一個須要彈出的數字壓入棧頂爲止。若是全部的數字都壓入棧了仍然沒有找到下一個彈出的數字,那麼該序列不多是一個彈出序列。測試

然而有的小夥伴仍是容易被繞暈,這時候不妨咱們能夠直接做一個表格來模擬他們的壓棧出棧過程,數據就採用咱們題設中的數據吧~spa

用做圖和模擬數據更容易給面試官一個你是個喜歡思考的好同事喲~code

首先看看咱們正確的數據。it

判斷操做 操做 彈出數字
棧沒數據,push 數組還有數據、壓入 壓入 1  
棧頂是 1,不等於pop[0],push 數組還有數據、壓入 壓入 一、2  
棧頂是 2,不等於pop[0],push 數組還有數據、壓入 壓入 一、二、3  
棧頂是 3,不等於pop[0],push 數組還有數據、壓入 壓入 一、二、三、4  
棧頂是 4,等於pop[0],彈出數字 4 彈出 一、二、3 4
棧頂是 3,不等於pop[1],push 數組還有數據、壓入 壓入 一、二、三、5  
棧頂是 5,等於pop[1],彈出數字 5 彈出 一、二、3 5
棧頂是 3,等於pop[2],彈出數字 3 彈出 一、2 3
棧頂是 2,等於pop[3],彈出數字 2 彈出 1 2
棧頂是 1,等於pop[4],彈出數字 1 彈出   1

實際上咱們在草稿紙上並不須要作這麼標準的表格,只要能表現意思便可。io

咱們仔細觀察能夠得知,咱們判斷壓入仍是彈出甚至是得出肯定結論的標準是,先看當前棧頂元素和彈出的數字是否相等,若是相等則直接彈出;若是不相等則直接看看壓入數組中還有沒有元素,若是有則直接壓入到輔助棧;若是已經沒有數據則表明第二個序列不是第一個序列的彈出棧。table

編寫程序代碼

實際上咱們心中已經大概知道怎麼寫了。

private static boolean isPushStack(int[] push, int[] pop) { if (push == null || pop == null || pop.length != push.length) return false; Stack<Integer> stack = new Stack<>(); int j = 0; for (int i = 0; i < pop.length; i++) { // 第一步判斷棧頂元素是否和 pop[i] 相等 if (!stack.isEmpty() && pop[i] == stack.peek()) { // 若是相等則直接 pop() stack.pop(); } else { // 棧頂和 pop[i] 不相等,則判斷 push 數組還有沒有數據 // 若是 push 數組沒數據了,棧頂元素又不等於 pop[i],則說明不符合要求 if (j == push.length) return false; while (j < push.length) { // 若是還有數據,則直接 push stack.push(push[j]); ++j; // push 後繼續判斷棧頂元素是否和 pop[i] 相等; if (pop[i] == stack.peek()) { // 若是相等則彈出棧,而且推出內層循環 stack.pop(); break; } } } } return true; } 

驗證測試用例

寫畢代碼後,咱們得用本身事先準備的測試用例測試一下。

  • 測試 1 和測試 2 咱們已經考慮到了,這樣的狀況直接在功能以前就判斷,不符合條件的直接返回 false,測試經過。

  • 傳入{1,2,3,4,5} 和 {4,5,3,2,1}:

    1. 進入循環,i = 0,pop[i] = 4,直接進入 else 語句,開始 push 數據,一直 push 到 j = 3。
    2. 此時棧內元素爲 {1,2,3,4},push 裏面還剩下 {5}。由於 pop[0] 等於棧頂,因此進入 if 語句,彈出 4,退出 while 循環;
    3. i = 1,棧內元素爲{1,2,3},棧頂元素不等於 pop[1] = 5,進入 else 語句。push 數組還有數據,直接 push,結束後 j = 5,棧內元素爲 {1,2,3,5},棧頂恰好等於 pop[1],故彈出數字 5,退出 while 循環;
    4. i = 2,棧內元素爲{1,2,3},棧頂元素剛剛等於 pop[2] ,彈出數字 3;
    5. i = 3,棧內元素爲 {1,2},棧頂元素剛等於 pop[3],彈出數字 2;
    6. i = 4,棧內元素爲 {1},棧頂元素剛剛等於 pop[4],彈出數字 1;
    7. for 循環能直接執行結束,返回 ture,測試經過。
  • 傳入 {1,2,3,4,5} 和 {4,3,5,1,2}:

    1. 進入循環,i = 0,pop[i] = 4,因爲同上,因此直接進入到上面的步驟 3;
    2. 此時 i = 1,棧內元素爲 {1,2,3},由於棧頂元素等於 pop[1],彈出數字 3;
    3. i = 2,棧內元素爲 {1,2},棧頂元素不等於 pop[2],進入 else 語句,此時 push 數組還有元素 {5},因此進入 while 循環。push 後棧內元素爲 {1,2,5},棧頂元素等於 pop[2],因此彈出數字 5,退出 while 循環;
    4. i = 3,棧內元素爲{1,2},pop[3] = 1,和棧頂元素不相等,因此進入 else 語句,因爲 push 裏面已經沒有了元素,因此直接返回 false,測試經過。
  • 傳入 {1} 和 {2}:

    進入循環,i = 0,pop[i] = 2,進入 else 語句,不相等,直接進入 while 循環,push 後棧內元素爲 {1},棧頂元素和 pop[i] 不相等,此時 j = 1,不符合 while 循環條件。循環結束,外循環也結束,返回 true。測試不經過。

修復程序邏輯

因此咱們如今應該着重處理一下單個數字的狀況,分析後明顯能夠獲得,咱們要判斷這種狀況只須要再判斷結束 for 循環後棧內是否還有元素和 push 裏面仍是否有元素便可。

因此在最後增長一個條件判斷便可。

public class Test16 { private static boolean isPushStack(int[] push, int[] pop) { if (push == null || pop == null || pop.length != push.length) return false; Stack<Integer> stack = new Stack<>(); int j = 0; for (int i = 0; i < pop.length; i++) { // 第一步判斷棧頂元素是否和 pop[i] 相等 if (!stack.isEmpty() && pop[i] == stack.peek()) { // 若是相等則直接 pop() stack.pop(); } else { // 棧頂和 pop[i] 不相等,則判斷 push 數組還有沒有數據 // 若是 push 數組沒數據了,棧頂元素又不等於 pop[i],則說明不符合要求 if (j == push.length) return false; while (j < push.length) { // 若是還有數據,則直接 push stack.push(push[j]); ++j; // push 後繼續判斷棧頂元素是否和 pop[i] 相等; if (pop[i] == stack.peek()) { // 若是相等則彈出棧,而且推出內層循環 stack.pop(); break; } } } } // 增長判斷 if (!stack.isEmpty() && j == push.length) return false; return true; } public static void main(String[] args) { int[] push = {1, 2, 3, 4, 5}; int[] pop1 = {4, 5, 3, 2, 1}; int[] pop2 = {3, 5, 4, 2, 1}; int[] pop3 = {4, 3, 5, 1, 2}; int[] pop4 = {3, 5, 4, 1, 2}; System.out.println(isPushStack(push, pop1)); System.out.println(isPushStack(push, pop2)); System.out.println(isPushStack(push, pop3)); System.out.println(isPushStack(push, pop4)); int[] push1 = {1}; int[] pop5 = {2}; System.out.println(isPushStack(push1, pop5)); int[] push2 = {1}; int[] pop6 = {1}; System.out.println(isPushStack(push2, pop6)); } } 

上面在代碼邏輯上並無作多少操做,因此咱們只須要再傳入 {1} 和 {1} 測試就能夠了。

直接進入到 while 循環,push 後棧內元素爲 {1},由於棧頂元素剛剛等於 pop[0],因此推出數字 1。此後棧內無元素,因此直接返回 true。

總結

我親愛的小夥伴想必也必定在上面的分析中收穫到東西了吧,這也是南塵給你們的箴言。

  • 在思路不是很清晰的時候畫表或者畫圖來處理;
  • 在驗證測試用例的時候,必定從簡單的開始,好比上面,咱們其實更加建議先驗證單個數字的狀況。

拓展延伸

本次學習的方法將很是有效,不信你們能夠試試下明天的拓展題。

面試題:從上到下打印二叉樹的每一個結點,同一層按照從左到右的順序打印。例如數的結構以下:

​ 1
2 3
4 5 6 7

則依次打印 一、二、三、四、五、六、7

相關文章
相關標籤/搜索