数据结构-KMP 算法(Knuth-Morris-Pratt 字符串查找算法)

2024-03-22 11:10

本文主要是介绍数据结构-KMP 算法(Knuth-Morris-Pratt 字符串查找算法),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.什么是KMP算法:快速的从一个主串中找出一个你想要的子串

       KMP算法是一种改进的字符串匹配算法。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。

首先,对于这个问题有一个很单纯的想法:从左到右一个个匹配,如果这个过程中有某个字符不匹配,比较指针就跳回去(比较指针回溯),将模式串向右移动一位。

/*** 暴力破解法* ts 主串* ps 模式串* 如果找到,返回在主串中第一个字符出现的下标,否则为-1*/
public static int bf(String ts, String ps) {int i = 0; // 主串的位置int j = 0; // 模式串的位置while (i < t.length && j < p.length) {if(t[i]==p[j]){//当两个字符相同,就比较下一个i++;j++;} else{i=i-j+1;// 一旦不匹配,i后退j=0;//j归0}}if(j==p.length){return i-j;} else{return -1;}
}

比较指针回溯使算法效率低,而KMP算法可以做到仅仅后移模式串,比较指针不回溯。

2.KMP算法实现过程

当某个字符不匹配时,我们观察发现箭头左边部分,上下字符串模式串和主串是完全匹配的。

模式串左右两端两个字串是完全匹配的,称为模式串的公共前后缀。

KMP核心:直接移动模式串,将公共前缀移动到公共后缀。

因为前后缀是匹配的,可以保证当前比较指针所在的位置左边的串上下匹配,且不会跳过某些匹配的情况。

注意:如果模式串存在多对公共前后缀,我们要取最长公共前后缀。

对于KMP算法只需研究模式串就可以。

3.KMP转化为代码形式(如何构建next数组)

首先把模式串放入数组中,模式串是从数组下标1开始的(根据个人喜好)。模式串的每一位都有可能与主串不匹配。

首先假设若1号位发生不匹配。

1号位与主串下一位比较。

若2号位发生不匹配。

 例题

1.剪花布条

一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?

输入格式

输入数据为多组数据,读取到 # 字符时结束。每组数据仅有一行,为由空格分开的花布条和小饰条。花布条和小饰条都是用可见 ASCII 字符表示的,不会超过  个字符。

注意:这个 # 应为单个字符。若某字符串开头有 #,不意味着读入结束!

输出格式

对于每组数据,输出一行一个整数,表示能从花纹布中剪出的最多小饰条个数。

样例

输入

abcde a3
aaaaaa aa
#

输出

0
3

数据范围与提示

对于全部数据,字符串长度<=1000 。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
int n,m,next[maxn];
char s[maxn],t[maxn];//s[]为模式串,t[]为匹配串void getnext(){next[0]=0;for(int i=1;i<n;i++){int j=next[i-1];while(t[j]!=t[i]&&j>0){j=next[j-1];}if(t[j]==t[i]){next[i]=j+1;}else{next[i]=0;}}
} int kmp(){int j=0;int sum=0;for(int i=0;i<m;i++){while(t[j]!=s[i]&&j>0)j=next[j-1];if(t[j]==s[i]) {j++;}if(j>=n){sum++;j=0;}}return sum;
}int main(){while(~scanf("%s",s)){if(s[0]=='#'){break;}scanf("%s",t);m=strlen(s);n=strlen(t);getnext();printf("%d\n",kmp());}return 0;
} 

2.Power Strings

给定若干个长度  的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。如:ababab 则最多有  个 ab 连接而成。

输入格式

输入若干行,每行有一个字符串。特别的,字符串可能为 . 即一个半角句号,此时输入结束。

样例

输入

abcd
aaaa
ababab
.

输出

1
4
3

数据范围与提示

字符串长度<=1e6 。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
char a[N];
int p[N],n;
void kmp()
{p[1]=0;int j=0;for(int i=1;i<n;i++){while(j>0&&a[j+1]!=a[i+1]){j=p[j];}if(a[j+1]==a[i+1]){j++;//如果已经相等,则看接下来的字符相不相等,若不相等则返回,说明还没有开始重复;否则接着匹配}p[i+1]=j;//开始时不相等,那么j不自增,继续看之后的串哪个i开始与j匹配}
}
int main()
{while(1){scanf("%s",a+1);if(a[1]=='.'){break;}n=strlen(a+1);kmp();if(n%(n-p[n])==0){printf("%d\n",n/(n-p[n]));} else{printf("%d\n",1);}}return 0;
}

3.Radio Transmission

给你一个字符串,它是由某个字符串不断自我连接形成的。但是这个字符串是不确定的,现在只想知道它的最短长度是多少。

输入格式

第一行给出字符串的长度 ,第二行给出一个字符串,全由小写字母组成。

输出格式

输出最短的长度。

样例

输入

8
cabcabca

输出

3

对于样例,我们可以利用 abc 不断自我连接得到 abcabcabc,读入的 cabcabca 是它的子串。

数据范围与提示

对于全部数据,1<=L<=1e6。

#include <bits/stdc++.h>
using namespace std;
char p[1000005];
int next[1000005],len;
void get_next()
{int i,j;next[0]=j=-1;i=0;while(i<len){while(j!=-1&&p[j]!=p[i]){j=next[j];}  next[++i]=++j;}
}int main()
{int n;cin>>n;scanf("%s",p);len=strlen(p);get_next();
//    for(int i=0;i<len;i++)
//    {
//        cout<<next[i]<<" ";
//    }cout<<n-next[n];return 0;
}

这篇关于数据结构-KMP 算法(Knuth-Morris-Pratt 字符串查找算法)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/835181

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯: