H:用户请求中的品牌
时间限制:
1000ms
内存限制:
65536kB
描述
馅饼同学是一个在百度工作,做用户请求(query)分析的同学,他在用户请求中经常会遇到一些很奇葩的词汇。在比方说“johnsonjohnson”、“duckduck”,这些词汇虽然看起来是一些词汇的单纯重复,但是往往都是一些特殊品牌的词汇,不能被拆分开。为了侦测出这种词的存在,你今天需要完成我给出的这个任务——“找出用户请求中循环节最多的子串”。
输入
输入数据包括多组,每组为一个全部由小写字母组成的不含空格的用户请求(字符串),占一行。用户请求的长度不大于100,000。
最后一行输入为#,作为结束的标志。
输出
对于每组输入,先输出这个组的编号(第n组就是输出“Case n:”);然后输出这组用户请求中循环节最多的子串。如果一个用户请求中有两个循环节数相同的子串,请选择那个字典序最小的。
样例输入
ilovejohnsonjohnsonverymuch
duckduckgo
aaabbbcccisagoodcompany
#
样例输出
Case 1: johnsonjohnson
Case 2: duckduck
Case 3: aaa
【答案】
#include <iostream> #include <string> #include <vector> #include <stdlib.h> #include <utility> using namespace std; pair<int, string> fun(const string& str) { vector<string> substrs; int maxcount = 1; int count = 1; string substr; int i = 0; int j = 0; int k = 0; int len = str.length(); string tempStr; int iLen = 0; int iCnt = 0; char chTmp; for(i = 0; i < len; ++i) { substrs.push_back(str.substr(i,len-i)); } for(i = 0; i < len; ++i) { for( j = i+1; j < len; ++j) { count = 1; if(substrs[i].substr(0,j-i) == substrs[j].substr(0,j-i)) { ++count; for(k = j + (j-i); k < len; k+=(j-i)) { if(substrs[i].substr(0,j-i) == substrs[k].substr(0,j-i)) { ++count; } else { break; } } } if(count > maxcount) { maxcount = count; substr = substrs[i].substr(0,j-i); tempStr = substr; iLen = substr.length(); iCnt = maxcount; while(iCnt > 1) { substr.insert(iLen,tempStr); iCnt--; } } } } if(substr.length() == 0) { chTmp = (char)str[0]; for( int i = 1; i < len; i++ ) { if( str[i] < chTmp ) { chTmp = str[i]; } } substr = chTmp; } return make_pair(maxcount,substr); } int main(void) { string str; pair<int,string> rs; int iGroup = 0; while(cin >> str) { if(str == "#") { break; } rs = fun(str); cout << "Case " << ++iGroup << ": "<< rs.second << "\n"; } return 0; }
0.题目的本质还是求最大子串问题,只是在输出方面有所变动,但“换汤不换药”。
1.此题一致显示Wrong Answer,但对于测试数据都是能通过的。不知道何故,求网友指出原因。
2.此题参考了《程序员面试baodian》里面字符串处理部分的代码,做了相应修正。(源代码有错误!)
3.感觉比下面网友提供的要精炼不少:
#include<iostream> #include<cstdio> using namespace std; #include<string.h> #include<math.h> int wa[200000],wb[200000],wv[200000],wsum[200000]; int height[200000],sa[200000],rank[200000]; int n,ans,len,pos; char str[200000]; int R[200000]; int f[200000][20]; int a[200000],num; int cmp(int *r,int a,int b,int l) { return r[a]==r[b] && r[a+l]==r[b+l]; } void da(int *r,int *sa,int n,int m) //倍增算法 r为待匹配数组 n为总长度 m为字符范围 { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;++i) wsum[i]=0; for(i=0;i<n;++i) wsum[x[i]=r[i]]++; for(i=1;i<m;++i) wsum[i]+=wsum[i-1]; for(i=n-1;i>=0;--i) sa[--wsum[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;++i) y[p++]=i; for(i=0;i<n;++i) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;++i) wsum[i]=0; for(i=0;i<n;++i) wsum[wv[i]]++; for(i=1;i<m;i++) wsum[i]+=wsum[i-1]; for(i=n-1;i>=0;--i) sa[--wsum[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } void calheight(int *r,int *sa,int n) //求height数组 { int i,j,k=0; for(i=0;i<=n;++i) rank[sa[i]]=i; for(i=0;i<n;height[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); } int mmin(int x,int y) { return x<y?x:y; } void rmqinit(int n) //初始化rmq { int i,j,k,m; m=(int)(log(1.0*n)/log(2.0)); for(i=1;i<=n;i++) f[i][0]=height[i]; for(i=1;i<=m;++i) for(j=n;j>=1;--j) { f[j][i]=f[j][i-1]; k=1<<(i-1); if(j+k<=n) f[j][i]=mmin(f[j][i],f[j+k][i-1]); } } int get_rmq(int x , int y) //询问x、y后缀的最长公共前缀 { int m,t; x=rank[x] , y=rank[y]; if(x>y) t=x,x=y,y=t; ++x; m=(int)(log(1.0*(y-x+1))/log(2.0)); return mmin(f[x][m],f[y-(1<<m)+1][m]); } int main(void) { int i,j,k,ca=0,l,s,t,p,cnt; char c; while(scanf("%s",str)!=EOF) { if(str[0]=='#') break; n=strlen(str); for(i=0;i<n;++i) R[i]=str[i]-'a'+1; R[n]=0; da(R,sa,n+1,28); calheight(R,sa,n); rmqinit(n); ans=1; num=0; pos=0; for(l=1;l<=n/2;++l) //枚举长度 { for(i=0;i<n-l;i+=l) { if(str[i]!=str[i+l]) continue; k=get_rmq(i,i+l); s=k/l+1; p=i; t=l-k%l; cnt=0; for(j=i-1;j>=0 && j>i-l && str[j]==str[j+l];j--) { ++cnt; if(cnt==t) s++ , p=j; else if(rank[j]<rank[p]) p=j; } if(ans<s) { pos=p; len=s*l; ans=s; } else if(ans==s && rank[pos]>rank[p]) { pos=p; len=s*l; } } } printf("Case %d: ",++ca); if(ans<2) { c='z'; for(i=0;i<n;++i) if(str[i]<c) c=str[i]; printf("%c\n",c); continue; } for(i=0;i<len;++i) printf("%c",str[i+pos]); puts(""); } return 0; }