【字符串匹配】【KMP算法】Leetcode 28 找出字符串中第一个匹配项的下标☆

【字符串匹配】【KMP算法】Leetcode 28 找出字符串中第一个匹配项的下标

---------------🎈🎈题目链接🎈🎈-------------------


🔴任务:要在文本串:aabaabaafa 中查找是否出现过一个模式串:aabaaf

(1)前缀和后缀

前缀是指不包含最后一个字符的,所有以第一个字符开头的连续子串。

比如aabaaf的前缀包括:a,aa,aab,aaba,aabaa

后缀是指不包含第一个字符的,所有以最后一个字符结尾的连续子串。

比如aabaaf的后缀包括:f,af,aaf,baaf,abaaf

(2)前缀表(最长相同的前缀和后缀的长度)

前缀表(最长相同的前缀和后缀的长度)

前缀表(最长相同的前缀和后缀的长度)

前缀表(最长相同的前缀和后缀的长度)

作用:记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀

模式串aabaaf的前缀表:

字符串 最长相等前后缀
a 0
aa 1
aab 0
aaba 1
aabaa 2
aabaaf 0

前缀表的任务 :当前位置匹配失败,找到之前已经匹配上的位置,再重新匹配。

也意味着在某个字符失配时,前缀表会告诉你下一步匹配中,模式串应该跳到哪个位置。

文本串 a a b a a b a a f
模式串下标 0 1 2 3 4 5
模式串 a a b a a f
--前缀表-- 0 1 0 1 2 0

当匹配到 b 的时候,模式串为 f ,匹配失败。

于是寻找 f 前面的字符串 aabaa, 他的最长相等前缀和后缀字符串是 aa , 因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面(即前缀表中发现冲突位置的前面的字符串------aabaa对应的前缀表为【2】,因此找到模式串中下标索引为【2】的位置 ------ b 的位置开始)重新匹配就可以了。

文本串 a a b a a b a a f
模式串 a a b a a f

(3)匹配过程示意

(4)next数组的实现方法

next数组详解视频!
代码随想录文字版
!!!!!代码随想录视频版本!!!!!

1.初始化

【i:后缀的末尾】初始化为1,

【j:前缀的末尾】初始化为0 , next [ 0 ] = 0
j:也代表了i包括i之前的字符串的最长相等前后缀长度

2.处理前后缀不相等的情况 :

j连续回退 ------------ j=next [ j-1 ], (在j大于0的情况下)

3.处理前后缀相同的情况:

j++  →  更新next数组:next [ i ] = j   →    i++

4.求next数组的程序:

java 复制代码
1.初始化 【i:后缀的末尾】初始化为1,  【j:前缀的末尾,也代表i包括i前字符的最长相等前后缀长度】初始化为0 ,   next[0] = 0
2.处理前后缀不相等的情况
3.处理前后缀相同的情况

 //求前缀表next
    private void getNext(int[] next, String s){
        int j = 0;  // 初始化j为前缀末尾0,i为后缀的末尾
        next[0] = 0;
        for(int i = 1; i < s.length(); i++){ 
            while(j > 0 && s.charAt(j) != s.charAt(i)){ 
                j = next[j-1];
            }
            if(s.charAt(j) == s.charAt(i)){ // 如果相同,前缀末尾j++
                j++;
            }
            next[i] = j;  // 将前缀的长度给next[i]
        }
    } 

题目做法

解法1 KMP算法

时间复杂度O(N)

空间复杂度O(N)

java 复制代码
  class Solution {
    public int strStr(String haystack, String needle) {
        if(haystack.length() < needle.length()) return -1;

        int[] next = new int[needle.length()];
        getNext(next, needle);
        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
    private void getNext(int[] next, String s){
        int j = 0;  // 初始化j为前缀末尾0,i为后缀的末尾
        next[0] = 0;
        for(int i = 1; i < s.length(); i++){ 
            while(j > 0 && s.charAt(j) != s.charAt(i)){ 
                j = next[j-1];
            }
            if(s.charAt(j) == s.charAt(i)){ // 如果相同,前缀末尾j++
                j++;
            }
            next[i] = j;  // 将前缀的长度给next[i]
        }
    } 
}

解法2 暴力做法

从大字符串的第一个元素开始,比对小字符串,一旦出现不一样的就从大字符串的下一个元素开始进行比对

如果小字符串遍历结束时都一样,则return对应的下标

如果大字符串遍历完小字符串还没遍历完,return-1

遍历完大字符串前都找不到的话就return -1

时间复杂度O(N^2)

空间复杂度O(N)

java 复制代码
class Solution {
    public int strStr(String haystack, String needle) {
        // 暴力做法
        char[] ch1 = haystack.toCharArray();
        char[] ch2 = needle.toCharArray();
        int result = -1;
        for(int i = 0; i < ch1.length; i++){ // haystack的遍历
            if(ch1[i] == ch2[0]){
                int outside = i;
                int inside = 0;
                while(ch1[outside] == ch2[inside]){
                    outside++;
                    inside++;
                    if(inside == ch2.length){return outside-ch2.length;}
                    else if(outside == ch1.length){return result;}
                }
            }
        }
        return result;
    }
}
相关推荐
Lenyiin9 分钟前
01.02、判定是否互为字符重排
算法·leetcode
鸽鸽程序猿24 分钟前
【算法】【优选算法】宽搜(BFS)中队列的使用
算法·宽度优先·队列
Jackey_Song_Odd24 分钟前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
ProtonBase27 分钟前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
Watermelo61728 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
乐之者v33 分钟前
leetCode43.字符串相乘
java·数据结构·算法
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
古希腊掌管学习的神2 小时前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
云边有个稻草人2 小时前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
半盏茶香2 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法