1. 程式人生 > >2018/2/20 每日一學 trie樹

2018/2/20 每日一學 trie樹

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樹