zoukankan      html  css  js  c++  java
  • 【字符串】KMP字符串匹配

    百度百科

    Definition

    (KMP)算法是一个字符串匹配算法。他接收两个字符串(A,B),返回(B)(A)中出现的所有位置。

    以下称需要被匹配的串(A)为主串,可能在主串中多次出现的串(B)为模式串。约定主串的长度为(n),模式串的长度为(m)

    朴素的想法显然是对使用两个指针(i,j)分别指向(A,B)。枚举(i)的位置,暴力右移(j)观察是否匹配。复杂度(O(nm))

    考虑当一个位置失配的时候,如果主串的当前位置与模式串前面的某些位置相同,则可以直接跳到前面的位置,而不用从头开始。

    举个例子:

    主串:aaabbbc

    模式串:aabbbc。

    从主串第一个位置开始匹配,当(i=2,j=2)时,发现(i+1)(j+1)失配,但是考虑完全不需要从第二个位置令(i=2,j=1)重新匹配,而是直接令(j)等于可以与(i)匹配的上一个前缀,即可重新匹配。所谓上一个前缀,设(j)被赋值为(k),则(k)满足主串[i-k~i]==模式串[1~k]。我们可以使用一个(next)数组直接预处理这个前缀,然后直接在失配时令模式串指针向前按照(next)数组向前跳即可。

    考虑(next)数组的求法:把模式串错一位与自身匹配。j跳到的位置显然就是当前位置的(next)

    Example

    传送门

    Description

    如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

    为了减少骗分的情况,接下来还要输出子串的前缀数组next。

    Input

    两行分别是(s1)(s2)

    Output

    若干行,每行包含一个整数,表示s2在s1中出现的位置

    接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值。

    Hint

    字符串长度不超过(10^6)

    Code

    #include<cstdio>
    #include<cstring>
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long int ll;
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch=getchar(),lst=' ';
    	while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    	while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	if(lst == '-') x=-x;
    }
    
    namespace IO {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x,const char aft,const bool pt) {
    	if(x < 0) {x=-x,putchar('-');}
    	rg int top=0;
    	do {IO::buf[++top]=x%10+'0';} while(x/=10);
    	while(top) putchar(IO::buf[top--]);
    	if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T a,const T b) {return a > b ? a : b;}
    template <typename T>
    inline T mmin(const T a,const T b) {return a < b ? a : b;}
    template <typename T>
    inline T mabs(const T a) {return a < 0 ? -a : a;}
    
    template <typename T>
    inline void mswap(T &_a,T &_b) {
    	T _temp=_a;_a=_b;_b=_temp;
    }
    
    const int maxn = 1000010;
    
    char s1[maxn],s2[maxn];
    int nxt[maxn];
    
    void KMP(char *a,char *b,int l1,int l2,bool pt) {
    	rg int i,j=0;
    	for(i=pt?1:2;i<=l1;++i) {
    		while(j&&(b[j+1] != a[i])) j=nxt[j];
    		if(b[j+1] == a[i]) ++j;
    		if(!pt) nxt[i]=j;
    		if(j == l2) {
    			qw(i-l2+1,'
    ',true);
    		}
    	}
    }
    
    int main() {
    	scanf("%s
    %s",s1+1,s2+1);
    	int l1=strlen(s1+1),l2=strlen(s2+1);
    	KMP(s2,s2,l2,l2,false);
    	KMP(s1,s2,l1,l2,true);
    	for(rg int i=1;i<l2;++i) qw(nxt[i],' ',true);
    	qw(nxt[l2],'
    ',true);
    	return 0;
    }
    
  • 相关阅读:
    利用jquery获取html中被选中的input的值
    获取表单选中的值(利用php和js两种方式)
    复习
    Ajax请求中的async:false/true的作用
    Jquery
    C#创建控制台项目引用Topshelf的方式,部署windows服务。
    你循环的时候就可以给他们赋值了,那么就不用addClass,再根据类选择器处理,代码能一气呵成就别写成两段了
    SQL server 数据库中插入中文变???格式乱码的问题另一种容易忽略的情况(C#操作dapper)
    SQL 两个表有关联,通过其中一个表的列,更新另一个表的列。
    SQL server 存储过程中 列传行
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9878556.html
Copyright © 2011-2022 走看看