字符串模式匹配,这种题考察肯定不能用暴力写,最好能写出KMP算法
暴力匹配
暴力匹配很容易想到,时间复杂度是(N-L)L
N,L分别是str和pattern的长度
class Solution {
public:
int strStr(string haystack, string needle) {
int m = haystack.size();
int n = needle.size();
if(n == 0)
return 0;
for(int i=0;i<=m-n;i++){
if (haystack[i] == needle[0]){
string s = haystack.substr(i,n);
if(s == needle)
return i;
}
}
return -1;
}
};
暴力的一个小优化,检测到不匹配的字符就停止检测
/
class Solution {
public:
int strStr(string haystack, string needle) {
int m = haystack.size();
int n = needle.size();
if(n == 0)
return 0;
for(int i=0;i<=m-n;i++){
if (haystack[i] != needle[0])
continue;
for (int j=0;j<n;++j){
if (haystack[i+j] != needle[j])
break;
if (j == n - 1)
return i;
}
}
return -1;
}
};
KMP算法
KMP算法的核心是前缀函数,对于长度为 m 的字符串 s,其前缀函数
π
(
i
)
(
0
≤
i
<
m
)
\pi(i) (0 \le i < m)
π(i)(0≤i<m)
表示 s 的子串 s[0:i]的最长的相等的真前缀与真后缀的长度。特别地,如果不存在符合条件的前后缀,那么
π
(
i
)
=
0
\pi(i) = 0
π(i)=0。其中真前缀与真后缀的定义为不等于自身的的前缀与后缀。
aabaaab
这个前缀的好处是在匹配模式串时能够获得已经匹配到的字符数量;
比如当前扫描到aabaaa, 假设之前aab子串中匹配到aa是成功的,之后的字符失败了,现在再匹配还是要匹配aa,然后再扫描后面的字符,也就是后缀要有aa
前缀函数的计算
假设串为aabaaaabaaaab;
在i的位置有
π
(
i
)
=
t
\pi(i) = t
π(i)=t,i + 1之后,s[i+1] 对应的字符是 s[t]
也就是说如果 s[i+1]=s[
π
(
i
)
=
t
\pi(i) = t
π(i)=t] , 那么
π
(
i
+
1
)
=
π
(
i
−
1
)
+
1
\pi(i + 1) = \pi(i−1)+1
π(i+1)=π(i−1)+1
class Solution {
public:
int strStr(string haystack, string needle) {
int n = haystack.size(), m = needle.size();
if (m == 0) {
return 0;
}
vector<int> pi(m);
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && needle[i] != needle[j]) {
j = pi[j - 1];
}
if (needle[i] == needle[j]) {
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && haystack[i] != needle[j]) {
j = pi[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/implement-strstr/solution/shi-xian-strstr-by-leetcode-solution-ds6y/
来源:力扣(LeetCode)