一句话概括题意:在输入的所有电话号码中输出每一个号码的最短的特有的标识符(就是一段子串只在此电话号中有在其他号码中没有)
看完题解大部分都用的什么时间戳,看不懂,就采用了复杂一点但好理解的,抵消-寻找-还原 的三步走战略。但是还是调了好长时间的bug,因为一般的tire树只需要将所有的字符串依次插入到tire树中一次便可,而此题需要将每个电话号的0~8位,1~8位,2~8位,,,,,7~8位,8位依次插入到tire树中,正因为忽略了此要点,所以tire数组开小了。看代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
struct Tire {
int num;//记录树中每个节点出现的次数
int next_s[15];
Tire(){
num=1;
memset(next_s,-1,sizeof(next_s));
}
}tire[1000000];//数组大小要远大于70000*9
ll cnt=0;
char str[70005][15];
void insert(int s,int id){//传进的参数表示&str[id][s].
int p=0;
for(int i=s;str[id][i]!='\0';i++){
if(tire[p].next_s[str[id][i]-'0']==-1){
tire[p].next_s[str[id][i]-'0']=++cnt;
p=cnt;
}
else{
p=tire[p].next_s[str[id][i]-'0'];
tire[p].num++;
}
}
}
ll LEN,BEGIN;
//寻找
void find(ll s,ll id){
int p=0;
for(int i=s;str[id][i]!='\0';i++){
//此if可有可无---剪枝
if(tire[p].next_s[str[id][i]-'0']==-1){
return ;
}
p=tire[p].next_s[str[id][i]-'0'];
if(tire[p].num==0){//抵消后第一个num==0的点说明此后缀的前缀是s~i独有的子串
if(i-s<LEN){//保留最小的LEN(更新or不更新)
LEN=i-s;
BEGIN=s;
return ;
}
}
}
}
//抵消
void work_1(ll s,ll id){
int p=0;
for(int i=s;str[id][i]!='\0';i++){
if(tire[p].next_s[str[id][i]-'0']==-1){
return ;
}
p=tire[p].next_s[str[id][i]-'0'];
tire[p].num--;//将此后缀的前缀的子树的节点计数减一(将此前缀删掉)
}
}
//还原
void work_2(ll s,ll id){
int p=0;
for(int i=s;str[id][i]!='\0';i++){
if(tire[p].next_s[str[id][i]-'0']==-1){
return ;
}
p=tire[p].next_s[str[id][i]-'0'];
tire[p].num++;//将此后缀的前缀还原
}
}
int main(){
ll n;
scanf("%lld",&n);
getchar();
for(int i=0;i<n;i++){
scanf("%s",str[i]);
getchar();
}
for(int i=0;i<n;i++){
for(int j=0;j<str[i][j]!='\0';j++){
insert(j,i);//构造后缀的前缀树
}
}
for(int i=0;i<n;i++){
BEGIN=0;
LEN=0x3f3f3f3f;
for(int j=0;j<str[i][j]!='\0';j++){
work_1(j,i);//删除str[i]的所有后缀的前缀子树
}
for(int j=0;j<str[i][j]!='\0';j++){
find(j,i);//寻找最小的LEN
}
for(int j=0;j<str[i][j]!='\0';j++){
work_2(j,i);//还原str[i]的所有后缀的前缀子树
}
for(int j=BEGIN;j<=BEGIN+LEN;j++){
cout<<str[i][j];//找到最小的子串的起点和长度后输出
}
cout<<endl;
}
return 0;
}