manacher算法
1.Manacher马拉车算法介绍
Manacher算法,又称马拉车算法。用于计算字符串每一个位置为对称中心的回文串长度,即可以用来查询一个长度为的最长回文字串。他的时间复杂度是。是该情景中效率最高的(你不遍历整个字符串咋求出来)
回文串就是从头读到尾部和从尾部读到头都一样的字符串,例如“abbba”。一个回文串是镜像对称的,也就是说他反转之后也是和原串相同的,我们就是依靠这个性质来跑出马拉车算法的。
回文串有两种,一种是奇数的串,就是字符个数有奇数个。一种是偶数的串,例如“abba”就是一个。对于奇数的传,我们可以发现他的对称中心就是中间的‘b’,但是偶数的串呢。他就有2个对称中心,一个是第二个字符‘b’,一个是第三个字符‘b’(门前有两颗树,一颗是B树,另一个也是B树)
总之偶数的回文串对称中心有2个。
2.暴力法求解
不是说讲马拉车吗?怎么先给我讲暴力法啦?
其实马拉车就是暴力法的改进。所以我们先讲讲暴力法如何求解。
我会枚举!,每次选一个点让后判断是不是回文串!
我会优化!我们考虑到上述加粗的,一个回文串是镜像对称的,也就是说我们可以枚举中心,让后向左右两边拓展。例如以“abc”来说,以b为中心,,所以直接结束!
时间复杂度
写起来差不多就是核心这个循环,其中表示回文半径
1 | while (s[i+p[i]+1]==s[i-p[i]-1]){//+1和-1是向外拓展一格 |
我们仔细思考一下为什么效率低,可以发现我们每次枚举端点都会扫一遍字符串,在最坏的情况下这个字符串里面有许多的回文串,而且都很长,效率近乎降至,所以马拉车就是利用上面镜像的性质,减少了重复检查。
3.马拉车算法核心
这里引用Lstdo的博客图
首先我们设和跟别表示目前找到的回文串左端点最左的位置和右端点最右的位置,表示这个回文串的对称中心。
回到回文串,回文串的性质是镜像对称,也就是我们可以得出一个重要的性质回文的镜像也是回文。
例如上图,如果处有一个回文字串,黄色部分完全一致,那么对称过去处也就肯定有一个回文字串。我们可以很简单的求出来的位置就是的,也就是说我们可以直接把的值赋给…吗?
处理时,问题并没有那么的简单,这里我们将一一列举。
- 最普通的情况,这种情况就是上面的情况,我们就直接赋值即可。
- 如下,如果发现我们直接赋值的话,那么肯定会超过
那就不能直接赋值,这个时候我们要尽可能缩在区间内,所以我们要和和取。 - 当在右端点的后面
这没办法啦,只能暴力扩展啦。
综上:
- 如果,就更新
- 暴力拓展
- 更新和
这就是马拉车,十分甚至九分的简单
等会!你这个我数了(不是哥们),是奇数串!那如果是偶数串呢?
我们不得不说这确实是一个问题,中心为一个字符或两个编码十分的麻烦。我们这里运用一个小技巧,就是在的每一个字符左右插入一个不属于的字符,比如说’#',把“abcba”变成“#a#b#c#b#a#”,中心字符还是c,如果是偶数串,那么“abba”变为“#a#b#b#a#”唉这不就变成奇数串,中心就是两个b中间夹的“#”。但是还有一个问题,会越界啊。这个时候我们可以在开头和结尾各加上2个不同的字符,比如说“$”和“&”,这样就变成了 ” $#a#b#c#b#a#& “在暴力拓展的时候就不会越界了。
代码如下
1 | // TODO:学麻辣烫车 |