leetcode每日一题28. 实现 strStr() 一文让你彻底了解KMP算法

leetcode每日一题28. 实现 strStr() KMP算法 一文让你彻底了解KMP算法

写在前面

最近状态可能不大好,加上天气寒冷,脚板冰凉,时常熬夜昨晚脑阔发昏就草草睡觉了,一觉醒来已经十点钟了,天气日渐转凉,希望各位友友们可以好好注意身体哦~话不多说,每日打卡从我做起,冲冲冲!

题目

  1. 实现 strStr()
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,
请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。
如果不存在,则返回  -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?
这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。
这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。

示例

示例1:

输入:haystack = "hello", needle = "ll"
输出:2

示例2:

输入:haystack = "aaaaa", needle = "bba"
输出:-1

示例3:

输入:haystack = "", needle = ""
输出:0

KMP思路解析

KMP算法是什么?

它是一个著名的字符串匹配算法,效率高的离谱,但是理解起来却十分的复杂!

这个算法一般来说,如果第一遍无法掌握时,之后再看就会花费成倍的精力

话不多说,咱们来由浅入深好好理解这个’非人’的算法吧~

本人参阅了《labulangdong的算法小抄》一书,说真的拉不拉东的算法思路绝了!!!特此推荐

下文约定:str代表的是文本串,pattern是匹配串,KMP算法就是在str中查找对应的子串pattern。如果存在返回子串的起始下标,没有就返回-1。KMP用到了回溯的思想!

1、暴力匹配一遍就会

字符串匹配当然可以用暴力来破解,思路在于从str起始索引0进行匹配pattern,匹配上了则返回起始索引,找不到就将索引后移至1,以此类推…

在这里插入图片描述

代码实现

class Solution {
    public int strStr(String haystack, String needle) {
        int n = haystack.length(), m = needle.length();
        //双重for循环
        for (int i = 0; i + m <= n; i++) {
            boolean flag = true;
            for (int j = 0; j < m; j++) {
                if (haystack.charAt(i + j) != needle.charAt(j)) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                return i;
            }
        }
        return -1;
    }
}

执行结果

在这里插入图片描述

及其容易理解,但是你会发现这样的时间复杂度在O(n^2)那如何进行优化呢?KMP的算法创始人们告诉你了这个非人算法.

2、KMP算法究竟是何方神圣?

在这里插入图片描述
KMP 算法的不同之处在于,它会花费空间来记录一些信息,在上述情况中就会显得很聪明。由于pattern中根本不存在c字符,所以可以直接跳过这个字符:

KMP算法省略了重复查询的过程,大大优化了速率,尤其是在字符串很长的情况下,极大地优化了时间速率。

KMP算法框架:

class Solution {
    public int strStr(String str, String pattern) {
        if (pattern.length() == 0)return 0;

        int m = str.length();
        int n = pattern.length();

        str = " " + str;
        pattern = " " + pattern;
        
		//第一个难点!!!
		//寻找next数组用于进行后续回溯
        int [] next = new int [n+1];
        //从第二个字符开始遍历
        for (int i = 2 ,j = 0 ;i< n+1;i++){
        	//当 此时的字符与前一个字符进行匹配 匹配失败则进行回溯
            while (j> 0 && pattern.charAt(i) != pattern.charAt(j+1)) j = next[j];
            //匹配成功 就让j后移
            if (pattern.charAt(i) == pattern.charAt(j+1))j++;
            //记录此时回溯数组 下标j
            next[i] = j;
        }
		//此时匹配Str与pattern 从0至m 依次进行匹配
        for (int i = 1,j = 0;i<m+1;i++){
        	//匹配失败 就回溯
            while(j > 0 && str.charAt(i) != pattern.charAt(j+1)) j = next[j];
            //成功就后移j
            if (str.charAt(i) == pattern.charAt(j+1))j++;
            //当j的长度=子串长度时 返回 此时坐标-子串长度获取得到初始位置。
            if (n == j)return i - n ;
        }
        return -1;
    }
}

KMP重点在于如何获取这个next数组!!!
next数组中的难点在于回溯坐标的确定
当此时匹配当前字符与下一个字符不相互匹配时就需要进行回溯到的位置,
否则就一直进行匹配下一个字符。

执行效率
在这里插入图片描述

写在最后

如果此题你掌握了 个人建议可以去刷刷214.最短回文串这道题
思路是大题一致的甚至更为’简单’一些。加油!,相信你自己是可以的!

今天是2021-12-28
坚持打卡每一天~
从小付做起

最后

每天进步点 每天收获点

愿诸君 事业有成 学有所获

如果觉得不错 别忘啦一键三连哦~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alascanfu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值