题目描述:
瑞神今年大三了,他在寒假学会了英文的26个字母,所以他很兴奋!于是他让他的朋友TT考考他,TT想 到了一个考瑞神的好问题:给定一个字符串,从里面寻找连续的26个大写字母并输出!但是转念一想, 这样太便宜瑞神了,所以他加大了难度:现在给定一个字符串,字符串中包括26个大写字母和特殊字 符'?',特殊字符'?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字 母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现 的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果 不存在,输出-1! 这下HRZ蒙圈了,他刚学会26个字母,这对他来说太难了,所以他来求助你,请你帮 他解决这个问题,报酬是可以帮你打守望先锋。
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二 个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排 在前。
AB??EFGHIJKLMNOPQRSTUVWXYZ
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ABDCEFGHIJKLMNOPQRSTUVWXYZ
例如 上面两种填法,都可以构成26个字母,但是我们要求字典序最小,只能取前者。 注意,题目要求的是 第一个出现的,字典序最小的!
input:
输入只有一行,一个符合题目描述的字符串。
output:
输出只有一行,如果存在这样的子串,请输出,否则输出-1
My Solution:
对于字符串,每次从起点向后遍历26个字母,然后判断是否存在重复字符,如果有则不符合,继续向后遍历,如果都不重复,则符合输出。
由于问号“?”可以替代其他任何字符,所以只要26个字符不重复出现其他字母就可,最后输出的时候把问号填充为没有出现的字符,并且使得字典序最小(未出现的按字典序从小到大依次填充)
本题可以优化的一点是可以记录下重复字符的位置,然后后面遍历的时候可以直接从前面出现的重复字符的下一个位置开始!
类似滑动窗口
Code
1 #include<iostream> 2 #include<string> 3 #include<cstring> 4 using namespace std; 5 //AABBCDEF?GHIJKLMNOPQRSTUVWXYZ 6 int ch[27],yes=0; 7 int main(){ 8 string str; 9 cin>>str; 10 int len=str.length(); 11 //cout<<len<<endl; 12 int i=0,j=0; 13 //cout<<'a'-'0'<<endl; 14 while(i+25 < len){ 15 memset(ch,0,sizeof(ch)); 16 for(j=i;j<i+26;j++){ 17 if(str[j] == '?') 18 ch[26]++; 19 else 20 { 21 if(ch[str[j]-'A']) 22 { 23 //i=j; 24 break; 25 } 26 else 27 ch[str[j]-'A']=1; 28 } 29 } 30 //cout<<"i: "<<i<<endl; 31 if(j == i+26)//满足 32 { 33 int index=0; 34 35 while(i<j){ 36 if(str[i] != '?') 37 cout<<str[i]; 38 else { 39 while(ch[index]){ 40 index++; 41 } 42 cout<<char(index+'A'); 43 index++; 44 } 45 46 i++; 47 } 48 cout<<endl; 49 yes=1; 50 break; 51 } 52 i++; 53 } 54 if(!yes) 55 cout<<-1<<endl; 56 return 0; 57 }