[IR] String Matching
BWT
KMP
Boyer-Moore
BWT
[IR] BWT+MTF+AC 中已经介绍了BWT (Burrows–Wheeler_transform)数据转换算法,
这种变换方式不仅方便压缩,同时对pattern search也带来了意想不到的好处。
事实上,BWT形式的数据,可以仅还原局部数据,而非必须还原完整的文件。
Left
Symbol | #Less Than |
A | 0 |
B | 3 |
N | 4 |
[ | 6 |
] | 7 |
Right
Position | Symbol | #Matching(idx) | |
B | +->:[ | 0 | |
N | +->:A | 0 | |
N | +->:A | 1 | |
[ | E | 0 | |
A | +->:B | 0 | |
A | +->:N | 1 | |
] | :A | 0 | |
A | +->:N | 2 |
图示化以上搜索过程(其中一步Postion:5):
匹配的过程,实际就是搜索范围逐渐缩小的过程,如下:
若能持续搜索到Pattern最后一个字符,则说明该字符串(pattern)在文本中。
时间复杂度就是O(len(pattern))。
Knuth-Morris-Pratt (KMP)
因为brute Force太蠢,所以有了该算法。
• Brute force pattern matching runs in time O(mn) in the worst case.
• But most searches of ordinary text take O(m+n), which is very quick.
那么,剩下的唯一问题就是,如何构造《部分匹配表》(Partial Match Table)
P[j]: The largest prefix of P[0 .. j-1] that is a suffix of P[1 .. j-1].
"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABACAB"为例,
[0] ABACAB- P[0 .. -1]的前缀和P[1 .. -1]的后缀为“非法”,共有元素的长度为-1;
[1] ABACAB- P[0 .. 0]的前缀和P[1 .. 0]的后缀为空,共有元素的长度为0;
[2] ABACAB- P[0 .. 1]的前缀为{A},P[1 .. 1]的后缀为空,共有元素的长度为0;
[3] ABACAB- P[0 .. 2]的前缀为{A, AB},P[1 .. 2]的后缀为{A},共有元素的长度为1;
[4] ABACAB- P[0 .. 3]的前缀为{A, AB, ABA},P[1 .. 3]的后缀为{AC, C},共有元素的长度为0;
[5] ABACAB- P[0 .. 4]的前缀为{A, AB, ABA, ABAC},P[1 .. 4]的后缀为{ACA, CA, A},共有元素的长度为1;
但,也有缺陷:
KMP doesn’t work so well as the size of the alphabet increases
– more chance of a mismatch (more possible mismatches)
– mismatches tend to occur early in the pattern, but KMP is faster when the mismatches occur later
Boyer-Moore Algorithm
算是一种改进形式,跟重视后缀;头部对齐,从尾部比较。
Most text processors use BM for “find” (&“replace”) due to its good performance for general text documents.
Ref: 字符串匹配的Boyer-Moore算法
Link: http://www.cs.utexas.edu/users/moore/publications/fstrpos.pdf
特点:《好字符规则》和《坏字符规则》,以最大移动值为准。
一个简单的示例:
Step 1
首先,"字符串"与"搜索词"头部对齐,从尾部开始比较。
这是一个很聪明的想法,因为如果尾部字符不匹配,那么只要一次比较,就可以知道前7个字符(整体上)肯定不是要找的结果。
我们看到,"S"与"E"不匹配。这时,"S"就被称为"坏字符"(bad character),即不匹配的字符。
我们还发现,"S"不包含在搜索词"EXAMPLE"之中,这意味着可以把搜索词直接移到"S"的后一位。如下:
Step 2
依然从尾部开始比较,发现"P"与"E"不匹配,所以"P"是"坏字符"。
但是,"P"包含在搜索词"EXAMPLE"之中。所以,将搜索词后移两位,两个"P"对齐。(利用了pattern内部的信息)
这个两位是怎么来的呢?
Ans:《坏字符规则》
后移位数 = 坏字符的位置 - 搜索词中的上一次出现位置
OK,根据这个规则,再重新审视Step1 and Step2。
Step 1: 后移位数=6-(-1)=7 // -1:在pattern中未发现坏字符
Step 2: 后移位数=6-4=2 // 4:在pattern中idx=4发现坏字符
However,这样是不够的,在某种情况下还不能达到更优的移动策略。
继续我们的示例:
Step 1
依然从尾部开始比较,"E"与"E"匹配;接下来,匹配了更多。
比较前面一位,"MPLE"与"MPLE"匹配。我们把这种情况称为"好后缀"(good suffix),即所有尾部匹配的字符串。
注意,"MPLE"、"PLE"、"LE"、"E"都是好后缀。
但接下来,继续比较前一位,发现"I"与"A"不匹配。所以,"I"是"坏字符"。
根据"坏字符规则",此时搜索词应该后移 2 - (-1)= 3 位。如下:
但,看上去这个move不是很聪明的样子,显然可以一次性移动更多步。
初步看上去,并没有利用到Pattern中两次出现的E。
如何利用?
Ans:《好后缀规则》
后移位数 = 好后缀的位置 - Pattern中的上一次出现位置
OK,根据这个规则,再重新审视Step1。
Step 1: 后移位数=6-=6 // 0:"好后缀"(MPLE、PLE、LE、E)之中[Ref:KMP"部分匹配表"],只有"E"在"EXAMPLE"出现在头部,idx=0
- "好后缀"的位置以最后一个字符为准。假定"ABCDEF"的"EF"是好后缀,则它的位置以"F"为准,即5(从0开始计算)。
- 如果"好后缀"在搜索词中只出现一次,则它的上一次出现位置为 -1。也就是pattern靠前的位置没有再出现了呢。
- 如果"好后缀"有多个,
- 最长的那个"好后缀",位置灵活;考前位置出现的话,优先选!否则,查看其他“好后缀”。
- 其他"好后缀",上一次出现位置必须在头部。
比如,假定"BABCDAB"的"好后缀"是"DAB"、"AB"、"B",这时"好后缀"的上一次出现位置是什么?
BABCDAB
BABCDAB
BABCDAB <----
回答是,此时采用的好后缀是"B",它的上一次出现位置是头部,即第0位。
这个规则也可以这样表达:如果最长的那个"好后缀"只出现一次,则可以把搜索词改写成如下形式进行位置计算"(DA)BABCDAB",即虚拟加入最前面的"DA"。
更巧妙的是,这两个规则的移动位数,只与搜索词有关,与原字符串无关。因此,可以预先计算生成《坏字符规则表》和《好后缀规则表》。使用时,只要查表比较一下就可以了。
那么,如何事前制表?
Ref: http://www.cs.utexas.edu/users/moore/publications/fstrpos.pdf
[IR] String Matching的更多相关文章
- Binary String Matching
问题 B: Binary String Matching 时间限制: 3 Sec 内存限制: 128 MB提交: 4 解决: 2[提交][状态][讨论版] 题目描述 Given two strin ...
- NYOJ之Binary String Matching
Binary String Matching 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Given two strings A and B, whose a ...
- ACM Binary String Matching
Binary String Matching 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Given two strings A and B, whose alp ...
- 南阳OJ----Binary String Matching
Binary String Matching 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Given two strings A and B, whose alp ...
- Binary String Matching(kmp+str)
Binary String Matching 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Given two strings A and B, whose alp ...
- Aho - Corasick string matching algorithm
Aho - Corasick string matching algorithm 俗称:多模式匹配算法,它是对 Knuth - Morris - pratt algorithm (单模式匹配算法) 形 ...
- [POJ] String Matching
String Matching Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 4074 Accepted: 2077 D ...
- String Matching Content Length
hihocoder #1059 :String Matching Content Length 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 We define the ...
- NYOJ 5 Binary String Matching
Binary String Matching 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 Given two strings A and B, whose alp ...
随机推荐
- 使用Block传值
使用Block的地方很多,其中传值只是其中的一小部分,下面介绍Block在两个界面之间的传值: 先说一下思想: 首先,创建两个视图控制器,在第一个视图控制器中创建一个UILabel和一个UIButto ...
- Linux - 函数的栈帧
栈帧(stack frame),机器用栈来传递过程参数,存储返回信息,保存寄存器用于以后恢复,以及本地存储.为单个过程(函数调用)分配的那部分栈称为栈帧.栈帧其实是两个指针寄存器, 寄存器%ebp为帧 ...
- 商城项目实战 | 1.1 Android 仿京东商城底部布局的选择效果 —— Selector 选择器的实现
前言 本文为菜鸟窝作者刘婷的连载."商城项目实战"系列来聊聊仿"京东淘宝的购物商城"如何实现. 京东商城的底部布局的选择效果看上去很复杂,其实很简单,这主要是要 ...
- stm32中的延时函数
//粗延时函数,微秒 void delay_nus(u16 time) { u16 i=0; while(time--) { i=10; //自己定义 while(i--) ; } } //毫秒级的 ...
- JS作用域相关知识(#精)
在学习<你不知道的JS>一书中,特将作用域相关知识在此分享一下: #说到作用域,就不得不提到LHS查询和RHS查询: 1)如果查询目的是对变量进行赋值,则使用LHS查询 2)如果查询目的是 ...
- Python 三级菜单与优化(一层循环嵌套)
优化的思路是使用单层循环嵌套完成三级菜单,这个优化思路我非常喜欢,我喜欢在编程的时候用最少的东西写出同样的效果,通常这样会绕来绕去,但非常有趣!!! 需求: 1.运行程序输出第一级菜单: 2.选择一级 ...
- javaWeb项目(SSH框架+AJAX+百度地图API+Oracle数据库+MyEclipse+Tomcat)之一 基础Struts框架搭建篇
即将开始着手写这个项目,所以希望通过这篇博客来记录自己学习的过程 今天开学第一天,就上了软件工程实践课,自己也开始着手做这个大作业了.首先我的项目名称叫做智能班车管理系统. 项目的概况: 该软件产品是 ...
- Angularjs快速入门(二)
说说上一节的例子,$scope 我们没有创建这个对象,直接绑定就能获取里面的对象,这种风格遵循了一种叫迪米特法则的设计模式. 然后angular还有一种很强大的功能叫“指令”. 就是你可以吧模板编写成 ...
- 树型权限管理插件:jQuery Tree Multiselect详细使用指南
1.认识jQuery Tree Multiselect 这个插件允许用户以树型的形式来呈现列表复选框的选择.多用于权限管理中用于分配不同的权限.使用文档,请参考: https://github ...
- 使用虚拟机CentOS7部署CEPH集群
第1章 CEPH部署 1.1 简单介绍 Ceph的部署模式下主要包含以下几个类型的节点 Ø CephOSDs: A Ceph OSD 进程主要用来存储数据,处理数据的replication,恢复 ...