leetcode链接 https://leetcode.com/problems/longest-palindromic-subsequence/
public class 最长回文子序列 {
// 1. 根据s 逆序生成s2 求s和s2的最长公共子序列即是最长回文子序列
public int longestPalindromeSubseq(String s) {
char[] chars = s.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = chars.length - 1; i > 0; i--) {
sb.append(chars[i]);
}
String s2 = sb.toString();
return longestCommonSubsequence2(s, s2);
}
public int longestCommonSubsequence2(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
return 0;
}
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
int[][] dp = new int[s1.length()][s2.length()];
dp[0][0] = str1[0] == str2[0] ? 1 : 0;
for (int i = 1; i < s1.length(); i++) {
dp[i][0] = str1[i] == str2[0] ? 1 : dp[i - 1][0];
}
for (int j = 1; j < s2.length(); j++) {
dp[0][j] = str1[0] == str2[j] ? 1 : dp[0][j - 1];
}
for (int i = 1; i < s1.length(); i++) {
for (int j = 1; j < s2.length(); j++) {
int p1 = dp[i - 1][j];
int p2 = dp[i][j - 1];
int p3 = str1[i] == str2[j] ? 1 + dp[i - 1][j - 1] : 0;
dp[i][j] = Math.max(p1, Math.max(p2, p3));
}
}
return dp[str1.length - 1][str2.length - 1];
}
public static int longestPalindromeSubseq2(String s) {
char[] chars = s.toCharArray();
return process(chars, 0, chars.length - 1);
}
private static int process(char[] chars, int l, int r) {
if (l == r) {
return 1;
}
if (l == r - 1) {
return chars[l] == chars[r] ? 2 : 1;
}
int p1 = process(chars, l + 1, r);
int p2 = process(chars, l, r - 1);
int p3 = process(chars, l + 1, r - 1);
int p4 = chars[l] == chars[r] ? 2 + process(chars, l + 1, r - 1) : 0;
return Math.max(Math.max(p1, p2), Math.max(p3, p4));
}
public static int longestPalindromeSubseq3(String s) {
char[] chars = s.toCharArray();
int[][] dp = new int[chars.length][chars.length];
dp[chars.length - 1][chars.length - 1] = 1;
for (int i = 0; i < chars.length - 1; i++) {
dp[i][i] = 1;
dp[i][i + 1] = chars[i] == chars[i + 1] ? 2 : 1;
}
for (int i = 2; i < chars.length; i++) {
int temp = i;
for (int j = 0; j < chars.length && temp < chars.length; j++,temp++) {
int p1 = dp[j + 1][temp];
int p2 = dp[j][temp - 1];
int p3 = dp[j + 1][temp - 1];
int p4 = chars[j] == chars[temp] ? 2 + dp[j + 1][temp - 1] : 0;
dp[j][temp] = Math.max(Math.max(p1, p2), Math.max(p3, p4));
}
}
return dp[0][chars.length - 1];
}
public static int longestPalindromeSubseq4(String s) {
char[] chars = s.toCharArray();
int[][] dp = new int[chars.length][chars.length];
dp[chars.length - 1][chars.length - 1] = 1;
for (int i = 0; i < chars.length - 1; i++) {
dp[i][i] = 1;
dp[i][i + 1] = chars[i] == chars[i + 1] ? 2 : 1;
}
for (int i = 2; i < chars.length; i++) {
int temp = i;
for (int j = 0; j < chars.length && temp < chars.length; j++,temp++) {
dp[j][temp] = Math.max(dp[j + 1][temp],dp[j][temp - 1]);
if(chars[j] == chars[temp]) {
dp[j][temp] = Math.max(dp[j][temp],2 + dp[j + 1][temp - 1]);
}
}
}
return dp[0][chars.length - 1];
}
/**
* i/j 0 1 2 3 4
* 0 1 1 1 3 5
* 1 x 1 1 3 3
* 2 x x 1 1 1
* 3 x x x 1 1
* 4 x x x x 1
*/
public static int longestPalindromeSubseq5(String s) {
char[] chars = s.toCharArray();
int[] dp = new int[chars.length]; // 使用一维数组来存储最长回文子序列的长度
dp[chars.length - 1] = 1; // 初始化最后一个字符为回文子序列的长度为1
for (int i = chars.length - 2; i >= 0; i--) {
int prev = 0; // 存储上一次迭代的dp[j]的值
dp[i] = 1; // 单个字符本身即为回文子序列,初始化为1
for (int j = i + 1; j < chars.length; j++) {
int temp = dp[j]; // 存储当前dp[j]的值
if (chars[i] == chars[j]) {
dp[j] = prev + 2; // 如果当前字符相等,则最长回文子序列长度增加2
} else {
dp[j] = Math.max(dp[j], dp[j - 1]); // 如果不相等,则取前一个字符和当前字符的最长回文子序列长度的较大值
}
prev = temp; // 更新prev为当前dp[j]的值
}
}
return dp[chars.length - 1]; // 返回整个字符串的最长回文子序列的长度
}
public static void main(String[] args) {
System.out.println(longestPalindromeSubseq4("12321"));
System.out.println(longestPalindromeSubseq5("12321"));
}
}