KMP算法字符串查找子串
题目:
经典的KMP算法
分析:
和KMP算法对应的是BF算法,其中BF算法时间复杂度,最坏情况下可以达到O(n*m),而KMP算法的时间复杂度是O(n + m),所以,KMP算法效率高很多。
但是KMP算法不太好理解,其中牵涉到next数组,目标就是让模式串尽可能的往右滑动,减少比较次数,比如
a b a b c
-1 0 0 1 2
比如我们比较ababc时,如果c比较发现错误,前面的abab已经比较成功,那么下次比较,我们只需要从aba的最后一个a开始比较,这样省去了从头开始比较。
算法代码:
- #include <iostream>
 - #include <cstdlib>
 - #include <cstdio>
 - using namespace std;
 - //这是整个kmp中最核心的地方
 - int get_next(const char*t, int *next)
 - {
 - int i = 0;
 - int j = -1; //设置j = -1,非常巧妙
 - int len = strlen(t);
 - memset(next,0, sizeof(int) * len);
 - next[0] = -1;
 - while(i < len - 1)
 - {
 - if(j == -1 || t[i] == t[j]) //前面的判断,j == -1, 非常巧妙
 - {
 - i++;
 - j++;
 - next[i] = j; //将后面的next数组元素赋值
 - }
 - else
 - j = next[j];
 - }
 - }
 - int kmp(const char *s, const char *t)
 - {
 - int i = 0;
 - int j = 0;
 - int next[100];
 - get_next(t,next);
 - while(i < strlen(s) && j < strlen(t))
 - {
 - if(j == - 1 || s[i] == t[j]) //如果j为-1,或者模式串和主串相等,两者继续往下比较
 - {
 - i++;
 - j++;
 - }
 - else
 - j = next[j];
 - }
 - if(j >= (int)strlen(t))
 - {
 - cout << "found " << endl;
 - return 0;
 - }
 - cout << "not found" <<endl;
 - return 0;
 - }
 - //暴力法
 - int brute_force(const char *s, const char *t)
 - {
 - int i, j;
 - i = 0;
 - while(i < strlen(s))
 - {
 - j = 0;
 - while(j < strlen(t))
 - {
 - if(s[i] == t[j])
 - {
 - i++;
 - j++;
 - }
 - else
 - {
 - i = i - j + 1;
 - break;
 - }
 - }
 - if(j == (int)strlen(t))
 - {
 - cout << "found" << endl;
 - return 0;
 - }
 - }
 - cout << "not found" << endl;
 - return 0;
 - }
 - int main()
 - {
 - brute_force("abcdef", "abcdef");
 - kmp("abcdef", "aaaa");
 - return 0;
 - }
 
总结:
KMP算法非常经典,同时这个算法实现很多地方非常巧妙。
优化思路
| 
 
下标i 
 | 
 
0 
 | 
 
1 
 | 
 
2 
 | 
 
3 
 | 
 
4 
 | 
 
5 
 | 
 
6 
 | 
 
7 
 | 
 
8 
 | 
 
9 
 | 
| 
 
p(i) 
 | 
 
a 
 | 
 
b 
 | 
 
c 
 | 
 
d 
 | 
 
a 
 | 
 
a 
 | 
 
b 
 | 
 
c 
 | 
 
a 
 | 
 
b 
 | 
| 
 
next[i] 
 | 
 
-1 
 | 
 
0 
 | 
 
0 
 | 
 
0 
 | 
 
0 
 | 
 
1 
 | 
 
1 
 | 
 
2 
 | 
 
3 
 | 
 
1 
 | 
| 
 
下标i 
 | 
 
0 
 | 
 
1 
 | 
 
2 
 | 
 
3 
 | 
 
4 
 | 
 
5 
 | 
 
6 
 | 
 
7 
 | 
 
8 
 | 
 
9 
 | 
| 
 
p(i) 
 | 
 
a 
 | 
 
b 
 | 
 
c 
 | 
 
d 
 | 
 
a 
 | 
 
a 
 | 
 
b 
 | 
 
c 
 | 
 
a 
 | 
 
b 
 | 
| 
 
next[i] 
 | 
 
-1 
 | 
 
0 
 | 
 
0 
 | 
 
0 
 | 
 
0 
 | 
 
1 
 | 
 
1 
 | 
 
2 
 | 
 
3 
 | 
 
1 
 | 
| 
 
优化的next[i] 
 | 
 
-1 
 | 
 
0 
 | 
 
0 
 | 
 
0 
 | 
 
-1 
 | 
 
1 
 | 
 
0 
 | 
 
0 
 | 
 
3 
 | 
 
0 
 | 
KMP算法字符串查找子串的更多相关文章
- KMP 算法 & 字符串查找算法
		
KMP算法 Knuth–Morris–Pratt algorithm 克努斯-莫里斯-普拉特 算法 algorithm kmp_search: input: an array of character ...
 - 【原创】通俗易懂的讲解KMP算法(字符串匹配算法)及代码实现
		
