最长回文字串(Manacher算法)

1. 动态规划

struct huiwen{
    int start;
    int end;
};

char * longestPalindrome(char * s){
    
    long long int n;
    n=strlen(s);
    bool dp[n][n];
    //dp[i][j]表示从第i个字符到第j个字符组成的字符串是否为回文子串
    
    
    memset(dp, 0, sizeof(dp));
    
    for(int i=0;i<n;i++){
        dp[i][i]=true;
    }
    
    struct huiwen max; //记录最长回文字串的起始位置和终止位置
    max.start=0;
    max.end=0;
    
    for(int L=2;L<=n;L++){ //枚举长度
        for(int l=0;l<n;l++){ //枚举左边界
            
            int r=L+l-1;
            if(r>=n) break; //跳出一层循环
            
            
            if(l+1 <= r-1) //回文子串长度最小为3
                dp[l][r]= dp[l+1][r-1] && s[l]==s[r];
            else //回文子串长度为2
                dp[l][r]= s[l]==s[r];
            
            
            
            if(dp[l][r]){ //如果是回文子串
                if(L>(max.end-max.start+1)) { //如果这个回文子串更长,记录它的起始位置和终止位置
                    max.start=l;
                    max.end=r;
                }
            }
            
        }
    }
    s[max.end+1]='\0';
    //printf("max.start=%d max.end=%d\n",max.start,max.end);
    return &s[max.start];
}

2.中心扩展算法

struct huiwen{
    int start;
    int end;
};

struct huiwen expandAroundCenter(char *s, int left, int right){
    long long int n;
    n=strlen(s);
    
    while(left>=0 && right<n && s[left]==s[right]){
            left--;
            right++;
    }
    
    struct huiwen ans;
    ans.start=left+1;
    ans.end=right-1;
    
    return ans;
}

char * longestPalindrome(char * s){
    
    long long int n;
    n=strlen(s);
    
    struct huiwen max;
    max.start=0;
    max.end=0;
    
    struct huiwen res;
    for(int i=0;i<n;i++){
        res=expandAroundCenter(s, i, i);
        if((res.end-res.start)>(max.end-max.start))
            max=res;
        
        
        res=expandAroundCenter(s, i, i+1);
        if((res.end-res.start)>(max.end-max.start))
            max=res;

    }
    
    
    s[max.end+1]='\0';
    return &s[max.start];
}

3.Manacher算法(马拉车算法)

struct huiwen{
    int start;
    int end;
};


int SolveArm(char *s, int left, int right){ //求臂长
    long long int n;
    n=strlen(s);
    
    
    while(left>=0 && right<n && s[left]==s[right]){
        left--;
        right++;
    }
    
    
    return (right-left-2)/2; //[(right-1)-(left-1)]/2
}

//Manacher算法(马拉车算法)
//只针对长度为奇数的子串
struct huiwen Manacher(char *s){
    long long int n;
    n=strlen(s);
    
    int arm_len[n];
    struct huiwen ans;
    ans.start=0;
    ans.end=-1;
    
    int j=-1, j_add_arm=-1; //j是已得的回文子串能覆盖的最大范围
    for(int i=0;i<n;i++){
        int i_arm;
        
        if(j_add_arm>i){ //如果能覆盖到i
            int i_sym = 2*j-i; //i关于j镜面对称的位置为:j-(i-j)
            int min_arm = fmin( arm_len[i_sym], j_add_arm-i) +1 ;//最关键的一步!
            i_arm = SolveArm(s, i-min_arm, i+min_arm);//就不用从i开始扩展
        }
        
        else{
            i_arm = SolveArm(s, i, i);
        }
        
        arm_len[i]=i_arm;
        
        
        if(i+i_arm > j_add_arm){ //更新已得最长回文zi串 能覆盖的最大范围
            j=i;
            j_add_arm=i+i_arm;
        }
        
        if(i_arm*2+1 >= ans.end-ans.start+1){ //更新最长回文子串开始和结束的位置
            ans.start=i-i_arm;
            ans.end=i+i_arm;
        }
    }
    
    return ans;
}



char * longestPalindrome(char * s){
    long long int n;
    n=strlen(s);
    
    //插入#,对字符串进行预处理
    char s1[2*n+2];
    for(int i=0;i<n;i++){
        s1[2*i]='#';
        s1[2*i+1]=s[i];
    }
    s1[2*n]='#';
    s1[2*n+1]='\0';
    
    //printf("%s\n",s1);
    
    struct huiwen ans = Manacher(s1);
    //得到最长回文字串开始和结束的位置(有#号)
    
    //ans.start和ans.end处肯定对应的是#号
    //s1中第i个位置对应s1中第(i-1)/2个位置,即[i/2]取整
    int start=(ans.start+1)/2; 
    int end=(ans.end-1)/2;
    
    
    s[end+1]='\0';
    return &s[start];
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值