这里写自定义目录标题
- 马拉车算法
- 剑指 Offer II 020. 回文子字符串的个数
马拉车算法
马拉车算法可以以接近线性时间判断计算回文串长度,遍历每一个中心点,再向两遍扩充
- 填充字符
 其中$ ! 作为边界,添加#可以避开对偶数回文串的讨论,所有回文串都是奇数回文串
| 原字符串 | 填充后字符串 | 
|---|---|
| abba | $#a#b#b#a#! | 
| aba | $#a#b#a#! | 

 当考虑以
    
     
      
       
        i
       
      
      
       i
      
     
    i为中心点的字符串时,
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       f[i]
      
     
    f[i]为以
    
     
      
       
        i
       
      
      
       i
      
     
    i为中心点的回文串的半径,
    
     
      
       
        R
       
       
        m
       
       
        a
       
       
        x
       
      
      
       Rmax
      
     
    Rmax为当前回文串的最大右端点,
    
     
      
       
        N
       
       
        o
       
       
        d
       
       
        e
       
      
      
       Node
      
     
    Node为相应中心点,
    
     
      
       
        i
       
      
      
       i
      
     
    i和
    
     
      
       
        j
       
      
      
       j
      
     
    j是以
    
     
      
       
        N
       
       
        o
       
       
        d
       
       
        e
       
      
      
       Node
      
     
    Node为中心点的回文串中对应部分
-  初始化 
 利用回文串的特性进行初始化, i i i和 j j j(也就是图中蓝色方块)是相等的,所以可以直接用 f [ j ] f[j] f[j]初始化 f [ i ] f[i] f[i]
 j = 2 ∗ n o d e − i j=2*node-i j=2∗node−i
 初始化(要考虑边界情况)
 f [ i ] = ( i < R m a x ) ? m i n ( f [ j ] , R m a x − i + 1 ) : 1 f[i]=(i<Rmax)?min(f[j],Rmax-i+1):1 f[i]=(i<Rmax)?min(f[j],Rmax−i+1):1
-  向外扩展 
 继续向两边判断是否还有相等的字符
-  维护Rmax和Node 
-  一些细节: 
 回文串的半径为 f [ i ] − 1 f[i]-1 f[i]−1 因为在匹配中一定是停止于#符号 例如#a#b#b#a# 所以半径减1,或者说 f [ i ] f[i] f[i]的半径中包括了中心点和最后的#号,在上面的例子中半径为 #b#a#
 求回文串个数时要除以2,因为有#号
剑指 Offer II 020. 回文子字符串的个数
class Solution {
public:
    int countSubstrings(string s) {
        string t="$#";
        int f[2005],rmax=1,node=1,ans=0;
        int i;
        int n=s.length();
        for(i=0;i<n;i++){
            t+=s[i];
            t+='#';
        }
        t+='!';
        int m=t.length();
        // cout<<t<<endl;
        for(i=1;i<m-1;i++){
            f[i]=(i<=rmax)?min(f[2*node-i],rmax-i+1):1;
            while(t[i-f[i]]==t[i+f[i]])f[i]++;
            if(rmax<i+f[i]-1){
                rmax=i+f[i]-1;
                node=i;
            }
            ans+=f[i]/2;
        }
        return ans;
    }
};



















