算法提升之字符串(字典树)

今天给大家分享的是关于字符串中字典树的内容,这个内容可以帮助我们更好地理解有关字符串的相关知识,将字符串变为数组存在里面,方便统计字符串的内容。主要用于解决多个母字符串,然后询问字串是否存在的问题。

希望大家可以好好地阅读这部分内容,这是关于字典树的模版内容,相信可以帮助大家更好地理解。

题目描述:

小 Z 同学非常喜欢找事,现在有很多名为"事"的字符串,现在小 Z 想要找"事",请你帮助他判断,他今天是否找了两件相同的事。

输入描述

输入第一行包含一个整数 n,表示小 Z 今天找了多少事。

接下来 n 行分别表示 n 件事。

事的输入量不超过 103 ,每个"事"字符串的长度不超过 1000,且所有字母均为小写。

输出描述

若有相同的事输出1,否则输出0。

输入案例:

复制代码
12
acd
acd
asdfsdf
asd
f
saf
asdf
sfasdfs
f
asdf
asf
asdfs

输出案例:

复制代码
1

代码部分:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int nex[1004][26];
int cnt[1004];
int nx=2;
void insert(char a[]){
  int x=1;
  for(int i=0;a[i];i++){
   if(!nex[x][a[i]-'a'])nex[x][a[i]-'a']=nx++;
   x=nex[x][a[i]-'a'];
  }
  cnt[x]++;
}
bool find(char a[]){
  int x=1;
  for(int i=0;a[i];i++){
    x=nex[x][a[i]-'a'];
  }
  return cnt[x]>1;
}
int main()
{
  int n;cin>>n;
  for(int i=0;i<n;i++){
    char a[1004];
    cin>>a;
    insert(a);
    if(find(a)){
    cout<<1<<endl;
    return 0;
  }
  }
  cout<<0<<endl;
  return 0;
}

⚠️⚠️注意数组的范围

问题二:

问题描述

小蓝是图书馆的管理员,他负责管理图书馆的所有书籍。图书馆有 N 本书,每本书都有名字,分别为 S1​,S2​,...,SN​。

图书馆的读者们经常来询问小蓝,他们会给小蓝一个字符串 T,希望小蓝能告诉他们,图书馆里有多少本书的名字是以 T的前缀开头的。小蓝需要回答他们 M 次这样的询问。

现在,小蓝需要你的帮助。你能帮助小蓝解决这个问题,从而提升图书馆的服务质量吗?

输入格式

第一行输入两个整数 N 和 M(1≤N,M≤104)。

接下来 N 行,每行输入一个字符串Si​,表示图书馆中的一本书的名字。

接下来 M 行,每行一个字符串 T,表示读者的询问。

输入字符串的总长度不超过 2×105,且仅包含小写字母。

输出格式

对于每个询问,输出一个整数,表示图书馆中以字符串 T 开头的书的数量。

每个答案占一行。

输入案例:

cpp 复制代码
5 2
ababc
ababd
aba
ab
a
abab
ccc

输出案例:

cpp 复制代码
2
0

代码部分:

cpp 复制代码
#include <bits/stdc++.h>
const int N=1e5+3;
using namespace std;
int nex[N][26];int nx=2;int cnt[N];
void insert(char a[]){
 int x=1;
 for(int i=0;a[i];i++){
  if(!nex[x][a[i]-'a'])nex[x][a[i]-'a']=nx++;
  x=nex[x][a[i]-'a'];cnt[x]++;
 }
}
int check(char a[]){
  int x=1,res=0;
  for(int i=0;a[i];i++){
    x=nex[x][a[i]-'a'];
    res=cnt[x];
  }
  return cnt[x];
}
int main()
{
  int m,n;cin>>m>>n;
  for(int i=0;i<m;i++){
    char a[N];
    cin>>a;
    insert(a);
}
for(int i=0;i<n;i++){
  char b[N];
  cin>>b;
  cout<<check(b)<<endl;
}
  return 0;
}

这道题也是关于字典树的经典问题,可以拿这道题作为模版问题进行记忆。

第三题:

问题描述

依依是一个住在海边小镇的女孩,她的朋友们分散在世界的各个角落。他们有一个特殊的传递信息的方式,那就是通过海洋传递瓶中信。每个瓶中信里,都装着一串由小写英文字母组成的信息,代表一个友情的密码。

这个夏天,依依在海滩上捡到了 N 个瓶中信,每个瓶中信里都有一条由小写英文字符组成的信息,这些信息分别来自她的 N个朋友。我们记第 i 个朋友的信息为 Si​,其中 i=1,2,...,N。

为了找出与自己最有缘分的朋友,依依决定比较这些信息的相似度。这里的"相似度"指的是两条信息从头开始,最长能够匹配的字符数量。

注意,依依并不想比较一条信息与它自身的相似度。

现在,依依希望你能帮助她找出对于每条信息 Si​,哪条信息与其最相似,即从开头开始,最长能连续匹配的字符的数量是多少。

输入格式

输入的第一行包含一个整数 N(1≤N≤104)。

接下来的 NN 行,每行包含一个由小写字符构成的字符串 Si​,表示小蓝的一个朋友在信封里刻写的信息。保证i=1∑N​∣Si​∣≤105。

输出格式

输出共 N 行,对于每条信息 Si,输出一个整数,表示与 Si​ 最接近的信息的最长公共前缀的长度。

输入案例:

cpp 复制代码
3
abc
ab
bc

输出案例:

cpp 复制代码
2
2
0

代码部分:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+12;
string a[10005];int nex[N][27],cnt[N],nx=2;

void insert(string s)
{int x=1;int n=s.size();
for(int i=0;i<n;i++)
{
  if(!nex[x][s[i]-'a'])nex[x][s[i]-'a']=nx++;
  x=nex[x][s[i]-'a'];cnt[x]++;
}}

int check(string s)
{int x=1,res=0;int n=s.size();
for(int i=0;i<n;i++)
{
  x=nex[x][s[i]-'a'];
  if(cnt[x]>1)res=i+1;
}return res;}

int main()
{int n;cin>>n;
for(int i=1;i<=n;i++){cin>>a[i];insert(a[i]);}//加入树上
for(int i=1;i<=n;i++)cout<<check(a[i])<<endl;
  return 0;
}

这道题也是关于字典树的问题,明天我将介绍一种更加常用的字符串模型--01🌲

好了,今天的分享就到这里,希望大家多多关注,我们后续再见👋