Manacher算法详解

特点

manacher也就是我们戏称的马拉车算法是处理回文串的强力武器,一般处理回文串的方法是中心扩展法,这样使得时间复杂度O(n*n)简直爆表,一般好的算法都在O(n*lgn)以下。manacher可以使得处理回文串的时间复杂度减少为O(n)。它是通过回文串的对称性,使得我们在已扩展范围内的回文长度可以很方便得出。
看完后你可以尝试下:leetcode 5. 最长回文子串

字符串处理

为了减少判断单轴还是对称的回文串,我门通过使用字符分割的方法处理字符串。单轴回文“aba”通过处理后变为“#a#b#a#”,可以顺利从b扩展,对称回文“aa”通过处理后变成#a#a#也可以顺利从中间的#扩展。我们在扩展的时候#只会和#去对比,所以#是啥无所谓,可以和原本的字符集相交。

算法步骤

1.我们需要一个变量center和P表示当前最大的扩展半径和中心点。
2.以第i个点为中心的的回文串可以通过该点关于P的对称点来获取,并且尝试继续扩展该点以更新center和P。
3.重复步骤2。
我们做个简单的小题,就是查找字符串中所有的回文串,通过注释让大家更清楚整个算法的流程:

let str  = "abaacabcdc";
//第一步:处理原字符串
let strArr = [],index = 0;
strArr[index++]="#";
for(let i=0;i<str.length;i++){
   strArr[index++]=str[i];
   strArr[index++]="#";
}
//左右扩展函数
function expand(arr,left,right){
     while(left>=0 && right<arr.length && arr[left]===arr[right]){
        left--;right++;
    }
    return (right-left-2)/2;//返回的是扩展的半径
}
//manacher
let center = 0,P=0;//center和P最远范围回文串的中心点和半径
let r = [];//r[i]表示arr[i]回文串的半径
for(let i=0;i<strArr.length;i++){
    let mirror = 2*center - i;//计算i关于center的对称点
    r[i] = 0;//arr[i]可以扩展的半径
    if(i<=center+P){//i不能超过已扩展范围
        r[i]= Math.min(center+P-i,r[mirror]);//r[i]的半径不能超过已扩展的范围,下面会继续扩展。
    }
    let hr = expand(strArr,i-r[i],i+r[i]);//尝试继续扩展半径
    r[i] = hr;//更新半径
    if(r[i]>1){//半径大于1为回文,打印字符串中所有的回文
      console.log(str.slice((i-r[i])>>1,(i+r[i])>>1))
    }
    if(i+hr>center+P){//更新最远的半径
        center = i;
        P=hr;
    }
}

感觉挺好理解的,如果耐心看的话,步骤不多,可比KMP要简单。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值