leetcode 5最長部分列問題のパリンドローム

タイトル説明

文字列sを考えると、最も長い部分文字列パリンドロームを見つけることです。あなたは1000秒の最大の長さと仮定することができます。

例1:

入力:「babad」
出力:「BAB」
注:「ABA」は有効な答えがあります。
例2:

入力: "cbbd"
出力: "BB"

 

 

暴力的な解決する方法:Siの場合に寸法N * Nアレイflage、flageを定義[i] [j]はSjとのパリンドローム配列,,,,,,、I、J端パリンドロームの長さの文字列で開始を表します、次いでflage [i] [j]は長さ、そうでなければ値0です。次いで、素子アレイの最大値を削除して戻り、それぞれのパリンドロームサブストリングをflage。この方法は、時間複雑度はO(N ^ 3)、空間的複雑度はO(1)であってもよい、(最良の結果のデータを保存する時、アレイの必要性を排除する)---複雑さが大きすぎるタイムアウトであります

 / **
     *メソッドの暴力
     *仮定flage [I] [J] I、J端パリンドロームの長さの文字列で始まるを表します。
     * iの長さサイズの回文配列の終わりに始まると全てのjを計算し、パリンドローム配列が0に設定されているではありません
     *
     * @Param 
     * @return 
     * / 
    パブリック文字longestPalindrome1(文字列S){

        // A [I] [j]はパリンドローム配列保存の長さがあれば0に直接ではなく、、、Iで文字列の末尾にJを開始を表す
        整数最大= 1、X = 0、Y = 0 ;
         int型 LEN = S.長さ();
         INT [] [] flage = 新しい新しい INT [LEN] [LEN];
         のためのINT ; I <LEN; I = 0 I ++)flage [I] [I] = 1 ;
         のためのINT I = 0。 I <lenは、I ++ ){

            int型 J ++; J <LEN J = I + 1 ){
                flage [I] [J] = TheLengthOfStr(s.substring(I、J + 1 ))。

                もし(MAX < flage [I] [J]){
                    最大 = flage [I] [J]。
                    X = I;
                    Y = J。
                }
            }
        }
        戻り s.substring(X、Y + 1 )。
    }

 

方法2:動的プログラミングは、本質的に暴力の方法の改良版であります

これは、配列P [I] [j]がパリンドローム配列かどうかをSjにシリコンを保存し、状態遷移方程式P [I] [J] = {P [I + 1] [J-1] &&のSi == Sjを}を使用している使用します、Pの初期条件[i]は[I] = 1、P [I] [I + 1] = Siの== S(I + 1)

二つの要素の回文文字列を探して起動し、三つの要素の回文文字列を検索し、四つの要素の回文文字列を見つけ、パリンドローム配列のk個の要素までこのように続けます。時間計算量はO(N ^ 2)であり、空間的な複雑さはO(N ^ 2)であります 

 パブリック文字列longestPalindrome2(文字列S){
         // 先初始化一位
        のchar [] cSubstr = s.toCharArray()。
        int型 maxValueの= 0 ;
        int型の低= 0、高い= 0 ;
        INT LEN = s.length()。
        ブール [] [] P = 新しい ブール[LEN] [LEN]。
        以下のためにINT I 0 =; I <LEN; I ++ ){
            P [i]は[I] = 

        }
        // k番目要素Pに2つの要素が[-J 1] [1-JK。] 
        ブール isFlage = falseに;
         のためint型のk = 1; K <LENあり、k ++ ){
            フロック = ;
            int型 ; J <LEN J ++ J = K {)
                P [J - K] [J] = cSubstr [J - K] == cSubstr [J] &&(K == 1 || P [J-K + 1] [J-1 ])。
                もし(P [J - K] [J] &&!isFlage){
                    maxValueの = K。 = J - K。
                    高い = J;
                    フロック = ;
                }
            }
        }
        戻り s.substring(ロー、ハイ+ 1 )。
    }

 

方法3:中央の拡張方法、実際には、すべての可能な中心点の列挙は、そう最大文字列長のパリンドロームを取得します。上記2例中心点が選択を考慮するように、パリンドローム配列の偶数または奇数の長さがあってもよいように。

