出棧順序問題講解 藍橋杯

引言:最近刷數據結構的題,刷到一組元素入棧,他的出棧順序有可能是哪些時卡住,之前沒有關注此類問題,便寫下總結

先通過幾個例題講解下出棧順序問題

1.

一個棧的入棧序列是a,b,c,d,e則棧的不可能的輸出序列是:()

A edcba         B decba           C dceab            D abcde

 棧之根本——後進先出(Last In First Out , LIFO)初次接觸到這個問題的人,或許會認爲入棧abcde,所以出棧只能是edcba所以BCD都不對。

      其實是這個問題描述有歧義,應該是分段入棧的順序,也就是說,可能先入棧a,取出a,入棧b,取出b……,所以D也是可能的。

      知道這個意思了以後,就要明確這個問題的矛盾根本所在:第一次出棧d,說明什麼?說明a,b,c一定早已入棧(入棧順序決定的)。那麼在出棧d以後,a,b,c的出棧順序一定是c,b,a,而不用理會中間穿插着出棧了d後面的字符(因爲可以再入棧,再出棧嘛)。所以立即選中C,不用猶豫,理由簡單:d出棧了,abc一定已經入棧,那麼abc只能以cba的順序出棧,C不符合,OK!

舉一個更加直觀的例子:

如棧順序是:1 2 3 4 ,如何正確理解出棧?

    (1)入棧順序是1 2 3 4,就是指這四個數依次入棧:
             數據4入棧之前,1 2 3肯定已經入棧了;
             數據3入棧之前,1 2肯定已經入棧了,而4還沒入棧;
             數據2入棧之前,1肯定已經入棧了,而2 3 4還沒入棧;
             數據1最先入棧,2 3 4還沒入棧。
    (2)既然入棧順序是1 2 3 4,3 4入棧的時候,1 2 肯定已經入棧了,怎麼會在後面再入棧。
    (3)先拿4 3 1 2這個出棧序列來說,4最先出來,說明此時1 2 3(底到頂順序)還都在棧中;接下來只有3能出棧,3出來後,棧中爲1 2(底到頂順序);再接下來只有2能出棧,所以如果出棧序列前兩個是4 3的話,後兩個只能是2 1。再看個正確的出棧序列:2 4 3 1;2最先出來,說明它出來時,3 4還沒入棧,而1已入棧且還在棧中;接着是4出來,說明此時3也在棧中(3要比4先入棧),此時棧中有1 3(底到頂順序);然後只能

總之,挨個看出棧序列的數據,根據入棧順序,分析它出來時,棧中應該還有誰,而有誰還沒入棧,然後分析此時可不可能是它出棧。

下面針對藍橋杯問題,編程來進行分析。 

題目:

X星球特別講究秩序,所有道路都是單行線。一個甲殼蟲車隊,共16輛車,按照編號先後發車,夾在其它車流中,緩緩前行。

    路邊有個死衚衕,只能容一輛車通過,是臨時的檢查站,如圖所示。

    X星球太死板,要求每輛路過的車必須進入檢查站,也可能不檢查就放行,也可能仔細檢查。

    如果車輛進入檢查站和離開的次序可以任意交錯。那麼,該車隊再次上路後,可能的次序有多少種?

    爲了方便起見,假設檢查站可容納任意數量的汽車。

    顯然,如果車隊只有1輛車,可能次序1種;2輛車可能次序2種;3輛車可能次序5種。
    現在足足有16輛車啊,親!需要你計算出可能次序的數目。

 

分析題意:此題的類型爲N個元素的出棧問題,題意爲16個元素的出棧順序有多少種。

 

我們把n個元素的出棧個數的記爲f(n), 那麼對於1,2,3, 我們很容易得出:

                                    f(1)= 1     //即 1

                                    f(2)= 2     //即 12、21

                                    f(3)= 5     //即 123、132、213、321、231

然後我們來考慮f(4), 我們給4個元素編號爲a,b,c,d, 那麼考慮:元素a只可能出現在1號位置,2號位置,3號位置和4號位置(很容易理解,一共就4個位置,比如abcd,元素a就在1號位置)。

分析:

 1) 如果元素a在1號位置,那麼只可能a進棧,馬上出棧,此時還剩元素b、c、d等待操作,就是子問題f(3);

 2) 如果元素a在2號位置,那麼一定有一個元素比a先出棧,即有f(1)種可能順序(只能是b),還剩c、d,即f(2),    根據乘法原理,一共的順序個數爲f(1)* f(2);

 3) 如果元素a在3號位置,那麼一定有兩個元素比1先出棧,即有f(2)種可能順序(只能是b、c),還剩d,即f(1),

根據乘法原理,一共的順序個數爲f(2) * f(1);

 4) 如果元素a在4號位置,那麼一定是a先進棧,最後出棧,那麼元素b、c、d的出棧順序即是此小問題的解,即        f(3);

結合所有情況,即f(4) = f(3) +f(2) * f(1) + f(1) * f(2) + f(3);

爲了規整化,我們定義f(0) = 1;於是f(4)可以重新寫爲:

f(4) = f(0)*f(3) + f(1)*f(2) + f(2) * f(1)+ f(3)*f(0)

然後我們推廣到n,推廣思路和n=4時完全一樣,於是我們可以得到:

f(n) = f(0)*f(n-1) + f(1)*f(n-2) + ... +f(n-1)*f(0)

方法二:

      但這只是一個遞推公式(若編程實現,需要維護一個一維數組,時間複雜度爲O(n^2))。怎麼把它轉化爲通項公式呢,複雜度僅爲O(1)?


於是上網搜索一下,原來真的有這麼一個公式:C(2n,n)/(n+1) (C(2n,n)表示2n裏取n),並且有個名字叫Catalan數。附上wiki的鏈接,寫得太詳細了: http://en.wikipedia.org/wiki/Catalan_number  


現在的問題就是:怎麼從上述的遞推公式求出C(2n,n)/(n+1) ? 有興趣的朋友歡迎留言討論!

我抽象了下問題,在知乎上問了個問題,其中有一個答案提出了“折現法”,從幾何上推出了“n個元素進棧有多少個出棧順序”這個問題的答案是C(2n,n)-C(2n,n-1),化簡一下即得Catalan number。推薦大家看一看。

代碼:

public class Main {
 
	// 不用管出站後車的數量和順序,因爲進站順序和出站順序已經決定出站時的排序
	static int fun(int a, int b) {// a是等待進站的數目,b是站中的數目
		if (a == 0)// 此時已全部進站,出站時的順序只有一種
			return 1;
		if (b == 0)// 此時車站爲空,只能讓車進站
			return fun(a - 1, 1);
		// 有兩種走法:1、讓一輛車進站 ;2、讓一輛車出站
		return fun(a - 1, b + 1) + fun(a, b - 1);
	}
 
	static int fun(int a) {
		return fun(a, 0);
	}
 
	public static void main(String[] args) {
		System.out.println(fun(16));
	}
}

答案:35357670

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章