力扣28 找出字符串中第一个匹配项的下标
题目:
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
示例:
输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
思路:
暴力匹配:
时间复杂度:O(mxn) 空间复杂度:O(1)
两层循环:一层遍历文本串,第二层遍历模式串,一一匹配,如果发现不匹配,则从文本串的第二位重新开始匹配,直至成功。
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if(m > n){
return -1;
}
// 当 needle 是空字符串时应当返回 0
if(m == 0){
return 0;
}
for (int i = 0; i <= n-m; 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;
}
}
KMP算法(模式匹配):
时间复杂度:O(n+m) 空间复杂度:O(m)
KMP的经典思想:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。
前缀:包含首字母,不包含尾字母的所有子串
后缀:包含尾字母,不包含首字母的所有子串
比如模式串aabaaf:前缀(a、aa、aab、aaba、aabaa) 后缀(f、af、aaf、baaf、abaaf)
前缀表:找最长前后缀
a | 0 |
aa | 1 |
aab | 0 |
aaba | 1 |
aabaa | 2 |
aabaaf | 0 |
所以模式串aabaaf的前缀表为
a | a | b | a | a | f |
0 | 1 | 0 | 1 | 2 | 0 |
当aabaaf和文本串匹配冲突时,将j移动到最大前后缀后一位
求next数组的几种方式:
核心:遇见匹配冲突,要回退到合适位置
(1)前缀表 (2)整体右移 (3)整体减一
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
//当needle长度大于haystack时,返回-1
if(m > n){
return -1;
}
// 当needle是空字符串时,返回0
if(m == 0){
return 0;
}
//next数组
int[] next = new int[m];
getNext(next, needle);
//初始化
int j = 0;
for (int i = 0; i < n; i++) {
//当不匹配时,j移动到最大前后缀后一位
while (j > 0 && needle.charAt(j) != haystack.charAt(i))
j = next[j - 1];
//匹配则一直往后移动
if (needle.charAt(j) == haystack.charAt(i))
j++;//这一步后,如果没有其他问题就回到i++循环
//当匹配位数结束时,返回第一个匹配项下标
if (j == m)
return i - m + 1;
}
return -1;
}
//构造next数组
private void getNext(int[] next, String s) {
//1.初始化
int j = 0;
next[0] = 0;
for (int i = 1; i < s.length(); i++) {
//2.前后缀不匹配
while (j > 0 && s.charAt(j) != s.charAt(i))
j = next[j - 1];
//3.前后缀匹配
if (s.charAt(j) == s.charAt(i))
j++;
//4.next数组更新
next[i] = j;
}
}
}
构造next数组代码解析:
则,前面肯定有七位是重合的(如果next数组就是前缀表本身,则next[16]=7)
此时比较第16位和第8位,如果相等,则next[17]=8+1=9