有限自动机字符串匹配
引言:
本文参考自《算法导论》中 “32.3 利用有限自动机进行字符串匹配” ,其目的不仅仅是为了改善常规算法的时间复杂度问题,更是为了给在解决类似情况提供一个有限自动机方案的参考。
很多字符串匹配算法都要建立一个有限自动机,它是一个处理信息的简单机器,通过对文本字符串 T 进行扫描,找出模式 P 的所有出现位置。这些字符串匹配的自动机都非常有效:它们只对每个文本字符检查一次,并且检查每个文本字符时所需的时间为常数。因此,在模式预处理完成并建立好自动机后进行匹配所需要的时间为 O(n) 。
1、朴素字符串匹配算法:
朴素字符串匹配算法时通过一个循环找到所有有效偏移,
该循环对 n-m+1 个可能的 s 进行检测,看是否满足条件 P[1…m] = T[s+1…s+m]。
朴素字符串匹配算法伪代码:
NAIVE-STRING-MATCHER(T,P)n=T.lengthm=P.lengthfor s = 0 to n-mif p[1...m] == T[s+1,s+m]print "Pattern occurs with shift" s
最坏的情况下,朴素字符串匹配算法运行时间为 O((n-m+1)m)。
2、有限自动机:
一个有限自动机 M 是一个 5 元组(Q,q, A, ∑,δ)
Q 是状态的有限集合
q∈Q 是一个初始状态
A 包含于 Q 是一个特殊的接受状态集合
∑ 是有限输入字母表
δ 是一个从 Q✖∑ 到 Q 的函数,称为 M 的转移函数
下图为有限自动机的状态转移图,模式串为 ababaca 。
转移函数算法伪代码:
其中, Pk ⊇ Pqa 表示 Pk是 Pqa的后缀。
COMPUTE-TRANSITION-FUNCTION(P,∑)m = P.lengthfor q = 0 to mfor each charater a∈∑k = min(m+1,q+2)repeatk = k - 1until Pk ⊇ Pqaδ(q,a) = kreturn δ
有限自动机算法伪代码:
FINITE-AUTOMATON-MATCHER(T,δ,m)n = T.lengthq = 0for i = 1 to nq = δ(q,t[i])if q == mprint "Pattern occurs with shift" i-m
3、详细代码:
转载自 https://blog.csdn.net/giftedpanda/article/details/86774815
。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>using namespace std;bool Matching_Prefix_Suffix(char* P,int k,int q,char c)
{ //P为模式串 K为要验证的前缀和后缀的字符串长度if(k==0) //q为当前自动机主线长度return true; //k=0 空字符串 前缀和后缀肯定相等if(k==1){ //只有一个字符串 证明自动机刚好开始创建return P[0]==c; //如果模式串的第一个和其中的c相等 前缀等于后缀}return P[k-1]==c&& (!strncmp(P,P+q-k+1,k-1)); //检验P[0...k-1]==P[q-k+1...q]
}vector<map<char,int> > Compute_Transition_Function( char *P,const char* input_character)
{ //计算转移函数的值int m=strlen(P); //模式串的长度int j=0,k;printf("The main length of Finite_Automaton_Matcher is %d\n",m);vector<map<char,int> >transition_map(m+1); //创建一个vector 一共有m+1个数据for(int i=0;i<m;i++){ //对于模式串的长度j=0;while(input_character[j]!='\0'){ //对于输入串的每一种可能字符k= min(m+1,i+2); //因为对于长度为i的字符串 它的转移函数最大值为ido{ //数组下标从0开始 再加上后面k一来就减1 所以为i+2k=k-1; //找到一个最大值k使得模式串的P[0...k]==P[...n-1]}while(!Matching_Prefix_Suffix(P,k,i,input_character[j]));transition_map[i][input_character[j]]=k;j++;}}return transition_map; //返回一个vector 每一个元素为 map<char,int>
} //char 为自动机中的字符 int 为转移函数值void Finite_Automaton_Matcher(char* T,char* P,vector<map<char,int> >transition_map)
{int n=strlen(T); //文本串长度int m=strlen(P); //模式串长度int q=0; //转移函数的值for(int i=0;i<n;i++){ //对于文本串中的每一个字符q = transition_map[q][T[i]]; //迭代 前一个字符的转移函数值if(q==m) //转移函数的值等于模式串的长度printf("Pattern occurs with shift %d\n",i+1-m); //模式串的有效位移为i-m+1}
}int main()
{const char* input_character="abc"; //输入字母表char T[]="abababacaba"; //文本串char P[]="ababaca"; //模式串vector<map<char,int> >transition_map=Compute_Transition_Function(P,input_character);Finite_Automaton_Matcher(T,P,transition_map);return 0;
}
此外,有关字符串匹配的 KMP 算法,请参见:
https://blog.csdn.net/qq_30534935/article/details/100713917
。
有限自动机字符串匹配相关推荐
- 字符串——字符串匹配
文章目录 字符串匹配 一.基本概念 字符串匹配问题 符号和术语 后缀重叠引理 二.朴素字符串匹配算法 三.Rabin-Karp算法(字符串Hash算法) 进制Hash 质数Hash 四.利用有限自动机 ...
- java中字符串的精确匹配_Java最佳实践–字符串性能和精确字符串匹配
java中字符串的精确匹配 在使用Java编程语言时,我们将继续讨论与建议的实践有关的系列文章,我们将讨论String性能调优. 我们将专注于如何有效地处理字符串创建, 字符串更改和字符串匹配操作. ...
- Java最佳实践–字符串性能和精确字符串匹配
在使用Java编程语言时,我们将继续讨论与建议的实践有关的系列文章,我们将讨论String性能调优. 我们将专注于如何有效地处理字符串创建, 字符串更改和字符串匹配操作. 此外,我们将提供我们自己的用 ...
- 算法导论(三)字符串匹配
字符串匹配方法对于在编辑文本程序时,能极大的提升响应效率,如网址查询搜索引擎,DNA序列匹配等. 基本定义 字符串匹配问题的形式定义: 文本(Text)是一个长度为 n 的数组 T[1..n]: 模式 ...
- 字符串(字符串匹配)
一.字符串匹配问题.基础 1.假设文本是一个长度为n的数组T,而模式是长度为m的数组P,我们希望在文本T中寻找模式P 如果P出现在T中的第s个位置,那么我们称其有效偏移为s,在其他不匹配的位置称为无效 ...
- CCF - 201409-3 - 字符串匹配
问题描述 试题编号: 201409-3 试题名称: 字符串匹配 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你 ...
- 字符串匹配shiftand算法
令人惊叹的Shift-And/Shift-Or 写在前面:Shift-And/Shift-Or是如此令人惊叹的算法,在KMP基础上开始一段神奇之旅. 目的:以Shift-And算法为载体,试图在减少思 ...
- 字符串匹配数据结构 --Trie树 高效实现搜索词提示 / IDE自动补全
文章目录 1. 算法背景 2. Trie 树实现原理 2.1 Trie 树的构建 2.2 Trie树的查找 2.3 Trie树的遍历 2.4 Trie树的时间/空间复杂度 2.5 Trie 树 Vs ...
- 2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FFT)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FF ...
- Rabin-Karp ( 字符串匹配 )详解
字符串匹配,例从 字符串S 中( 长度为 n ),找到 字符串T ( 长度为 m ) 经典思路:遍历 字符串 S,对于每个都为起点,匹配一次,则 O( n m )的复杂度 但是这样我们就对 字符 重复 ...
最新文章
- C++——简单数据类型及布尔类型
- C++/C++11中std::exception的使用
- c++ mqtt客户端_MQTT安全性设计详解
- Leetcode 455.分发饼干 (每日一题 20210708 同类型题)
- 【快速入门Linux】2_Linux命令—基本使用
- 一直弹出adb已停止工作(远程主机强迫关闭现有的连接)的最简单完美解决法
- Java Wbe 学习心得 day06
- 苹果录制屏幕在哪设置_屏幕录像专家如何录全屏 屏幕录像专家全屏录制设置方法...
- 百度竞价推广:关键词首页指导价分析及竞价出价技巧
- kotlin遍历数据同时删除之利用kotlin迭代器安全删除
- pytorch 常用目标检测评价指标总结
- 微信中屏蔽分享按钮一把梭快速干
- Android在线工具
- 大数据学习入门规划?和学习路线
- linux配置4g网络命令_Linux常用操作练习汇总
- luogu P2056 采花
- 正态分布均值μ的贝叶斯Bayes估计推导
- 如何抓住下一波零售风口?看影刀RPA玩转零售自动化
- 了解CAP(一致性、可用性、分区容错性)
- 计算机等级考试到底是怎么考的?