好久没有刷题了,虽然参加过ACM,但是始终没有融会贯通,没有学个彻底。我干啥都是半吊子,一瓶子不满半瓶子晃荡。
就连简单的Manacher算法我也没有刷过,常常为岁月蹉跎而感到后悔。

问题描述

给定一个字符串s,求最长回文子串。
回文子串的回文指的是abccba这种从前往后读和从后往前读一样。
子串必须连续(比如从i到j,s[i:j]),不是最长子序列(最长回文子序列怎么求?),子序列是可以不连续的。

算法大意

ans[i]表示以字符i为中心的最长回文子串的长度
now表示now+ans[now]取得最大值的那个下标
对于当前字符i,如果i处在以now为中心的回文子串里,那么ans[i]的求法可以参考i关于now的对称点的回文子串长度,也就是ans[now-(i-now)].
例如:1j34now67i9,假设ans[j]=1,那么ans[i]也等于1,因为i和j都处在以now为中心的回文子串里面,它们是对称的。

上面所述即为算法关键,其余情形很容易自己想到。
但是Manacher算法用到了两个技巧

加#号,统一处理

ans[i]中记录的是以i为中心的最长回文子串,如果不作处理,这样只能够检测出长度为奇数的回文子串的最大长度。所以有一个巧妙的预处理。
给定字符串abcc,扩充成#a#b#c#c#。
#a#b#a# 长度为3,以字符为中心的情况
#a#a#a#a# 长度为4,以#为中心的情况
这样奇数偶数统一化处理。

首部加上一个怪异字符$,减少条件判断

如果在for循环中检测两个条件,那是很费事的,效率低。
如何判断一个条件有很多次无效的判断?就看这个条件发挥作用,影响程序分支的次数和进行条件求值的次数。
边界条件判断影响分支的次数很少,但却每次都要进行判断。
通过加上一个终止字符,就能够避免边界条件判断。
在Manacher算法中,要求回文子串同时要防止下标越界。所以直接在开头插入一个\$字符,这样肯定因为失配而终止。

复杂度分析

Manacher算法为线性复杂度,因为从前往后有一个指针一直是单方向运动,没有回溯。
对于数组中的多个指针,如果都是单向运动,尽管它们运动的顺序和步长不同,那也一定是线性复杂度。

代码

#include<stdio.h>
#include<iostream>
using namespace std;
const int N = 110009;
char s[N];
char a[N * 2];
int ans[N * 2];
int now;
int main(){
    freopen("in.txt", "r", stdin);
    while (scanf("%s", s) != -1){
        if (s[0] == 0)continue;
        //#号法预处理
        int j = 0;
        a[j++] = '$';//这样就能少判断一点,不用考虑边界问题了
        for (int i = 0; s[i]; i++){
            a[j++] = '#';
            a[j++] = s[i];
        }
        a[j++] = '#';
        //开始算法主体部分
        now = 1;
        ans[0] = ans[1] = 0;
        for (int i = 2; i < j; i++){
            if (now + ans[now] < i){//如果当前字符不在阴影里,只能自力更生
                int k = i;
                while (a[k] == a[i - (k - i)]) k++;
                ans[i] = k - i - 1;
                now = i;
            }
            else{
                int right = now - (i - now);
                if (right - ans[right]>now - ans[now]){
                    ans[i] = ans[right];
                }
                else{
                    int k = now + ans[now];
                    while (a[k] == a[i - (k - i)])k++;
                    ans[i] = k - i - 1;
                    now = i;
                }
            }
        }
        //寻找答案,这部分可以直接放在求ans的过程中
        int ma = 0;
        for (int i = 1; i < j; i++){
            if (ma < ans[i])ma = ans[i];
        }
        printf("%d\n", ma);
    }
    return 0;
}

最长回文子序列

动态规划:复杂度都是O(n^2)
方法一:
a[i,j]表示s[i,j]之间最长回文子序列。则a[i,j]可以来自a[i+1,j-1],a[i-1,j],a[i,j-1].
方法二:
将s和s反过来得到的字符串求最长公共子序列

