给定一个模式串S,以及一个模板串P,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模板串P在模式串S中多次作为子串出现。

求出模板串P在模式串S中所有出现的位置的起始下标。

输入格式

第一行输入整数N,表示字符串P的长度。

第二行输入字符串P。

第三行输入整数M,表示字符串S的长度。

第四行输入字符串M。

输出格式

共一行,输出所有出现位置的起始下标(下标从0开始计数),整数之间用空格隔开。


一个字符串匹配的模板, 求字符串A在字符串B中各次出现的位置, kmp分为两步:

1.对字符串A进行自我匹配, next[i]表示"A中以i结尾的非结尾前缀子串"与"A的前缀"能够匹配的最大长度, 即:

next[i] = max{j}, j < i 且 A[i - j + 1 ~ i] == A[1 ~ j]

当j不存在时, next[i] = 0;

2.对字符串A与B进行匹配, f[i]表示"B中以i结尾的非结尾前缀子串"与"A的前缀"能够匹配的最大长度, 即:

f[i] = max{j}, j < i 且 B[i - j + 1 ~ i] == A[1 ~ j]

引理:j是next[i]的一个候选项, 即j  < i 且 A[i - j +1 ~ i] == A[1 ~ j], 则小于j的最大next[i]的候选项是next[j];

根据优化后计算的next数组 , 当f[i] = n(A的长度)时, i - n 则是A在B中出现的位置;

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 100;
const int MAXM = 3e3 + 10;
const double eps = 1e-5; template < typename T > inline void read(T &x) {
x = 0; T ff = 1, ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') ff = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
} template < typename T > inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
} int n, m, next[MAXN], f[MAXN];
char P[MAXN], M[MAXN]; int main() {
read(n);
scanf("%s", P + 1);
read(m);
scanf("%s", M + 1);
for(int i = 2, j = 0; i <= n; ++i) {
while(j && P[j + 1] != P[i]) j = next[j];
if(P[j + 1] == P[i]) ++j;
next[i] = j;
}
for(int i = 1, j = 0; i <= m; ++i) {
while(j && (j == n || P[j + 1] != M[i])) j = next[j];
if(P[j + 1] == M[i]) ++j;
f[i] = j;
if(f[i] == n) {
write(i - n);
putchar(' ');
}
}
return 0;
}

其实用hash来做更加显然, 在O(N)的时间内预处理字符串的hash值, 枚举B中每个位置i(n <= i <= m) ,检查A的hash值和B的子串B[i - n + 1 ~ i] 是否相同即可

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 5e5 + 100;
const int MAXM = 3e3 + 10;
const double eps = 1e-5; template < typename T > inline void read(T &x) {
x = 0; T ff = 1, ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') ff = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
} template < typename T > inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
} int n, m;
unsigned long long x, q[MAXN], a[MAXN];
char p[MAXN], s[MAXN]; int main() {
read(n);
scanf("%s", p + 1);
read(m);
scanf("%s", s + 1);
for(int i = 1; i <= n; ++i) {
x = x * 131 + (p[i] - 'a' + 1);
}
q[0] = 1;
for(int i = 1; i <= m; ++i) {
q[i] = q[i - 1] * 131;
a[i] = a[i - 1] * 131 + (s[i] - 'a' + 1);
}
for(int i = n; i <= m; ++i) {
if(a[i] - a[i - n] * q[n] == x) {
write(i - n);
putchar(' ');
}
}
return 0;
}

