算法修炼Day57|647. 回文子串 ● 516.最长回文子序列

49 阅读2分钟

LeetCode:647. 回文子串 - 力扣(LeetCode)

1.思路

方法一:暴力解法:两层for循环分别做起始位置的定位,内层wile对区间内字符判断是否为回文子串。

方法二:中心扩展法,分别对奇数偶数位进行中心位的判断。

方法三:动态规划:

2.代码实现
// 方法一:暴力解法
class Solution {
    public int countSubstrings(String s) {
        int sum = 0;
        for (int i = 0; i < s.length(); i++) {
            for (int j = i; j < s.length(); j++) {
                String str = s.substring(i, j + 1); //[i, j + 1)左闭右开的区间
                int left = 0;
                int right = str.length() - 1;
                boolean bln = true;
                while (left < right) {
                    if (str.charAt(left) != str.charAt(right)) {
                        bln = false;
                        break;
                    }
                    left++;
                    right--;
                }
                if (bln) {
                    sum++;
                }
            }
        }
        return sum;
    }
}
// 方法二:中心扩展法
class Solution {
    public int countSubstrings(String s) {
        int sum = 0;
        // 中心扩展,可能以i为中心,也可能以 i 和 i + 1 为中心的扩展,分别对应字符串的奇数和偶数个
        for (int i = 0; i < s.length(); i++) {
            for (int j = 0; j <= 1; j++) {
                int left = i;
                int right = i + j;
                while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
                    left--;
                    right++;
                    sum++;
                }
            }
        }
        return sum;
    }
}
// 动规
class Solution {
    public int countSubstrings(String s) {
        // dp[i][j],表示 i 到 j 的字符是否为回文子串。[i, i+1, ..., j-1, j]
        boolean[][] dp = new boolean[s.length()][s.length()];
        int sum = 0;
        for (int i = s.length() - 1; i >= 0; i--) { // 从下往上遍历
            for (int j = i; j < s.length(); j++) { // 从左往右遍历
                if (s.charAt(i) == s.charAt(j)) {
                    if (j - i <= 1) {
                        sum++;
                        dp[i][j] = true;
                    } else if (dp[i + 1][j - 1]) {
                        sum++;
                        dp[i][j] = true;
                    }
                }
            }
        }
        return sum;
    }
}
3.复杂度分析

时间复杂度:O(n^2).

空间复杂度:O(n).

LeetCode:516. 最长回文子序列 - 力扣(LeetCode)

1.思路

子序列中的最大回文子串如果存在,一定是包含首尾位置的最大值。

dp定义:dp[i][j],表示从 i 到 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]);
}

遍历顺序:根据递推公式来,从左向右,从下向上。

初始化:dp[i][i] = 1;

2.代码实现
class Solution {
    public int longestPalindromeSubseq(String s) {
        int[][] dp = new int[s.length()][s.length()];
        for (int i = s.length() - 1; i >= 0; i--) {
            dp[i][i] = 1;
            for (int j = i + 1; j < s.length(); 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][s.length() - 1];
    }
}
3.复杂度分析

时间复杂度:O(n^2).

空间复杂度:O(n).