最长回文子串(Java 动态规划)Longest Palindromic Substring

Longest Palindromic Substring

LeetCode 原题,这里主要说一下自己的动态规划解法和思路,希望对大家理解这个有所帮助。

暴力解法为遍历所有子串,逐个判断是否是回文字串。
接下来我们来优化暴力解法,暴力解法的问题在于没有用到回文字串的特性,只是用了定义去检验一个字串是不是回文,所以这个题的题眼在于利用回文字串的特性。
如果一个字串是回文字串,那么去掉左右两边的字符之后依然是回文。
也可以说是一个回文字串,左右两边加上相同的字符,也是回文字串。
使用索引 ij 来表示一个字符串从索引 ij 的子串,则:

dp[i][j]表示索引i到j的子串是否是回文
dp[i][j] = true表示是回文,反之则为false

dp[i][i]只有一个字符,必是回文
关键点在于找到关系:dp[i][j] = dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
长的子串dp[i][j]依赖于短的子串dp[i + 1][j - 1],所以由短到长依次计算
1、先计算一个字符,全为true
2、再计算两个字符,如果两个字符一样则为true
3、然后计算大于三个字符,直到整个字符串

1、定义二维数组存储dp的结果值
2、单个字符(起点终点索引相同)全部为true
3、两个字符如果字符相同为true(注意数组不要越界)
4、依次循环三个字符、四个字符......
5、有起点索引 i,有子串长度 k 则可以得到终点索引 j (同样注意数组越界问题)
6、比较回文子串长度与保存的result长度

class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        boolean[][] dp = new boolean[len][len];//<1>
        String result = s.substring(0, 1);
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;//<2>
        }
        for (int i = 0; i < len - 1; i++) {
            dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1);//<3>
            if (dp[i][i + 1]) {
                result = s.substring(i, i + 1 + 1);
            }
        }        
        //<4>
        for (int k = 3; k <= len; k++) {
            for (int i = 0; (i + k) <= len; i++) {
                int j = i + k - 1;//<5>
                dp[i][j] = dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j);
                if (dp[i][j] && (j - i + 1) > result.length()) {//<6>
                    result = s.substring(i, j + 1);
                }
            }
        }
        return result;
    }
}

你可能感兴趣的:(最长回文子串(Java 动态规划)Longest Palindromic Substring)