【字符串匹配】【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;
    }
}
相关推荐
x138702859573 小时前
c语言排雷游戏(基础版9*9)
c语言·算法·游戏
折哥的程序人生 · 物流技术专研3 小时前
Java 23 种设计模式:从踩坑到精通 | 原型模式 —— 克隆对象,深拷贝与浅拷贝的坑你踩过吗?
java·设计模式·架构·原型模式·单一职责原则
装不满的克莱因瓶4 小时前
基于 OpenResty 扩展开发实现动态服务注册与发现能力
java·开发语言·架构·openresty
程序员小羊!4 小时前
06Java 异常机制与常用类
java
weixin_523185324 小时前
Java基础知识总结(四):引用数据类型与参数传递机制
java·开发语言·python
sheeta19984 小时前
LeetCode 每日一题笔记 日期:2026.06.06 题目:2196. 根据描述创建二叉树
笔记·算法·leetcode
小欣加油4 小时前
leetcode994 腐烂的橘子
数据结构·c++·算法·leetcode·bfs
宸津-代码粉碎机5 小时前
Spring AI企业级实战|从RAG优化到Agent多工具调度
java·大数据·人工智能·后端·python·spring
噢,我明白了5 小时前
QueryWrapper的使用
java
Chase_______5 小时前
【Java基础 | 15】集合框架(中):Set、HashSet、TreeSet 与哈希表
java·windows·散列表