/*
题意:找出能唯一标示一个字符串的最短前缀,如果找不出,就输出该字符串。
思路:trie树,所谓唯一最短前缀,就是这个前缀的最后一个字母在之前所有输入的
字符串中只出现过一次(除了找不到的以外),构树的时候每个字母出现一次再所对应的
value++,最后判断这个串的哪个字母是首个出现了一次的字母,则从这个串开始到这个
首次出现了一次的字母结束就是对应的唯一前缀。
*/
#include<iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
const int MAXN=1005;
const int MAXM=100005;
struct Node
{
int value;//标记出现的次数
int child[26];//孩子节点
Node()
{
value=0;
memset(child,0,sizeof(child));
}
};
Node trie[MAXM];
int trieN=0;
void create(char s[])//构树
{
int x=0;
for(int i=0;i<strlen(s);i++)
{
int d=s[i]-'a';
if(trie[x].child[d]==0)//不存在这个孩子节点
{
trie[++trieN]=Node();//则构建出一个孩子节点。
trie[x].child[d]=trieN;//孩子节点的下标。
x=trie[x].child[d];//转移节点。
trie[x].value++;//出现次数+1
}
else//存在这个孩子节点
{
x=trie[x].child[d];//转移节点
trie[x].value++;//出现次数+1
}
}
}
int Search(char s[])//寻找前缀
{
int x=0;//出根节点开始
int len=strlen(s);
for(int i=0;i<len;i++)
{
int d=s[i]-'a';
x=trie[x].child[d];//转换子树
if(trie[x].value==1)//如果这个字母只出现一次,则返回这个
{ //字母所在的下标
return i;
}
}
return len-1;//否则,不存在唯一前缀,则按要求输出整个串,所以返回这个串的长度
}
int main()
{
char s[MAXN][25];
int t=0;
while(scanf("%s",s[t])!=EOF)//输入数据,构树
{
create(s[t]);
t++;
}
for(int i=0;i<t;i++)
{
cout<<s[i]<<' ';//输出原串
int k=Search(s[i]);//寻找唯一前缀的最后一个字母的下标。
for(int j=0;j<=k;j++)
{
cout<<s[i][j];
}
cout<<endl;
}
return 0;
}
暑假- Trie树-(A - Shortest Prefixes)
最新推荐文章于 2020-03-26 20:11:37 发布