leetcode每日一题28. 实现 strStr() KMP算法 一文让你彻底了解KMP算法
写在前面
最近状态可能不大好,加上天气寒冷,脚板冰凉,时常熬夜昨晚脑阔发昏就草草睡觉了,一觉醒来已经十点钟了,天气日渐转凉,希望各位友友们可以好好注意身体哦~话不多说,每日打卡从我做起,冲冲冲!
题目
- 实现 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
坚持打卡每一天~
从小付做起
最后
每天进步点 每天收获点
愿诸君 事业有成 学有所获
如果觉得不错 别忘啦一键三连哦~