题目:

经典的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开始比较,这样省去了从头开始比较。

算法代码:

  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <cstdio>
  4. using namespace std;
  5. //这是整个kmp中最核心的地方
  6. int get_next(const char*t, int *next)
  7. {
  8. int i = 0;
  9. int j = -1; //设置j = -1,非常巧妙
  10. int len = strlen(t);
  11. memset(next,0, sizeof(int) * len);
  12. next[0] = -1;
  13. while(i < len - 1)
  14. {
  15. if(j == -1 || t[i] == t[j]) //前面的判断,j == -1, 非常巧妙
  16. {
  17. i++;
  18. j++;
  19. next[i] = j;    //将后面的next数组元素赋值
  20. }
  21. else
  22. j = next[j];
  23. }
  24. }
  25. int kmp(const char *s, const char *t)
  26. {
  27. int i = 0;
  28. int j = 0;
  29. int next[100];
  30. get_next(t,next);
  31. while(i < strlen(s) && j < strlen(t))
  32. {
  33. if(j == - 1 || s[i] == t[j])    //如果j为-1,或者模式串和主串相等,两者继续往下比较
  34. {
  35. i++;
  36. j++;
  37. }
  38. else
  39. j = next[j];
  40. }
  41. if(j >= (int)strlen(t))
  42. {
  43. cout << "found " << endl;
  44. return 0;
  45. }
  46. cout << "not found" <<endl;
  47. return 0;
  48. }
  49. //暴力法
  50. int brute_force(const char *s, const char *t)
  51. {
  52. int i, j;
  53. i = 0;
  54. while(i < strlen(s))
  55. {
  56. j = 0;
  57. while(j < strlen(t))
  58. {
  59. if(s[i] == t[j])
  60. {
  61. i++;
  62. j++;
  63. }
  64. else
  65. {
  66. i = i - j + 1;
  67. break;
  68. }
  69. }
  70. if(j == (int)strlen(t))
  71. {
  72. cout << "found" << endl;
  73. return 0;
  74. }
  75. }
  76. cout << "not found" << endl;
  77. return 0;
  78. }
  79. int main()
  80. {
  81. brute_force("abcdef", "abcdef");
  82. kmp("abcdef", "aaaa");
  83. return 0;
  84. }

总结:

KMP算法非常经典,同时这个算法实现很多地方非常巧妙。

优化思路

KMP算法是可以被进一步优化的。
我们以一个例子来说明。譬如我们给的P字符串是“abcdaabcab”,经过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
但是,如果此时发现p(i) == p(k),那么应当将相应的next[i]的值更改为next[k]的值。经过优化后可以得到下面的表格:
下标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
(1)next[0]= -1 意义:任何串的第一个字符的模式值规定为-1。
(2)next[j]= -1 意义:模式串T中下标为j的字符,如果与首字符
相同,且j的前面的1—k个字符与开头的1—k
个字符不等(或者相等但T[k]==T[j])(1≤k<j)。
如:T=”abCabCad” 则 next[6]=-1,因T[3]=T[6]
(3)next[j]=k 意义:模式串T中下标为j的字符,如果j的前面k个
字符与开头的k个字符相等,且T[j] != T[k] (1≤k<j)。
即T[0]T[1]T[2]。。。T[k-1]==
T[j-k]T[j-k+1]T[j-k+2]…T[j-1]
且T[j] != T[k].(1≤k<j);
(4) next[j]=0 意义:除(1)(2)(3)的其他情况。

