leetcode5 最长回文子串

2 篇文章 0 订阅
2 篇文章 0 订阅

leetcode5 最长回文子串(Manacher算法)

1.题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例:

输入: “babad”
输出: “bab”

注意: “aba”也是一个有效答案。

2.manacher算法

奇回文(如 aba)和偶回文(如abba)归一化处理
  • 在字符串s的前端添加 $** 字符防止越界(代码中有说明越界点),字符串s尾端已有 ‘\0’**
  • 添加#字符于字符串s各字符之间
    如abacddc
i01234567
s[i]abacddc\0
i0123456789101112131415
s_new[i]$#a#b#a#c#d#d#c#

* 参数设定
id 为当前最长回文串的中心
mx 为当前最长回文串的右边界
p[i] 为以i为中心的回文串半径
参考下图:
image

  • 关键点(动态规划思想)
    i 在当前最长回文子串内时( mx>i ),以 i 为中心的回文子串长度:

    p[i] = max > i ? min(p[2*id - i], mx-i) : 1;
    
    1. 要么等于其 关于id对称点j为中心的回文子串长度(前提:以j为中心的回文子串包含在当前最长回文子串内)
    2. 要么以其为中心的回文子串右端 超出mx ( 此时p[i]设为mx-i,且继续寻找边界 )

3.代码

string longestPalindrome(string s) {
        int max_str = 0; // 最长回文子串的长度
        int front_index; // 最长回文子串的起始位
        if(s.empty())
            return 0;

        // 初始化s
        string new_s;
        new_s.push_back('$');
        new_s.push_back('#');
        for(int i = 0; i < s.length(); i++)
        {
            new_s.push_back(s[i]);
            new_s.push_back('#');
        }

        vector<int> p(new_s.length());

        int id = 0;
        int mx = 0;
        for(int i = 1; i < new_s.length(); i++)
        {
            // p[i]为当前i位置回文子串的半径,回文子串长度为p[i] - 1
            // 加速方式(动态规划):p[i] = max > i ? min(p[2*id - i], mx-i) : 1;
            if(mx > i)
                p[i] = min(p[2*id - i], mx-i);
            else
                p[i] = 1;

            // 前后搜索,越界点
            while(new_s[i + p[i]] == new_s[i - p[i]])
                p[i]++;

            if(p[i] - 1 > max_str){
                front_index = (i - p[i] + 2)/2 - 1; // 一定是 #......# 的形式
                max_str = p[i] - 1;
            }
            if(p[i] + i > mx){
                mx = p[i] + i;
                id = i;
            }
        }

        return s.substr(front_index, max_str);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值