关于字符串与AC自动机算法

强颜欢笑 提交于 2019-11-27 12:38:46

相信大家都多少了解字符串

先大概说一说两种常用字符串的类型:

1.str:string; 2.str:ansistring;

string类型,长度为255,一般处理较短的字符串,而ansistring类型,则大概有2G,用来处理比较大的数据,当然,ansistring类型也可以由一个庞大的字符数组代替。

字符串的常用函数和过程列表:

函数和过程名 作用
copy(a,b,c) 取a串中从第b个字符开始的c个字符
length(a) 获取a串的长度
pos(a,b) 在b串中找字串a
str(a,b) 把整数a转成字符串并存入b串中
val(a,b) 把字符串a转化成数字并存入整数b内
delete(a,b,c) 删除串a中从第b个字符开始的c个字符
insert(a,b,c) 在串字符位置插入子串c
upcase(a) 将字母a转换成大写字母

用初级到爆的题举个例子

求输入英文句子单词的平均长度 每行一个输出

相信大家都会做, 完整代码如下:

Var n:longint;     s:string; Begin     readln(n);     for i:=1 to n do     Begin         readln(s);         l:=l+length(s);     end;     write(l div n);//假设都可以除尽 end.

每一道字符串的题都会有一个容易出错的问题——输入。 许多连这道题都出错的新手们非常有可能在输入上出差错。因为回车也是一个字符,用chr函数表示就是chr(13)(好像是吧)

{用一个简单的程序测试一下} var a:longint;     s:string; begin         read(a);         read(s);         writeln(a);         write(s); end.

运行之后(我用的是CP Pascal Editor 3.5编译的):

很显然,字符串s根本就没有输入,所以为空串。
{用一个简单的程序测试一下} var a:longint;     s:string; begin         readln(a);//把read修改成了readln         read(s);         writeln(a);         write(s); end.

改过的程序运行之后:

现在,s不在为空串,而是成为了键盘输入的'1'。

再举一个例子。 验证下面结论: 一个各位数字不同且都不为0的N位数X(3<=N<=5), 将组成该数的各位数字重新排列成一个最大数和一个最小数作减法, 其差值再重复前述运算, 若干次后必出现一个N位数Y, 使之重复出现. 例如: X=213, 则有213→321-123=198 981-189=792 972-279=693 963-369=594 954-459=495 954-459=495 这时Y=495。(注意:重复不仅仅是与上一次的数相同,也可能是出现成段的多个数反复重复) 代码如下:

var x,ch,sm,bg:string;     i,p,l,s,b,y,t:longint;     bz:boolean;  procedure Fd(n:string); var a:string[10];     k:string[5];     a2:array[1..10] of longint=(0,0,0,0,0,0,0,0,0,0); begin     a:='**********';      for i:=1 to l do     begin         val(n[i],p);         a[p+1]:=n[i];          a2[p+1]:=a2[p+1]+1;     end;      bg:='';     for i:=10 downto 1 do     begin         if a2[i]<>0 then         begin             k:='*****';             fillchar(k,5,a[i]);              bg:=bg+copy(k,1,a2[i]);         end;     end;      sm:='';     for i:=l downto 1 do     begin         sm:=sm+bg[i];     end;      val(sm,s);     val(bg,b); end;  begin     read(x);     l:=length(x);     ch:=x;     bz:=false;     t:=0;      repeat         Fd(x);          y:=b-s;         str(y,x);          if pos(x,ch)<>0 then bz:=true;         ch:=ch+'_'+x;         t:=t+1;     until bz;      write(t-1); end.

好了,讲完那两个水题和字符串,该步入正题了——AC自动机。那么,AC自动机算法到底是什么呢?

AC自动机其实就是一种多模匹配算法,多模匹配就是什么呢?我们先说说单模,再来了解多模。单模就是给你一个单词,然后给你一个字符串,问你这个单词是否在这个字符串中出现过,这个问题可以用KMP算法完成。但是,如果现在给你很多个单词,然后给你一段字符串,问你有多少个单词在这个字符串中出现过呢?使用暴力,当然是可行的,用每一个单词对字符串用KMP,这样虽然理论上可行,但是很可能是TLE,当单词的数量比较多并且字符串很长的情况下不能有效的解决这个问题,这时候AC自动机算法就出来了。

AC自动机算法

首先,第一步是生成构造一个Trie树,Trie树是一个哈希树的变种,因为重点不在这里,所以我不细讲。接下来的第二步和第三步是构造失败指针和模式匹配过程。

不多说什么,马上举个例子:

由于最近功课过于繁忙,Jack竟然忘记了自己电脑的密码, 幸运的是Tim在设计电脑密码的时候,用了一个非常特殊的方法记录下了密码。 这个方法是:Jack把密码和一些假密码共同记录在了一个本子上面。 为了能够从这些字符串中找出正确的密码,Tim又在另外一个本子上面写了一个字符串, 而正确的密码就是在这个字符串里出现次数最多的一个密码。

很典型的一道AC自动机题。 那个……因为太麻烦,所以没有编……(打脸ing)

时代在发展,世界不能没有字符串,从我们日常使用的文字,到各种编排号码;从上海,到悉尼……字符串是一种文化,有许许多多关于它的算法,这些算法不仅用于程序员的代码,更是关乎着信息化时代,如果要通俗地讲,那就是关乎着我们的品质生活。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!