马拉车——Manacher一篇看上去很靠谱的理解(代码显然易懂)
由于回文分为偶回文(比如 bccb)和奇回文(比如 bcacb),而在处理奇偶问题上会比较繁琐,所以这里我们使用一个技巧,在字符间插入一个字符(前提这个字符未出现在串里)。举个例子:s="abbahopxpo"
,转换为s_new="$#a#b#b#a#h#o#p#x#p#o#"
(这里的字符 $ 只是为了防止越界,下面代码会有说明),如此,s 里起初有一个偶回文abba
和一个奇回文opxpo
,被转换为#a#b#b#a#
和#o#p#x#p#o#
,长度都转换成了奇数。
定义一个辅助数组int p[]
,p[i]
表示以s_new[i]
为中心的最长回文的半径,例如:
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
s_new[i] | $ | # | a | # | b | # | b | # | a | # | h | # | o | # | p | # | x | # | p | # |
p[i] | 1 | 2 | 1 | 4 | 5 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 6 | 1 | 2 | 1 |
可以看出,p[i]-1
正好是原字符串中最长回文串的长度。
Manacher 算法之所以快,就快在对 p 数组的求法上有个捷径,看下图:
设置两个变量,mx 和 id 。
mx 代表以s_new[id]
为中心的最长回文最右边界,也就是mx=id+p[id]
。
假设我们现在求p[i]
,也就是以s_new[i]
为中心的最长回文半径,如果i<mx
,如上图,那么:
if (i < mx)
p[i] = min(p[2 * id - i], mx - i);
2 * id -i
其实就是等于 j ,p[j]
表示以s_new[j]
为中心的最长回文半径,见上图,因为 i 和 j 关于 id 对称,我们利用p[j]
来加快查找。
代码:
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std; char s[];
char s_new[];
int p[]; int Init()
{
int len = strlen(s);
s_new[] = '$';
s_new[] = '#';
int j = ; for (int i = ; i < len; i++)
{
s_new[j++] = s[i];
s_new[j++] = '#';
} s_new[j] = '\0'; //别忘了哦 return j; //返回s_new的长度
} int Manacher()
{
int len = Init(); //取得新字符串长度并完成向s_new的转换
int maxLen = -; //最长回文长度 int id;
int mx = ; for (int i = ; i < len; i++)
{
if (i < mx)
p[i] = min(p[ * id - i], mx - i); //需搞清楚上面那张图含义, mx和2*id-i的含义
else
p[i] = ; while (s_new[i - p[i]] == s_new[i + p[i]]) //不需边界判断,因为左有'$',右有'\0'
p[i]++; //我们每走一步i,都要和mx比较,我们希望mx尽可能的远,这样才能更有机会执行if (i < mx)这句代码,从而提高效率
if (mx < i + p[i])
{
id = i;
mx = i + p[i];
} maxLen = max(maxLen, p[i] - );
} return maxLen;
} int main()
{
while (printf("请输入字符串:\n"))
{
scanf("%s", s);
printf("最长回文长度为 %d\n\n", Manacher());
} return ;
}
马拉车——Manacher一篇看上去很靠谱的理解(代码显然易懂)的更多相关文章
- Maven系列第6篇:生命周期和插件详解,此篇看过之后在maven的理解上可以超越同级别90%的人!
maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能. 这是maven系列第6篇. 整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部 ...
- 回调函数通俗解析(之前看了很久都不理解,今天终于ok啦)
自学jquery的时候,看到一英文词(Callback),顿时背部隐隐冒冷汗.迅速google之,发现原来中文翻译成回调.也就是回调函数了.不懂啊,于是在google回调函数,发现网上的中文解释实在是 ...
- HDU - 3068 最长回文(马拉车Manacher)题解
思路:马拉车裸题,我们用一个p[i]数组代表以i为中心的最大回文半径.这里用了一个小技巧,如果一个串是aaaa这样的,那我们插入不相干的字符使它成为#a#a#a#a#,这样无论这个串是奇数还是偶数都会 ...
- 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务 | 百篇博客分析OpenHarmony源码 | v41.03
百篇博客系列篇.本篇为: v41.xx 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...
- x01.os.15: 看上去很美
张碧晨在韩国学的不是技巧,而是基本功:气息!声音由气息托着,似真声而不是真声,似假声又不是假声,所以才能在动听的地方唱得更动听.编程也是一样,基本功很重要:内存!所谓的黑客高手,攻击的一大手段,便是利 ...
- 看上去很美 国内CDN现状与美国对比
CDN的理想与现实 多年以前,当<Kingdom of Heaven>这部史诗电影发行的时候,中国的影迷使用电驴和BT来寻找种子,而那个时候,高清也才刚刚进入电影领域,我的同事不惜用自家的 ...
- 你只是看起来很努力(只是做了一遍真题,草草的对了一遍答案,然后冲出自习室继续她学生会的事情了,骗自己更容易)good——想起了自己在六大时候的无奈
(转)你只是看起来很努力一次上课,一个女孩子垂头丧气的跟我说,老师,我考了四次四级,还没过,究竟是为什么. 我说,你真题做了吗?单词背了吗?她拿出已经翻破了的真题,跟我说,你讲的所有的题目我连答案都记 ...
- Spring Boot 揭秘与实战(四) 配置文件篇 - 有哪些很棒的特性
文章目录 1. 使用属性文件2. YAML文件 1.1. 自定义属性 1.2. 参数引用 1.3. 随机数属性 1.4. application-{profile}.properties参数加载 3. ...
- 美国诚实签经验——中英文行程单、往返机票、用英语面试的申请者通过率>用中文面试的申请者的通过率、一直保持着微笑,看上去很自信,也很诚恳、户口簿带上最好
在排队等待时据我的观察,用英语面试的申请者通过率>用中文面试的申请者的通过率.一家人申请通过率>单个人通过率:商务签证通过率>旅游签证通过率 一. 面签材料 1. 必备材 ...
随机推荐
- 试着利用BAPI 寻找F-59创建凭证的函数
功能块代码 F-59开发类 FIBP事务说明 支付请求 事物:FBP1Screen 0BKPF-BLART = AB________________________________________从程 ...
- django 查询
mail = UserProfile.objects.get(email = email) get如果没有查询到会抛出一个不存在的异常 ...
- LeetCode:最长公共前缀【14】
LeetCode:最长公共前缀[14] 题目描述 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flo ...
- Python 5 面对对象编程
面向对象编程: 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向过程编程 ...
- docker多个容器连接 将 Rails 程序部署到 Docker 容器中
在docker中使用MySQL数据库 https://yq.aliyun.com/articles/583765 将 Rails 程序部署到 Docker 容器中
- AJAX实现三级联动
省市区三级联动插件: 主页面:为方便使用,不用写过多代码,只写一个id为sanji的div,若别的页面要用,只需写一个id为sanji的div,加载上jQuery与sanji.js文件即可 <! ...
- iOS 事件响应者链的学习(也有叫 UI连锁链)
当发生事件响应的时候,必须知道由谁来响应事件.在iOS中,由响应链来对事件进行响应,所有的事件响应的类都是继承于UIResponder的子类,响应链是一个由不同对象组成的层次结构,其中每个对象将依次获 ...
- iOS 52个技巧学习心得笔记 第二章 对象 , 消息, 运行期
1. 属性 在开发过程中经常要用到定义属性,@property和@synthesize是经常用到的属性, property在.h文件中作声明,@synthesize在.m文件中用于实现 // Stud ...
- 转:ADO,OLEDB,ODBC,DAO的区别
ODBC(Open Database Connectivity,开放数据库互连) 1992年,微软公司开放服务结构(WOSA,Windows Open Services Architecture)中有 ...
- latin-1
Latin1是ISO-8859-1的别名,有些环境下写作Latin-1.ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII ...