leetcode练习题5--最长回文子串

本文详细介绍了求解最长回文子串的多种算法,包括动态规划法、中部扩展法及Manacher's Algorithm等,深入探讨每种方法的原理与实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最长回文子串(longest Palindrome)

①longest common substring

将原字符串str1整个转置(reverse)得到str2,对str2的所有子字符串substr2,检查str1是否包含substr2,如果包含,这里要特别注意检查,substr2是否是一个回文串,例如str1=“bacac”,则str2=“cacab”,此时substr2=“cac”,正确,但是若str1=“eeecdfeee”,则str2="eeefdceee",此时substr2=“eee”,错误,所以对于substr2是否是回文串的检查是非常必要的。

要点:利用动态规划的方法找出原字符串和它转置后得到的字符串的“最长公共字符串”,同时要保证该“最长公共字符串”是一个回文串

以下是我的具体实现,leetcode上面说时间复杂度为O(n^2,然后我写了一下,一直是超时错误,不知道从哪里改进了〒_〒)

public String longestPalindrome(String s) {
        StringBuffer str1 = new StringBuffer();
//整个转置之后得到的字符串
StringBuffer str2 = new StringBuffer(s);
str2.reverse();
int[][] c = new int[2][s.length()+1];
int maxI=0;//当前最长公共子字符串的位置  
   int length=0;//最长公共子字符串的长度  
   for(int i = 1; i < s.length()+1; i++)    
   {    
       for(int j = 1; j < str2.length()+1; j++)    
       {    
           if(s.charAt(i-1)==str2.charAt(j-1))     
               c[1][j]=c[0][j-1]+1;             
           else    
               c[1][j]=0;  
 
           if(c[1][j]>length){ 
            if(s.substring(i-c[1][j],i).equals(str2.substring(s.length()-i,s.length()-i+c[1][j])))
              {
            length=c[1][j];                                              
               maxI=i;  
              }
           }  
       }   
       for(int k=0;k<str2.length()+1;k++)
            {
                c[0][k]=c[1][k];
                c[1][k]=0;
            }
       
   }  
  return s.substring(maxI-length, maxI).toString(); 

②暴力破解法(穷举所有的子串,并判断其是否是回文串),时间复杂度O(n^3),超时

③动态规划法,时间复杂度O(n^2)

 int length=s.length();  
   int maxlength=1;  
   int start =0;  
   boolean[][]P = new boolean[s.length()][s.length()];  
   for(int i=0;i<length;i++)//初始化准备  
   {  
       P[i][i]=true; //对称点为一个字母
       if(i<length-1&&s.charAt(i)==s.charAt(i+1))  
       {  //对称点为两个字母
           P[i][i+1]=true;  
           start=i;  
           maxlength=2;  
       }  
   }
   for(int len=3;len<=length;len++)//子串长度  
       for(int i=0;i<=length-len;i++)//子串起始地址  
       {  
           int j=i+len-1;//子串结束地址  
           if(P[i+1][j-1]&&s.charAt(i)==s.charAt(j))  
           {  
               P[i][j]=true;  
               maxlength=len;  
               start=i;  
           }  
       }  
       return s.substring(start,start+maxlength);

④中部扩展法(leetcode给出的简洁明了的代码)

public String longestPalindrome(String s) {
    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);
}

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

⑤Manacher's Algorithm

这个算法最大的亮点就是在每一个字符之间手动加入了一个#字符,包括字符串的头部和尾部。时间复杂度为O(n)

例如:str1="aba",预处理之后就变成了=》“#a#b#a#”,这样处理之后新的str1就只能是关于一个字母对称的字符串,不用考虑关于两个字母中心对称的情况,接下来要做的和④中部扩展法的大体相似,不过只需要考虑对称点为一个字母的情况

public String longestPalindrome(String s) {
    int start = 0, end = 0;
    for (int i = 0; i < s.length(); i++) {
        int len = expandAroundCenter(s, i, i);//对称点为一个字母
        if (len > end - start) {
            start = i - (len - 1) / 2;
            end = i + len / 2;
        }
    }
    return s.substring(start, end + 1);
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值