回文子串算法

法一:简单方法

            两层循环对字符串中所有的子串进行定位,进而判断是否是回文子串,复杂度O(n^3)。

           方法简单,易想到,但暴力,易超时。

       

 for(i=0;i<m;i++)
    {
        for(j=i;j<m;j++)
        {
            int ok=1;
            for(k=i;k<=i+(j-i)/2;k++)  // i,j定位,使用k扫描匹配
                if(s[k]!=s[i+j-k])  ok=0;
            if(ok && j-i+1>max)  {max=j-i+1;x=i;y=j;}  //最长更新
        }

    }

法二:动态规划

     还是使用两层循环对子串定位,b[i][j]表示以i,j 为边界的子串是否是回文。

     不同的是使用动态规划,通过子结构的递推关系来求取最优解,

       b[i][j] = (s[i]==s[j])&&isPa(b,i+1,j-1)        // i位置与j位置相同,则判断其去掉两边后的子串

      出口:  i==j  b[i][j]=1

     但是时间复杂度O(n^2),还是易超时

//b[m][m]中每个元素初始化为0
for(i = 0; i < m; i++)
  for(j = i + 1; j < m; j++)
    if(isPa(b, i, j) == 1 && j - i > mj - mi)
      mj = j; mi = i;

//isPa函数定义如下 
isPa(int b[] , int i, int j)
  if(b[i][j] != 0)
    return b[i][j];
  
    if(j <= i)
    b[i][j] = 1;
  else
    b[i][j] = (b[i] == b[j]) && isPa(b, i + 1, j - 1);
  return b[i][j];

法三:manacher算法

下面介绍manacher,复杂度O(n)。

由于回文分为偶回文和奇回文,为了统一处理,使用一个技巧,具体做法是:在字符串首尾,及各字符间各插入一个不相关字符,如#。这样保证了回文串都是奇数。

原串:abcdcbaf

下标 id

 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
拷贝串 # a # b # c # d # c # b # a # f #
数组p 1 2 1 2 1 2 1 8 1 2 1 2 1 2 1 2  

容易证明,p[id] - 1 就是回文子串在原串中的长度,如上例中,最长子串为 abcdcba ,长度为7,p[8] - 1 = 7。

算法关键在于如何求出p。

变量 MaxId 记录扫描串时所到达的最右边的下标;

id 记录扫描到最右边串时当前子串的中心;

这个是leetcode里面Longest Palindromic Substring的回答: 

#define min(a,b) (a) > (b)? (b): (a)
char* longestPalindrome(char* s) {
    char auxStr[2001];
    int i, p[2001] = {0}, MaxId = 0, id = 0, leng, j, start = 0;
    
   //拷贝数组
    auxStr[0] = '^';
    for (i = 0; s[i] != '\0'; ++i){
        auxStr[i+1+i+1] = s[i];
        auxStr[i+1+i] = '#';
    } 
    auxStr[i+1+i] = '#';
    auxStr[i+1+i+1] = '\0';

    for (i = 1; auxStr[i] != '\0'; i++){    //对每个元素扫描 i
        if (MaxId > i)    //MaxId回文串最右边界
            p[i] = min(MaxId - i, p[id + id  - i]);
        else
            p[i] = 1;
        while (auxStr[i + p[i]] == auxStr[i - p[i]])
            ++p[i];
        if (MaxId < i + p[i]){
            MaxId = i + p[i];
            id = i;
        }
        if (p[start] < p[i])
            start = i;
    }
    i = (start - p[start])/2;
    leng = p[start] - 1;
    for (j = 0; j < leng; ++i){
        auxStr[j++] = s[i];
    }
    auxStr[j] = '\0';
    return auxStr;
}

Longest Palindromic Substring
发布了46 篇原创文章 · 获赞 15 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/sinat_34686158/article/details/82183890
今日推荐