天天看点

【leetcode.5】最长回文子串

                                                最长回文子串

一、要求

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。      

示例 2:

输入: "cbbd"
输出: "bb"      

二、解法

这里我们采用动态规划。

主要思路:

(1)声明一个布尔类型的二维数组dp,boolean[][] dp = new boolean[len][len],len为字符串s的长度,那么如果dp[i][j]为true时,则表示字符串s从第i个位置开始到第j个位置结束之间的子字符串为回文子串。

如:s="abac",那么此时dp声明为dp[4][4],那么dp[0][0],dp[1][1],dp[2][2],dp[3][3],dp[0][2]都为true,表示对应位置的字母都是回文子串,那么这里最大长度的回文子串为aba。

(2)如果dp[i][j]为true,那么dp[i+1][j-1]也必定为true,即“abba”为回文子串,那么“bb”也为回文子串。因此我们的状态转移方程为dp[i+1][j-1]=true&&s.charAt(i)==s.charAt(j)  =>  dp[i][j]为true。

(3)如果j-i<=2时,即可能为回文的字符串最大长度为3时,如果有s.charAt(i)==s.charAt(j),就直接断定dp[i][j]=true,并不需要dp[i+1][j-1]=true。即当s="abad",i=0;j=2,s.charAt(0)==s.charAt(2),则直接判定aba为回文字符串,即dp[0][2]=true。

(4)使用两层for循环,外层循环指示器i控制所求字符串的开始位置,内层循环指示器j控制所求字符串的结束位置。但不是简单的使得i从0开始,i++,j=i,j++,而是需要i从最大值开始,即字符串的长度-1开始,i--,j=i,j++,先求出小范围内下标大的dp情况,再求出大范围内下标小的情况,因为后者依赖前者。例如dp[0][3]依赖dp[1][2]的值。

三、代码演示

public String longestPalindrome(String s) {
        if (s == null || s.equals("")) {
            return "";
        }
        int len = s.length();
        boolean[][] dp = new boolean[len][len];
        int maxLen = 0;
        int start = 0;
        int stop = 0;
        for (int i = len - 1; i >= 0; i--) {
            for (int j = i; j < len; j++) {
                if ((s.charAt(i) == s.charAt(j)) && (j - i <= 2 || dp[i + 1][j - 1])) {
                    dp[i][j] = true;
                    if (maxLen < j - i + 1) {
                        maxLen = j - i + 1;
                        start = i;
                        stop = j;
                    }
                }
            }
        }
        return s.substring(start, stop + 1);
    }      

代码提交结果:

【leetcode.5】最长回文子串

四、复杂度分析

(1)时间复杂度