字符串进阶 小白笔录

做完一部分字符串题后,对字符串的很多操作有了一点眉头,所以现在准备写一篇字符串进阶,参考《算法竞赛从入门到进阶》的题目流程,把字符串题从头刷到尾。

字符串进阶(从入门到入坑)

字符串的基本操作

poj3981-字符串替换

在这里插入图片描述
gets函数(也可以是gets_s函数)读取一行,存入char数组,一个个暴力。
在这里插入图片描述
2.getchar()读取一个字符
EOF表示ctrl+z,终止循环
在这里插入图片描述
3.getline()+find+replace函数
getline读取一行,包括空格,是对cin无法处理空格的改进
find()找字符串,找第一个能和该字符串匹配的第一个字符的位置,找到返回位置,找不到返回-1
replace就是替换字符串,3个参数,第一个位置,第二个长度,第三个是要替换的
在这里插入图片描述

字符串反转:reverse()函数,输入string后,reverse(str.begin(),str.end())
还有一些可能用到的
find_first_of(string s)在字符串中找包含s任意字符的第一个位置。
find_last_of(string s)最后一个位置
find_first_not_of找到第一个不与字符串匹配的

字符串哈希

字符串哈希,顾名思义,就是给字符串一个hash值,减少重复。常用的是BKDRHash,就像我们判断整数12345一样,对12345进行哈希的话就是11w+21k+3100+410+5,每个整数的哈希值都是这样计算的,那么字符串哈希也是,我们把它当作是一个seed进制的数,对于一个字符串S,长度为len,哈希值为S[0] * seed * (len-1)+s[1] * seed *(len-2)…等等,然后把这个存储起来,表示一个字符串的哈希值,有人肯定认为这直接map不就好了,确实,但是对于一些特殊的查找,要处理字符串啥的,就很麻烦,所以这里用哈希。
题目有hdu2648,hdu4821,hdu4080,hdu4622,hdu4622等,哈希主要是先定义一个结构体满足hash的所有操作,其次进行对应的字符串查找。每道题有每道题的查找方法,所以要会变。
下面是hdu4821的题解

hdu4821-String

在这里插入图片描述
意思就是找一个长m*l的子串,使得这子串里m个长为l的子子串互不相等。问有几个这样的子串。
这里有一个类似滑动窗口的思想,是为了让map的删减更加方便。
这个大家还是看其他题解。
在这里插入图片描述

hdu4080 Stammering Aliens

在这里插入图片描述
题意就是输入一个m,一个字符串s,找至少有m个子字符串相等的最长子字符串
字符串哈希,不过,要用二分,因为字符子串的长度单调。最长长度为k,那么看看k+1行不行,如果k不行,那么看k-1行不行(表示单调)
用map或者sort快排是2种解法。都是nlogn的复杂度
我的一直TLE,后来复制粘贴别人的代码,还是TLE,估摸着应该不是我的问题
在这里插入图片描述

字典树

就像查一个dog单词一样,我们先查d,再查o,最后g,字典树就是这个原理。把所有公共前缀的放在一个树枝上,不同的延伸出去。
主要功能:字符串检索,词频统计,字符串排序,前缀匹配

hdu1251 统计难题

在这里插入图片描述
经典的字典树问题,用数组,不要数据结构,不然会超空间
并且不要用gets_s函数,在hdu里判题会判错,用gets,我vs软件不能用gets,所以用gets_s来代替
这里trie[p][n]表示第p个字符串+26字母当中第n+1个字母形成的新字符串的位置。
在这里插入图片描述

KMP算法

这里我也讲不清楚
推荐一篇大佬博客,仔细看,很清晰
https://blog.csdn.net/tukangzheng/article/details/38438481?utm_medium=distribute.pc_feed_404.none-task-blog-BlogCommendFromMachineLearnPai2-9.nonecase&depth_1-utm_source=distribute.pc_feed_404.none-task-blog-BlogCommendFromMachineLearnPai2-9.nonecas
模板题目

hdu2087 剪花条布

在这里插入图片描述
KMP经典题目,就是从一个母串中找一个子串,时间复杂度为n+m,主要用到next数组,KMP最难的就是next数组的理解。
我这边推荐先看那篇博客,然后再看我的解析,我的解析可能比较抽象
先看看我的getnext事怎么得到的,先申明k=-1表示初始化,next0=-1是初始状态。然后从下标1-len-1进行求next,为何用while呢,这样保证我们得到的k是有效的,k就代表知道我找到了s[k]==s[i-1]或者我已经在模板串里找不到可以相同的了(即k=-1时),k++表示我们往后移动一个位置,观察后面的字母是否和s[i]相同,然后分情况赋值(那篇博客讲了),不仅如此,这里k++还有一个作用,那就是for的下一层循环时,对s[k]和s[i-1]进行判断,不妨看一个这样的字符串ABD ABC ABDE(中间空格只是为了看的更清楚),当一层循环执行到最后,即k++结束后,我们已经保证了前面的k-1个字符和后缀那些相同了,比如k=2,i=6,表示我们s0,s1和s3,s4相同,然后我们看看下标2的s2与si-1是否相同,不相同,代码k=nextk就把k置为0(这里只是针对这个例子),那么下次循环,k=0表示什么表示我们前k-1个字符与后缀相同,k-1=-1就代表前面没字符匹配后缀了,ABD和ABC不同,那么往后不管加什么都不会相同ABD+x!=ABC+x,如果相同呢,就是如果给的字符串是ABC ABC ABDE,那么相同后k=3,i=7,比较sk和si-1发现相同,k++。

在这里插入图片描述

hdu1686 oulipo

在这里插入图片描述
第二种类型的字符串查找,上一种对1个字符串中切割子字符串,这个子字符串最多几个,不能有公共的字符
这一种是求一个字符串中一个子字符串的最多数量,能有公共的字符
这里因为要比较前缀后缀相等,不需要对next进行优化,优化的话反而不好。其次就是kmp那个最后一个if代码,多了2行,i–,表示因为我们处理到这一步时,肯定经过一个i++,j++,所以i–保持i不变,j=nextj,保证我们最优的进行查找。为何这里要j=nextj,而不j=0,因为这里允许有公共字符,其次,凭什么这个操作保证有最长公共字符呢,因为next的性质,next表示前几个字符的前缀后缀最长相等数,母串的i处表示后缀,子串的j处表示前缀,所以可以。
在这里插入图片描述

AC自动机

这对我这种新手真是劝退级别的难度了
我怎么爬上来的呢,先看教学视频,b站什么的,然后刷博客,接着,自己举例画图模拟,然后代码模拟,然后习惯后,进行刷题。
题目建议先别hdu2222,因为没有数据,并且不知道错什么
建议洛谷,真的很好用,建议从第一个AC刷起

AC自动机 (简单版)

时间复杂度不用管,直接暴力AC自动机
在这里插入图片描述
在这里插入图片描述

AC自动机(强化版)

管理时间复杂度,并且有了一点技巧
在这里插入图片描述
主要把握一个时间的话就是AC_q那个代码的二重循环,因为结点满足trie树,那么这些特殊的结点也肯定满足,所以暴力跳fail,肯定能跳到后缀相同的最长地方,所以不会错过答案,比如对于she和he都是模板子串,母串是she,那么我们每遍历一个点,暴力跳fail一下,到了e这时,我们暴力跳到了he这个分支,得到了这个答案。当然有人用vector存结点,但是不推荐,速度比较慢。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值