Manacher算法

1.解决的问题:

用于找出一个字符串中的最大回文字串的长度

2.问题的核心:

求得以每个点为中心的最大回文串的半径长度(用一个数组存)————该数组还可以用于很多回文字符串问题求解

3.得到该数组的思路:

(1).建立两个变量R,C(R表示到当前中心位置为止,所能扩到的最右边界区域,C则是与R对应的一个中心点)

(2).使用R,C的处理思路:
 如果当前位置i小于等于R,则去找到i关于C的对称点i1和R关于C的对称点L,根据i1的最大回文串的左边界情况进行讨论:
 1.如果i1左边界在L内部(右侧),则说明i的最大回文串长度和i1相等
 2.如果i1左边界在L外部(左侧),则说明i的最大回文串长度为 i1 - L
 3.如果i1左边界与L重叠,则说明i的最大回文串长度至少为i1-L,再从R点开始继续右扩判断能不能右扩来得到长度

 

4.代码实现及解析:

 1 public static char[] ManacherString(String str) {//将字符串进行处理(1221->#1#2#2#1#)
 2         char[] charArray = str.toCharArray();
 3         char[] rst = new char[2 * charArray.length + 1];
 4         int index = 0;
 5         for (int i = 0; i < rst.length; i++) {
 6             rst[i] = (i & 1) == 0 ? '#' : charArray[index++]; 
 7         }
 8         return rst;
 9     }
10     
11     public static int Manacher(String str) {
12         if (str == null || str.length() == 0) {
13             return 0;
14         }
15         char[] charArray = ManacherString(str);
16         int[] pArr = new int[charArray.length];//以每个点为中心的最大回文串的半径长度的数组
17         int C = -1;//中心位置
18         int R = -1;//最右侧位置的再向右一位
19         int max = Integer.MIN_VALUE;
20         for (int i = 0; i < charArray.length; i++) {//每个中心点的回文字串都要求
21             pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1;//先判断至少有多少回文串长度
22             while (i + pArr[i] < charArray.length && i - pArr[i] > -1) {//进行右扩
23                 if (charArray[i + pArr[i]] == charArray[i - pArr[i]]) {
24                     pArr[i]++;
25                 } else {
26                     break;
27                 }
28             }
29             max = Math.max(max, pArr[i]);
30         }
31         return max - 1;//原字符串的最长回文串长度恰好等于新字符串最长回文串的半径的长度 - 1
32     }

 

posted @ 2022-05-04 19:39  jue1e0  阅读(31)  评论(0)    收藏  举报