最长回文子串-----“马拉车”算法

Manacher算法

这个算法有一个很巧妙的地方,它把奇数的回文串和偶数的回文串统一起来考虑了。这一点一直是在做回文串问题中时比较烦的地方。这个算法还有一个很好的地方就是充分利用了字符匹配的特殊性,避免了大量不必要的重复匹配。
算法大致过程是这样。先在每两个相邻字符中间插入一个分隔符,当然这个分隔符要在原串中没有出现过。一般可以用‘#’分隔。这样就非常巧妙的将奇数长度回文串与偶数长度回文串统一起来考虑了(见下面的一个例子,回文串长度全为奇数了)

主要的三个变量:


1.pArr[] —–回文半径
例如 ¥1¥2¥1¥
pArr[3]=4 代表2这个数字能扩出去4个(包括他自己)


2.pr —-初始为0 代表回文半径即将到达的位置
例如 ¥1¥2¥1¥
当扫到1的时候,pr更新成3(3这个位置的值是2)。当扫到2的时候,pr就更新到了最后。


3. index—-当pr更新的时候,那个回文中心的位置
例如 ¥1¥2¥1¥
当扫到2的时候,pr更新到了最后,index就更新为3,记录下此时回文中心的位置。


接下来,我们分几种情况来讨论。
第一种情况,在index和pr-1之间,对于i点关于index 的对称点来说,它的回文半径*2要是比index的回文半径小,那么i的回文半径很好理解,就是它对称点的回文半径。
举个例子: ¥c¥a¥b¥a¥d**¥{**d(¥a¥b¥a¥)c¥c¥}

第二种情况,在index和pr-1之间,对于i点关于index 的对称点来说,它的回文半径*2要是比index的回文半径大,那么i的回文半径也很好计算,就是pr-1-i。因为被封死了,后边是出不去的。虽然左边可以aba这样浪。
举个例子: ¥a¥b¥a¥c{¥a(¥b¥)}d¥

第三种情况,在index和pr-1之间,对于i点关于index 的对称点来说,它的回文半径*2要是比index的回文半径一样,此时就需要判断i的回文半径能不能再大点。
举个例子: ¥d¥a¥b¥a¥(c{¥a¥b¥a¥}c)¥
此时这个c按道理也能加进去。此时可能会更新pr。因为它又要往后边找了。

第四种情况,i没有被包住。只能暴力括了。。必然更新pr。


总结来说,前两种情况不会更新pr。第三种可能会更新,第四种必然会更新。


你可能感兴趣的:(Data,struct,and,algorithm)