力扣 Top100 5. 最长回文子串

89 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目来源:leetcode-cn.com/problems/lo…

大致题意: 给一个字符串,求出其最长的回文子串

思路

可以直接使用动态规划,使用一个 n*n 的二维数组 dp[i][j] 表示 i - j 的子串是否是回文串

动态规划

使用 dp[i][j] 表示 i-j 的子串是否为回文串,那么

  • 若 i 位字符与 j 位字符不相等,显然不为回文串,dp[i][j] 为 false
  • 若 i 位字符与 j 位字符相等,若此时子串长度小于等于 3,则子串一定为回文串;否则 dp[i][j] 的值即为 dp[i+1][j-1] 的值

算法过程为:

  1. 使用 n*n 的二维布尔数组 dp[i][j] 表示 i - j 的子串是否是回文串,并存下目前的最长回文子串,初始时,dp[i][i] 为 true
  2. 从长度 2 遍历到长度 n
  3. 每次遍历,都遍历当前长度的所有子串,判断是否为回文串。遍历过程中,更新最长回文串

具体看代码:

public String longestPalindrome(String s) {
        int max = 1;    // 最长回文子串的长度
        int begin = 0;  // 最长回文子串的起始位置
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        // 初始化
        for (int i = 0; i < n; i++) {
            dp[i][i] = true;
        }
        // 遍历长度 2 至 n
        for (int len = 2; len <= n; len++) {
            // 遍历当前长度的所有子串
            // i 可以视为子串左边界
            for (int i = 0; i < n - len + 1; i++) {
                // j 可以视为子串右边界
                int j = i + len - 1;
                // 若边界处字符不等,一定不为回文串,跳过
                if (s.charAt(i) != s.charAt(j)) {
                    continue;
                }
                // 相等的情况
                // 若子串长度小于等于 3,一定为回文串
                if (j - i < 3) {
                    dp[i][j] = true;
                } else {    // 长度大于 3,是否是回文串与内部字符串相关
                    dp[i][j] = dp[i + 1][j - 1];
                }
                // 更新最长的回文串
                if (dp[i][j] && len > max) {
                    max = len;
                    begin = i;
                }
            }
        }
        return s.substring(begin, max + begin);
    }