【刷题1】LeetCode 5. 最长回文子串 java题解

1.题目

在这里插入图片描述

2.方法一:暴力

时间复杂度O(N的三次方):这里 N 是字符串的长度,枚举字符串的左边界、右边界,然后继续验证子串是否是回文子串,这三种操作都与N相关;
空间复杂度:O(1),只使用到常数个临时变量,与字符串长度无关。

3.方法二:动态规划

3.1 分析

初始状态dp[i][i]=true。
如果c[i]!=c[j],返回false;
如果c[i]==c[j],要看i和j之间字串是不是回文串,如果字串也是,dp[i][j]=true。(转移方程dp[i][j]=dp[i+1][j-1])
边界情况:[i+1][j-1]长度小于等于1(即j-i<3),dp[i][j]必定为true。

保存结果:起始下标beginIndex和回文串长度maxLength。这样可以省去每次截取字串消耗的时间。等返回时再截取最终结果。

3.2 代码

class Solution {
    public String longestPalindrome(String s) {
        int len=s.length();
        if(len<2)
            return s;
        char[] charArray=s.toCharArray();
        boolean[][] dp=new boolean[len][len]; 
        int maxLength=1;//最长回文串的长度
        int begin=0;//最长回文串的起始下标
        //初始化
        for(int i=0;i<len;i++){
            dp[i][i]=true;
        }
        for(int j=1;j<len;j++){//枚举右边界
            for(int i=0;i<j;i++){//枚举左边界
            	//字符不相等
                if(charArray[i]!=charArray[j]){
                    dp[i][j]=false;
                    continue;
                }
                if(j-i+1<=3){//字串长度小于等于3,即中间只有一个数,必定可以
                    dp[i][j]=true;
                }
                else{
                    dp[i][j]=dp[i+1][j-1];
                }
                //更新最大值
                if((j-i+1)>maxLength&&dp[i][j]){
                    maxLength=j-i+1;
                    begin=i;
                }
            }
        }
        return s.substring(begin,begin+maxLength);
    }
}

3.3 复杂度

时间复杂度O(N²)
空间复杂度O(N²)

3.4 结果

在这里插入图片描述

4.方法三:中心扩散法

4.1 思路

边界情况即为子串长度为 1或 2的情况。我们枚举每一种边界情况,并从对应的子串开始不断地向两边扩展。如果两边的字母相同,我们就可以继续扩展,例如从 P(i+1,j-1) 扩展到 P(i,j);如果两边的字母不同,我们就可以停止扩展,因为在这之后的子串都不能是回文串了。

4.2 代码

class Solution {
    public String longestPalindrome(String s) {
        int len=s.length();
        if(len<2)
            return s;
        int maxLen=1;
        String maxStr=s.substring(0,1);//最短结果是第一个字符
        //将中心位置枚举到len-2即可
        for(int i=0;i<=len-2;i++){
                String a=find(s,i,i);//得到奇数长度
                String b=find(s,i,i+1);//得到偶数长度
                String str=a.length()>b.length()?a:b;
                if(maxLen<str.length()){
                    maxLen=str.length();
                    maxStr=str;
            }
        }
        return maxStr;
    }
    public String find(String s,int i,int j){
        int left=i;
        int right=j;
        int len=s.length();
        while(left>=0&&right<len&&s.charAt(left)==s.charAt(right)){
            left--;
            right++;
        }
        return s.substring(left+1,right);//因为最后[left]!=[right],所以left和right都不能取
    }
}
class Solution {
    public String longestPalindrome(String s) {
        if (s == null || s.length() < 1) {
            return "";
        }
        int start = 0, end = 0;
        for (int i = 0; i < s.length(); i++) {
            int len1 = expandAroundCenter(s, i, i);
            int len2 = expandAroundCenter(s, i, i + 1);
            int len = Math.max(len1, len2);
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return s.substring(start, end + 1);
    }

    public int expandAroundCenter(String s, int left, int right) {
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            --left;
            ++right;
        }
        return right - left - 1;
    }
}

复杂度

在这里插入图片描述

5. 方法四:马拉车

算法介绍

https://www.cxyxiaowu.com/2665.html
https://zhuanlan.zhihu.com/p/70532099

代码

class Solution {
    public String longestPalindrome(String s) {
        StringBuilder t=new StringBuilder();
        t.append("$#");
        for(int i=0;i<s.length();i++){
            t.append(s.charAt(i));
            t.append("#");
        }
        t.append("!");
        int imax=0,rmax=0,ans=0;
        int n=t.length();
        int[] f=new int[n];//以i为中心的字串数
        int start=1,end=0;//初始长度为0
        for(int i=1;i<n;i++){
            f[i]=(i<=rmax?Math.min(f[2*imax-i],rmax-i+1):1);
            while(i+f[i]<n&&i-f[i]>=0&&t.charAt(i+f[i])==t.charAt(i-f[i])){
                f[i]++;
            }
            //当前半径大于最长半径
            //更新中心点和最右点
            if(i+f[i]-1>rmax){
                imax=i;
                rmax=i+f[i]-1;
            }
            //当前长度大于最大长度,更新最大长度的起始点
            if(((rmax-imax)*2+1)>(end-start+1)){
                start=imax-(rmax-imax);
                end=rmax;
            }
        }
        StringBuilder res=new StringBuilder();
        for(int i=start;i<=end;i++){
            char c=t.charAt(i);
            if(c!='#')
                res.append(c);
        }
        return res.toString();
    }
}

复杂度

时间O(n):由于 Manacher 算法只有在遇到还未匹配的位置时才进行匹配,已经匹配过的位置不再匹配,因此对于字符串 S 的每一个位置,都只进行一次匹配,算法的复杂度为 O(N) 。
空间O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值