LeetCode最長の回文部分文字列
@author:Jingdai
@date:2020.11.13
トピックの説明(5つの質問)
文字列
s
を指定してs
、最長の部分文字列の回文を検索します。s
最大長は1000と想定できます。
サンプル入力
"babad"
サンプル出力
"bab"
注:「aba」も有効な答えです。
アイデアとコード
動的計画法
まず、動的計画法でこの問題を解決する方法を見てください。動的計画法にとって最も重要なことは、状態遷移方程式を見つけることです。文字列の場合、回文の場合は、その前後の1文字を(境界の問題を考慮せずに)削除しても、それでも回文です。つまり
s[i]-s[j]
、パリンドロームシーケンスの場合s[i+1]-s[j-1]
もパリンドロームシーケンスです。逆にs[i]-s[j]
、パリンドロームシーケンスが必要な場合はs[i]
、s[j]
同等であり、パリンドロームシーケンスである必要がありs[i+1]-s[j-1]
ます。ここで、二次元アレイを有する
isPalindrome
サブストリングが、パリンドロームで表すisPalindrome[i][j]
ようにtrue
代表s[i]-s[j]
パリンドロームストリング。その場合、状態遷移方程式は次のようになります。初期条件もすぐに利用できます。それは
i
、j
等しくisPalindrome[i][j]
なければならないときtrue
です。ここで注意すべき点は越え問題の順序は、ということである
isPalindrome[i][j]
必要性は、計算に使用するisPalindrome[i+1][j-1]
ことは、結果をisPalindrome[i+1][j-1]
最初に横断する必要があり、isPalindrome[i+1][j-1]
中にisPalindrome[i][j]
左下の位置、それが使用する権利1に左、上から下へ線ではないトラバースラインは、することができますここでトラバース。以下は特定のコードです。
public String longestPalindrome(String s) { if (s == null || s.length() == 0) return null; if (s.length() == 1) return s; char[] chars = s.toCharArray(); int len = s.length(); boolean[][] isPalindrome = new boolean[len][len]; for (int i = 0; i < len; i++) { isPalindrome[i][i] = true; } int longestLen = 1; int start = 0; int end = 0; for (int j = 1; j < len; j++) { for (int i = 0; i < j; i++) { if (j == i+1) { isPalindrome[i][j] = chars[i] == chars[j]; } else { isPalindrome[i][j] = isPalindrome[i+1][j-1] && chars[i] == chars[j]; } if (isPalindrome[i][j] && j-i+1 > longestLen) { longestLen = j-i+1; start = i; end = j; } } } return s.substring(start, end+1); }
中心拡散法
中心拡散法はその名の通り、各中心の回文の長さを求め、その長さから最長の戻りを見つける必要があります。
図に示すように、中心には2つの選択肢があり、1つは要素自体であり、もう1つは2つの要素間のギャップです。ここで我々が使用
left
し、right
2つの変数が表す場合left
とright
等しく、素子自体の代表である場合right=left+1
、中心は二つの要素の間隔を表します。中心を選択した後、各中心について、両側の文字が等しい場合は、中央の回文の長さに2を追加します。それ以外の場合は、直接戻ります。文字列全体のすべての中心をトラバースして、最大の長さを見つけて戻ります。
ここで注意すべきことの1つは、2つのセンターによって選択されたパリンドローム文字列の初期値が異なることです。コードを作成するときに判断する必要があります。
以下は特定のコードです。
public String longestPalindrome(String s) { if (s == null || s.length() == 0) return null; if (s.length() == 1) return s; char[] chars = s.toCharArray(); int start = 0; int end = 0; int longestLen = 1; int tempOddLen = 0; int tempEvenLen = 0; int tempMaxLen = 0; for (int i = 0; i < chars.length - 1; i++) { tempOddLen = palindromeLength(chars, i, i); tempEvenLen = palindromeLength(chars, i, i+1); tempMaxLen = tempOddLen > tempEvenLen ? tempOddLen : tempEvenLen; if (tempMaxLen > longestLen) { longestLen = tempMaxLen; start = i - (longestLen - 1) / 2; end = start + longestLen - 1; } } return s.substring(start, end+1); } public int palindromeLength(char[] s, int left, int right) { int len = 0; if (left == right) len = -1; while (left >=0 && right <= s.length - 1 && s[left] == s[right]) { left--; right++; len += 2; } return len; }