给一个字符串,找出它的最长的回文子序列的长度。例如,如果给定的序列是“BBABCBCAB”,则输出应该是7,“BABCBAB”是在它的最长回文子序列。 “BBBBB”和“BBCBB”也都是该字符串的回文子序列,但不是最长的。注意和最长回文子串的区别(参考:最长回文串)!这里说的子序列,类似最长公共子序列LCS( Longest Common Subsequence)问题,可以是不连续的。这就是LPS(Longest Palindromic Subsequence)问题。
最直接的解决方法是:生成给定字符串的所有子序列,并找出最长的回文序列,这个方法的复杂度是指数级的。下面来分析怎么用动态规划解决。
1)最优子结构
假设 X[0 ... n-1] 是给定的序列,长度为n. 让 L(0,n-1) 表示 序列 X[0 ... n-1] 的最长回文子序列的长度。
1. 如果X的最后一个元素和第一个元素是相同的,这时:L(0, n-1) = L(1, n-2) + 2 , 还以 “BBABCBCAB” 为例,第一个和最后一个相同,因此 L(1,n-2) 就表示蓝色的部分。
最直接的解决方法是:生成给定字符串的所有子序列,并找出最长的回文序列,这个方法的复杂度是指数级的。下面来分析怎么用动态规划解决。
1)最优子结构
假设 X[0 ... n-1] 是给定的序列,长度为n. 让 L(0,n-1) 表示 序列 X[0 ... n-1] 的最长回文子序列的长度。
1. 如果X的最后一个元素和第一个元素是相同的,这时:L(0, n-1) = L(1, n-2) + 2 , 还以 “BBABCBCAB” 为例,第一个和最后一个相同,因此 L(1,n-2) 就表示蓝色的部分。
2. 如果不相同:L(0, n-1) = MAX ( L(1, n-1) , L(0, n-2) )。 以”BABCBCA” 为例,L(1,n-1)即为去掉第一个元素的子序列,L(0, n-2)为去掉最后一个元素。
2)重复子问题
具体实例及实现代码如下所示:
/** * @Title: LPS.java * @Package dynamicprogramming * @Description: TODO * @author peidong * @date 2017-6-12 上午9:36:55 * @version V1.0 */ package dynamicprogramming; /** * @ClassName: LPS * @Description: 最长回文子序列 * @date 2017-6-12 上午9:36:55 * */ public class LPS { /** * * @Title: lpsRecursion * @Description: 利用递归求解LPS * @param seq 字符串 * @param i 起始位置 * @param j 终止位置 * @return * @return int * @throws */ public static int lpsRecursion(String seq, int i, int j){ //边界条件,只有一个元素 if(i == j) return 1; if(i > j) return 0; //只计算序列seq[i...j] //如果首尾相同 if(seq.charAt(i) == seq.charAt(j)) return lpsRecursion(seq, i+1, j-1) + 2; //首尾不同 return Math.max(lpsRecursion(seq, i, j-1), lpsRecursion(seq, i+1, j)); } /** * * @Title: lps * @Description:利用动态规划求解LPS * @param seq * @param n * @return * @return int * @throws */ public static int lps(String seq, int n){ //创建状态转移矩阵 int[][] tc = new int[n][n]; int temp; //初始化状态转移矩阵 for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ tc[i][j] = 0; } } for(int i = 0; i < n; i++) tc[i][i] = 1; //构建状态转移矩阵 for(int i = 1; i < n; i++){ temp = 0; //考虑所有连续的长度为i+1 的子串 for(int j = 0; j + i < n; j++){ //如果首尾相同 if(seq.charAt(j) == seq.charAt(j+i)) temp = tc[j+1][j+i-1]+2; else temp = Math.max(tc[j+1][j+i], tc[j][j+i-1]); tc[j][j+i] = temp; } } return tc[0][n-1]; } /** * @Title: main * @Description: TODO * @param args * @return void * @throws */ public static void main(String[] args) { // TODO Auto-generated method stub String seq = "acmerandacm"; int n = seq.length(); System.out.println("利用递归求解LPS结果:"+ lpsRecursion(seq, 0, n-1)); System.out.println("利用dp求解LPS结果:"+ lps(seq, n)); } }