day57 ● 647. 回文子串 ● 516.最长回文子序列

73 阅读1分钟

回文子串和最长回文子序列都是比较经典的回文问题,而动态规划是解决这类问题的常用方法。本文将介绍如何使用动态规划解决这两个问题,并提供Java代码实现。

  1. 回文子串

1.1 问题描述

给定一个字符串,计算这个字符串中有多少个回文子串。

1.2 解法

定义dp[i][j]表示字符串从i到j是否为回文子串,如果是则dp[i][j]=true,否则为false。那么有以下递推式:

如果s[i] == s[j],且dp[i+1][j-1]为true,则dp[i][j]为true;

如果s[i] == s[j],且j-i<=2,则dp[i][j]为true;

否则dp[i][j]为false。

根据上述递推式,我们可以得到以下Java代码实现:

public int countSubstrings(String s) {
    int n = s.length();
    boolean[][] dp = new boolean[n][n];
    int count = 0;

    for (int i = n - 1; i >= 0; i--) {
        for (int j = i; j < n; j++) {
            if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) {
                dp[i][j] = true;
                count++;
            }
        }
    }

    return count;
}

时间复杂度为O(n^2),空间复杂度为O(n^2)。

  1. 最长回文子序列

2.1 问题描述

给定一个字符串,找到其中最长的回文子序列。

2.2 解法

定义dp[i][j]表示字符串从i到j中最长回文子序列的长度。那么有以下递推式:

如果s[i] == s[j],则dp[i][j] = dp[i + 1][j - 1] + 2;

否则dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1])。

根据上述递推式,我们可以得到以下Java代码实现:

public int longestPalindromeSubseq(String s) {
    int n = s.length();
    int[][] dp = new int[n][n];

    for (int i = n - 1; i >= 0; i--) {
        dp[i][i] = 1;
        for (int j = i + 1; j < n; j++) {
            if (s.charAt(i) == s.charAt(j)) {
                dp[i][j] = dp[i + 1][j - 1] + 2;
            } else {
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
            }
        }
    }

    return dp[0][n - 1];
}

时间复杂度为O(n^2),空间复杂度为O(n^2)。

总结:

回文子串和最长回文子序列都是使用动态规划解决的经典问题。使用动态规划可以求解这两个问题,并且时间复杂度和空间复杂度都为O(n^2)。