【数据结构】刷题记录【字典树】

AcWing 124 前缀统计
解题思路: 因为查询的是前缀,只需要将单词中的每个字母的cnt相加即可
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
int son[maxn][26],cnt[maxn],idx;
char str[maxn];
void add(char *str){
    int p=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cnt[p]++;
}
int ask(char *str){
    int p=0,res=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u]) break;
        p=son[p][u];
        res+=cnt[p];
    }
    return res;
}
void AC(){
    int n,m;
    cin>>n>>m;
    while(n--){
        cin>>str;
        add(str);
    }
    while(m--){
        cin>>str;
        cout<<ask(str)<<endl;
    }
}
int main(){
    AC();
    return 0;
}

AcWing 835. Trie字符串统计

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int son[N][26],cnt[N],idx;
char str[N];
void insert(char *str){
    int p=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u]) son[p][u]=++idx;
        p=son[p][u];
    }
    cnt[p]++;
}
int query(char *str){
    int p=0;
    for(int i=0;str[i];i++){
        int u=str[i]-'a';
        if(!son[p][u]) return 0;
        p=son[p][u];
    }
    return cnt[p];
}
int main(){
    int n;
    cin>>n;
    while(n--){
        char op[2];
        scanf("%s%s",op,str);
        if(*op=='I') insert(str);
        else printf("%d
",query(str));
    }
    return 0;
}

AcWing 143. 最大异或对
解题思路: 有点贪心的感觉,我们每一次都走与当前这一位相反的位置,也就是让异或值最大,如果说没有相反的位置可以走的话,那么就走相同的位置.
代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 100010, M = 3000000;
int n;
int a[N], son[M][2], idx;
void insert(int x)
{
    int p = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int &s = son[p][x >> i & 1];
        if (!s) s = ++ idx;
        p = s;
    }
}
int search(int x)
{
    int p = 0, res = 0;
    for (int i = 30; i >= 0; i -- )
    {
        int s = x >> i & 1;
        if (son[p][!s])
        {
            res += 1 << i;
            p = son[p][!s];
        }
        else p = son[p][s];
    }
    return res;
}
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d", &a[i]);
        insert(a[i]);
    }
    int res = 0;
    for (int i = 0; i < n; i ++ ) res = max(res, search(a[i]));
    printf("%d
", res);
    return 0;
}


AcWing161. 电话列表
思路: 满足答案的关系只有两种,一种是插入的串是之前的串的前缀,那么只要看在插入过程中是不是没有新增节点;另一种是插入的串包括之前的串,也就是之前的串是插入的串的前缀,这个只要看看有没有走到打了标记的点就好了。所以只需要在插入时判断即可;

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int son[maxn][10],cnt[maxn],idx;
char str[maxn];
int add(char *str){
    int p=0,f1=0,f2=1;
    for(int i=0;str[i];i++){
        int u=str[i]-'0';
        if(!son[p][u]) son[p][u]=++idx,f2=0;
        p=son[p][u];
        if(cnt[p]) f1=1;
    }
    cnt[p]=1;
    if(f1||f2) return 1;
    return 0;
}
void AC(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        idx=0;
        memset(son,0,sizeof son);
        memset(cnt,0,sizeof cnt);
        bool flag=true;
        while(n--){
            cin>>str;
            if(add(str)) flag=false;
        }
        if(flag) puts("YES");
        else puts("NO");
    }
}
int main(){
    AC();
    return 0;
}

未完待续
待刷题目合集:字典树题目 - Virtual Judge
密码:ludicpc

参考博客:AcWing 161. 电话列表 - AcWing
字典树题目总结_天亮说晚安-CSDN博客

原文地址:https://www.cnblogs.com/OvOq/p/14853208.html