leetcode 516. 最長回文部分列 (JAVA) ソリューション

トピックへのリンクhttps://leetcode.cn/problems/longest-palindromic-subsequence/description/?utm_source=LCUS&utm_medium=ip_redirect&utm_campaign=transfer2china

目次

タイトル説明:

激しい再帰:

動的プログラミング:


タイトル説明:

string を指定すると s 、その中で最長の回文サブシーケンスを見つけて、そのシーケンスの長さを返します。部分シーケンスは、一部の文字を削除するか、残りの文字の順序を変更せずに文字を削除しないことによって形成されるシーケンスとして定義されます。

例 1:

入力: s = "bbbb"
出力: 4
説明:可能な最長の回文サブシーケンスは "bbbb" です。

例 2:

入力: s = "cbbd"
出力: 2
説明:可能な最長の回文サブシーケンスは "bb" です。

ヒント:

  • 1 <= s.length <= 1000
  • s 小文字の英字のみで構成されます

この質問の知識ポイントは動的計画法ですが、動的計画法から直接話すと少し理解しにくいかもしれません。

したがって、この記事は暴力的再帰から動的プログラミングまでです。

タイトルから、この質問は不連続な回文部分文字列を探し、その最大シーケンスの長さを返していると結論付けることができます。

つまり、次のようになります。

a2b42a

の最長の回文サブシーケンスは次のとおりです: a2b2a または a242a。どちらも5 を返すため、どちらも受け入れられます。

激しい再帰:

まず、最長の回文部分列の長さを返す関数を作成しましょう。

//主函数
public int longestPalindromeSubseq(String s) {
        char[] str = s.toCharArray();
        return maxString(str, 0, str.length-1);
}

//假设该函数可以返回最长回文子序列的长度
public static int maxString(char[] str, int l, int r) {}

私たちが作成した maxString() メソッドは、str string [l, r] 間隔の最長の回文サブシーケンスの長さを返すことができます。

分析から次の結論が導き出されます。

2 つの特殊なケース:

  • まず、l と r が等しい場合、現時点では文字が 1 つだけであることが証明され、戻り値は 1 であることがわかります。
  • 入力配列に2 つの文字しかない場合、つまり l + 1 == r の場合 、2 つの文字が等しい場合は 2 を返し等しくない場合は 1 を返します

よくある状況:

  • どちらの文字も最長の回文部分列には存在しません例: a1221b -> 1221;
  • 右側の文字は、最長の回文部分列には存在しません。例: 1221b -> 1221;
  • 左側の文字は、最長の回文部分列には存在しません。例: a1221 -> 1221;
  • 両側の文字は、最長の回文サブシーケンスに存在します例: 1w221 -> 1221。

 この時点で、コードは次のように記述できます。

//主函数
public int longestPalindromeSubseq(String s) {
        char[] str = s.toCharArray();
        return maxString(str, 0, str.length-1);
}

//假设该函数可以返回最长回文子序列的长度
public static int maxString(char[] str, int l, int r) {
        //先判断两种特殊情况
        if (l == r){
            return 1;
        }
        if (l + 1 == r){
            return str[l] == str[r] ? 2 : 1;
        }
        //余下的四种情况
        int a1 = maxString(str, l + 1, r - 1);
        int a2 = maxString(str, l, r - 1);
        int a3 = maxString(str, l + 1, r);
        int a4 = str[l] == str[r] ? 2 + maxString(str, l + 1, r - 1) : 0;
        
        //因为题目要求返回最长序列长度  所以需要返回这四个的最大值
        return Math.max(Math.max(a1, a2), Math.max(a3, a4));
}

 この時点で、次のものを送信できます。

 失敗しましたが、エラー メッセージから、私たちの考え方が正しいことがわかります。

動的プログラミング:

再帰バージョンを取得したら、それに基づいて動的プログラミング バージョンを作成できます

 l と r だけがmaxString() メソッドの変数であり、両方の値の範囲が[0, str.length - 1] である ためです。

この時点で、 l と rのすべてのケースをリストする2 次元配列を作成し 、配列の添字の値 [0, str.length - 1] を返して答えを得ることができます。

長さがわずか 5 であると仮定すると、次のl 行、r 列の2 次元配列を作成できます。

public static int maxString(char[] str, int l, int r) {

        int[][] arr = new int[str.length][str.length];
        
}

 

フォームに入力する次の段階では、再帰関数に従って直接入力できます ( 「a1221」を例にします)。 

 

 

このとき、[0, 4] の位置の値が最終的な答えとなります。 

 各位置の関係に従って、再帰は次のように最適化されます。

public static int maxString(char[] str, int l, int r) {

        int[][] arr = new int[str.length][str.length];
        //因为不存在l < r的情况所以下三角的空间不用
        for (int i = 0; i < str.length; i++) {
            if (i == 0){//填第一条对角线
                int j = 0;
                while(j < str.length) {
                    arr[j][j] = 1;
                    j++;
                }
            }else if (i == 1) {//填第二条斜线
                int j = 1;
                while(j < str.length) {
                    arr[j - 1][j] = (str[j - 1] == str[j]) ? 2 : 1;
                    j++;
                }
            }else {//其他
                int j = i;
                int k = 0;
                while(j < str.length){
                    int a1 = arr[k + 1][j - 1];
                    int a2 = arr[k][j - 1];
                    int a3 = arr[k + 1][j];
                    int a4 = str[k] == str[j] ? 2 + arr[k + 1][j - 1] : 0;
                    arr[k][j] = Math.max(Math.max(a1, a2), Math.max(a3, a4));
                    j++;
                    k++;
                }
            }

        }
        return arr[0][str.length-1];
}

この時点で提出してください。 

 

おすすめ

転載: blog.csdn.net/2302_76339343/article/details/132278140