2018/2/20 每日一學 trie樹
阿新 • • 發佈:2018-02-20
oot 表示 多少 turn cst fin bool arc trie
看看這個問題:
給出n個單詞和m個詢問,每次詢問一個前綴,回答詢問是多少個單詞的前綴。n<=200000
相信一些人除了暴力枚舉貌似就沒法子了……
其實我們可以用tire樹。
什麽是trie樹?
顯然這是個樹(廢話),那麽我們用f[i][j]=k,表示編號為i的第j個子節點編號為k,那麽我們從root開始訪問就行了。
看代碼吧:
void insert()//插入單詞s { len=strlen(s);//單詞s的長度 root=0;//根節點編號為0 for(int i=0;i<len;i++) { int id=s[i]-‘a‘;//第二種編號 if(!trie[root][id])//如果之前沒有從root到id的前綴 trie[root][id]=++tot;//插入,tot即為第一種編號 root=trie[root][id];//順著字典樹往下走 } }
是不是很簡單,那查詢呢?
bool find() { len=strlen(s); root=0;//從根結點開始找 for(int i=0;s[i];i++) { int x=s[i]-‘a‘;// if(trie[root][x]==0) return false;//以root為頭結點的x字母不存在,返回0 root=trie[root][x];//為查詢下個字母做準備,往下走 } return true;//找到了 }
最後是前綴和?
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int trie[400001][26],len,root,tot,sum[400001];
bool p;
int n,m;
char s[11];
void insert()
{
len=strlen(s);
root=0;
for(int i=0;i<len;i++)
{
int id=s[i]-‘a‘;
if(!trie[root][id]) trie[root][id]=++tot;
sum[trie[root][id]]++;//前綴後移一個位置保存
root=trie[root][id];
}
}
int search()
{
root=0;
len=strlen(s);
for(int i=0;i<len;i++)
{
int id=s[i]-‘a‘;
if(!trie[root][id]) return 0;
root=trie[root][id];
}//root經過此循環後變成前綴最後一個字母所在位置的後一個位置
return sum[root];//因為前綴後移了一個保存,所以此時的sum[root]就是要求的前綴出現的次數
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>s;
insert();
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
cin>s;
printf("%d\n",search());
}
}
2018/2/20 每日一學 trie樹