字典树模板题

                                    Phone List

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let’s say the phone catalogue listed these numbers: 
1. Emergency 911 
2. Alice 97 625 999 
3. Bob 91 12 54 26 
In this case, it’s not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob’s phone number. So this list would not be consistent. 
InputThe first line of input gives a single integer, 1 <= t <= 40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1 <= n <= 10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.OutputFor each test case, output “YES” if the list is consistent, or “NO” otherwise.Sample Input
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
Sample Output
NO
YES

字典树的入门题,当然直接字符串匹配应该也是能做出来。在写这道题之前我们先来学习下字典树Trie

附上博客:http://blog.youkuaiyun.com/bbbblzy/article/details/78757037

前缀树还是很好理解,我们按照输入的顺序,建树。这个题是数字,0~9,我们就只需要开10个分叉。

题目意思:我们需要判断一个电话号码是不是其他的前缀。具体注释见代码

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
#include<vector>
#include<stack>
#include<list>
using namespace std;
const int INF =100100+5;
const int maxn = 110010+5//切记数组开大10倍
int trie[maxn][10];//静态字典树
int f[maxn];//染色
bool flag;
int cnt;
char s[12];
void _insert()
{
    int i;
    int len=strlen(s+1);
    int tem=0;
    for(i=1; i<len; i++)
    {
        if(!trie[tem][s[i]-'0']) trie[tem][s[i]-'0']=++cnt;//移动
        tem=trie[tem][s[i]-'0'];
        if(f[tem]) flag=false;// 在移动过程中 判断其他字符串是不是这个字符串前缀
    }
    if(trie[tem][s[len]-'0']) flag=false;//单独判断 这个单词是否为其他单词前缀
    else trie[tem][s[len]-'0']=++cnt;
    f[trie[tem][s[len]-'0']]=1;//染色 代表这个单词出现过 详细见上面推荐的字典树博客
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        flag=true;
        cnt=0;
        memset(f,0,sizeof(f));
        memset(trie,0,sizeof(trie));

        for(int i=1; i<=n; i++)
        {
            scanf("%s",s+1);
            if(flag) _insert();//这里如果出现过前缀了我们没必要在加入字典树了 已经达到题目的要求
        }
        if(flag) printf("YES\n");//出现了
        else printf("NO\n");
    }
}
/* 字典树特性 比较突出的就是消耗空间换时间*/

                                    Shortest Prefixes

A prefix of a string is a substring starting at the beginning of the given string. The prefixes of "carbon" are: "c", "ca", "car", "carb", "carbo", and "carbon". Note that the empty string is not considered a prefix in this problem, but every non-empty string is considered to be a prefix of itself. In everyday language, we tend to abbreviate words by prefixes. For example, "carbohydrate" is commonly abbreviated by "carb". In this problem, given a set of words, you will find for each word the shortest prefix that uniquely identifies the word it represents. 

In the sample input below, "carbohydrate" can be abbreviated to "carboh", but it cannot be abbreviated to "carbo" (or anything shorter) because there are other words in the list that begin with "carbo". 

An exact match will override a prefix match. For example, the prefix "car" matches the given word "car" exactly. Therefore, it is understood without ambiguity that "car" is an abbreviation for "car" , not for "carriage" or any of the other words in the list that begins with "car". 
Input
The input contains at least two, but no more than 1000 lines. Each line contains one word consisting of 1 to 20 lower case letters.
Output
The output contains the same number of lines as the input. Each line of the output contains the word from the corresponding line of the input, followed by one blank space, and the shortest prefix that uniquely (without ambiguity) identifies this word.
Sample Input
carbohydrate
cart
carburetor
caramel
caribou
carbonic
cartilage
carbon
carriage
carton
car
carbonate
Sample Output
carbohydrate carboh
cart cart
carburetor carbu
caramel cara
caribou cari
carbonic carboni
cartilage carti
carbon carbon
carriage carr
carton carto
car car
carbonate carbona

题目大概意思:输出唯一前缀,输入以文件结束输入。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
#include<vector>
#include<stack>
#include<list>
using namespace std;
const int maxn=10000+10;
int trie[maxn][35];
char s[maxn][35];
int in[maxn];
int cnt=0;
int n=1;
void _insert(char *a)
{
    int temp=0;
    int len=strlen(a);
    for(int i=0; i<len; i++)
    {
        in[temp]++;
        if(!trie[temp][a[i]-'a']) trie[temp][a[i]-'a']=++cnt;
        temp=trie[temp][a[i]-'a'];
    }
    in[temp]++;//这里要自增
}
void Find(char *a)
{
    int len=strlen(a);
    int temp=0;
    for(int i=0; i<len; i++)
    {
        //cout<<temp<<"        "<<in[temp]<<endl;
        if(in[temp]==1)//等于1的时候代表 就只有它这个字符串出现过到这里 直接退出了
            break;
        printf("%c",a[i]);
        temp=trie[temp][a[i]-'a'];//更新单词的下一个点
    }
}
int main()
{
    while(scanf("%s",s[n])==1)
    {
        _insert(s[n]);
        n++;
    }
    n--;
    for(int i=1; i<=n; i++)
    {
        printf("%s ",s[i]);
        Find(s[i]);
        printf("\n");
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值