- 因为考试要考动态规划,所以研究了下算法,参考了网上许多资料,但是自己总结一次,印象会更加深刻。
- 源题目是输入character,这里换一个短点的,好分析一点,以bcdca为例。
- 以db[i][j]代表从字符索引i到字符索引j的最长回文子序列。当然db[0][4]就是指的bcdca的最长回文子序列。其实这个问题和最长公共子序列问题非常像。
- 接下来,我们考虑如何求db[0][4]的最长回文子序列。
我们很容易得到下面的递归程序
private static int getResult(char[] con, int i, int j) {
// TODO Auto-generated method stub
if (i==j) {
return 1;
}
if (i>j) {
return 0;
}
if (con[i]==con[j]) {
return getResult(con, i+1, j-1)+2;
}else {
return Math.max(getResult(con, i+1, j),getResult(con, i, j-1));
}
}
5.于是就通过递归算出了dp[0][4]=3,于是我们很容易得出下面这张表格。在这张表格中我们能查到dp[i][j]的任意值。这个代码实现部分就是两次循环。我会在后面给出来。
6.这里我们得到了最长子回文的长度,接下来就是如何把这个字符串求出来的问题。我们简单了分析一下思路,以dp[0][4]以例,这个其它就是2+1,这里面的2就代表着有首尾相等的情况,我们把这个首尾相等时的i和j求出来。不就得到了回文的字母吗?也就是说通过还原dp的求解过程。得到回文的字母。
7.代码如下,将输入换成character.
public class huiwen {
public static void main(String[] args) {
// TODO Auto-generated method stub
String con="character";
int[][] db=new int[9][9];
//生成二维数组表
for(int i=0;i<con.length();i++)
{
for(int j=i;j<con.length();j++)
{
db[i][j]=getResult(con.toCharArray(), i, j);
// System.out.println("db"+"["+i+"]"+"["+j+"]"+db[i][j]);
}
}
char[] res=new char[db[0][con.length()-1]]; //得到回文长度
int m=0; //m代表结果字符数组索引开始
int n=res.length-1; //n代表结果字符数组索引最后一位
char[] res1=con.toCharArray();
int i=0;
int j=con.length()-1;
int index=res.length-1; //得到循环次数
//还原dp的,从开头和结尾同时开始
while(index>=0)
{
if (i<con.length()&&db[i][j]==db[i+1][j]) {
i++;
}else if (j>=0&&db[i][j]==db[i][j-1]) {
j--;
}else {
//这种情况就代表dp[i][j]=dp[i+1][j-1]+2这种情况,这里的首和尾是相同的。取出首
//和尾的字符填充到结果字符数组中,然后i++,j--继续从两边向中间搜索。
res[m]=res1[i];
res[n]=res1[j];
i++;
j--;
m++;
n--;
index=index-2; //一次填充两个字符
}
}
//将结果字符数组生成字符串
System.out.println(String.valueOf(res));
}
private static int getResult(char[] con, int i, int j) {
// TODO Auto-generated method stub
if (i==j) {
return 1;
}
if (i>j) {
return 0;
}
if (con[i]==con[j]) {
return getResult(con, i+1, j-1)+2;
}else {
return Math.max(getResult(con, i+1, j),getResult(con, i, j-1));
}
}
}