7.6.1 Shortest Prefixes

文章描述了一种使用Trie树数据结构找到能唯一标识单词的最短前缀的方法。在给定的单词列表中,每个单词都需要找到一个最短的前缀,这个前缀不能是其他单词的前缀。通过构建Trie树并遍历,可以有效地解决这个问题。
摘要由CSDN通过智能技术生成

任务描述

字符串的前缀是从给出的字符串的开头开始的子字符串。"carbon"的前缀是:"c","ca","car","carb","carbo"和"carbon"。在本题中,空串不被视为前缀,但是每个非空字符串都被视为其自身的前缀。在日常语言中,我们会用前缀来缩写单词。例如,"carbohydrate" (“碳水化合物”)通常被缩写为"carb"。在本题中,给出一组单词,请您为每个单词找出能唯一标识该单词的最短前缀。 在给出的样例输入中,"carbohydrate"可以被缩写为"carboh",但不能被缩写为"carbo"(或者更短),因为有其他单词以"carbo"开头。 完全匹配也可以作为前缀匹配。例如,给出的单词"car",其前缀"car""car"完全匹配。因此,"car""car"的缩写,而不是"carriage"或列表中以"car"开头的其他任何其他词的缩写。

编程要求

根据提示,在右侧编辑器补充代码。

测试说明

输入说明

输入至少有两行,最多不超过1000行。每行给出一个由1到20个小写字母组成的单词。

输出说明

输出的行数与输入的行数相同。输出的每一行先给出输入对应行中的单词,然后给出一个空格,最后给出唯一(无歧义)标识该单词的最短前缀。

平台会对你编写的代码进行测试:

测试输入:

 
  1. carbohydrate
  2. cart
  3. carburetor
  4. caramel
  5. caribou
  6. carbonic
  7. cartilage
  8. carbon
  9. carriage
  10. carton
  11. car
  12. carbonate

预期输出:

 
  1. carbohydrate carboh
  2. cart cart
  3. carburetor carbu
  4. caramel cara
  5. caribou cari
  6. carbonic carboni
  7. cartilage carti
  8. carbon carbon
  9. carriage carr
  10. carton carto
  11. car car
  12. carbonate carbona
    #include <cstdio>
    #include <algorithm>
    #include <memory.h>
    using namespace std;
    const int MAXN=1000+10;
    const int maxnode=100005;
    const int sigma_size=26;
    char str[MAXN][25];            //第i个单词为str[i]
    int tot;                       //单词编号
    int ch[maxnode][sigma_size];   //节点i的编号为j的子节点为ch[i][j]
    char val[maxnode];             //节点v的访问次数
    
    struct Trie{                                         //定义名为Trie的结构体类型
        int sz;                                          //节点编号
        Trie(){sz=1;memset(ch[0],0,sizeof(ch[0]));}      //初始化
        int idx(char c){return c-'a';}                   //返回字母c的序值
    
        void insert(char *s)                             //构造单词*s对应的Trie树
        {
            int u=0,n=strlen(s);                         //根节点编号为0,计算字符串s的长度n
            for(int i=0;i<n;i++)                         //依次插入字串的每一个字母
            {
                int c=idx(s[i]);                         //计算第i个字母的序值
                if(!ch[u][c])                            //若节点u编号为c的子节点空
                {
                    memset(ch[sz],0,sizeof(ch[sz]));     //节点sz为叶节点
                    val[sz]=0;                           //sz的访问次数为0
                    ch[u][c]=sz++;                       //sz设为节点u编号为c的子节点,设下一个节点编号sz++
                }
                u=ch[u][c];                              //取节点u序值为c的子节点编号,该节点的访问次数+1
                val[u]++;
            }
        }
        void query(char *s)                              //计算和输出单词*s的最短前缀
        {
            int u=0,n=strlen(s);                         //从根出发,计算单词*s的长度
            for(int i=0;i<n;i++)                         //依次搜索*s的每个字母
            {
                putchar(s[i]);                           //第i个字母作为前缀字符输出
                int c=idx(s[i]);                         //计算第i个字母的序数值c
                if(val[ch[u][c]]==1)return;              //若u的序数值c的子节点仅被访问一次,则退出
                u=ch[u][c];                              //继续沿序数值c的子节点搜索下去
            }
        }
    };
    int main(){
        tot=0;                                           //单词数初始化
        Trie trie;                                       //trie为Trie类型的结构体变量
        while(scanf("%s",str[tot])!=EOF){                //输入编号为tot的单词
            trie.insert(str[tot]);                       //构建对应的对应的Trie树
            tot++;                                       //计算下一个单词编号
        }
        for(int i=0;i<tot;i++)                           //依次处理每个单词
        {
            printf("%s ",str[i]);                        //输出编号为i的单词
            trie.query(str[i]);                          //计算和输出该单词的最短前缀
            printf("\n");                                //换行
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值