关键思想在于把输入的字符既看作图形符号,又看做数字,预处理算出模式P的d进制的值p,时间复杂度为Θ(m),让后针对n - m + 1个有效偏移s计算出相应的ts,这里是由于利用ts来计算ts+1,时间复杂度是Θ(1),因此总的时间复杂度为Θ(n - m + 1),为了避免p和ts的值太大,不能在常数时间里计算,引入一个合适的素数q,p和ts对q取模,这样数就不至于太大,关键的步骤是把p和ts逐个进行比较找出所有的伪命中点s,再用平凡的比较方法比较P[1..m]和T[s + 1.. s + m]是否相等得到s是否为一个命中点。

该算法的运行时间为O(m) + O(n - m + 1),最坏情况下为O((n - m + 1)m),期望的复杂度为O(n)。代码实现为:

#include <iostream>
#include <string>
using namespace std; int pow_of_d(int d, int m)
{
int res = 1;
while(m > 0)
{
if(m & 1) res = res * d;
d = d * d;
m >>= 1;
}
return res;
} void RABIN_KARP_MATCHER(string T, string P, int d, int q)
{
int n = T.length();
int m = P.length();
int h = pow_of_d(d, m - 1) % q; int p = 0;
int t = 0;
for(int i = 0; i < m; i++)
{
p = (d * p + (P[i] - 48)) % q;
t = (d * t + (T[i] - 48)) % q;
} for(int s = 0; s <= n - m; s++)
{
if(t == p)
{
bool flag = true;
for(int i = 0; i < m; i++)
{
if(P[i] != T[s + i])
{
flag = false;
break;
}
}
if(flag)
cout<<s<<endl;
}
if(s < n - m)
{
t = ((d * (t - (T[s] - 48) * h) + (T[s + m] - 48)) % q + q) % q;
}
}
} int main()
{
string T = "2359023141526739921";
string P = "31415";
int d = 10;
int q = 13;
RABIN_KARP_MATCHER(T, P, d, q);
return 0;
}

最新文章

  1. 2016 ACM赛后总结
  2. VRRP虚拟路由器冗余协议
  3. GCC编译器编译链接
  4. JAVA设计模式--State(状态模式)
  5. MVC框架 - 捆绑
  6. Unity3D中关于场景销毁时事件调用顺序的一点记录
  7. SSD论文优秀句子
  8. jps命令(Java Virtual Machine Process Status Tool)
  9. 函数stripslashes去除转义 shopnc 搜索框过滤特殊字符 输入单斜杆会自动转义
  10. Task和backStack(本篇章核心)
  11. The Rings Akhaten
  12. Block使用的简单总结
  13. eclipse中常用提高效率的快捷键
  14. [LeetCode] Merge Two Binary Trees 合并二叉树
  15. 四大组件之 BroadcastReceiver小结
  16. 【原】Java学习笔记032 - 多线程
  17. Python 3安装MySQLdb
  18. leetcode771
  19. Linux下查看磁盘挂载的几种方法
  20. arm cortex-m0plus源码学习(三)GPIO

热门文章

  1. C#基础|面向对象之多态
  2. c语言的自动类型转换
  3. 什么是实时应用程序自我保护(RASP)?
  4. 如何启动 SQL Server Agent(SQL Server 配置管理器)
  5. easyui源码翻译1.32--panel(面板)
  6. [jobdu]树中两个结点的最低公共祖先
  7. Apache CXF 例子
  8. 判断微信内置浏览器的UserAgent
  9. (转载)四种常见的 POST 提交数据方式
  10. 通过Java SE 7自带的监控服务(WatchService API)实现类似.NET FileWatcher的功能