字符串相关算法

1.Manacher算法(计算回文串)

(1)小改造

中心拓展法求回文串都会吧,是不是分类讨论了,回文串长度为奇数和回文串长度为偶数两种情况。
马拉车呢很聪明,他将代求串进行下边这种改造:
在这里插入图片描述
这样做有什么好处呢?
不管原回文串长度是奇数还是偶数,在T中长度都是奇数

(2)辅助数组Len[]

在这里插入图片描述
len[i] 表示以i为中心的回文串的半径
len[i]-1就是S中回文串的长度(这个自己想一下就行,很简单的,如果有哨兵,这个不满足)

(3)Len数组的计算

首先从左往右依次计算Len[i],当计算Len[i]时,Lenj已经计算完毕。设P为之前计算中各回文串右端点能到达的最大值,并且设取得这个最大值的回文串的中心为po,那么就有两种情况:

3.1:i<=P
3.1.1 Len[j]<P-i (就是如图所示,Po的回文串能包含j的回文串)

在这里插入图片描述
很显然Len[i]=Len[j]了
3.1.2 Len[j]>=P-i (如下图所示,下图画的也不是很准,反正就是Po不能包含或者恰好包含j时)
我们只能确定Len[i]>=P-i,后边也可能还会回文,所以就只能老老实实匹配了
在这里插入图片描述
3.2:i>P
在这里插入图片描述
这种情况就不能在之前的Len中获得有用的长度信息了,所以从长度为1开始匹配就完事了。
没了,简单吧

(4)时间复杂度分析

emmm,都说是O(n),和Z算法类似,但是吧我不会分析,等以后咱也弄懂了,就回来补上

(5)模板代码

有一点要指出的是:如果用了哨兵len[i]-1可能不再是原串中回文串的长度,因为第0个字符是哨兵,是不可能与添加的’$'匹配的,这就导致len[i]可能就是原回文串,自己想(本来改造添加的字符能互相匹配所以len[i]-1才是原回文串的长度,你这改造添加的第一个字符不能匹配了,所以就不用-1了)

//参数是字符串,结果是改造后的数组对应的半径
    public int[] manacher(String x){
        if(x==null||x.length()==0) return null;
        char[] chars=new char[x.length()*2+1];
        for(int i=0;i<x.length();i++){
            chars[2*i]='$';
            chars[2*i+1]=x.charAt(i);
        }
        chars[0]='&';
        chars[chars.length-1]='*';
        int p=-1;
        int pi=-1;
        int []len=new int[chars.length];
        len[0]=1;
        len[len.length-1]=1;
        for(int i=1;i<len.length-1;i++){
            if(p>i){//可以尝试不用匹配
                int mirror=2*pi-i;
                int mlen=len[mirror];
                if(i+mlen-1<p){//完全不用自己撇皮
                    len[i]=mlen;
                }else{//还要自己匹配一段
                    int mylen=p-i+1;
                    int left=i-mylen;
                    int right=i+mylen;
                    while(chars[left--]==chars[right++]) mylen++;//哨兵:不与任何人匹配(不和任何人配对,不会被情所困,这就是哨兵的魅力)所以不需要再加越界判断,但是有利有弊,为len[i]-1=原字符串中回文串长度 这个等式画上了不等号
                    len[i]=mylen;
                }
                if(i+len[i]-1>p){
                    p=i+len[i]-1;
                    pi=i;
                }
            }else{//必须要自己匹配了
                int mylen=1;
                int left=i-1;
                int right =i+1;
                while(chars[left--]==chars[right++]) mylen++;
                len[i]=mylen;
                if(i+len[i]-1>p){
                    p=i+len[i]-1;
                    pi=i;
                }
            }
        }
        return len;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值