栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

21、★★★ KMP算法-字符串匹配算法-28.实现strStr()

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

21、★★★ KMP算法-字符串匹配算法-28.实现strStr()

题目描述:

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回  -1 。

来源:力扣(LeetCode)

KMP算法理解:

循环比较中,主子符串的位置是不回退的;就是每次回退比较 子字符串中的内容;先将最大的 公共前后缀重叠,如果不对,就以该不符合的点为界限,继续搜寻该点之前的最大公共前后缀!

解题重要步骤:

①正确的创建 next数组(等同于前缀表);

②使用for循环遍历主字符串,结合next数组进行 遍历对比。

KMP学习:

kmp算法的理解:

相比于暴力,降低比较的次数;

①在出现不匹配的字符处,主字符串S和子字符串P一部分内容是对照的;默认为字符数组,如图:

S[1] 与P[0]对比,明显不可能成功;S[2]与P[0]也不能成功 !

下次比较的时候,尝试跳过不可能成功的尝试!

引出next数组:也就是找最大的相等的前后缀(在子字符串中找),实际还是为了下次比较时,用子字符串的前缀 抵消掉 主字符串中 到 不匹配处之前的后缀!也就是匹配上了,不需要再进行比较,直接从原来不匹配处继续比较!

②next数组:就是记录最大相同前后缀的长度:如下所列

 ③最重要:next数组的构建:在P字符串中自己与自己匹配对比:其实等价于与S主字符串比较了

next[i] 就是 i位置上的,之前子串的最大相等前缀的长度;落在了第一个不相等的位置;如上next[4]就等于2,落在了 b 字符处!

则 不断往后计算时,

一个重要的对比:前缀必然包含子串头;后缀必然包含子串尾!

1)如果 P[x] = P[next[x-1]] ,就直接加1,next[x] = now + 1;此时的now就等于next[x-1];

2)如果不相等,就将原来的 前缀作为一个串,找到他的最大相等的前缀,把now更新,now = next[now - 1]继续比较;不断迭代往前;

3)now最终只能回到 0 处,不能再往前!

next数组的构建:

for循环:

        int size = s.length();
        int[] next = new int[size];
        int now = 0;//此时代表的也是 next[0]的值,此时为0
        //注意 now的值和 数组下标的对应关系;now刚好是最大公共前后缀后一位的位置!
        for(int i = 1;i < size;i++){//从一开始构造
            if(s.charAt(i) == s.charAt(now)){
                now++;//now后移
                next[i] = now;
            }
            //此时不相同了,就是后缀长度不能加1;甚至一个都没有;要循环回去
            else if(now != 0){
                //直接在上一个位置的 最大前后缀的字符串里 往前找
                now = next[now - 1];
                //此时后面 i 不能加1
                //使用 while和此不一样
                i--;
            }
            else{
                //此时往前找到了头now = 0;并且还不相等,就是首位都不相等
                next[i] = now;
            }
        }

while循环

        int[] next = new int[p.length];
        int now = 0;//其实就是第一个位置 index为0时,next数组的元素
        int i = 1;
        while(i < p.length){
            //如果后缀加一,与前缀加一的位置相同,就在该位置的next 加以
            if(p[i] == p[now]){
                now++;
                next[i] = now;
                i++;
            }
            //如果加一不相等,且此时还没到最初的位置,则
            else if(now != 0){
                now = next[now - 1];
            }
            //如果已经到了头 就是p[i] != p[now] && now == 0
            else{
                next[i] = now;
                i++;
            }
        }

思路:

1)暴力查找:每次后移一位,时间复杂度O(N * M)

2)KMP算法:每次跳跃多位,将不可能成功的情况排除!时间复杂度 O(N +M)

代码:

1)KMP算法:每一步详解写在了代码上

class Solution {
    public int strStr(String haystack, String needle) {
        if(needle.length() == 0) return 0;
        char[] ne = needle.toCharArray();
        int[] next = getNext(ne);//得到next数组
        int j = 0;
        for(int i = 0;i < haystack.length();i++){
            //如果没匹配上
            while(j > 0 && needle.charAt(j) != haystack.charAt(i)) j = next[j - 1];
            //对上了,就后移,继续比较
            if(needle.charAt(j) == haystack.charAt(i)) j++;
            if(j == needle.length()) return i - needle.length() + 1;
        }
        return -1;//循环结束也没有找到合适的字串
    }
    //构建 next数组
    int[] getNext(char[] p){
        int[] next = new int[p.length];
        int now = 0;//其实就是第一个位置 index为0时,next数组的元素
        int i = 1;
        while(i < p.length){
            //如果后缀加一,与前缀加一的位置相同,就在该位置的next 加以
            if(p[i] == p[now]){
                now++;
                next[i] = now;
                i++;
            }
            //如果加一不相等,且此时还没到最初的位置,则
            else if(now != 0){
                now = next[now - 1];
            }
            //如果已经到了头 就是p[i] != p[now] && now == 0
            else{
                next[i] = now;
                i++;
            }
        }
        //得到的就是 next数组,要匹配的字符串的next数组
        return next;
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768067.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号