字典树和kmp
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
j=nest[j]; //对应字符不等,移动到next[j]
}
if(j>T_len) return 1;//匹配成功
else return 0;//匹配不成功
}
求next数组
void getNext(Sstring S){ int i=0,j=-1; next[0]=-1; while(i<len){
(3)接着取得要查找关键词的第二个字母,并进一步 选择对应的子树进行检索。
(4) ... 关键词的所有字母已被取出,则读取附在该结点上 的信息,即完成查找。
Trie的数据结构定义
• • • • •
struct dictree {
dictree *child[26]; //总共26个字母,所以孩子最多 26个! int n; //根据需要变化,可以用来标记是不是尾节 点或者出现次数等!
定义
• next: 为对应模式串的数组 • 设字符串为 s1s2s3...sm ,其中s1,s2,s3,...
si,... sm均是字符,则next[i]=m,当且仅当满 足如下条件:字符串s1s2...sm equals 字符串 s(i-m+1)...si-1 si 并且s1s2...sm s(m+1) unequals s(i-m) s(i-m+1)...si-1 si。 模式串前缀的最长匹配数。
KMP算法的运行过程
• i = 1 2 3 4 5 6 7 8 9 …… • A=abababaabab… • B= ababacb
j= 1234 567
next: 0 0 1 2 3 0 0
暴力算法则将字符串B向后移动一位后,重新匹配
KMP算法的运行过程
• i = 1 2 3 4 5 6 7 8 9 …… • A=abababaabab… • B= ababacb
补充:多叉树和二叉树
二叉树分叉数量<=2
多叉树分叉数量任意
Trie的图示
特点:
• •
利用串的公共前缀>节约内存 根结点不包含任何 字母
• •
其余结点仅包含一 个字母(非元素) 每个结点的子节点 包含字母不同
创建字典树:
• 单词表: •A • AN • ASP • AS • ASC
ASCII BAS BASIC
思路:
将每个单词枚举每个分开的位置,比如 ahat可以分成 a hat ah at aha t 这三组,查找这三组单词只要有一组同时存在则 输出ahat;比如a和hat都存在于单词表中。
字典树和map的作用就是查找单词是否存在
Map的方法
• 以上两道例题的参考代码都是动态申请 • 空间,用的指针。 • 以下是一个非指针的字典树的模板, • 不喜欢指针的同学可以看看,数组模
j= next: 123 4 567 0012300
KMP算法将字符串B向后移动到next[i]位后,重新匹配
KMP算法的运行过程
• i = 1 2 3 4 5 6 7 8 9 …… • A=abababaabab… • B= ababacb
j= next: 1234 567 0012300
对应字符相等则继续向下匹配
-1,i=0; next[i]={Max{k|0<k<i,其中 ‘0~k-1’ 与‘i-k+1~i-1’ 相匹配}; 0,其他;
KMP算法的运行过程
• 我们用两个指针i和j分别表示,A[i-j+ 1..i]与
B[1..j]完全相等。也就是说,i是不断增加的, 随着i的增加j相应地变化,且j满足以A[i]结尾 的长度为j的字符串正好匹配B串的前 j个字符 (j当然越大越好),现在需要检验A[i+1]和 B[j+1]的关系。 j==m,就说B是A的子串(B串已经整完了)
• 例如:text: abcabca,
朴素算法(暴力!)
• 枚举text中的每一个位置,判断以该位置
为起始位置的长度为m的子串是否与s匹 配.
• 显然时间复杂度为O(m*n)
朴素算法过程:
伪代码如下:
void fun(char *text,char *s){ for(i=0;i<n;i++){//n为text的长度 for(j=0;j<m;j++)//m为模式串的长度 if(text[i + j]!=s[j])//一旦不匹配,则不再继续检查 break;
时间复杂度分析
• 由于while循环的不确定性,好像时间复杂
度很高.
• 但事实上,我们可以看到无论是j还是temp,
它只在程序的最后+1,故最多+n(+m)。因 而while循环最多-n(-m),因而算法的复杂度 都是线性的.
• next的复杂度O(m),KMP的复杂度为O(n)
示例—(hrbust-1309)
KMP算法
它是:在一个长字符串中匹配一个短 子串的无回溯算法。
定义
• s: 模式串 , m: 模式串的长度 • text: 要匹配的字符串, n:text的长度 • text中能找到与s完全一样的子串,例如:
abcabca中含有abc;认为text与模式串 匹配,当然text也可能与模式串有多处匹 配 s:abc 则text与s 匹配的位置有3和6
Leabharlann Baiduba b band abc
Sample Output 2 3 1 0
虽然可以用map, 可是太慢了~ Map方法大家自 己想想哈~
初步分析
假设单词表容量为M,需要统计的前缀数 量为N,单词的平均长度为L,则常规算法 的时间复杂度是? Question: 如果单词表容量很大->查找效率? ->低 更有效率的方法:字典树
j=
next:
1234 567
0012300
遇到不匹配的时候,KMP算法则将字符串B向后移 动到next[i]位后,重新匹配
KMP伪代码
int KMP(Sstring S,Sstring T){ int i=0,j=0; while( i<=S_len && j<=T_len ) { if(S[i]==T[j] || j==-1) else { ++i;++j; }//匹配则向后移动一位
拟 提
• 指针,优点是静态开辟,时间快,但 • 前开辟较大的内存,比较耗内存。 • 仅供参考:
相关练习
• HDOJ-1075What Are You Talking About • HDOJ-1251统计难题 • HDOJ-1298T9 • HDOJ-1800 Flying to the Mars • ZOJ-1109
if(j==m){//模式串匹配到最后一个字母,则表示匹配成功
printf(“匹配成功\n”); return ;} } printf(“无法匹配 ”); }
KMP算法
• 作为一种无回溯的算法,它是高效的,
待会儿你将看到它的时间复杂度为 O(m+n),空间复杂度也为O(m+n)
• 而且,它很容易理解,代码也很短
对于字符串S,如果存在正整数p使得
1≤ x≤ |S|-p:Sx= Sx + p。
那么称p是S的循环周期(Period),e = |S| /p是S
的指数(Power),任何长度为p的S的子串都是S
的一个循环节(Repetend),特别的,当e≥2时,
S是个大小为p的重复字符串(Repetition or Ppower word)。
一、字典树
什么是字典树?
字典树:又称为Trie,是一种用于快速检索的多 叉树结构。Trie把要查找的关键词看作一个字符 序列,并根据构成关键词字符的先后顺序构造用 于检索的树结构;一棵m度的Trie树或者为空, 或者由m棵m度的Trie树构成。
特别地:和二叉查找树不同,在Trie树中, 每个结点上并非存储一个元素。
查找效率分析
• •
•
在trie树中查找一个关键字的时间和树中包含的 结点数无关,而取决于组成关键字的字符数。 (对比:二叉查找树的查找时间和树中的结点 数有关O(log2N)。)
如果要查找的关键字可以分解成字符序列且不 是很长,利用trie树查找速度优于二叉查找树。
若关键字长度最大是5,则利用trie树,利用5次 比较可以从265=11881376个可能的关键字中 检索出指定的关键字。而利用二叉查找树至少 要进行log2265=23.5次比较。
• 如果a[i+1]==b[j+1],i和j各加1,什么时候
KMP算法的运行过程
• i = 1 2 3 4 5 6 7 8 9 …… • A=abababaabab… • B=ababacb
j=1234 567 如果a[i+1]!=b[j+1],这时候怎么办? j=5时,a[i+1]!=b[j+1],我们要把j改成比它 小的值j’。改成多少合适呢?
用途:数据库里学的索引等以及电子目录查找等
空 词 典
插 入 A
插 入 AN
插 入 ASP
插 入 AS
插 入 ASC
插 入 ASCII
插 入 BAS
插 入 BASIC
Trie的查找(最主要的操作)
(1)在trie树上进行检索总是始于根结点。
(2)取得要查找关键词的第一个字母,并根据该字母 选择对应的子树并转到该子树继续进行检索。
• 通俗地讲,next[i]保存了以s[i]为结尾的后缀与
定义
•
字符串: a b a b a c b next[i] :-1 0 0 1 2 3 0 0
•
•
字符串: a b c a b a b c a b c a b c a b next[i]: -1 0 0 0 1 2 1 2 3 4 5 3 4 5 3 4 5
KMP算法的运行过程
• i = 1 2 3 4 5 6 7 8 9 …… • A=abababaabab… • B= ababacb
j= next: 1234 567 0012300
遇到不匹配的时候,KMP算法则将字符串B向后移 动到next[i]位后,重新匹配
KMP算法的运行过程
• i = 1 2 3 4 5 6 7 8 9 …… • A=abababaabab… • B= ababacb
题意:输入两个字符串s和t,查找字符串s中 是否有t这个字符串。
Sample Input
abcdefg abcde abcde bcdef
Sample Output
yes no
剩下的几页有点小小难噢~不过大家如果真正理解了 kmp,剩下的也好理解喽~课下自学哈~
So easy!
关于next的一个性质
示例—(HDOJ-1247)
题意:输入一些字符串,输出由别的两个单 词组成的单词。
Sample Input a ahat hat Sample Output ahat hatword
hatword
hziee word
分析:
虽然还是可以用map,但是map太慢了~
前者是字典树的代码,31ms,代码长度1729KB 后者是map的代码 ,359ms,代码长度529KB Map方便,代码好写,但是慢!因为stl都慢! 字典树运行快!效率高! 一旦数据加强或时限变小,则map会TLE了
if(j==-1||s[i]==s[j])
{ i++;j++; next[i]=j;} else j=next[j]; } }
next数组的求解实质: KMP算法本身与求next数组的算法 很类似,只是字符串S既是模式串 也是主串。 Next数组优化后的数组nextval: 详细可见: ①百度百科kmp算法 ②严蔚敏kmp视频 ③ http://blog.csdn.net/guo_love_p eng/article/details/6618170
ACM暑假培训
字典树、KMP 扩展:扩展kmp、AC自动机、后缀数组
负责任:彭文文 指导人:孟祥凤 哈尔滨理工大学ACM集训队
参考学习资料
图书:
《算法导论》(第二版) ,机械工业出版社,P557~P568 《算法竞赛入门经典训练指南》,P208~P214
练习题:
字典树:
Hdu1075(简单) Hdu1251(简单) Hdu4099(难!字典树+大数相加) KMP: hdu1686(给两个字符串a,s,判断a在s里出现的个数 ) hdu3336(稍难,kmp+dp,给一个字符串,输出所有字符串前缀的总个数)
}; dictree *root;
统计难题 (HDOJ-1251)
Ignatius最近遇到一个难题,老师交给他很多 单词(只有小写字母组成,不会有重复的单词出
现),现在老师要他统计出以某个字符串为前缀
的单词数量(单词本身也是自己的前缀).
Sample Input bababa band bee absolute acm