next数组初始化
char a[1000006];//原串
char p[1000006];//子串
int pmt[1000006];void getNext(int m){int j=0;pmt[0]=0;for(int i=1;i<m;++i){while(j>0 && p[i]!=p[j])j=pmt[j-1];if(p[i]==p[j])++j;pmt[i]=j;}
}
以下实例基于上述getNext函数及数据结构执行:
实例1:寻找并输出匹配位置
下例代码中,n为原串a长度,m为子串p长度。以原串第一个字母为下标‘0’位置。
void kmp_findstr(int n,int m){getNext(m);for(int i=0,j=0;i<n;i++){while(j && a[i]!=p[j])j=pmt[j-1];if(a[i]==p[j])++j;if(j==m){cout<<i-j+1<<endl;j=pmt[j-1];}}
}
实例2:寻找第一次匹配位置
函数返回原串第一次匹配子串的位置,如果不匹配则返回-1。
int kmp_findfirst(int n,int m){int place=-1;getNext(m);for(int i=0,j=0;i<n;++i){while(j>0 && p[j]!=a[i])j=pmt[j-1];if(p[j]==a[i])++j;if(j==m){place=i-m+1;break;}}return place;
}
实例3:计算匹配次数
int kmp_strcount(int n,int m){int i,j=0,res=0;getNext(m);for(i=0;i<n;++i){while(j>0 && p[j]!=a[i])j=pmt[j-1];if(p[j]==a[i])++j;if(j==m)++res;}return res;
}
PS: 力扣周赛最后一题用到KMP了,直接AC。 😊
顺便附上源代码:
class Solution {
private:char num[1000006];char p[1000006];int kmp_next[1000006];void getNext(int m){int j=0;kmp_next[0]=0;for(int i=1;i<m;++i){while(j>0 && p[i]!=p[j])j=kmp_next[j-1];if(p[i]==p[j])++j;kmp_next[i]=j;}}int kmp(int n,int m){int i,j=0,res=0;getNext(m);for(i=0; i<n; ++i){while(j>0 && p[j]!=num[i])j=kmp_next[j-1];if(p[j]==num[i])++j;if(j==m)++res;}return res;}
public:int countMatchingSubarrays(vector<int>& nums, vector<int>& pattern) {int n=nums.size(),m=pattern.size();for(int i=0;i<n-1;i+=1){if(nums[i+1]>nums[i])num[i]='a';else if(nums[i+1]==nums[i])num[i]='b';else if(nums[i+1]<nums[i])num[i]='c';}num[n-1]='d';for(int i=0;i<m;i+=1){if(pattern[i]==1)p[i]='a';else if(pattern[i]==0)p[i]='b';else if(pattern[i]==-1)p[i]='c';}int res=kmp(n,m);return res;}
};