9.21《最长回文子串》

题目描述如下:

熟悉的回文串问题,解法有很多,但大致可归为以下两类:

一:从头尾(外部)开始一一对应找回文串(即找到和头对应的回文尾部,再一步步向内逼近验证)

二:以其中的中心向两边找(即左右分别向外找寻,一一对应)

我的第一思路都是以第一种验证方式为基础。看到回文的后进先出的性质,我第一时间想到的便是利用“栈”结构。但是尝试之后发现主要问题有两个:一代码冗杂,二中心的验证麻烦

总的来说就是吃力不讨好,于是我又想过,利用字符串操作进行寻找,代码如下:

这里主要解释验证回文函数is_huiwen,我的思路十分暴力:

1.传入一个字符串的首地址,目的便是寻找以这个字符串首字母为首的回文字符串,若有返回最长字符串,若无,返回rs_none

2.接下来用fore和back分别代表前指针和后指针,令前指针等于字符串首地址,后指针等于字符串末尾地址。

3.开始大循环:当前后指针未走到一起时,证明验证没有结束。

4.验证步骤如下:先找到和前指针对应的首字符相同的字符所在位置,接着进入第二个循环,前后向内逼近,每次都需要验证前后指针包含的字符相同。如若不同,则fore回到字符串首,back到上次位置前一个位置,继续寻找下一个和首字符相同字符的位置进行验证。

5.当前后指针相邻,且字符相同或当前后指针重合,证明向内验证成功,返回该字符串。

6.若整个循环都没有满足的字串,返回re_none。

分析:这种解法的好处在于,验证到的第一个回文字符串便是以该字符为首的最长字符串。缺点是重复遍历过多导致时间复杂度过高。

接下来介绍第二种解法:

来自:Mia

中心拓展算法:便是验证的策略改为由内向外延申。该解法的特点是:速度快,遍历少,实现容易。

首先我们需要讨论所给字符串共有多少个回文中心:

回文中心可按字符数分为两大类:单数和双数。

如: abcd,单数回文中心可为:a b c d

双数回文中心为: ab bc cd

可见单数回文中心共n个,而双数回文中心共n-1个。

所以,一个字符串的回文中心共n+n-1==2*n-1个。我们需要对这些回文中心进行延申,直到两边对应位置的字符串不相同。

但是,这么做还能有改进方法:

多次遍历中,显然有很多重复的遍历,怎么减少这些便利呢?

接下来介绍马拉车法:Manacher

首先处理 字符串的单双数问题,对字符串进行处理,利用#填充字符的前一个位置以及字符串的最后一个位置

这样,长度为n的字符串就变为了长度为2*n+1的字符串,恒为奇数。且这么做后,双数中心便不存在了,如其中一个中心为#b,则左右为一位置为a和#,显然一字符一#,不会相同。

那么接下来就开始寻找每个单数中心对应的最长回文字符串:

同样的由中心向两边延申,我们可以发现,此时的回文长度/2再减一就是本来不做处理时单字符对应的回文长度,我们将其定位回文半径R。所以我们接下来只用寻找这些R的最大值就行了。

到这之后,我们还可以尽可能地减少重复便利:

我们在所有已经验证的字符串中找到回文最靠右的坐标,定为pos,并将其最长回文末端位置标记为MaxRight

那么现在正在访问位置i一定在pos之前,讨论目前i的遍历:

题解永远不可能只有一种,我在以后的学习日志中除了自己的解决方法还会更新大佬们的解题方法,并用自己的理解阐释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值