Manacher算法
简介
Manacher算法主要应用于判断最长回文子串的问题
Manacher算法的步骤
在说步骤之前,先说下暴力的解决的方案,遍历字符串的每个字符,以每个字符为中心,往外扩,记录往外扩的最大长度,即为最长回文子串的长度。代码最后展示
言归正传,我们来说说Manacher算法是怎么解决的!
它分为四种情况,在说四种情况前,我们先来明确算法中的几个基础变量:C,R,i,i’,pArr[i],先解释下这些都是干嘛的。
- C:表示和R对应的中心字符
- R:表示回文子串的右边界:可能这块有点别扭,意思就是,这个R是只能增,它记录的是,往右遍历的过程中,最后一个回文子串的右边界
- i:遍历的过程中对应的字符索引
- i’:和i关于C对称的字符索引
- pArr[i]:表示以i为中心的回文半径(长度算上i本身)
解释完这些变量的含义,我们来分析下它的步骤:
- 当i在R外的时候,只能暴力扩,没有优化,扩张成功,R增加
- 当i在R内的时候,我们找到i关于C对称的i’,
- 当i+i’的回文半径之后涉及范围超过R的时候,不用扩,直接出答案
- 当i+i’的回文半径之后涉及范围在R上的时候,不用扩,直接出答案
- 当i+i’的回文半径之后涉及范围在R内的时候,往外扩,扩成功,R增加
我们来看下实现代码:(唉,不知道这个啥时候又会忘,我很绝望呀!)
/**
* Author:markusZhang
* Date:Create in 2020/7/27 21:55
* todo: Manacher算法:解决最长回文字符串问题
*/
public class Manacher_Str {
/**
* 暴力求解
*/
public static int process_1(String s){
if (s == null || s.length() == 0){
return 0;
}
char []str = s.toCharArray();
str = manageStr(str);
int max = Integer.MIN_VALUE;
for (int i=0;i<str.length;i++){
int len = 1;
int left = i-1;
int right = i+1;
while(left > -1 && right < str.length){
if (str[left] == str[right]){
len++;
}else{
break;
}
left--;
right++;
}
max = Math.max(max,len);
}
return max-1;
}
/**
* 针对暴力进行加速
*/
public static int process_2(String s){
if (s == null || s.length() == 0){
return 0;
}
char []str = s.toCharArray();
str = manageStr(str);
//以下四个变量是整个算法最基础的部分
int max = Integer.MIN_VALUE;//最后返回的结果
int []pArr = new int[str.length];//用于记录以每个元素为中心往外扩的最大半径
int C = -1;// 中心位置
int R = -1;// 扩充成功的下一个位置
for (int i = 0 ; i < str.length ; i++){
//这句话的意思是,i在R内吗?不在的话就直接为1,如果在R内的话,结果为i到R的距离与i'的扩充半径的最小值
pArr[i] = i<R?Math.min(pArr[2*C-i],R-i):1;
while(i-pArr[i] > -1 && i+pArr[i] < str.length){
if (str[i-pArr[i]] == str[i+pArr[i]]){
pArr[i]++;
}else{
break;
}
}
if (i+pArr[i] > R){
R = i+pArr[i];
C = i;
}
max = Math.max(max,pArr[i]);
}
return max-1;
}
/**
* 处理字符串使字符串的前后和每个字符之间填充'#'
*/
private static char[] manageStr(char[] str){
StringBuilder sb = new StringBuilder();
sb.append("#");
for (int i=0;i<str.length;i++){
sb.append(str[i]);
sb.append("#");
}
return sb.toString().toCharArray();
}
public static void main(String[] args) {
String s = "babad";
System.out.println(process_1(s));
System.out.println(process_2(s));
}
}