题目要求
Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length of s is 1000.
Example 1:
Input:
"bbbab"
Output:
4
One possible longest palindromic subsequence is "bbbb".
Example 2:
Input:
"cbbd"
Output:
2
One possible longest palindromic subsequence is "bb".
现有一个字符串s,要求找出最长的回文子序列的长度。这里要注意,子序列和子字符串不同,允许序列中的元素不是连续的。
思路和代码
这是一道典型的动态规划的题目,假设我们已经知道数组中任意长度为i的子字符串的最长回文子序列长度,则可以推导出长度为i+1的子字符串的最长回文子序列长度。推导过程如下:
首先假设tmp[j-i][j]
记录了[j-i,j]
子字符串中的最长回文子序列长度,则对于[j-i-1, j]
我们可知一定会有两种情况
-
s[j-i-1]==s[j]
则最大的子序列长度等于tmp[j-i][j-1]+2
,即等于[j-i,j-1]
这个子字符串中的最大子序列长度加上2 -
s[j-i-1]!=s[j]
,则最大的子序列长度等于Math.max(tmp[j-i][j], tmp[j-i-1][j-1])
,即等于[j-i,j]
和[j-i-1,j-1]
两个子字符串中能够找出来的最大子序列长度。
代码如下:
public int longestPalindromeSubseq(String s) {
int[][] tmp = new int[s.length()][s.length()];
for(int i = 0 ; i<s.length() ; i++) {
for(int j = 0 ; j+i<s.length() ; j++) {
if (i==0) {
tmp[j][j+i] = 1;
}else if (s.charAt(j) == s.charAt(j+i)) {
if (i==1) {
tmp[j][j+i] = 2;
} else {
tmp[j][j+i] = 2 + tmp[j+1][j+i-1];
}
}else {
tmp[j][j+i] = Math.max(tmp[j][j+i-1], tmp[j+1][j+i]);
}
}
}
return tmp[0][s.length()-1];
}
一个空间复杂度的优化在于,我们只用一个一维数组存储以下标i为结尾的任意长度的子字符串的最长子序列,其中dp[j]
存储的是[j,i]
子字符串的最长子序列。那么,当计算下标为i+1结尾的任意长度的子字符串的最长子序列时,同样可以推导出来。
public int longestPalindromeSubseq2(String s) {
char[] str = s.toCharArray();
//dp[j]表示以j为开头的的[j~i]的最长回数子序列长度,当i=s.length-1时,则dp中存储了所有以j为开始最远到i的最长回数子序列长度
int[] dp = new int[str.length];
int max = 0;
for (int i=0; i<dp.length; i++) {
dp[i] = 1;
int maxSoFar = 0;
for (int j=i-1; j>=0; j--) {
int prev = dp[j];
if (str[i] == str[j]) {
dp[j] = maxSoFar + 2;
}
maxSoFar = Math.max(prev, maxSoFar);
}
}
for (int i : dp){
max = Math.max(max, i);
}
return max;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。