HDU3068 回文串 Manacher算法的更多相关文章

  1. 最长回文---hdu3068 (回文串 manacher 算法模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3068 题意很清楚:就是求一个串s的子串中最长回文串的长度:这类题用到了manacher算法 #incl ...

  2. luoguP4555 [国家集训队]最长双回文串 manacher算法

    不算很难的一道题吧.... 很容易想到枚举断点,之后需要处理出以$i$为开头的最长回文串的长度和以$i$为结尾的最长回文串的长度 分别记为$L[i]$和$R[i]$ 由于求$R[i]$相当于把$L[i ...

  3. bzoj 2565: 最长双回文串 manacher算法

    2565: 最长双回文串 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem. ...

  4. 37:密码截取(回文串manacher算法)

    题目描述:Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解.比如 ...

  5. 【BZOJ2565】最长双回文串 (Manacher算法)

    题目: BZOJ2565 分析: 首先看到回文串,肯定能想到Manacher算法.下文中字符串\(s\)是输入的字符串\(str\)在Manacher算法中添加了字符'#'后的字符串 (构造方式如下) ...

  6. UESTC-1975弗吉桑(回文串,manacher算法)

    弗吉桑 Time Limit: 3000 MS     Memory Limit: 64 MB Submit Status 弗吉桑是一座横跨清水河大草原的活火山,位于子科技大学主楼东北方约 80km ...

  7. 回文串--Manacher算法(模板)

    用途:在O(n)时间内,求出以每一个点为中心的回文串长度. 首先,有一个非常巧妙的转化.由于回文串长度有可能为奇数也有可能为偶数,说明回文中心不一定在一个字符上.所以要将字符串做如下处理:在每两个字母 ...

  8. Palindrome(最长回文串manacher算法)O(n)

     Palindrome Time Limit:15000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit ...

  9. 九度OJ 1528 最长回文子串 -- Manacher算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1528 题目描述: 回文串就是一个正读和反读都一样的字符串,比如"level"或者"n ...

随机推荐

  1. html+ccs3太阳系行星运转动画

    做一个太阳系八大行星的运转动画,不包括行星的卫星,所有行星围绕太阳公转,行星采用纯色,暂时没有自转. 效果静态图: 动画中包括:太阳及各行星,运行轨道,行星公转动画. 先画好草图,设计好大小和位置,根 ...

  2. Entity Framework 教程——EF体系结构

    EF体系结构 下图是一张EF体系结构的全景图,让我们单独了解各个组件的用处. EDM (Entity Data Model): EDM由3个主要部分组成,概念模块(Conceptual Model), ...

  3. C#开发微信门户及应用(23)-微信小店商品管理接口的封装和测试

    在上篇<C#开发微信门户及应用(22)-微信小店的开发和使用>里面介绍了一些微信小店的基础知识,以及对应的对象模型,本篇继续微信小店的主题,介绍其中API接口的封装和测试使用.微信小店的相 ...

  4. (原创)解决.net 下使用uploadify,在火狐浏览器下的error 302

    简单粗劣说下哈,通过uploadify中flash在火狐下上传,造成了erroe 302, 是因为其session丢失,并修改了其sessionID. 网上有很多案列,可并没有这么直接.感觉绕了点弯. ...

  5. delphi连接sql存储过程

    针对返回结果为参数的 一. 先建立自己的存储过程 ALTER PROCEDURE [dbo].[REName] ) AS BEGIN select ROW_NUMBER() over(order by ...

  6. 用canvas绘制折线图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. call_user_func()的参数不能为引用传递 自定义替代方法

    php手册 中关于 请注意,传入call_user_func()的参数不能为引用传递. 关于这个情况的解释,可自己搜索.我们可以自己定义一个函数解决这样的问题,实例如下: <?php ini_s ...

  8. ASP.NET的六大内置对象

    ASP.NET 六大内置对象(System.Web.UI.Page类): 1.Response 2.Request 3.Server 4.Application 5.Session 6.Cooki R ...

  9. Angular版本1.2.4在IE11的IE8模式下出错解决方案

    今天,群里一个兄弟抛出一个问题(如上),截图说明. 打断点调试下,貌似是console里面的log方法出错了,如下: 这个是console的log方法,为什么错呢,继续: 我们会发现,在这里是检测fu ...

  10. 【代码笔记】iOS-自定义弹出框

    代码: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [s ...