数据结构 KMP 串的模式匹配 (25 分)

给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出。如果找不到,则输出“Not Found”。

本题旨在测试各种不同的匹配算法在各种数据情况下的表现。各组测试数据特点如下:

  • 数据0:小规模字符串,测试基本正确性;
  • 数据1:随机数据,String 长度为 105​​,Pattern 长度为 10;
  • 数据2:随机数据,String 长度为 105​​,Pattern 长度为 102​​;
  • 数据3:随机数据,String 长度为 105​​,Pattern 长度为 103​​;
  • 数据4:随机数据,String 长度为 105​​,Pattern 长度为 104​​;
  • 数据5:String 长度为 106​​,Pattern 长度为 105​​;测试尾字符不匹配的情形;
  • 数据6:String 长度为 106​​,Pattern 长度为 105​​;测试首字符不匹配的情形。

输入格式:

输入第一行给出 String,为由英文字母组成的、长度不超过 106​​ 的字符串。第二行给出一个正整数 N(10),为待匹配的模式串的个数。随后 N行,每行给出一个 Pattern,为由英文字母组成的、长度不超过 105​​ 的字符串。每个字符串都非空,以回车结束。

输出格式:

对每个 Pattern,按照题面要求输出匹配结果。

输入样例:

abcabcabcabcacabxy
3
abcabcacab
cabcabcd
abcabcabcabcacabxyz
 

输出样例:

abcabcacabxy
Not Found
Not Found

 

 

 

测试点5 6 超时的关键点在于 1.要使用KMP算法 2.大量数据不能使用链表, 不能使用字符链表 char * ,应该用字符串string 或者字符数组 char [] 

 

参考  https://blog.csdn.net/weixin_45845039/article/details/108905362 

#include <iostream>
#include <string>
using namespace std;

int kmpnext[1000001];

void getkmpnext(string pattern){
    int j{0},k{-1};
    kmpnext[0]=-1;
    while(j<pattern.size()-1){
        if(k==-1||pattern[j]==pattern[k]){
            j++;k++;
            kmpnext[j]=k;
        }else{
            k=kmpnext[k];
        }
    }
}

int judge(string str,string pattern){
    int slen=str.size();
    int plen=pattern.size();
    getkmpnext(pattern);
    int j{0},k{0};
    while(j<slen){
        if(k==-1||str[j]==pattern[k]){
            j++;k++;
        }else{
            k=kmpnext[k];
        }
        if(k==plen){
            return j-k;
        }
    }
    return -1;
}

int main(){
    int n;
    string str;
    string pattern;
    cin >> str;// str;
    cin >> n;
    for(int i=0;i<n;i++){
        cin >> pattern;
        int k=judge(str,pattern);
        if(k!=-1){
            char *p=&str[k];
            printf("%s\n",p);
        }else{
            cout << "Not Found" <<endl;
        }
    }
    return 0;
}

 

 

KMP算法改进 使测试点5 尾字符不匹配的情况快速更新,省去部分无效迭代

  • 数据5:String 长度为 106​​,Pattern 长度为 105​​;测试尾字符不匹配的情形;
void getkmpnext(string pattern){
    int j{0},k{-1};
    kmpnext[0]=-1;
    while(j<pattern.size()-1){
        if(k==-1||pattern[j]==pattern[k]){
            j++;k++;
            if(pattern[j]!=pattern[k]){
                kmpnext[j]=k;
            }else{
                kmpnext[j]=kmpnext[k];
            }
        }else{
            k=kmpnext[k];
        }
    }
}

 

 

 

 

使用char* 会使测试点5 6 超时 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;

void getNext(vector<int> &next,char* pattern){
    int j{0},k{-1};
    next[0]=-1;
    while(j<strlen(pattern)-1){
        if(k==-1||pattern[j]==pattern[k]){
            j++;k++;
            next[j]=k;
        }else{
            k=next[k];
        }
    }
}

int main(){
    int n;
    char str[1000001],pattern[1000001];
    scanf("%s",str);// str;
    int slen=strlen(str);
    cin >> n;
    for(int i=0;i<n;i++){
        scanf("%s",pattern);
        int plen=strlen(pattern);
        vector<int> next(plen);
        getNext(next, pattern);
        int j{0},k{0};
        while(j<slen&&k<plen){
            if(k==-1||str[j]==pattern[k]){
                j++;k++;
            }else{
                k=next[k];
            }
        }
        if(k==plen){
            char *p=&str[j-k];
            cout << p <<endl;
        }else{
            cout << "Not Found" <<endl;
        }
    }
    return 0;
}

 

posted @ 2021-05-27 01:45  keiiha  阅读(431)  评论(0编辑  收藏  举报