字符串匹配 ?kmp : hash的更多相关文章

  1. 字符串匹配KMP算法详解

    1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有比较详细的通俗易懂的讲解,另一方面也怪自己没有沉下心来研究.最近在leetcode上又遇见字符串匹配的题目,以此 ...

  2. 字符串匹配-KMP

    节选自 https://www.cnblogs.com/zhangtianq/p/5839909.html 字符串匹配 KMP O(m+n) O原来的暴力算法 当不匹配的时候 尽管之前文本串和模式串已 ...

  3. zstu.4194: 字符串匹配(kmp入门题&& 心得)

    4194: 字符串匹配 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 206  Solved: 78 Description 给你两个字符串A,B,请 ...

  4. 字符串匹配KMP算法

    1. 字符串匹配的KMP算法 2. KMP算法详解 3. 从头到尾彻底理解KMP

  5. 字符串匹配--kmp算法原理整理

    kmp算法原理:求出P0···Pi的最大相同前后缀长度k: 字符串匹配是计算机的基本任务之一.举例,字符串"BBC ABCDAB ABCDABCDABDE",里面是否包含另一个字符 ...

  6. 字符串匹配KMP算法的C语言实现

    字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...

  7. 字符串匹配KMP算法的讲解C++

    转自http://blog.csdn.net/starstar1992/article/details/54913261 也可以参考http://blog.csdn.net/liu940204/art ...

  8. 字符串匹配KMP算法(转自阮一峰)

    转自 http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字符串匹配是计算 ...

  9. 【Foreign】字符串匹配 [KMP]

    字符串匹配 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 3 3 6 3 1 2 1 2 ...

  10. 【Luogu P3375】字符串匹配KMP算法模板

    Luogu P3375 模式串:即题目中的S2所代表的意义 文本串:即题目中的S1所代表的意义 对于字符串匹配,有一种很显然的朴素算法:在S1中枚举起点一位一位匹配,失配之后起点往后移动一位,从头开始 ...

随机推荐

  1. Java实现文件下载

    一.html <button class="ui-btn ui-btn-primary left20" onclick="downloadXlsTemplate() ...

  2. EcShop首页显示特定分类的精品新品热销特价等推荐商品

    EcShop首页显示特定分类的精品新品热销特价等推荐商品 很多大型的B2C商城都有特定分类专区,该分类下的[分类名称].[推荐子分类 或 推荐品牌].[大图片/推荐单品].[推荐商品].[促销商品]. ...

  3. Shell系列(1)- Shell概述

    Shell是什么 Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动.挂起.停止甚至时编写一些程序 Shell还是一个功能 ...

  4. 12306抢票算法居然被曝光了!!!居然是redis实现的

    导读 相信大家应该都有抢火车票的经验,每年年底,这都是一场盛宴.然而你有没有想过抢火车票这个算法是怎么实现的呢? 应该没有吧,咱们今天就来一一探讨.其实并没有你想的那么难 bitmap与位运算 red ...

  5. Hive On Spark保姆级攻略

    声明: 此博客参考了官网的配置方式,并结合笔者在实践网上部分帖子时的踩坑经历整理而成 这里贴上官方配置说明: [官方]: https://cwiki.apache.org//confluence/di ...

  6. IE浏览器设置兼容性

    因为IE浏览器不兼容高版本的Jquery.Bootstrap等JS框架,导致页面在Google浏览器和在IE的显示完全不一样,所以需要对页面进行兼容性设置 <!--设置兼容性--> < ...

  7. Python3入门系列之-----循环语句(for/while)

    前言 for循环在Python中是用的比较多的一种循环方法,小伙伴需要熟练掌握它的使用 本章节将为大家介绍 Python 循环语句的使用.Python 中的循环语句有 for 和 while for循 ...

  8. List接口常用实现类对比

    相同点 都实现了List接口 储存了有序 可重复的数据 不同点 ArrayList 线程不安全 但是效率高 底层使用 Object[] elementData 实现 LinkedList 底层使用双向 ...

  9. 设计模式如何提升 vivo 营销自动化业务扩展性 | 引擎篇01

    在<vivo 营销自动化技术解密 |开篇>中,我们从整体上介绍了vivo营销自动化平台的业务架构.核心业务模块功能.系统架构和几大核心技术设计. 本次带来的是系列文章的第2篇,本文详细解析 ...

  10. openssl 生成证书上 grpc 报 legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

    最近用传统的方式 生成的证书上用golang 1.15. 版本 报 grpc 上面 ➜ ~ go version go version go1.15.3 darwin/amd64 上面调用的时候报错了 ...