任务描述
字符串的前缀是从给出的字符串的开头开始的子字符串。"carbon"
的前缀是:"c","ca","car","carb","carbo"和"carbon"
。在本题中,空串不被视为前缀,但是每个非空字符串都被视为其自身的前缀。在日常语言中,我们会用前缀来缩写单词。例如,"carbohydrate"
(“碳水化合物”)通常被缩写为"carb"
。在本题中,给出一组单词,请您为每个单词找出能唯一标识该单词的最短前缀。 在给出的样例输入中,"carbohydrate"
可以被缩写为"carboh"
,但不能被缩写为"carbo"
(或者更短),因为有其他单词以"carbo"
开头。 完全匹配也可以作为前缀匹配。例如,给出的单词"car"
,其前缀"car"
与"car"
完全匹配。因此,"car"
是"car"
的缩写,而不是"carriage"
或列表中以"car"
开头的其他任何其他词的缩写。
编程要求
根据提示,在右侧编辑器补充代码。
测试说明
输入说明
输入至少有两行,最多不超过1000行。每行给出一个由1到20个小写字母组成的单词。
输出说明
输出的行数与输入的行数相同。输出的每一行先给出输入对应行中的单词,然后给出一个空格,最后给出唯一(无歧义)标识该单词的最短前缀。
平台会对你编写的代码进行测试:
测试输入:
carbohydrate
cart
carburetor
caramel
caribou
carbonic
cartilage
carbon
carriage
carton
car
carbonate
预期输出:
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 <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"); //换行 } }