最长回文子串(le)

              最长回文子串(Longest Palindromic Substring

     问题描述:给一个字符串s,返回它的最长回文子串。

     问题解释:回文字符串有点类似于我们曾学过的回文联,比如“雾锁山头山锁雾,天连碧水碧连天”。比如s='abac', 输出 应该是'aba'。再比如说,ABCBA, 这个回文字符串的中心为C,长度为5。如果对此仍不理解,出门左转百度或者google,可以找到比较权威的定义。

    解决方案:

    一、蛮力法(brute force)   time complexity:O(n^3)

            这个就不上代码了,直接穷举所有情况,找到最长回文子串。


   二、动态规划(dynamic programming)    time complexity:O(n^2)

        动态规划的思想在于减少子问题的计算量,重点是分解成一个个子问题。

        我们定义P[i] [j]为Boolean 数组,当P[i] [j]为true的时候表示,s.substring(i,j+1)是回文串(s.substring(start,end)是截取s.charAt(start)到s.charAt(end-1)的子串);相反则表示不是回文串。

        并且P[i] [j]可以由P[i+1] [j-1]推导出,有:P[i] [j]= (P[i+1] [j-1] && s.charAt(i)==s.charAt(j))。

        分析这个表达式,比如对于s字符串ABBAC,P[1] [2]=true,P[0] [3]=(P[0+1] [3-1] && s.charAt(0)==s.charAt(3))

显然P[0] [3]也为true. 

       另外,动态规划的初始化为,P[i][i]=true   因为单个的字符满足回文要求;

                                                      P[i][i+1]=(s.charAt(i)==s.charAt(i+1))    两个相邻的字符要看是否相等

        则动态规划的递归实现如下:

        //Recursion 

        // Set P[][] as Boolean array 
public Boolean P(String s,int i,int j){
    s=this.s;
if (i==j) {P[i][j]=true; return P[i][j];}
if (j==(i+1)) {P[i][j]=(s.charAt(i)==s.charAt(j)); return P[i][j];}
P[i][j] = P(s,i+1,j-1) && (s.charAt(i)==s.charAt(j)); 
return P[i][j];
}

       然而递归规划如果用递归实现,虽然说理解简单,但是仍旧有相当大的重复计算量,可以采用循环的方式实现:

       //how to avoid unnecessary calculation
public void solve(){
//initialize the P[i][i] and P[i][i+1]
for(int i=0;i<s.length();i++){
P[i][i]=true;
if(i<s.length()-1) //avoid out of bound of array
if (s.charAt(i)==s.charAt(i+1))
   P[i][i+1]=true;
else P[i][i+1]=false;
}

//expand 
for(int len=3;len<=s.length();len++)
for(int i=0;i<s.length()&&i+len-1<s.length();i++){//avoid out of bound of array
int j=i+len-1;
if(i+1<s.length() && j-1>0 && P[i+1][j-1] && s.charAt(i)==s.charAt(j))
P[i][j]=true;
else P[i][j]=false;
}
}

        动态规划的时间复杂度分析:(1)初始化的时间复杂度为O(n)

                                                       (2)后面拓展的时间复杂度为O(n^2)

        所以总的时间复杂度为O(n^2)

    三、中心拓展法(Expand around center)     time complexity:O(n^2)

      这个先上代码,是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;
}
     对于主函数的For循环就是遍历字符串s,len1对应的是最长回文子串的中心为字符,len1对应另一种情况;

     对于函数expandAroundCenter就是,以for循环遍历到的字符x为中心,向两个方向扩展回文子串,直至不能得到更大的回文子串或者碰到字符串的边界。返回以x为中心的最长回文子串长度。

    当遍历结束后必能得到解。

    时间复杂度分析:对于for循环的每一个遍历的元素,调用了expandAroundCenter函数,而对于该函数拓展的最大长度不可能大于n,所以时间复杂度小于等于O(n^2)

    四、Manacher's Algorithm

   这个算法又叫马拉车,估计是音译的,不过确实形象,留在下一篇再讲。


ps:

给大家一个这个问题的leetCode链接:https://leetcode.com/problems/longest-palindromic-substring/solution/




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值