Manacher算法(马拉车算法)

马拉车算法,我感觉这里的“马拉车”好像是音译过来的,所谓马拉车算法,就是用来求解最大回文数问题的,而最大回文数问题,往往是以字符串为在体的,所以,我们今天来说一说,如何能最高效的找到目标字符串的最大回文数。

 

1.想一想,如何找到一个字符串的最大回文数?我这里有三种思路:

 

  一.暴力求解,我们可以将一个长度为n的字符找到他的n!个字符串,然后通过遍历来找出这n!个字符串的最大回文数。

   时间复杂度:O(n^3);

   评价:这样做虽然简单易懂但是代价太高了,不建议使用;

二.字串渐进式求解,首先,我们需要将该字符串进行格式化,在每一个字符之间添加一个特定的标识符(这里我们使用“#”),遍历这个字符串的每一个元素,并且判断每一个元素的最大回文数。

    为什么要在每个字符之间添加一个特定的标识符呢?最大回文数有奇数,也有偶数,如果出现“abccba”这种情况,如果不添加标识符,就无法得到正确结果,添加标识符,就是为了消除这种情况。

    时间复杂度:O(n^2);

三.也就是我们进今天的主家了,马拉车算法:

Manacher算法(马拉车算法)_第1张图片

看看上面这个字符串,我们可以轻易的看出第五位式最长回文数的中心,最长回文数的长度是7,没错,这些确实可以轻易的得出,那么,我们还可以看出什么呢?我们还可以看出以第五位为轴,2-4,6-8对称。我们看完了第五位,看第六位,第六位的最长回文数是多少呢?一眼看出是1,有没有不用眼睛就能知道是1的方法呢?有!

          我们可已发现,和点6对称的点4的最长回文数也是1,为什么呢?因为他们关于点5对称。而且点4的最大回文数是1,而且

2-4,6-8是堆成的,所以我们不需要关心点6后面的字符,直接由点4提供给我们的信息直接得出点六的最大回文数。

那么我们继续往后走,到了点7,我们可以知道点7对应的是点3,而点3的最长回文数是3,而且点三的回文字符串正好包含于2-4中,所以我们可以断定,点7的最长回文数必定大于或等于3。为什么是大于或等于而不直接让它等于呢?因为我们根据堆成知道了6-8关于点7对称,但是我们不知道第九位是什么值,所以无法判断,那么这时候我们要怎么办呢?我们这时候就需要判断第九位和第五位是否相同了,如果相同,那么我们就将再一次像利用点5的对称性一样利用点7的对称性来判断电8,甚至点9....。

 

总结,该算法就是通过利用前面已得到的字符的最大回文数的对称性来为后续的判断提供方便,在最理想的时候,该算法的时间复杂度可降低到O(n);

下面是本人利用Java实现的代码。

public class PlalindromeString {
	
	
	/**
	 * 判断一个字符串是不是回文数字符串(本算法中用不到,思维其实很简单)
	 * @param str
	 * @return
	 */
	private boolean IsPlalindromeString(String str) {
		
		//获取字符串的长度
		int len=str.length();
		
		for(int i=0;i右边界,则需要向右扩展,变更中心点。
				if(LenArr[length]+i>=rightSide) {
					LenArr[i]=rightSide-i;
				}
			}
			
			//右边界移动
			if(init) {
					
				for(int j=i+LenArr[i]+1;i+LenArr[i]+1=0 ;j++) {
					if(str.charAt(j)==str.charAt(2*i-j)) {
						LenArr[i]=LenArr[i]+1;
					}else {
						break;
					}
						
				}
				
				centerAddress=i;
				rightSide=i+LenArr[i];
				
				//判断以当前点为中心的回文数串的长度是否大于已记录的最大回文数的长度,如果大于,那么我们就将其记录
				
				if(LenArr[i]>longgest) {
					longgest=LenArr[i];
					center=i;
				}
			}
		}
		
		StringBuffer sb=new StringBuffer("");
		
		for(int i1=center-LenArr[center];i1

 

你可能感兴趣的:(Manacher算法(马拉车算法))