非线性字符串数据结构串讲

书接去年,今天作业不想写了,滚过来写总结。顺便保留我刚略微学会的串串。

声明:作者由于水平不高,所以有些定理不能严谨证明,所以若是初学者请移步别处。

1.Trie树

定义

Trie树又叫字典树,是非常显然的一种字符串数据结构。

具体来说,我们如果手上有很多字符串,我们可以通过建一个Trie树来做一些简单的操作。

其构建过程可以看一下图,非常显然,本质就是把字符串的相同部分压缩一下。

比如我们对

复制代码
aa

aba

ba

caaa

cab

cba

cc

建一个Trie就长这样。

构建

图来自OI wiki

然后构建这块也挺简单的

代码

cpp 复制代码
int len,idx,cnt[N],tr[N][70];
ll getid(char c){
	if(c>='A'&&c<='Z') return c-'A';
	else if(c>='a'&&c<='z') return c-'a'+26;
	else return c-'0'+52;
}
void add(string s){
	len=s.size();
	s=' '+s;
	int p=0;
	for(int i=1;i<=len;i++){
		int id=getid(s[i]);
		if(!tr[p][id]) tr[p][id]=++idx;
		p=tr[p][id];
		cnt[p]++;
	}
}
ll ask(string s){
	len=s.size();
	s=' '+s;
	int p=0;
	for(int i=1;i<=len;i++){
		int id=getid(s[i]);
		if(!tr[p][id]) return 0;
		p=tr[p][id];
	}
	return cnt[p];
}

空间这块,最坏情况每个字符串的每个字符都要新开一个节点,所以空间开即可。

上一道例题

AT_arc219_a ARC219A Similarity

AT_arc219_a ARC219A Similarity

正难则反

这个比较困难

所以就把S串01翻转,那么就是找出一个串串使得不能与任何一个S串相同。

那你给这些反串建出Trie后,找一个还没有被经过的节点即可。

例题结束

与异或相关

其实我们的Trie树不只能在字符串上用

因为在我们眼里数是有二进制的,二进制我们就可以想到01串。

我们就可以把数字当做01串建Trie树

当我们遇到一些神秘有关异或的题目时,

我们一想Trie树,二想线性基

比如来道题,给定你一个序列和x值,让你从这个序列中选一个元素,使之其与x的异或值最大。

考虑异或的性质,二进制位上不同为一,相同为0。

所以我们对序列建Trie树,把给定的x二进制分解,从高往低位的贪心的尽可能与x当前位不同。就行了。

来一道有意思的应用

P5283 十二省联考 2019 异或粽子

题解

2.AC自动机

定义

AC自动机,由两部分构成Trie树和fail树。

AC自动机的本质上就是建出Trie树后连fail边。

这里我们给出fail边的定义。

在Trie树上,每一个节点表示一个字符串。

fail边指向这个节点所代表的字符串 最长的后缀 所代表的节点。

图例

example:

图来自OI wiki

比如这个Trie树

给他建fail边就应该是这样的

由于根节点代表的是空串,空串是任何字符串的后缀。

所以当你实在在Trie树上找不到后缀时,就直接无脑连根结点就可以啦。

然后AC自动机的功能这块,可以通过拿一个字符串在上面跑得到在自动机上他的所有子串,不管通过Trie边还是fail边。

代码

cpp 复制代码
int n,m,len,idx=1;
string s;
struct trie{
	int son[29],fail;
	int flag;
}t[N];
struct AC_automation{
	void build(string s){
		len=s.size(); s=' '+s;
		int p=0;
		for(int i=1;i<=len;i++){
			int v=s[i]-'a'+1;
			if(!t[p].son[v]) t[p].son[v]=++idx;
			p=t[p].son[v];
		}
		t[p].flag++;
	}
	void getfail(){
		queue<int> q;
		for(int i=1;i<=26;i++) if(t[0].son[i]) q.push(t[0].son[i]);
		while(!q.empty()){
			int p=q.front();
			q.pop();
			for(int i=1;i<=26;i++){
				int v=t[p].son[i];
				int faf=t[p].fail;
				if(!v){
					t[p].son[i]=t[faf].son[i];
					continue;
				}
				t[v].fail=t[faf].son[i];
				q.push(v);
			}
		}
	}
	ll ask(string s){
		len=s.size(); s=' '+s;
		int p=0; ll ans=0;
		for(int i=1;i<=len;i++){
			int v=s[i]-'a'+1;
			int k=t[p].son[v];
			while(k>1&&t[k].flag!=-1){
				ans+=t[k].flag,t[k].flag=-1;
				k=t[k].fail;
			}
			p=t[p].son[v];
		}
		return ans;
	}
	
}AC;

P9613 CERC2019 K==S

大意就是构造一个长度为N的串串,让你是这个串串不包含给出的禁用短语作为子串,求方案数。

多模匹配想到建AC自动机并建图,由于不能含某些子串,所以不能走到这些子串的节点以及能通过跳fail边到这些子串的地方。

发现N很大,直接DP不行。但是状态转移固定,所以使用矩阵乘法优化DP就好了。

3.后缀数组

其实有点跑题了,因为后缀数组是线性的,但是后缀数组比较困难所以就写在这里了

定义

性质

图文来自洛谷

代码

cpp 复制代码
string s;
int sa[N],c[N],x[N],y[N],height[N],rk[N];
namespace SA{
	void getsa(){
		for(int i=1;i<=n;i++)++c[x[i]=s[i]];
		for(int i=2;i<=m;i++)c[i]+=c[i-1];
		for(int i=n;i;i--)sa[c[x[i]]--]=i;
		for(int k=1;k<=n;k*=2){
			int num=0;
			for(int i=n-k+1;i<=n;i++)y[++num]=i;
			for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
			for(int i=1;i<=m;i++)c[i]=0;
			for(int i=1;i<=n;i++)++c[x[i]];
			for(int i=2;i<=m;i++)c[i]+=c[i-1];
			for(int i=n;i;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
			swap(x,y);
			x[sa[1]]=1;
			num=1;
			for(int i=2;i<=n;i++){
				x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
			}
			if(num==n)break;
			m=num;
		}
	}
	void getheight(){
		for(int i=1;i<=n;i++) rk[sa[i]]=i;
		int k=0;
		for(int i=1;i<=n;i++){
			if(rk[i]==1) continue;
			if(k) k--;
			int j=sa[rk[i]-1];
			while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++;
			height[rk[i]]=k;
		}
	}
}
using namespace SA;

4.后缀自动机

相关推荐
wenyq71 分钟前
LeetCode 438. Find All Anagrams in a String
算法·leetcode
阳光宅男@李光熠2 分钟前
【电子通识】PCB外观检查机AVI(Automated Visual Inspection)
笔记·学习
LB21122 分钟前
力扣102 198 70 55
数据结构·算法·leetcode
所念皆星海9119 分钟前
Python学习---DAY10函数
开发语言·python·学习
刘天远9 分钟前
企业 Agent 需求怎么写:数据结构、流程图与 Python 校验
数据结构·人工智能·python·流程图
wy2002031415 分钟前
小机构怎么新增学习能力项目
学习
旖旎夜光18 分钟前
【LangChain实战】LangChain 学习笔记(一):从定义大模型到工具调用
人工智能·笔记·python·学习·langchain
鹿角片ljp27 分钟前
LeetCode 42:接雨水|前后最大值DP
算法·leetcode·动态规划
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】ChatGPT API
网络·c++·人工智能·websocket·网络协议·学习·chatgpt