题目:pat
表示模式串,长度为M
,txt
表示文本串,长度为N
。KMP 算法是在txt
中查找子串pat
,如果存在,返回这个子串的起始索引,否则返回 -1。
方法1:KMP算法,首先根据模式串求得其最大前缀和后缀数组,然后进行模式串和原串的匹配。
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0) {
return 0;
}
//求匹配串的最大前缀和后缀数组
int[] prefix = new int[m];
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && needle.charAt(i) != needle.charAt(j)) {
//核心步骤,固定写法
j = prefix[j - 1];
}
if (needle.charAt(i) == needle.charAt(j)) {
j++;
}
prefix[i] = j;
}
//字符串匹配
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
//核心步骤
j = prefix[j - 1];
}
if (haystack.charAt(i) == needle.charAt(j)) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
}
方法2:有限状态机,建立一个dp数组,dp[i][j]表示当状态i遇到j时下一刻的状态。
class Solution {
public:
//存储状态
vector<vector<int>>dp;
int patternMatching(string pattern, string value) {
int m=pattern.size();
int n=value.size();
dp.resize(m,vector<int>(256,0));
KMP(pattern);
int j=0;
for(int i=0;i<n;i++){
j=dp[j][value[i]];
//找到m个状态,即完成匹配
if(j==m) return i-m+1;
}
return -1;
}
void KMP(string &pattern){
dp[0][pattern[0]]=1;
int x=0;
for(int i=1;i<pattern.size();i++){
for(int j=0;j<256;j++){
//状态转移
//遇到匹配的字符,状态加1
if(pattern[i]==j){
dp[i][j]=i+1;
}else{//字符不匹配,回到前一个与当前状态相同的时刻
dp[i][j]=dp[x][j];
}
}
//更新与当前状态相同的上一状态
x=dp[x][pattern[i]];
}
}
};