代码随想录day09|KMP

文章:代码随想录

状态:看完视频才能实现

leecode 28 实现str()

思路:

这道题就是实现字符串匹配算法。KMP的经典例题。我觉得KMP的终点就是理解next数组的形成,也是一个递推,kmp字符匹配的过程。

//next数组中找最大相同前后缀,其实也可以理解为Kmp的过程。从j位置起始遍历的看作字串,i位置开始的看作主串。
// 当i,j位置的字符相同时,他们同时往后遍历,每相同一个,他们的相同前后缀长度也会加一。
//但要知道相同前后缀长度的意义,可以理解为从前面拿几个数放到后面他们时相同的。
//所以当i,j位置的值不相同怎么办?我们要尝试看有没有长度更小的相同前后缀吧。所以我们看j-1位置的值,看不匹配位置之前我们所找到的最大前后缀的长度
//所以这意味着我们把字符串的前几个字符移到尾部都是相同的,那么在这个基础上再看下一个匹不匹配,如果匹配就直接j+1,不匹配还需要再往j-1的位置递推。
//不匹配的情况,可以直接让j指针指向j-1位置上的值。比如j-1的位置为1,那么意味着可以跳过一位字符来比较,所以当j指向下标1,那么其实就是需要被比较的字符的位置,0被跳过了。

其实next数组实现之后,kmp的流程实现起来也很类似,所以要理解这个过程。

代码:

 //那么匹配子串的流程就是同时声明两个指针,一个指向主串,一个指向子串。核心就是让主指针不回退,子指针回退。
    // 匹配则同时遍历,不匹配则找到next数组中,不匹配位置的上一个位置的值,让子指针回退到这个值的位置再重新开始遍历比较.
    //这也是个递推的过程,从头部与尾部相同的最长前缀位置再往后遍历,不匹配则继续往前递推。这样就可以利用之前已经获取到的信息来遍历。
    public static int  strStr(String haystack, String needle) {
        int res=-1;
        int[] next=getNext(needle);
        int j=0;
        for (int i = 0; i < haystack.length(); i++) {
            while(j>0 && haystack.charAt(i)!=needle.charAt(j)){j=next[--j];}
            if(haystack.charAt(i)==needle.charAt(j)){
                j++;
            }
            if(j==needle.length()){
                res=i-j+1;
                break;
            }


        }

        return res;

    }

    public static int[] getNext(String needle) {
        int[] next = new int[needle.length()];
        int j = 0;
        next[0] = 0;

        for (int i = 1; i < needle.length(); i++) {
            //next数组中找最大相同前后缀,其实也可以理解为Kmp的过程。从j位置起始遍历的看作字串,i位置开始的看作主串。
            // 当i,j位置的字符相同时,他们同时往后遍历,每相同一个,他们的相同前后缀长度也会加一。
            //但要知道相同前后缀长度的意义,可以理解为从前面拿几个数放到后面他们时相同的。
            //所以当i,j位置的值不相同怎么办?我们要尝试看有没有长度更小的相同前后缀吧。所以我们看j-1位置的值,看不匹配位置之前我们所找到的最大前后缀的长度
            //所以这意味着我们把字符串的前几个字符移到尾部都是相同的,那么在这个基础上再看下一个匹不匹配,如果匹配就直接j+1,不匹配还需要再往j-1的位置递推。
            //不匹配的情况,可以直接让j指针指向j-1位置上的值。比如j-1的位置为1,那么意味着可以跳过一位字符来比较,所以当j指向下标1,那么其实就是需要被比较的字符的位置,0被跳过了。
            while(j>0 && needle.charAt(j)!=needle.charAt(i) ){
                j=next[--j];
            }
            if(needle.charAt(j)==needle.charAt(i)){ j++;}

            next[i]=j;
        }
        return next;

leecode 48 重复的子字符串

思路:

有两种实现方法 移动匹配和KMP,kmp实现也有两种方法。

先说移动匹配:

//移动匹配 因为如果一个字符串s,是由一个子串s‘重复组成的话,那么这个主串的长度一定是s’的整数倍。
// 所以如果我们将主串拼接,并从1的索引位置开始寻找,如果最后最先找到的主串不是拼接进来的主串,则证明能被重复子串形成

代码:

    public boolean repeatedSubstringPattern(String s) {
        return (s + s).indexOf(s, 1) != s.length();

    }

KMP:

有两种实现方法:
//第一种是从s+s中对s进行模式串匹配,找到s第一次出现的位置,逻辑和上面一样,就是自己实现indexOf算法。
//第二种就是找到字符尾部时最长相同前后缀不包含的部分,如果len能整除那部分,那么那就是最小的重复子串。随想录上有证明。
//结论为当一个字符串由重复子串组成的,最长相等前后缀不包含的子串就是最小重复子串 即len-(next[len]);而如果是由重复子串组成的主串,最后位置的最长前后缀也是字符的最长相等前后缀。

代码:

public boolean repeatedSubstringPatternKMP(String s) {
        int j=0;
        int len=s.length();
        int [] next=new int[len];
        next[0]=0;
        for (int i = 1; i <len ; i++) {
            while(j>0 &&s.charAt(j)!=s.charAt(i)){
                j=next[--j];
            }
            if (s.charAt(j)==s.charAt(i)){j++;}
            next[i]=j;
        }
        //结尾处没有相同前后缀时一定不是相同子串重复组成, 需要对等于0时做特殊处理
        if(next[len-1]>0 && len%(len- next[len-1])==0){
            return true;
        }


        return false;

    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值