KMP字符串匹配算法

5 篇文章 1 订阅
1 篇文章 0 订阅

哇哇哇!好难受,写了两个多小时,才通过全部样例。洛谷P1308

科普区(国内,国外

计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个W的出现位置。此算法通过运用对这个词在不匹配时本身就包含足够的信息来确定下一个匹配将在哪里开始的发现,从而避免重新检查先前匹配的字符

这个算法是由高德纳沃恩·普拉特在1974年构思,同年詹姆斯·H·莫里斯也独立地设计出该算法,最终由三人于1977年联合发表。(摘自维基百科)


kmp算法的核心思想是构造一个模式串构造一个next数组标记模式串。next数组标记当前位置在模式串中的最大前缀。当在与文本串比较的失败的时候,模式串直接返回到next数组对应下标的位置。而不用直接返回模式串的开头的位置,重新从模式串的开头查找,从而达到在O(n)时间完成对字符串的查找。

题目理解

这道题的思想是使用字符串匹配,虽然可以直接使用string进行比较。题目比较简单就当练习一下字符串比较查找。题目中需要注意的是给模式串和文本串的最后加一个“ ”空格,用于简化判断字符串的比较。另一个需要注意的是在匹配同一字符串的时候要注意开头字符串的无空格,文本中间单词前要有空格。


AC代码

#include <iostream>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
string s1,s2;

int next[10];

void getNext() {
    int k=0;
    memset(next,0,sizeof(next));
    for(int i=1; i<s1.length(); i++) {
        k = next[i-1];
        if(s1[i]==s1[k]) {
            next[i]=k+1;
        } else {
            while(true) {
                int temp=next[k];
                if(s1[i]==s1[temp]) {
                    next[i]=temp+1;
                    break;
                }
                if(temp<=0) {
                    next[i]=0;
                    break;
                }
                k--;
            }
        }
    }
}


int main() {
    getline(cin,s1);
    getline(cin,s2);
    s1 = s1 + " ";//添加空格简化问题
    s2 = s2 + " ";
    transform(s1.begin(),s1.end(),s1.begin(),::tolower);//字符串转小写
    transform(s2.begin(),s2.end(),s2.begin(),::tolower);
    getNext();//获取next数组
    int ans=0;
    int flag=-1;
    int i=0,j=0;
    while(i<s2.length()) {
        while(i<s2.length() && j<s1.length() && s1.at(j)==s2.at(i)) {
            if(j==s1.length()-1) {//结束
                if((i-j==0) || (i-j>0 && s2[i-j-1]==' ')) {//判断前缀空格
                    ans++;//匹配字符串自增
                    if(flag==-1) {//获取第一位匹配字符
                        flag=i-j;
                    }
                }
                j=0;
                break;//跳出循环
            }
            i++;
            j++;
        }
        i++;
        //**************
        j=next[j];//划重点,next数组的运用
        //**************
    }
    if(flag!=-1)
        cout<<ans<<" "<<flag<<endl;
    else
        cout<<-1<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值