博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
KMP算法
阅读量:5377 次
发布时间:2019-06-15

本文共 1686 字,大约阅读时间需要 5 分钟。

特点

假定文本串长度为n, 模式串长度为m, 朴素字符串比较时间复杂度为O(n*m),KMP算法时间复杂度为O(n+m)

朴素算法在匹配失败后重新从首部开始匹配,而KMP则利用模式串本身的特点,在匹配失败时不用每次都从模式串首部开始匹配,

关键就在于利用模式串的前缀和后缀相同的部分
比如char[] p = "abdabe", 当p[5] = e匹配失败时,朴素算法是重新从p[0]开始匹配,但通过观察,我们发现p[0,1]和p[3,4]相同,可以从p[3]开始匹配
这正是KMP的思想,next数组就对应着前面需要的关键观察信息(知道p[0,1] = p[3,4]相同),在这里next[4] = 1;

计算next数组

令next[i-1] = k 表示[0, i-1]的最长前缀后缀的索引k(不包括p[0, i]),即p[0, k] = p[i-k-1, i-1]相同

如何求p[0, i]的最长前缀后缀呢?

  • p[i] == p[k+1], 显然next[i] = k+1
  • p[i] != p[k+1], next[i] < k+1, 这时仍然有p[0, k] = p[i-k-1, i-1]相同, 我们再次在p[0, k]中找到最长前缀后缀,k = next[k], 然后在其后的位置检验

证明:

  • 若next[i] = k+1, 则p[i] == p[k+1],与题设不符
  • 若next[i] > k+1, 则next[i-1] > k,与题设不符

还是以上面的例子来说明,根据定义最后一个b位置next[4]=1,

  • 如果e位置能够和d位置匹配,则next[5]=1+1=2很合理
  • 如果e位置不能喝d位置匹配,则问题演化成d之前ab的前缀最长有多少和e之前的ab的后缀重合,这也就是next[2]

例题

class Solution {private:    vector
next; void ComputeNext(const string& p){ int n = p.size(); next.resize(n); int k = -1; next[0] = k; for(int i = 1; i < n; i++){ while(k > -1 && p[k+1] != p[i]){ k = next[k]; } if(p[k+1] == p[i]) k++; next[i] = k; } } int KMP(const string &t, const string &p){ ComputeNext(p); int k = -1; for(int i = 0; i < t.size(); i++){ while(k > -1 && p[k+1] != t[i]){ k = next[k]; } if(p[k+1] == t[i]) k++; if(k == p.size() - 1) return i - p.size() + 1; } return -1; }public: int strStr(string haystack, string needle) { return needle == "" ? 0 : KMP(haystack, needle); }};

转载于:https://www.cnblogs.com/qbits/p/10986489.html

你可能感兴趣的文章
星期五的收获
查看>>
proxmox 去除订阅提示
查看>>
使用Html.EditorFor()为文本框加上maxlength,placeholder等属性
查看>>
[转]后缀数组求最长重复子串
查看>>
设计模式——外观模式详解
查看>>
mysql (一)
查看>>
photoshop图层样式初识1
查看>>
【.NET】使用HtmlAgilityPack抓取网页数据
查看>>
typedef的使用
查看>>
基于位置的本地商铺个性化推荐
查看>>
职场上一个人情商高的十种表现
查看>>
【底层原理】深入理解Cache (下)
查看>>
Elasticsearch安装中文分词插件IK
查看>>
进阶4:常见函数-单行函数
查看>>
简述企业信息化与企业架构关系
查看>>
npoi List 泛型导出
查看>>
流程图怎么画?分享绘制流程图简单方法
查看>>
squid的处理request和reply的流程
查看>>
硬件_陀螺仪
查看>>
SSIS的部署和配置
查看>>