一、題目:
一個只包含'A'、'B'和'C'的字符串,如果存在某一段長度為3的連續子串中恰好'A'、'B'和'C'各有一個,那么這個字符串就是純凈的,否則這個字符串就是暗黑的。例如:
BAACAACCBAAA 連續子串"CBA"中包含了'A','B','C'各一個,所以是純凈的字符串
AABBCCAABB 不存在一個長度為3的連續子串包含'A','B','C',所以是暗黑的字符串
你的任務就是計算出長度為n的字符串(只包含'A'、'B'和'C'),有多少個是暗黑的字符串。
AABBCCAABB 不存在一個長度為3的連續子串包含'A','B','C',所以是暗黑的字符串
你的任務就是計算出長度為n的字符串(只包含'A'、'B'和'C'),有多少個是暗黑的字符串。
輸入描述:
輸入一個整數n,表示字符串長度(1 ≤ n ≤ 30)
輸出描述:
輸出一個整數表示有多少個暗黑字符串
輸入例子:
2 3
輸出例子:
9 21
二、答案解析:
剛開始做這個題的時候,很容易跟着題意,一步步往下走,然后掉“坑”里邊,既然要求暗黑字符串的的個數,順着想下去,可以先求出長度的n的字符串總共有幾種組合方式,當然是3^n中,然后我們對各種組合進行遍歷,使用KMP算法進行字符串模式匹配,計算出純凈字符串的種數,最后由總個數減去純凈字符串的個數即可求得黑暗字符串的個數,這種做法的一個關鍵問題就是循環,而循環的層數就是n,試想當n足夠大時,循環還能正常進行嗎,當然不行了,很容易發生棧溢出的情況,導致整個算法失敗。
換個思路想,其實我們可以采用動態規划的方法去解決問題,動態規划問題的關鍵在於推導公式(又叫狀態轉移公式),一般的推導公式如下:
M表示與過去相關的狀態數,Ki表示對應狀態的系數。
在本題中要求出長度為n的暗黑串個數,我們假設只與長度n-1的暗黑串有關,從前一個往后擴展一位,就需要從ABC中選一個進行擴展,而要保證暗黑串,必然要考慮n-1狀態時,結尾兩個字符的值,當然只有相同和不同兩種情況,
有:f(n-1)=s(n-1)+d(n-1)(公式一)
1.如果結尾字符相同(用s(n-1)表示),那么要組成暗黑串,擴展位可以是ABC中的任意一種,即共有3*s(n-1)種;
2.如果結尾字符不同(用d(n-1)表示),那么要組成暗黑串,擴展位只可以是前兩位的一種,一共有2*d(n-1)種;
得出公式:f(n)=3*s(n-1)+2*d(n-1)(公式二),
根據公式一,有f(n)=2*f(n-1)+s(n-1)(公式三),
再看第一種情形,在3*s(n-1)中只有一種是保證n狀態時,結尾兩個字符相同,比如n-1的狀態是AA,那么只有擴展位為A時,滿足條件;
再看第二種情形,在2*d(n-1)中只有一種是保證n狀態時,結尾兩個字符不同,比如n-1的狀態時AB,那么只有擴展位為A時,滿足條件 ;
即有s(n)=s(n-1)+d(n-1);(公式四)
最后由公式一、三、四可得,f(n)=2*f(n-1)+f(n-2),即為狀態轉移公式,算法如下:


