字典树初步练习

 

字典树:

一颗二十六叉树(只有小写(或大写)字母的话,数字是十叉,也有特殊的01字典树),

将串插入的时候,就按着儿子走,在最后结束位置打个标记(我一般开个标记数组)

感觉更像是一种思想。

 

关于清空的小技巧:

如果遇到多组输入了

tot清零(动态开点),把根的二十六个儿子清空,剩下的插入的时候,如果需要申请空间了,

先申请,然后清空所有儿子

可以降低时间复杂度

(对于某些特殊的oj,也可以降低空间复杂度,因为判断空间是操作的空间大小而不是开始时申请的空间大小)

 

hdu1251统计难题

统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀)

输入有些奇怪,别的没啥了

/*
    author:revolIA
    submit:;
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 3e5+7;
int Trie[maxn][30],tot,val[maxn];
void Insert(char *p,int pos = 0){
    for(;*p!='\0';p++){
        int to = *p-'a';
        val[pos]++;
        if(!Trie[pos][to])
            Trie[pos][to] = ++tot;
        pos = Trie[pos][to];
    }
    val[pos]++;
}
int Find(char *p,int pos = 0){
    for(;*p!='\0';p++){
        int to = *p-'a';
        if(!Trie[pos][to])return 0;
        pos = Trie[pos][to];
    }
    return val[pos];
}
char s[maxn];
int main(){
    bool flag = true;
    while(gets(s)){
        if(s[0] == '\0'){
            flag = false;
            continue;
        }
        if(flag){
            Insert(s);
        }else{
            printf("%d\n",Find(s));
        }
    }
    return 0;
}

 

 

hdu2072单词数

多组输入

一行多个单词,求这行不同的单词数

/*
    author:revolIA
    submit:;
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int Trie[maxn][30],tot,val[maxn];
int Insert(char *p,int pos = 0){
    int flag = 0;
    for(;*p;p++){
        int to = *p-'a';
        if(!Trie[pos][to])
            Trie[pos][to] = ++tot;
        pos = Trie[pos][to];
    }
    if(!val[pos]){
        flag = 1;
    }
    val[pos]++;
    return flag;
}
char s[maxn],t[maxn];
int main(){
    while(gets(s)){
        if(s[0] == '#')break;
        memset(val,0,sizeof(val));
        memset(Trie,0,sizeof(Trie));
        tot = 0;
        int ans = 0,cnt = 0,i = 0;
        while(s[i]){
            while(s[i] && s[i] == ' ')i++;
            while(s[i] && s[i] != ' ')
                t[cnt++] = s[i++];
            t[cnt] = '\0';
            if(cnt)ans += Insert(t);
            cnt = 0;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

 

 

hdu1247 Hat’s Words

给你一堆串,输出一些串x,x能被这堆串内两个串拼接成,即x=a+b,a,b在这堆串中

 

在想,有什么优雅的写法、结果tm的纯暴力拆解字符串、、

/*
    author:revolIA
    submit:;
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int Trie[maxn][30],tot,val[maxn];
void Insert(char *p,int pos = 0){
    for(;*p;p++){
        int to = *p-'a';
        if(!Trie[pos][to])
            Trie[pos][to] = ++tot;
        pos = Trie[pos][to];
    }
    val[pos]++;
}
bool Find(char *p,int pos = 0){
    for(;*p;p++){
        int to = *p-'a';
        if(!Trie[pos][to])return false;
        pos = Trie[pos][to];
    }
    return val[pos];
}
char s[maxn][50],t1[50],t2[50];
int main(){
    int cnt = 0;
    while(~scanf("%s",s[cnt]))Insert(s[cnt++]);
    for(int i=0;i<cnt;i++){
        int n = strlen(s[i]);
        if(n == 1)continue;
        for(int j=0;j<n-1;j++){
            t1[j] = s[i][j];
            t1[j+1] = '\0';
            strcpy(t2,s[i]+j+1);
            //printf("%s %s--->\n",t1,t2);
            if(Find(t1) && Find(t2)){
                printf("%s\n",s[i]);
                break;
            }
        }
    }
    return 0;
}

 

poj2001 Shortest Prefixes

 

给你一堆字符串,让你把他们简化为自己的某一个前缀,要求不会出现歧义

 

/*
    author:revolIA
    submit:;
*/
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int Trie[maxn][30],tot,val[maxn];
void Insert(char *p,int pos = 0){
    for(;*p;p++){
        int to = *p-'a';
        val[pos]++;
        if(!Trie[pos][to])
            Trie[pos][to] = ++tot;
        pos = Trie[pos][to];
    }
    val[pos]++;
}
void Out(char *p,int pos = 0){
    for(;*p;p++){
        int to = *p-'a';
        putchar(*p);
        pos = Trie[pos][to];
        if(val[pos] == 1)return;
    }
}
char s[maxn][50];
int main(){
    int cnt = 0;
    while(~scanf("%s",s[cnt]))Insert(s[cnt++]);
    for(int i=0;i<cnt;i++){
        printf("%s ",s[i]),Out(s[i]),printf("\n");
    }
    return 0;
}

 

poj 3630 Phone List

学会了个动态(大概)清空

 

题目问是否存在一个字符串是另一个字符串的前缀

 

那么直接插入字典树,考虑插入的字符串是较长的和较短的两种情况

维护一个路径的数组和一个结束点的数组

/*
    author:revolIA
    submit:;
*/
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
int Trie[maxn][10],tot,val[maxn],End[maxn],flag;
void Insert(char *p,int pos = 0){
    for(;*p;p++){
        int to = *p-'0';
        val[pos]++;
        if(!Trie[pos][to]){
            Trie[pos][to] = ++tot;
            for(int i=0;i<10;i++)Trie[tot][i] = 0;
        }
        pos = Trie[pos][to];
        if(End[pos])flag = 0;//有个比自己短的
    }
    if(val[pos])flag = 0;//自己比别人短
    val[pos]++;
    End[pos]++;
}
char s[maxn];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        flag = 1;
        while(n--){
            scanf("%s",s);
            if(flag)
                Insert(s);
        }
        printf("%s\n",flag?"YES":"NO");
        for(int i=0;i<10;i++)Trie[0][i] = 0;
        memset(val,0,(tot+5)*sizeof(int));
        memset(End,0,(tot+5)*sizeof(int));
        tot = 0;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值