力扣28 kmp实现strStr()

力扣28 实现strStr()


在这里插入图片描述
LPS[len - 1] 记录的是橘色字符串的最长的前缀和后缀,假如 LPS[len - 1]=3,那么前面 3 个字符和后面的 3 个字符相等

绿色的部分其实和橘色的部分相同。

LPS[len - 1] 记录的其实是 i 指针之前的字符串里的第二长的公共前缀和后缀(最关键点)。

更新 len = LPS[len - 1],继续比较 needle[i] 和 needle[len]。

class Solution {
    public int strStr(String haystack, String needle) {
        int m = haystack.length(), n = needle.length();
        if(n == 0){
            return 0;
        }
        // 暴力求解
        // for(int i = 0; i < m; ++i) {
        //     int k = i, j;
        //     if(i + n > m) { return -1;}
        //     for(j = 0; j < n; ++j) {
                
                
        //         if(haystack.charAt(k++) != needle.charAt(j)){
        //             break;
        //         }
        //     }
        //     if(j == n) { return i;}
        // }

        // KMP求解 O(m+n)
        int[] lps = getLps(needle); //获得LPS数组
        int i = 0, j = 0;
        while(i < m) {
            if(haystack.charAt(i) == needle.charAt(j)) {
                i++; j++;
                if(j == n) {
                    return i - n;
                }
            } else if(j > 0) {
                // haystack = "ABC ABCDAB ABCDABCDABDE" 
                // needle   =     "ABCDABD"  //j = 6

                // j = lps[6 - 1] = 2; 下一次直接从needle[2]开始比较,实现跳跃->
                // haystack = "ABC ABCDAB ABCDABCDABDE" 
                // needle   =         "ABCDABD"

                j = lps[j - 1]; 
            } else if(j == 0){
                i++;  //首字母都不相同,直接右移比较下一个字母
            }
        }
        return -1;
    }

    int[] getLps(String needle) {
        int n = needle.length();
        int[] lps = new int[n]; //初始化全为0
        
        // 规定自身不算公共子串,lps[0] = 0, 直接从lps[1]开始
        int i = 1, len = 0;
        while(i < n) {
            if(needle.charAt(i) == needle.charAt(len)) {
                lps[i++] = ++len; //lps[i] = len + 1, i = i + 1;
            } else if(len > 0) {
                len = lps[len - 1]; // 如果len > 0,尝试第二长的前缀与后缀,看是否能延续下去
            } else if(len == 0) {
                i++;  // 所有的前缀和后缀都不符合,则lps[i] = 0;(因为初始化都为0,不用再赋值) i++;
            }
        }

        return lps;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值