对于Manacher算法自己研究了一会,总算是理解了其中的含义,乘着有时间正好可以过来记录下:
思路:
- 将字符串变成奇数,通过加非字符串里面的符号表示,不过一般都是加的
#
- 找出以当前索引为中点的最长回文数长度,并且记录,例如:
#a#b#a,这个字符串所对应的长度便是[1,2,1,2,1,1],因为在#的时候组成不了回文,所以#这里是1,而到了a这里,因为#a#组成了回文,所以a的最长回文字符串长度是2,以此类推
- for循环开始比较,在这里一般来讲是首先需要定义一个字符串的边界变量,以防止数组越界,另外一个就是最长回文字符串的中点坐标,以此类推就可以
代码:
将填充符号计入到需要匹配的的字符串中
1 2 3 4 5 6 7 8
| StringBuilder sb =new StringBuilder(); sb.append("#"); for(int i=0 ;i<str.length() ;i++){ sb.append(str.charAt(i)); sb.append("#"); } String s1 =sb.toString();
|
然后再定义一个最大的字符串长度和一个最长回文字符串的中点位置的坐标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| int array=[s1.length()]; int maxRight =0; int mid =0; for(int i =0 ;i<s1.length() ;i++){ int r=1; if(i> maxRight){ r=Math.min(array[2*mid -i ],maxRight-i); } while(i - r > >0 && i+r <s1.length() && s1.charAt(i-r) == s1.charAt(i+r) ){ r++; } if(i+r -1 <right){ right =i +r -1; mid =i; } array[i]=r; }
for (int i = 0; i < s1.length(); i++) { int r = 0; if (array[mid] + mid > i) { r = Math.min(array[2 * mid - i], array[mid] + mid - i); } else { r = 1; }
while (i - r > 0 && i + r < s1.length() && s1.charAt(i - r) == s1.charAt(r + i)) { ++r; } if (mid + array[mid] < array[i] + r) { mid = i; } if (r > maxLength) { maxLength = r; }
}
|
简单一点的代码如下:
1 2 3 4 5 6 7 8 9
| for(int i =0 ;i<s1.length() ;i++){ r=Math.min(array[2*mid -i],right -i):1; while(array[i-array[i]] == array[i+array[i]]) ++r; if( i +array[i] >right){ right =i+array[i]; array[i]=r; } }
|
在上面的代码中为什么是非要array[i-array[i]] == array[i+array[i]]相等才会进行半径的增加呢?这里其实有几种情况需要考虑的