一.本文简介 本文的目的是简单明了的讲解KMP算法的思想及实现过程. 网上的文章的确有些杂乱,有的过浅,有的太深,希望本文对初学者是非常友好的. 其实KMP算法有一些改良版,这些是在理解KMP核心思想 ...
 - KMP算法 - 求最小覆盖子串
		
KMP与最小覆盖子串 最小覆盖子串:对于某个字符串s,它的最小覆盖子串指的是长度最小的子串p,p满足通过自身的多次连接得到q,最后能够使s成为q的子串. 比如: 对于s="abcab&quo ...
 - KMP算法之查找模式串在源串中出现的次数
		
问题描述: 给定两个字符串T, P.查找字符串P在字符串T中出现的次数. 解决方法: 典型的KMP算法的题目,在此使用的KMP算法为算法导论上介绍的算法.下一篇文章将详细介绍KMP算法的计算过程. 题 ...
 - KMP算法(查找子序列)
		
KMP类似暴力,但是不会和暴力完全一样,回溯到起点. 简单的说 假如 模板链字符串是: abcabcabcabd 寻找abcabd 在模板链出现的次数,并且输出该次数 ...
 - HDU-2087 剪花布条 字符串问题 KMP算法 查匹配子串
		
题目链接:https://cn.vjudge.net/problem/HDU-2087 题意 中文题咯 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条, ...
 - 串的两种模式匹配方式(BF/KMP算法)
		
前言 串,又称作字符串,它是由0个或者多个字符所组成的有限序列,串同样可以采用顺序存储和链式存储两种方式进行存储,在主串中查找定位子串问题(模式匹配)是串中最重要的操作之一,而不同的算法实现有着不同的 ...
 - Java KMP算法代码
		
1. KMP 算法(字符串匹配算法)较 BF(朴素的字符串匹配)算法有哪些改进 1) 在主串和子串匹配的过程中,主串不再回退,只改变子串的比较位置. 2) 为子串生成对应的next数组,每次匹配失败, ...
 - 回朔法/KMP算法-查找字符串
		
回朔法:在字符串查找的时候最容易想到的是暴力查找,也就是回朔法.其思路是将要寻找的串的每个字符取出,然后按顺序在源串中查找,如果找到则返回true,否则源串索引向后移动一位,再重复查找,直到找到返回t ...
 
随机推荐
- 8-IdentityServer4登录中心
			
1-新建webapi IdentityServer4服务器项目 E:\coding\netcore\IdentityServerSample>dotnet new webapi --name ...
 - Redis系列化方式有哪些?哪个系列化性能最好?
			
Redis系列化方式有JDK系列化.JSON系列化.XML系列化等多种.我专门测试过,在我的笔记本电脑上保存5万条User对象到Redis,JDK系列化方式平均要15秒,JSON系列化方式只要13秒多 ...
 - java 程序文本文档形式的编写,编译,及运行
			
一.程序的编写 1.在指定路径下新建文本文档 如在f盘新建了一个名为demo的文件夹,在该文件夹路径下新建了一个文本文档 2.打开文本文档,进行编写,例如: 3.保存 选择文件另存为,文件名称为你创建 ...
 - 从官网下载centos
			
今天想从官网下载6.5版本的CentOS,结果找了好一会儿才找到,赶紧记录下来,以备以后查询. 第一步在百度搜索centos,点击"Download CentOS",如下图所示. ...
 - Git中分支merge和rebase的适用场景及区别
			
Git merge是用来合并两个分支的. git merge b # 将b分支合并到当前分支 同样 git rebase b,也是把 b分支合并到当前分支 原理 如下: 假设你现在基于远程分 ...
 - 成都优步uber司机第三组奖励政策
			
今天成都优步又推出了优步司机第三组,第一二组的奖励大家都晓得,但是第三组的奖励怎么样呢?还是先看看官方给出的消息. 滴滴快车单单2.5倍,注册地址:http://www.udache.com/如何注册 ...
 - Python:TypeError: 'range' object doesn't support item deletion
			
报错代码: dataIndex = range(m) del (dataIndex[randIndex]) 报错信息: 错误原因: python3 range返回的是range对象,不是数组对象 解决 ...
 - Android Stadio配置了gralde的本地路径,但是windos 命令行还是会下载gradle
			
如下图: 已经在stadio 里面设置了gradle 的路径,但是在cmd 命令行里面不会去用这个路径. 解决方案:需要在环境变量里面设置一个gradle home GRADLE_USER_HOME ...
 - 腾讯WeTest开启“测试扶持计划”赠送重磅福利(含MTSC/TiD门票)
			
WeTest导语 伴随着互联网行业的发展,与各行各业的连接更加紧密,竞争也变得越发激烈,用户对于产品的体验开始变得更加“挑剔”.然而目前互联网产品却始终受到各类质量问题的困扰.以兼容问题为例,应用平台 ...
 - Linux命令应用大词典-第29章 SELinux管理
			
29.1 sestaus:显示SElinux的状态 29.2 getenforce:显示当前SELinux的应用模式 29.3 setenforce:修改SELinux的应用模式 29.4 getfa ...