字符串处理 —— 回文串相关 —— Manacher 算法
【概述】
Manacher 算法又称马拉车算法,用于求最长回文子串。
对于最长回文子串传统的求法的求法是以每个字符为中心,向两边寻找回文子串,在遍历完整个数组后即可得到最长回文子串,其时间复杂度为 O(n^2)
而马拉车算法,将求最长回文子串的时间复杂度提升到了线性,其时间复杂度只有 O(n)
【算法流程】
1.预处理
由于字符串的长度分为奇偶两种,因此对于初始的字符串,在每一个字符的左右都加上一个未在串中出现过的字符,得到一个新的字符数组 newStr[]。
比如:
- 奇数字符串:bob --> #b#o#b#
- 偶数字符串:noon --> #n#o#o#n#
这样一来,无论原字符串是奇数个字符还是偶数个字符,处理后的字符串字符的个数都是奇数个,这样就无需分情况讨论了。
2.设置辅助数组
接下来,还需要定义一个辅助数组 p[],其中 p[i] 表示以字符 newStr[i] 为中心的最长回文半径,若 p[i]=1,则该回文子串就是 newStr[i] 本身。
例如:以字符串 abbahopxp 为例
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
newStr[i] | $ | # | a | # | b | # | b | # | a | # | h | # | o | # | p | # | x | # | p | # |
p[i] | 1 | 2 | 1 | 2 | 5 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 4 | 1 | 2 | 1 |
可以看出,p[i]-1 即为原字符串中最长回文串的长度。
3.求解辅助数组
首先新增两个变量 mx 与 id,其中 mx 代表以 id 为中心的最长回文串的右边界,即:mx=id+p[id]
假设求以 i 为中心的最长回文半径,即求解 p[i],当 i<mx 时,那么有 p[i] = min(p[2*id-i], mx-i),否则 p[i]=1,其中 2*id-i 为图中的 j 点,即 p[j] 是以 j 为中心的最长回文半径
【复杂度分析】
基于回文串的性质,辅助数组 p[i] 的值基于以下三种情况得出:
1)j 的回文串有一部分在 id 的回文串之外
如上图,黑线为 id 的回文串,i 与 j 关于 id 对称,红线为 j 的回文,紫线为 i 的回文,虚线为以 id 为中心的回文右边界 mx,那么根据 p[i]=mx-i,即紫线的部分,那么可以得出,p[i] 无法得到更大的值
如上图,假设右侧新增的紫色 d 部分是 p[i] 可增加的部分,那么根据回文的性质,也即是说 id 的回文 = 黑线 + a + d,矛盾,假设不成立,因此 p[i] 无法再增加,得到一个更大的值
2)j 回文串全部在 i 内部
如上图,此时 p[i]=p[j],那么可以得出,p[i] 无法得到更大的值
如上图,假设右侧的红线 d 是 p[i] 可增加的部分,那么根据回文的性质,j 的回文 = j 之前的回文 + a + b,矛盾,假设不成立,因此 p[i] 无法再增加,得到一个更大的值
3)i 的回文串右端与 id 的回文串右端重合
如上图,此时 p[i]=p[j],或 p[i]=mx-i,此时 p[i] 可以继续增加,那么有:
while(newStr[i-p[i]]==newStr[i+p[i]]) p[i]++;
根据(1)(2)(3),容易推出 Manacher 算法的最坏情况,即为字符串内全是相同字符的时候,平均访问每个字符 5 次,同理,也容易推出 Manacher 算法的最佳情况,即为字符串内字符各不相同的时候,平均每个字符访问 4 次。
综上,Manacher算法的时间复杂度为 O(n)。
【实现】
char str[N];//原字符串
char newStr[N*2];//预处理后的字符串
int p[N*2];//辅助数组
int init(){//对原字符进行预处理newStr[0]='$';newStr[1]='#';int j=2;int len=strlen(str);for (int i=0;i<len;i++){newStr[j++]=str[i];newStr[j++]='#';}newStr[j] ='\0'; //字符串结束标记return j;//返回newStr的长度
}int manacher(){int len=init();//取得新字符串长度并完成字符串的预处理int res=-1;//最长回文长度int id;int mx=0;for(int i=1;i<len;i++){int j=2*id-i;//与i相对称的位置if(i<mx)p[i]=min(p[j], mx-i);elsep[i]=1;//由于左有'$',右有'\0',不需边界判断while(newStr[i-p[i]] == newStr[i+p[i]])//p[i]的扩大p[i]++;if(mx<i+p[i]){//由于希望mx尽可能的远,因此要不断进行比较更新id=i;mx=i+p[i];}res=max(res,p[i]-1);}return res;
}int main(){while (printf("请输入字符串:\n")){scanf("%s",str);printf("最长回文长度为 %d\n", manacher());}return 0;
}
字符串处理 —— 回文串相关 —— Manacher 算法相关推荐
- (回文串)Manacher算法
(回文串)Manacher算法 标签: ACM 回文串 Manacher 问题描述: 输入一个字符串,求出其中最大的回文子串.子串的含义是:在原串中连续出现的字符串片段.回文的含义是:正着看和倒着看相 ...
- 怎么判断一个字符串的最长回文子串是否在头尾_LeetCode 5 迅速判断回文串的Manacher算法...
本文始发于个人公众号: TechFlow 题意 Given a string s, find the longest palindromic substring in s. You may assum ...
- 字符串处理 —— 回文串相关
[回文串] 回文串,就是一个正读与反读都一样的字符串,比如:abcdcba.zxccxz 等 常见的回文串算法有:求字符串中最长回文串.判断一个字符串是否为回文串.在字符中添加/删除一个字符后是否为回 ...
- 字符串处理 —— 回文串相关 —— 求最长回文子串
[暴力枚举] 求最长回文串最容易的方法就是暴力枚举,求出字符串的每一个子串,然后判断是不是回文,找到最长的那个回文串 求每一个子串的时间复杂度为 O(N^2),判断一个子串是不是回文时间复杂度为 O( ...
- 字符串处理 —— 回文串相关 —— 添加/删除字符后是否为回文串
[问题] 给定一个字符串,问对该字符串,是否能通过添加一个字符后变为回文串. 若可以,输出 YES,否则输出 NO 对于该问题,首先要明白,删除一个字符与添加一个字符在判断回文串中是等价的. [暴力枚 ...
- 字符串处理 —— 回文串相关 —— 回文串的判断
[逐个比较] bool isPalindrome(string str){for(int i=0;i<str.size()/2;i++)if(str[i]!=str[str.size()-1-i ...
- 力扣--让字符串成为回文串的最少插入次数
力扣–让字符串成为回文串的最少插入次数 文章目录 力扣--让字符串成为回文串的最少插入次数 一.题目描述 二.分析 三.代码 相关题目: 腾讯–构造回文:腾讯–构造回文 最长回文子串和回文链表:最长回 ...
- 力扣- - 最短回文串(KMP算法)
力扣- - 最短回文串(KMP算法) 文章目录 力扣- - 最短回文串(KMP算法) 一.题目描述 二.分析之KMP算法 1.暴力法 2.KMP算法 3.next数组求法1:暴力查找最长的前后缀 4. ...
- 分割两个字符串得到回文串[抽象--去除具体个性取共性需求]
抽象 前言 一.分割两个字符串得到回文串 二.双指针 总结 参考文献 前言 抽象去个性留共性,是因为具体个性对于解决问题是个累赘.少了累赘,直击需求,才能进行问题转换或者逻辑转换. 一.分割两个字符串 ...
最新文章
- 【从零开始的ROS四轴机械臂控制】(五)- 构建运动控制服务
- php中mysql,PHP中的mysql
- Canvas 属性,方法
- java machine 报错_Eclipse启动时报错:No java virtual machine
- 联想android刷机教程视频,联想s939刷机教程(刷官方系统)
- 从VC++到GCC移植:谈两者的语法差异
- w7电脑蓝屏怎么解决_电脑蓝屏Win32k.sys怎么办
- 通向架构师的道路(第十四天)Axis2 Web Service安全之rampart
- Oracle内部错误ORA-07445[kpopfr()+339] [SIGFPE]一例
- java 的strip_javastript
- svg 转换为 pdf (batik 库+fop库)
- 南航计算机学院考研的专业课,【南航计算机考研】南航计算机考研经验贴
- html实现背景图片自动更换,如何实现在HTML中更换或添加网站背景图片
- Python和Numpy的加权抛硬币游戏的概率
- 局域网公用一个mysql数据库
- Vue刷新、跳转页面的数据保存方法: sessionStorage + Object.assign()
- 海思SDK安装过程以及OSDRV编译不成功出现的问题的解决
- 微信撤回消息服务器还有存底么,微信更新又来了,撤回消息大变化!还增加“查岗”功能......
- 读写文本文件-StreamReader和StreamWriter
- 极客日报:​​​字节员工操纵抖音热榜被判刑;微信群聊可直接访问电商外链;JetBrains发布新一代编辑器Fleet