zoukankan      html  css  js  c++  java
  • KMP初步

    KMP算法

    介绍

    用处:用于串的模式匹配,即找出模式串在主串中的出现位置

    朴素想法,直接遍历两个串,失配回到主串开始比较位置的下一位继续匹配,复杂度(O(nm))

    KMP算法即在(O(n+m))复杂度内匹配的算法

    算法实现

    通过一个叫(next)数组的东西,使指向主串的(i)指针不回溯,只改变指向模式串的(j)指针

    所以重点就是在于失配后(j)移动到哪里,也就是关于(next)数组的部分

    (Next[])的基本意义:

    在串ss中寻找串s,

    当前已经得到了(s[1…j-1]=ss[i-j+1…i-1])

    正在检查(s[j]与ss[i])是否相等,发现不相同,失配,

    (如果相同,i和j自增1,继续向后检查)

    如果按照暴力算法,ss上的“指针”需要回到i-j+1,s上的“指针”j需要回到0;

    我们试图让i往回不移动,仅仅是让j往回移动,移动到一个合适的、不会丢失任何匹配可能的位置,这个位置就是我们的Next[j]。

    (next)数组的定义是

    即最大的(P[1 , k-1] = P[j-k+1 ,j-1])

    求出next之后在失配时让(j=next[j])就是KMP算法了

    如何求出(next)

    已知 Next[j]=kn。

    即存在 (s[1,kn-1]=s[j-kn+1,j-1])

    (最长后缀等于字符串前缀)

    分情况讨论,对于(j+1)(现在需要求的Next数组位)有两种情况

    1. 若$ s[kn]=s[j]$,那么可以得到 (s[1,kn]=s[j-kn+1,j]) ,根据定义,不难推断出(Next[j+1]=kn+1)
    2. 若不相等,则转化为匹配自身的问题,不断地令(j=Next[j])直至出现 (s[kn]=s[j])(转化为1情况,(Next[j+1]=kn+1));或者(j=1)(找不到后缀等于前缀)匹配到头,(Next[j+1]=1)

    7月22日更新:

    找到了更好理解的kmp板子,这个模板中,nxt[i]表示最大的x,满足s[1 : x] 是s[1 : i] 的后缀,匹配的时候用前一个nxt来匹配。如果字符串从0开始,那么将j+1改为j,nxt[j]改为nxt[j-1]即可,j的初值不用改变

    模版

    #include <bits/stdc++.h>
    #define N 1000005
    using namespace std;
    
    int n, m;
    
    int nxt[N];
    int s[N], t[N];
    
    void getNext(int s[]) {
    	nxt[1] = 0;
        for (int i = 2, j = 0; i <= m; i++) {
            while (j && s[i] != s[j + 1]) j = nxt[j];
            if (s[i] == s[j + 1]) j++;
            nxt[i] = j;
        }
    }
    
    int kmp(int s[], int t[], int pos) {
    	for (int i = pos, j = 0; i <= n; i++) {
    		while (j && t[j + 1] != s[i]) j = nxt[j];
    		if (t[j + 1] == s[i]) j++;
    		if (j >= m) return i - m + 1;
    	}
    	return -1;
    }
    
    int main() {
    	int t1;
    	scanf("%d", &t1);
    	while (t1--) {
    		scanf("%d%d", &n, &m);
    		for (int i = 1; i <= n; i++) {
    			scanf("%d", &s[i]);
    		}
    		for (int i = 1; i <= m; i++) {
    			scanf("%d", &t[i]);
    		}
    		memset(nxt, 0, sizeof(nxt));
    		getNext(t);
    		printf("%d
    ", kmp(s, t, 1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    sql 将某列转换成一个字符串 for xml path用法
    IAsyncResult 接口异步 和 匿名委托
    存储过程和sql语句的优缺点
    ADO.net中常用的对象有哪些?分别描述一下。
    ASP.Net页面生命周期
    请说明在.net中常用的几种页面间传递参数的方法,并说出他们的优缺点。
    .net常用的传值的方法
    SQL列合并
    程序员的情书!
    程序员的表达!
  • 原文地址:https://www.cnblogs.com/artoriax/p/10683822.html
Copyright © 2011-2022 走看看