KMP算法字符串查找子串的更多相关文章

  1. KMP 算法 & 字符串查找算法

    KMP算法 Knuth–Morris–Pratt algorithm 克努斯-莫里斯-普拉特 算法 algorithm kmp_search: input: an array of character ...

  2. 【原创】通俗易懂的讲解KMP算法(字符串匹配算法)及代码实现

    一.本文简介 本文的目的是简单明了的讲解KMP算法的思想及实现过程. 网上的文章的确有些杂乱,有的过浅,有的太深,希望本文对初学者是非常友好的. 其实KMP算法有一些改良版,这些是在理解KMP核心思想 ...

  3. KMP算法 - 求最小覆盖子串

    KMP与最小覆盖子串 最小覆盖子串:对于某个字符串s,它的最小覆盖子串指的是长度最小的子串p,p满足通过自身的多次连接得到q,最后能够使s成为q的子串. 比如: 对于s="abcab&quo ...

  4. KMP算法之查找模式串在源串中出现的次数

    问题描述: 给定两个字符串T, P.查找字符串P在字符串T中出现的次数. 解决方法: 典型的KMP算法的题目,在此使用的KMP算法为算法导论上介绍的算法.下一篇文章将详细介绍KMP算法的计算过程. 题 ...

  5. KMP算法(查找子序列)

    KMP类似暴力,但是不会和暴力完全一样,回溯到起点. 简单的说  假如   模板链字符串是:        abcabcabcabd        寻找abcabd 在模板链出现的次数,并且输出该次数 ...

  6. HDU-2087 剪花布条 字符串问题 KMP算法 查匹配子串

    题目链接:https://cn.vjudge.net/problem/HDU-2087 题意 中文题咯 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条, ...

  7. 串的两种模式匹配方式(BF/KMP算法)

    前言 串,又称作字符串,它是由0个或者多个字符所组成的有限序列,串同样可以采用顺序存储和链式存储两种方式进行存储,在主串中查找定位子串问题(模式匹配)是串中最重要的操作之一,而不同的算法实现有着不同的 ...

  8. Java KMP算法代码

    1. KMP 算法(字符串匹配算法)较 BF(朴素的字符串匹配)算法有哪些改进 1) 在主串和子串匹配的过程中,主串不再回退,只改变子串的比较位置. 2) 为子串生成对应的next数组,每次匹配失败, ...

  9. 回朔法/KMP算法-查找字符串

    回朔法:在字符串查找的时候最容易想到的是暴力查找,也就是回朔法.其思路是将要寻找的串的每个字符取出,然后按顺序在源串中查找,如果找到则返回true,否则源串索引向后移动一位,再重复查找,直到找到返回t ...

随机推荐

  1. 深浅拷贝--python(预习中随手写的。因为当时很无聊。。。)

    需要知识准备,pyhton基本常识,python的小数据池概念. 深浅拷贝操作需要模块导入:import copy emmm,对于python中的两种数据类型来说. 1.数字,字符串 2.列表,元祖, ...

  2. 20145234黄斐《信息安全系统设计基础》第七周(Linux命令复习)

    已经到了11月,学期过半,而<信息安全系统设计基础>这门课也要到了期中考试了.所以,我在这里,对前半个学期的最基础的知识,做一个复习 复习计划分为两步,本次为Linux命令,下次计划复习g ...

  3. 使用OpenLayers发布地图

    OpenLayers是用于制作交互式Web地图的开源客户端JavaScript类库,制作的地图几乎可以在所有的浏览器中查看.因为是客户端类库,它不需要特殊的服务器端软件或配置,甚至不用下载任何东西就可 ...

  4. 1 多任务fork Unix/Linux/Mac

    # 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以 1.如下程序,来模拟“唱歌跳舞”这件事情 #-*- coding:utf-8 -*- import time de ...

  5. CF 1027 F. Session in BSU

    F. Session in BSU https://codeforces.com/contest/1027/problem/F 题意: n场考试,每场可以安排在第ai天或者第bi天,问n场考完最少需要 ...

  6. quartz 核心概念

    一.quartz 核心概念 1.scheduler是一个计划调度器容器,容器里面可以盛放众多的JobDetail和trigger,当容器启动后,里面的每个JobDetail都会根据trigger按部就 ...

  7. andriod学习一

    1.Android软件栈       2.Android模拟器        Android SDK 可以通过ADT+Eclipse或者命令行开发,调试,测试应用程序,设备可以使用模拟器或者真实设备, ...

  8. 使用gitlab时候 fork仓库不会实时从主仓库更新解决方案

    付费用户可以使用现成的方案,地址见 链接 但是私有gitlab时候,需要手动进行如下操作 1. Clone your fork: git clone git@github.com:YOUR-USERN ...

  9. mysql新手入门随笔4

    40.子查询:出现在其他SQL语句里的SELECT语句 例如:SELECT sname,mark FROM student WHERE mark = (SELECT max(mark) FROM st ...

  10. C++11 type_traits 之is_pointer,is_member_function_pointer源码分析

    源码如下: template<typename> struct __is_pointer_helper : public false_type { }; template<typen ...