<题目链接>
题目大意:
输入7e4个长度为9的字符串,每个字符串中只出现0~9这几种数字,现在需要你输出每个母串中最短的特有子串。
解题分析:
利用Trie树进行公共子串的判定,因为Trie树的特性是对节点的前缀字符串进行操作,所以为了转换成对母串中任意区间的字符串进行操作,我们对母串中的所有后缀字符串建树。下面用了一个比较优秀的Trie树模板。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int N = 7e4+10; 8 const int INF = 1e6; 9 char buf[N][11]; 10 int n,cur; 11 struct Trie{ 12 int nxt[N*11][12],num[N*11],time[N*11]; 13 int root,pos; 14 int newnode(){ 15 for(int i=0;i<10;i++)nxt[pos][i]=-1; 16 num[pos]=0,time[pos]=0; 17 return pos++; 18 } 19 void init(){ 20 pos=0;root=newnode(); 21 } 22 void insert(char str[]){ 23 int len=strlen(str); 24 int now=root; 25 for(int i=0;i<len;i++){ 26 int to=str[i]-'0'; 27 if(nxt[now][to]==-1) 28 nxt[now][to]=newnode(); 29 now=nxt[now][to]; 30 if(time[now]!=cur) //建立时间戳的意义是,避免相同母串中不同位置中的相同子串产生重复标记 31 num[now]++,time[now]=cur; //num[now]记录下含有这个子串的母串数量 32 } 33 } 34 int query(char str[]){ 35 int len=strlen(str); 36 int now=root; 37 for(int i=0;i<len;i++){ 38 now=nxt[now][str[i]-'0']; 39 if(num[now]==1)return i; 40 } 41 return -1; 42 } 43 }trie; 44 45 int main(){ 46 ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 47 cin>>n; 48 trie.init(); 49 for(int i=1;i<=n;i++){ 50 cin>>buf[i]; 51 cur=i; 52 for(int j=0;j<10;j++){ 53 trie.insert(buf[i]+j); //用每个母串的所有后缀建Trie树,然后利用Trie树对前缀字符串进行操作的特性,达到对母串字符区间的操作 54 } 55 } 56 for(int i=1;i<=n;i++){ 57 int le=0,ri=0,mn=INF; 58 for(int j=0;j<10;j++){ 59 int tmp=trie.query(buf[i]+j); 60 if(tmp!=-1 && mn>tmp){ //找到每个母串中符合条件的最短子串 61 mn=tmp;le=j,ri=j+tmp; 62 } 63 } 64 for(int j=le;j<=ri;j++)cout<<buf[i][j]; 65 puts(""); 66 } 67 }
2019-02-01