【算法面试宝典】最长回文子串 - LeetCode5

1 算法描述

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 

示例 2:

输入:s = "cbbd" 输出:"bb" 

示例 3:

输入:s = "a" 输出:"a" 

示例 4:

输入:s = "ac" 输出:"a" 

提示:

1 <= s.length <= 1000

s 仅由数字和英文字母(大写和/或小写)组成

2 解题思路

方案一:中心扩展法

        中心扩展法的思路是一次遍历字符串中的字符,以字符作为中心点像左右两侧扩展,左右两侧元素相等继续扩展,如果不相等或者一方扩展到字符串开头或结尾的位置,结束遍历并记下回文子串的长度,和最长的回文子串长度比较,留下最长的。

        中心扩展法会分两种情况,

情况一:子串长度是奇数,以中心点为中心对称,如下图所示:

情况二:子串长度是偶数,依次对称,如下图所示:

a,b,c,c,b,a是一个回文串,然而找不到对称中心,这样以一个元素为中心向两边扩展就不好用了,这里有一种比较方便的处理方式,就是对a,b,c,c,b,a进行填充,比如说用#进行填充,填充之后就又成了一个中心对称的回文串,因此对于一个串进行处理时,先进行扩充,这样可以使中心扩展时比较方便,不用对非中心对称的子串进行特殊处理。假设填充前的子串长度为 maxLen 那么扩充或的长度为:2 * maxLen+1,由这个关系也可以很方便的得到扩充前回文串的长度。

中心扩展法求最长回文子串长度的编码如下所示:

    /**
     * @Author boy
     * @Description 中心扩展法
     * @Date 2021/12/16 9:57 AM
     * @Param [str]
     * @return int
     */
    public static int PalindRomeSubString(String str){
        //字符中间插入 #
        StringBuffer sb = new StringBuffer();
        for (int i=0;i<str.length();i++){
            sb.append("#");
            sb.append(str.charAt(i));
        }
        sb.append("#");

        //字符串转化为字符数组
        char[] c = sb.toString().toCharArray();

        //最长回文子串的长度
        int maxLen = 0;

        //遍历逐个字符,以字符作为中心点向两边扩展,找到最长回文子串
        for (int i=0;i<c.length;i++){
            maxLen = Math.max(subpalidromelen(c,i),maxLen);
        }

        return maxLen;
    }

    /**
     * @Author boy
     * @Description 中心扩展函数
     * @Date 2021/12/16 10:02 AM
     * @Param [chs, i],chs为字符数组,i为中心扩展的中心位置
     * @return int
     */
    public static int subpalidromelen(char []chs,int i){
        int len = 0;//回文长度
        int left = i;//左指针
        int right = i;//右指针
        while (left>=0 && right<chs.length && chs[left]==chs[right]){
                left--;
                right++;
                len ++;
        }
        return --len;//填充之后的串,填充之前的回文子串值为len-1
    }

中心扩展法的时间复杂度是O(n^2),空间复杂度是O(1)。

方案二:动态规划

        解题思路:使用二维数组 f[i][j] 保存子串从i到j是否是回文子串,在求 f[i][j] 的时候如果 j-i >=2时,如果 f[i][j] 为回 文,那么 f[i+1][j-1] 也一定为回文,否则 f[i][j] 不是回文。如下图所示:

 动态规划递归方程:

 动态规划实现编码:

public int palindrome1(String str){
        char chs[]=str.toCharArray();
        int maxLen=0;
        boolean f[i][j]=new boolean[chs.length][chs.length];
        for(int j=0;j<str.length();j++)
        {
            f[j][j]=true;
            //一个元素肯定是回文串。
            for(int i=0;i<j;i++)
            {
                f[i][j]=(chs[j]==chs[i]&&(j-i<2||j>0&&f[i+1][j-1]));
                //如果chs[j]==chs[i]当串的长度小于等于2时,肯定是回文子串,如 1,1,就是回文串。
                //如果长度大于2时,则需要判断f[i+1][j-1]是不是回文。
                if(f[i][j])
                {                   
                    max_len=Math.max(max_len, j-i+1);
                }
                //max_len保存最大回文子串的长度。           
            }                       
        }
        return maxLen;
    }

猜你喜欢

转载自blog.csdn.net/u010482601/article/details/121969891