タイトル説明
https://leetcode-cn.com/problems/longest-palindromic-substring/
解決策(既存の問題-dp配列トラバーサルの順序はまだ明確ではありません)
初めてコードを渡す:
class Solution {
public String longestPalindrome(String s) {
//字符串,使用双指针,则使用二维数组
if(s==null) return null;
if(s.length()==0) return null;
if(s.length()==1) return s;
int[][]dp = new int[s.length()][s.length()];
//边界初始化
for(int i=0;i<s.length();i++){
for(int j=0;j<s.length();j++){
if(i>j)
dp[i][j] = 0;
else if(i==j)
dp[i][j] = 1;
}
}
int max = 0;
//递推
for(int i=s.length()-1;i>=0;i--){
for(int j=s.length()-1;j>=0;j--){
if(i<j){
if(s.charAt(i)==s.charAt(j) && dp[i+1][j-1]== j-i-1){
dp[i][j] = j-i+1;//当前的字符串就是一个回文串
}else
dp[i][j] = Math.max(
dp[i+1][j],Math.max(1,//注意,可能是1最大了
dp[i][j-1])
);
}
if(max<dp[i][j]){
max = dp[i][j];
}
}
}
if(max==1) return s.substring(0,1);
// System.out.println(dp[0][s.length()-1]+" "+max);
//在dp数组里面找到和dp[0][s.length()-1]相等的值,那么它就是此时的最长回文字串
for(int i=0;i<s.length();i++){
for(int j=0;j<s.length();j++){
if(i<j && dp[i][j]==j-i+1 && dp[i][j]==max){
//必须是该字串
//System.out.println(dp[0][s.length()-1]+" "+max+" "+i+" "+j);
return s.substring(i,j+1);
}
}
}//找不到,则不存在
return null;
}
}
2回目:
class Solution {
public String longestPalindrome(String s) {
//字符串,使用双指针,则使用二维数组
if(s==null) return null;
if(s.length()==0) return null;
if(s.length()==1) return s;
int[][]dp = new int[s.length()][s.length()];
//边界初始化
int max = 0;
//递推
for(int i=s.length()-1;i>=0;i--){
for(int j=s.length()-1;j>=0;j--){
if(i>j)
dp[i][j] = 0;
else if(i==j){
dp[i][j] = 1;
}else{
if(s.charAt(i)==s.charAt(j) && dp[i+1][j-1]== j-i-1){
dp[i][j] = j-i+1;//当前的字符串就是一个回文串
}else
dp[i][j] = Math.max(
dp[i+1][j],Math.max(1,//注意,可能是1最大了
dp[i][j-1])
);
}
if(max<dp[i][j]){
max = dp[i][j];
}
}
}
//if(max==1) return s.substring(0,1);
// System.out.println(dp[0][s.length()-1]+" "+max);
//在dp数组里面找到和dp[0][s.length()-1]相等的值,那么它就是此时的最长回文字串
for(int i=0;i<s.length();i++){
for(int j=0;j<s.length();j++){
if(i<=j && dp[i][j]==j-i+1 && dp[i][j]==max){
//必须是该字串
//System.out.println(dp[0][s.length()-1]+" "+max+" "+i+" "+j);
return s.substring(i,j+1);
}
}
}//找不到,则不存在
return null;
}
}
3回目:
class Solution {
public String longestPalindrome(String s) {
//字符串,使用双指针,则使用二维数组
if(s==null) return null;
if(s.length()==0) return null;
if(s.length()==1) return s;
int[][]dp = new int[s.length()][s.length()];
//边界初始化
int max = 0;
int start=0,end=0;
//递推
for(int i=s.length()-1;i>=0;i--){
for(int j=s.length()-1;j>=0;j--){
if(i>j)
dp[i][j] = 0;
else if(i==j){
dp[i][j] = 1;
}else{
if(s.charAt(i)==s.charAt(j) && dp[i+1][j-1]== j-i-1){
dp[i][j] = j-i+1;//当前的字符串就是一个回文串
if(dp[i][j]>max){
start = i;
end = j;
}
}else
dp[i][j] = Math.max(
dp[i+1][j],Math.max(1,//注意,可能是1最大了
dp[i][j-1])
);
}
if(max<dp[i][j]){
max = dp[i][j];
}
}
}
return s.substring(start,end+1);
}
}
4回目:
class Solution {
public String longestPalindrome(String s) {
//字符串,使用双指针,则使用二维数组
if(s==null) return null;
if(s.length()==0) return "";
if(s.length()==1) return s;
int[][]dp = new int[s.length()][s.length()];
//边界初始化
int max = 1;//最大值起码等于1
int start=0,end=0;
//递推
for(int i=s.length()-1;i>=0;i--){
for(int j=s.length()-1;j>=0;j--){
if(i>j)
dp[i][j] = 0;
else if(i==j){
dp[i][j] = 1;
}else{
if(s.charAt(i)==s.charAt(j) && dp[i+1][j-1]== j-i-1){
//之前的dp[i+1][j-1]本身就是回文串
dp[i][j] = j-i+1;//当前的字符串就是一个回文串,一定会有一个dp[i][j]会进到这里
if(dp[i][j]>max){
//只要进到这里,整体是回文串
start = i;
end = j;
max = dp[i][j];
}
}else//这里因为i<j,所以i+1<=j,dp[i+1][j]>=1,所以我们去掉了比较1
dp[i][j] = dp[i+1][j]>dp[i][j-1]?dp[i+1][j]:dp[i][j-1];
}
}
}
return s.substring(start,end+1);
}
}
問題があったことがわかりました:
コードテストに合格しましたが、
dp配列で理由がわかりません。最終的な計算結果dp [0] [s.length()-1]がmaxと等しくない場合があります。dp[i] [j]をs [iを意味するように明確に定義しました。 …j]最長の回文ストリング。
最後に、アイデアのデバッグに時間を費やし、問題を見つけました。
つまり、dp [i] [j-1]が計算されていない場合、それを使用して再帰的にdp [i] [j]を実行したので、j次元のトラバーサル方向が間違っているため、dp [0] [s.length()-1]は必ずしもmaxに等しくありません。しかし、なぜそれがテストに合格できるのか興味があります。
変更されたコード:
class Solution {
public String longestPalindrome(String s) {
//字符串,使用双指针,则使用二维数组
if(s==null) return null;
if(s.length()==0) return "";
if(s.length()==1) return s;
int[][]dp = new int[s.length()][s.length()];//dp[i][j]定义为从s[i..j]的最长回文串
//边界初始化
int max = 1;//最大值起码等于1
int start=0,end=0;
//递推
for(int i=s.length()-1;i>=0;i--){
//从图上可视化看出应该使用后序遍历
for(int j=0;j<s.length();j++){
if(i>j)
dp[i][j] = 0;
else if(i==j){
dp[i][j] = 1;
}else{
if(s.charAt(i)==s.charAt(j) && dp[i+1][j-1]== j-i-1){
//之前的dp[i+1][j-1]本身就是回文串
dp[i][j] = j-i+1;//当前的字符串就是一个回文串,一定会有一个dp[i][j]会进到这里
if(dp[i][j]>max){
//只要进到这里,整体是回文串
start = i;
end = j;
max = dp[i][j];
}
}else//这里因为i<j,所以i+1<=j,dp[i+1][j]>=1,所以我们去掉了比较1
dp[i][j] = dp[i+1][j]>dp[i][j-1]?dp[i+1][j]:dp[i][j-1];
}
}
}
//按理来说dp[0][s.length()-1]表示的是最大值,应该=max
return s.substring(start,end+1);
}
}