JavaScript力扣算法学习之回文对匹配(二)枚举前缀和后缀

相关链接:JavaScript算法学习之回文对匹配(一)暴力法

接着上篇,在上篇里我使用了暴力法来解决回文匹配的问题,尽管能够通过力扣的提交测试,但是太过粗暴,遇到大数据量的情况下效率不是很高。

所以我们肯定是要找一个聪明的办法的。思来想去,自己是想不出思路了,所以直接去看了官方的提供的方法,然后我用程序实现。就当练练编程,顺便学习一下新的思想和思维。

官方解法地址

枚举前缀和后缀

假设有两个字符串s1、s2。

并且,s1 + s2 能够构成一个回文串。这时候,会有三种情况:

1)s1.length = s2.length

2)s1.length > s2.length

3)s1.length < s2.length

翻译成白话,就是s1、s2可能一样长,也可能长度不一样。

1)讨论情况一:s1、s2一样长

如果它们一样长(情况1),那么s1、s2就互为翻转。比如:

s1 : ‘abc’

s2 :‘cba’

它们其实是对称的。

2)讨论情况二、三:s1、s2不一样长

其实无论s1、s2谁长,情况都是一样的。我们这里就假设s1比s2长,比如:

s1 : ‘abcc’

s2 :‘ba’

此时,我们发现,s1中有一部分是回文的,即’cc’这一部分。剩下的部分’ab’,则恰好与s2,即’ba’是对称的。

不仅如此,回文部分还应该恰好是s1的前缀或者后缀。

s1 : ‘abcc’ // 'cc’为后缀

s2 :‘ba’

s1 : ‘ccba’ // 'cc’为前缀

s2 :‘ab’

我们姑且把这回文部分称为回文前缀、回文后缀吧。

3)三种情况的统一

我们可以把情况一归结为情况二、三的一种特例,即s1去除掉回文前/后缀(其实是空字符串),余下部分(其实就是它自身)与s2也是对称的。

因此,我们可以把三种情况统一起来。如果s1、s2要组成回文串,那么长度更长的那一个,去除它自身的回文前/后缀后,剩余部分必然与另一个是对称的。

归纳成算法

我们将要操作的字符串命名为s。

根据上文我们发现的一些特征,要想知道在某个字符串集数组 [<String>] 里,有没有能够与s匹配成回文串的元素,我们可以这么操作:把s去除掉回文前缀(或后缀),看其剩余部分的对称是不是属于 [<String>] 的一个元素。归纳一下:

第一步:去除s的回文前缀(或后缀),得到剩余部分s-

第二步:计算s-的对称(即镜像)-s

第三步:判断-s是否在 [<String>] 里

在这里,我不关心s究竟是上文所说s1、s2中的哪一个。我只要把s当成一个普通的字符串处理即可。

举个例子,假设s = ‘abcc’, 那么它拥有回文后缀’cc’,我把这部分去除后,剩余部分是’ab’。‘ab’的对称是’ba’,所以能够与s匹配成新回文的字符串就是’ba’。此时,你可以把s理解为s1、s2较长的那一个。

注意:我们需要把’’(空字符串)也当成一种特殊的回文前/后缀处理。

上例中,‘abcc’除了’cc’这个回文后缀外,它还可以有’ ‘(空字符串)这种回文前缀(你当成后缀也可以),于是它的剩余部分就是’abcc’,即它自身。此时剩余部分的对称变成了’ccba’,可以发现:它们同样可以组成回文串!

马拉车算法和字典树

我们在上文提出的算法步骤,每一步都可以用暴力法来实现。例如第一步:

第一步:去除s的回文前缀(或后缀),得到剩余部分s-

我们可以继续像原来一样,用暴力法,遍历s的全部字符去找回文前缀或后缀。

第三步也是如此:

第三步:判断-s是否在 [<String>] 里

我们可以遍历 [<String>]里的所有元素,来判断-s是否是 [<String>]的一个元素。

但是呢,这样用暴力法解决,不就仍然原来一样粗暴了吗?不如对自己要求高一点,将优化进行到底。

对于第一步,我们可以使用一种名为 马拉车 (Manacher)算法 的方法。这是一种高效的寻找最大回文串的方法。

对于第二步,我们使用 字典树,它常用于字符串文本的检索、统计。

之后,我将分别用两篇文章介绍它们,然后再用一篇文章来将它们组合起来,用来解决我们的问题。

(未完待续)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值