问题描述:
给定一个字符串,如果只能在后面添加字符,最少添加几个能让字符串整体都是回文串,并且把整个回文字符串输出。
思想
定义dp数组,dp[i][j]表示从i位置开始,j位置结束的子串要变成回文串需要添加几个字符 //i的取值范围 0~str.length() j的取值范围 0~str.length()。
范围上尝试模型i<=j,除了对角线以外,左下角部分都是无效区域 。对角线表示i=j时,也就是子串只有一个字符的时候需要添加的字符数为0 。对角线的上一条斜线表示两个字符时需要添加的字符数,两个字符相同则是0,不等则是1。
普通位置 i j
情况一: c[i]=c[j],也就是i,j位置字符相同,那么就看i+1到j-1子串需要添加几个字符变为回文串 。
情况二:c[i] != c[j] ,此时又分为两种:
1>,i位置先不管,看i+1~j的子串需求添加几个字符,最后在加上和i位置配对的1个。
2>,j位置先不管,看i~j-1的子串需要添加几个字符,最后在加上和j位置配对的1个。
1> 2>中选最小的
代码
public static int minAddCharNum(String str) {
if (str == null) {
return 0;
}
char[] c = str.toCharArray();
int[][] dp = getDP(c);
return dp[0][c.length - 1];
}
//定义dp数组,dp[i][j]表示从i位置开始,j位置结束的子串要变成回文串需要添加几个字符
//i的取值范围 0~str.length() j的取值范围 0~str.length()
public static int[][] getDP(char[] c) {
int[][] dp = new int[c.length][c.length];
//范围上尝试模型i<=j,除了对角线以外,左下角部分都是无效区域
//对角线表示i=j时,也就是子串只有一个字符的时候需要添加的字符数为0
//对角线的上一条斜线表示两个字符时需要添加的字符数,两个字符相同则是0,不等则是1.
for (int i = 0; i < c.length - 1; i++) {
dp[i][i + 1] = c[i] == c[i + 1] ? 0 : 1;
}
//普通位置 i j
//1. c[i]=c[j],也就是i,j位置字符相同,那么就看i+1到j-1子串需要添加几个字符变为回文串
//2. c[i] != c[j] ,此时又分为两种
// 1>,i位置先不管,看i+1~j的子串需求添加几个字符,最后在加上和i位置配对的1个。
// 2>,j位置先不管,看i~j-1的子串需要添加几个字符,最后在加上和j位置配对的1个。
// 1> 2>中选最小的
for (int j = 2; j < c.length; j++) {
for (int i = j - 2; i >= 0; i--) {
if (c[i] == c[j]) {
dp[i][j] = dp[i + 1][j - 1];
} else {
int p1 = dp[i + 1][j] + 1;
int p2 = dp[i][j - 1] + 1;
dp[i][j] = Math.min(p1, p2);
}
}
}
return dp;
}
public static String getPalindrome(String str) {
if (str == null || str.length() < 2) {
return str;
}
char[] chas = str.toCharArray();
int[][] dp = getDP(chas);
char[] res = new char[chas.length + dp[0][chas.length - 1]];
int i = 0;
int j = chas.length - 1;
int resl = 0;
int resr = res.length - 1;
while (i <= j) {
if (chas[i] == chas[j]) {
res[resl++] = chas[i++];
res[resr--] = chas[j--];
} else if (dp[i][j - 1] < dp[i + 1][j]) {
res[resl++] = chas[j];
res[resr--] = chas[j--];
} else {
res[resl++] = chas[i];
res[resr--] = chas[i++];
}
}
return String.valueOf(res);
}
public static void main(String[] args) {
String str = "AB1CD2EFG3H43IJK2L1MN";
System.out.println(minAddCharNum(str));
System.out.println(getPalindrome(str));
}