https://vjudge.net/problem/OpenJ_Bailian-2797
书上说这题用贪心能写, 我想了半天越想越复杂, 其实用数据结构的话反而会更加简单
字典树是一种很基础的树, 就是把多个单词的每个字母拆分成树的一条枝, 重复字母的次数记在节点num值中, 对于很多问题可以大大简化求解步骤
比如此题来说, 我们为输入的多个单词建立一个字典树, 然后对于每个字符串的每个字母我们都查找到其节点num值为1(即只出现了一次), 就说明是该字符串的最短前缀
//最短前缀
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 1010;
struct Trie{
Trie *next[26];
int num; //该字母是多少个单词的前缀
}root;
void ainit(Trie* node) //初始化字典树
{
for(int i = 0; i < 26; i++)
node -> next[i] = NULL;
node->num=0;
}
void ainsert(char* str) //插入str到字典树中
{
Trie *p = &root;
for(int i = 0; str[i]; i++){
int t= str[i]-'a';
if(p->next[t] == NULL){ //如果该字母第一次出现, 建立子树
p->next[t] = new Trie;
ainit(p->next[t]);
}
p = p->next[t];
p->num++;
}
}
void afind(char* str)
{
Trie *p = &root;
for(int i = 0; str[i]; i++){
int t = str[i] - 'a';
//如果整个单词树遍历完也没有找到num为1的节点就输出自己
if(p->next[t] == NULL) return;
p = p->next[t];
printf("%c",str[i]); //每次都输出一点儿
//如果找到num为1的前缀直接输出
if(p->num==1) return;
}
}
int main()
{
ainit(&root);
int n = 0;
char alpha[maxn][25];
while(scanf("%s",alpha[n])!=EOF){
ainsert(alpha[n]);
n++;
}
//查找最短字符
for(int i = 0; i < n; i++){
printf("%s ",alpha[i]);
afind(alpha[i]);
printf("\n");
}
}
参考博客: https://blog.csdn.net/u013129143/article/details/82996375