LeetCode每日一题 28.实现 strStr()
难度:简单(其实不简单,要理解KMP算法)
语言:java
题目内容
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
解题思路
暴力解法比较简单,就是用i遍历haystack直到发现第一位与needle相同,然后开始用j遍历needle,分别为haystack[i+j] 和 nddle[j],直到不同,继续回到i进行遍历,复杂度为O(m*n),因为要两次遍历。代码如下
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0){
return 0;
}
for (int i = 0; i + m <= n; i++) {
for (int j = 0; j < m; j++) {
if (haystack.charAt(i + j) != needle.charAt(j)) {
break;
}
else if (j==m-1){
return i;
}
}
}
return -1;
}
}
另外的解法就是KMP算法,这是我第一次接触到这个算法,但是好像计算机考研的同学是需要学习这个的, 走捷径出国的代价就是很多知识都不知道啊。
KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。
这个以我的水平很难解释得清,我觉得借鉴外部视频会好很多,因为有动态的演示,放三个链接在下面,B站真的是学习宝藏。
我觉得看明白这仨,再来看题目就简单多了,其实就是对模式串的一个重复部分的分析,以跳过不必要的匹配部分。
那回到这道题目,可以用KMP算法来解答了,具体代码如下,详细部分见注释。
class Solution {
public int strStr(String haystack, String needle) {
if (needle.isEmpty()) return 0;
int n = haystack.length(), m = needle.length();
//先构建next函数
int[] next = new int[m];
for (int i = 1, j= 0; i<m; i++){
// i 为后缀末尾,j为前缀末尾(同时也是相同长度)
while (j>0 && needle.charAt(i) != needle.charAt(j)){
j = next[j-1]; // 向前一位寻找回退位置
}
if (needle.charAt(i) == needle.charAt(j)){
j++; //匹配相同,向后移动一位,同时更新相同前后缀的长度
}
next[i]=j; //更新next数组
}
//next函数的回退位置需要看前一位的值,next函数的解法基本类似,可以进行记忆
//接下来求解题目
for(int i = 0, j =0; i<n;i++){
while (j>0 && haystack.charAt(i) != needle.charAt(j)){
j = next[j-1];
}
if (haystack.charAt(i) == needle.charAt(j)){
j++;
}
if(j == m ){
return i-m+1;
}
}
}
}
私认为,直到这一个KMP算法可以解决相同字符串的问题就好了,死记硬背不是我们想要学习的方向,更多的是使用。