LeetCode 5 最长回文子串 Manacher(马拉车)算法 (C语言)

题目:

给你一个字符串 s,找到 s 中最长的回文子串。

示例1:

输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。

示例2:

输入:s = “cbbd”
输出:“bb”

示例3:

输入:s = “a”
输出:“a”

示例4:

输入:s = “ac”
输出:“a”

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

解题代码:

// 这个函数都能看懂
char * strSretreatment(char * s, int len){
    char *str    = (char *)malloc(len * sizeof(char));
    memset(str, 0x0, len * sizeof(char));
    str[len - 1] = '$'; // 防止越界
    str[0]       = '@'; // 防止越界
    for(int i = 1, j = 0; i < len - 1; i++){
        if(i % 2 != 0)
            str[i] = '#';
        else
            str[i] = s[j++];
    }
    return str;
}
char * longestPalindrome(char * s){

    if(strlen(s) == 1)
        return s;

    // 对字符串进行预处理
    int len    = 2 * strlen(s) + 3;
    // 预处理字符串
    char *str = strSretreatment(s, len);
    // 记录字符串每个位置的回文长度
    int *p = (int *)malloc(len * sizeof(int));
    // 标记最长回文串的中心点
    int mid = 0;
    // 标记最长回文串的最右端
    int right = 0;
    // 最长回文串的半径
    int maxLen = 0;
    // 最长回文串的中心
    int maxCenter = 0;

    for(int i = 1; i < len - 3; i++){

        /* 
            对我来说最难理解的地方:2*mid-i 是 i 相对于 mid 的对称点 因为是对称结构 所以p[2*mid-i] = p[i]
            如果i大于以mid为中心的回文串的右边界right 那就没有对称点 所以p[i] = 1
            如果p[2*mid-i] > right-i 说明只能对称到right-i的位置 所以p[i] = right - i
        */
        if(i < right)
            p[i] = p[2*mid-i] < (right-i) ? p[2*mid-i] : (right-i);
        else
            p[i] = 1;

        // 以中心点向两端扩散
        while(i-p[i] >= 0 && i+p[i] < len && str[i + p[i]] == str[i - p[i]]){
            p[i]++;
        }

        // i + p[i]表示当前所求位置回文串的又边界
        if(i + p[i] > right){
            right = i + p[i];
            mid = i;
        }
        //记录最长回文串的半径和中心位置
        if (p[i] > maxLen) {
            maxLen = p[i];
            maxCenter = i;
        }
    }
    // 原字符串中回文串起点(原字符串与预处理之后的字符串是二倍关系)
    int start = (maxCenter - maxLen) / 2;
    // 原字符串中回文串终点
    s[start + maxLen - 1] = '\0';
    s = s + start;

    return s;
}

吐槽:算法是真的牛,折磨了我好几天
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值