求解字符串匹配问题---KMP算法

模式串匹配,给定一个需要处理的文本串和一个需要再文本串中搜索的模式串,查询再该文本串中,给出的模式串的出现有无,次数,位置等
KMP的精髓在于,对于每次匹配失败后,我们都不会重新开始枚举,而是根据我们已经得知的数据,从某个特定的位置开始匹配,对于模式串的每一个,都有唯一的"特定变化位置",在这个匹配失败后的特定变化位置可以帮助我们利用已有的数据不用从头匹配,从而节约时间
要求KMP我们有两个步骤
1.求模式串的next数组

void getnext(){
int lenss=strlen(ss);
int i=0,j=-1;
Next[0]=-1;
while(i<lenss){
    if(j==-1 || ss[i] == ss[j]){//当j为-1 或者 ss[i] == ss[j] 时,我们把当前位置i的下一个,即 i+1 的要进行比较的位置变为 j+1
        Next[++i]=++j;
    }
    else {//匹配失败,j变为 他之前一个下一次要匹配的位置
        j = Next[j];
    }
}
}

2.根据题意求KMP

bool KMP(){//匹配查找子串
getnext();
int i=0,j=0;//i 代表文本串匹配位置 , j 代表模式串匹配位置
int lenstr = strlen(st);
int lenss = strlen(ss);
while(i < lenstr){
    if(j==-1 || st[i] == ss[j]){
        i++;
        j++;
    }
    else {
        j = Next[j];
    }
    if(j == lenss){
       return true;
    }
}
return false;
}

完整代码

#include<bits/stdc++.h>
using namespace std;
char st[1000010];
char ss[1000010];
int Next[1000010];
void getnext();
bool KMP(){//匹配查找子串
getnext();
int i=0,j=0;//i 代表文本串匹配位置 , j 代表模式串匹配位置
int lenstr = strlen(st);
int lenss = strlen(ss);
while(i < lenstr){
    if(j==-1 || st[i] == ss[j]){
        i++;
        j++;
    }
    else {
        j = Next[j];
    }
    if(j == lenss){
       return true;
    }
}
return false;
}
void getnext(){//得到next数组
int lenss=strlen(ss);
int i=0,j=-1;
Next[0]=-1;
while(i<lenss){
    if(j==-1 || ss[i] == ss[j]){//当j为-1 或者 ss[i] == ss[j] 时,我们把当前位置i的下一个,即 i+1 的要进行比较的位置变为 j+1
        Next[++i]=++j;
    }
    else {//匹配失败,j变为 他之前一个下一次要匹配的位置
        j = Next[j];
    }
}
}
int main(){
scanf("%s%s",st,ss);
//判断是否匹配到当前字符串
if(KMP()){
    printf("在文本串 %s 中,匹配到了子串 %s",st,ss);
}
else {
    printf("在文本串 %s 中,没有找到子串 %s",st,ss);
}
return 0;
}

题型(单个字符串匹配问题)
1.有无子串,出现了几次, 出现的位置
2.查找当前串的循环子串,就是找循环节,即是求最长公共前后缀
abcabcab
最长公共前后缀为5(abcab)
例如:
给你一个字符串 s1 ,它是由某个字符串 s2 不断自我连接形成的,但是字符串 s2 是不确定的,现在只想知道它的最短长度是多少
我们呢就只需要求它的next数组,因为后面的和前面的相匹配了,有循环,i就会不断地指向前面匹配到的j,(i 和 j 等距滑动),即next[i]!= 0,最后答案就是 n-next[n]

#include<bits/stdc++.h>
using namespace std;
char st[1000010];
char ss[1000010];
int Next[1000010];
void getnext(){
int lenss=strlen(ss);
int j=-1,i=0;
Next[0]=-1;
while(i<lenss){
    if(j==-1||ss[i]==ss[j]){
        Next[++i] = ++j; //如果当前位置匹配或者j==-1,Next就存上i的下一个就与j的下一个匹配
    }
    else
        j = Next[j];//不匹配回溯
}
}
int main(){
int n;
scanf("%d",&n);
scanf("%s",ss);
getnext();
printf("%d ",n-Next[n]);
return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种用于字符串匹配的高效算法,它可以在O(m+n)的时间复杂度内解决DNA匹配问题。下面是KMP算法的详细设计: 1. 预处理模式串(pattern): - 初始化两个指针i和j,分别指向模式串的第一个字符和第二个字符。 - 创建一个辅助数组next,用于存储每个字符对应的最长公共前后缀的长度。 - 将next初始化为-1,next初始化为0。 - 进入循环,直到i等于模式串的长度-1: - 如果j等于-1或者当前字符和模式串的第j个字符相等,则将i和j分别增加1。 - 如果当前字符和模式串的第j个字符相等,则将next[i+1]赋值为j。 - 否则,将next[i+1]赋值为next[j]。 - 否则,将j赋值为next[j]。 2. 匹配文本串(text): - 初始化两个指针i和j,分别指向文本串的第一个字符和模式串的第一个字符。 - 进入循环,直到i等于文本串的长度或者j等于模式串的长度: - 如果j等于-1或者当前字符和模式串的第j个字符相等,则将i和j分别增加1。 - 否则,将j赋值为next[j]。 3. 返回匹配结果: - 如果j等于模式串的长度,则表示匹配成功,返回匹配的起始位置为i-j。 - 否则,表示匹配失败,返回-1。 下面是一个使用KMP算法求解DNA匹配问题的示例代码: ```python def kmp_search(text, pattern): n = len(text) m = len(pattern) next = [-1] * m # 预处理模式串 i = 0 j = -1 while i < m - 1: if j == -1 or pattern[i] == pattern[j]: i += 1 j += 1 next[i] = j else: j = next[j] # 匹配文本串 i = 0 j = 0 while i < n and j < m: if j == -1 or text[i] == pattern[j]: i += 1 j += 1 else: j = next[j] # 返回匹配结果 if j == m: return i - j else: return -1 text = "ACGTACGTACGTACGT" pattern = "CGTACG" result = kmp_search(text, pattern) print("匹配的起始位置为:", result) # 输出:3 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值