パリンドローム配列の長さが偶数の場合、n-1個の可能な中心点があり、長さが奇数の場合、パリンドローム配列は、n個の可能な中心点があります。2N-1の状況、そのような焦点の合計がありました。時間計算量はO(N ^ 2)

 

 パブリック文字列longestPalindrome3(文字列S){
         int型 LEN = s.length();
         IF(LEN <= 1)リターンS; 
//は、上部最適と下限に対応するパリンドローム配列を表し、限界値を含む
intをスタート= 0、終了0 = ; のためのINT I = 0; I <LEN; I ++ ){
//奇数の場合
INT LEN1 = theLengthOfSubStr(S、私は、私は、LEN);
//でも
INT LEN2 theLengthOfSubStr =(S、I、I + 。1 、LEN); int型ル= Math.max(LEN1、LEN2); IF(ル>スタート- エンド){//新しい文字列の長さが長いパリンドローム、端部に対応するパリンドローム配列改変境界、スタートの場合 開始 = I - (LE-1)/ 2 = I + A / 2 } } 戻り s.substring(開始、終了+ 1 )。 } 公共 INT theLengthOfSubStr(文字列sは、INT、左INT右、INT LEN){ int型 L =左、R = 右。 一方、(L> = 0 && R <LEN && s.charAt(L)== s.charAt(R)){ R ++ ; L - ; } リターン R - L - 1 }

 

方法4:馬車法Manacher、KMPこのアプローチは、多少類似している二重カウントを避けることが知られている情報の一部を使用しています。このメソッドは、O(n)との時間複雑で非常に高速です。

このメソッドは、2つのヒントがあり、最初のサブストリングのパリティ回文長の問題を解決するための方法を使用して特殊文字を追加します。特殊文字のクロスボーダーの使用を防ぐために、表の2番目のポイント。

元の入力データがbabadであると仮定すると

最初のチップは、次に放置され、各要素の右側は「#」文字に追加されます。元のデータ長は、N、「#」文字が表示された数は、全データ長が奇数2N + 1となるように、N + 1であると仮定されます。

    #Bの## Bは##のD

第2の技術は本当にクロスボーダー小さなラベルを防ぐために、境界線の両端に特殊文字を追加します(コードが議論されます)

?#Bの## Bは##のD \ 0

いくつかの定義と概念

これは、[i]はCARRAY列アレイ、pは対称の中心として元素CARRAYパリンドローム配列[I]の最大半径を表します。IDは、左境界mlである右境界(包括的ではない)に対応する電流対称中心パリンドローム配列の最大長さに対応し、最大電流MXのパリンドローム配列を示しています。J = 2 * ID-iはIDがI対称の中心である場合に対応する対称点を表します。私たちは私の<mx、I、J、我々はjは左ボーダーJLで、[i]は、対応するPを見つけることが知られているP [j]を使用できるように、私たちが知っている対称P [J]の点に対応する、までJRの右の境界、これは二重計算を避けることができます。

我々は、対応するP [j]を算出する条件に応じて3つのケースに分けました

最初のケースでは、I <MX、j個のパリンドローム配列は、IDの外側の部分を有しています。この場合iは、Pを拡大し続けることができない[I] = P [J = 2 * ID-I]

IDの内側部分に第二ケースI <MX、j個のパリンドローム配列です。この場合iは、Pを拡大し続けることができない[I] = P [J = 2 * ID-I]

第三の場合は、iが<MX、Jパリンドローム配列がこの時点で左パリンドローム配列番号の一致の左端と一致p[i] = p[j]又はp[i] = mx - i、かつp[i]も増加し続けています。

次のように具体的なコードは

/ **
     *馬車車の方法の使用Menacher
     *
     * @Param Sのターゲット文字列
     * @return 
     * / 
    パブリック文字longestPalindrome4(文字列S){

        INT LEN = s.length()。
        もし(LEN <= 1)に戻り、S。
        など = 2 + 3 *のみチャー CARRAO [] = 新しい CHAR [だけ]。
        CARRAY [ 0] = '$' ;
        CARRAY [ 1] = '#' 
        CARRAY [lenは -1] = '\ n'は以下のためにint型 I = 2は、J = 0; iがLEN-1 <;私は= I + 2 ){
            CARRAY [I] = s.charAt(J ++ );
            CARRAY [I + 1] = '#' 
        }
        // P [I]ポイントCARRAYに保存されている[i]は、対称の中心の半径の最大長さである
        INT [] = P 新しい新しい INT [LEN];
         //は、最大半径の現在位置、存在する境界のMX現在の最大半径の中心位置を表します、MAXLENは、最大ランレングスパリンドローム
        のint = ID = 0、MX = 0、MAXLEN = -1、中-1 ;
         ためINT I = 1; I <-len 1; I ++ ){
             IF(I <MX){ // 対称P [I]求めるために使用できる 
                ( - 、MX P [I 2 ID *] - P [I] Math.min = I)を、
            } 他の
                P [I] = 1; // 長さ1
              両サイドには「$」と「\ 0」が追加されているので、境界を決定していない//オーバーフローを防ぎます
            一方(CARRAY [I - P [I]] == CARRAY [I + P [I]]){
                P [i]は ++ ;
            }
            // 更新現在の右端境界
            IF(I + P [I]> MX){
                MX = I + P [i]は、
                IDは = 私を。
            }
            System.out.println( + I + "P [I] =" + P [I] + "" "私は=" );
              // 。P [I] -電流の1 iが(パリンドローム配列の長さの中心であります削除#)
            IF(P [I] - 。1> MAXLEN){
                MAXLEN = P [I] - 1 
                メディア = I - MAXLEN。
            }

        }
        //現在の最良の回文配列の開始位置を表します
        培地 =中/ 2 

        戻り(培地、培地+ s.substring MAXLEN)。
    }

 

おすすめ

転載: www.cnblogs.com/09120912zhang/p/12585071.html