KMP入门
一、引例
题目描述
原题来自:HDU 2087
一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?
输入格式
输入数据为多组数据,读取到 # 字符时结束。每组数据仅有一行,为由空格分开的花布条和小饰条。花布条和小饰条都是用可见 ASCII 字符表示的,不会超过
1000
1000
1000 个字符。
注意:这个 # 应为单个字符。若某字符串开头有 #,不意味着读入结束!
输出格式
对于每组数据,输出一行一个整数,表示能从花纹布中剪出的最多小饰条个数。
样例
abcde a3
aaaaaa aa
#
0
3
数据范围与提示
对于全部数据,字符串长度 ≤ 1000 \leq 1000 ≤1000。
思路1
首先考虑采用哈希。
思路2——KMP算法
考虑一种更快、代码量更少的方法——KMP算法。
我们令第一个字符串为 s,第二个字符串为 t,需要求出 t 在 s 中不重叠的匹配个数。
KMP算法的思想:在匹配 s 的过程中,每次遇到失配的点 s[i]!=t[j],我们应该快速地选择 t[0...j-1] 的 border(参见字符串哈希),实现不往回移动 i 的前提下,快速地完成 s[0...i-1] 的后缀与 t 串前缀的最长匹配,由于外层下标 i 从左至右只走一遍,每次匹配时,j 同 i 一起向前移动,撤回border的次数一定小于向前移动的次数,因此整体时间复杂度为
O
(
n
)
O(n)
O(n)。

因此,问题转换为如何求出串 t 所有前缀的最大非平凡border,即实现一个前缀函数。
前缀函数
定义 nx[i] 表示 t[0...i] 的最长非平凡border的长度,特别地,nx[0] 为 0。
从 t[1] 开始逐个求前缀函数 t[i] 的过程如下:
- 设border长度的初值
int j = 0; while (j && t[i]!=t[j]) j = nx[j-1];//t[i]失配时,从长到短依次尝试t[i-1]的每一个borderif (t[i] == t[j]) ++j;// 若找到了某个border,可以匹配t[i],匹配长度加 1。nx[i] = j;// 记录t[i]border的长度
void match() {
for (int i = 1, j = 0; t[i]; ++i) {
while (j && t[i]!=t[j]) j = nx[j-1];
if (t[i] == t[j]) ++j;
nx[i] = j;
}
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!