【Manacher算法】HDU 3068 最长回文

HDU 3068 最长回文

题目:

  • 一个字符串,问最大回文串的长度。

思路:

  • 字符串长度范围在110000以内,所以用动态规划O(n ^ 2)和中心扩展算法O(n ^ 2)会超时。所以我们用更快的Manacher算法O(n)。

Manacher Algorithm【O(n)】

  • 为了避免字符串 s 长度奇数偶数的讨论,我们在字符串两两字符间插入特殊字符‘#’,然后再在首位置插入特殊字符‘$’,形成新的字符串 t .
  • 引入数组radius[ i ]:表示以 i 为中心的最长回文子串的半径。例如:“abcba”,radius[ 2 ] = 3.
  • 引入mx:表示回文子串能延伸到的最右端的位置(回文子串不包括mx),mx更新:mx = radius[ i ] + i .
  • 引入id:能延伸到最右端的那个回文串的中心
  • 定义Center,Len:表示字符串 t 中,当前位置之前最长回文串的中心和以Center为中心的回文串的半径
    最后的答案:
  • 最长回文子串的起始位置 start = ( Center - Len ) / 2
  • 长度:Len - 1
  • 也就是:s.substr((Center - Len) / 2, Len - 1) .

radius[ i ]的更新

  • 第一种情况: 如果mx - i > radius[ (id << 1) - i ],那么说明以 t [ (id << 1) - i ]为中心的回文子串含于在以 t [ id ]为中心的回文子串中
  • 第二种情况: 否则,说明 t [ (id << 1) - i ]为中心的回文子串可能不完全含于在以 t [ id ]为中心的回文子串中

在这里插入图片描述

  • 因为关于 t [ id ]为中心的回文子串是关于id左右对称的。所以,在第一种情况下,以t [ i ]为中心的回文子串一定和以t [ (id << 1) - i ]为中心的回文子串相同,这时候radius[ i ] = radius[ (id << 1) - i ]
  • 而在第二种情况下,那么只能保证以t [ i ]为中心,mx - i 为半径的这一段子串,也就是和以t [ (id << 1) - i ]为中心的回文子串以t [ id ]为中心的回文子串中的那一部分相等,这时候radius[ i ] = mx - 1
  • 而当mx <= i 的时候,radius[ i ] = 1 .
  • 也就是: radius[i] = mx > i ? min(radius[id * 2 - i], mx - i) : 1;

题目AC_Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxN = 11e4 + 5;

int Manacher(string &s)
{
    int len = s.size();
    string t = "$#";
    for(int i = 0; i < len ; i ++ )
    {
        t += s[i];
        t += "#";
    }
    len = t.size();
    vector<int> radius(len, 0);
    int mx = 0, id = 0;
    int Len = 0, Center = 0;
    for(int i = 1; i < len; i ++ )//这里从1开始是因为我们字符串 t 的第一个字符是无效特殊字符'$'
    {
        radius[i] = mx > i ? min(radius[id * 2 - i], mx - i) : 1;
        while(i + radius[i] < len && i - radius[i] >=0 && t[i + radius[i]] == t[i - radius[i]])
            ++ radius[i];
        if(radius[i] > Len)
        {
            Center = i;
            Len = radius[i];
        }
        if(mx < i + radius[i])
        {
            mx = radius[i] + i;
            id = i;
        }
    }
    return Len - 1;
}

int main()
{
    string s;
    while(cin >> s)
        cout << Manacher(s) << endl;
    return 0;
}

输出最长回文串_Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxN = 11e4 + 5;

string Manacher(string &s)
{
    int len = s.size();
    string t = "$#";
    for(int i = 0; i < len ; i ++ )
    {
        t += s[i];
        t += "#";
    }
    len = t.size();
    vector<int>radius(len, 0);
    int mx = 0, id = 0, Len = 0, Center = 0;
    for(int i = 1; i < len; i ++ )
    {
        radius[i] = mx > i ? min(mx - i, radius[(id << 1) - i]) : 1;
        while(i + radius[i] < len && i - radius[i] >= 0 && t[i + radius[i]] == t[i - radius[i]])
            ++ radius[i];
        if(mx < i + radius[i])
        {
            mx = i + radius[i];
            id = i;
        }
        if(Len < radius[i])
        {
            Len = radius[i];
            Center = i;
        }
    }
    return s.substr((Center - Len) / 2, Len - 1);
}

int main()
{
    string s;
    while(cin >> s)
        cout << Manacher(s) << endl;
    return 0;
}

Manacher’s Algorithm 马拉车算法 详解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值