HRZ学英语
题目描述
瑞神今年大三了,他在寒假学会了英文的26个字母,所以他很兴奋!于是他让他的朋友TT考考他,TT想 到了一个考瑞神的好问题:给定一个字符串,从里面寻找连续的26个大写字母并输出!但是转念一想, 这样太便宜瑞神了,所以他加大了难度:现在给定一个字符串,字符串中包括26个大写字母和特殊字 符’?’,特殊字符’?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现 的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果 不存在,输出-1! 这下HRZ蒙圈了,他刚学会26个字母,这对他来说太难了,所以他来求助你,请你帮 他解决这个问题,报酬是可以帮你打守望先锋。
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二 个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排 在前。例如
AB??EFGHIJKLMNOPQRSTUVWXYZ
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ABDCEFGHIJKLMNOPQRSTUVWXYZ
上面两种填法,都可以构成26个字母,但是我们要求字典序最小,只能取前者。
注意,题目要求的是 第一个出现的,字典序最小的!
输入格式
输入只有一行,一个符合题目描述的字符串。
输出格式
输出只有一行,如果存在这样的子串,请输出,否则输出-1。
样例输入1
ABC??FGHIJK???OPQR?TUVWXY?
样例输出1
ABCDEFGHIJKLMNOPQRSTUVWXYZ
样例输入2
AABCDEFGHIJKLMNOPQRSTUVW??M
样例输出2
-1
| 数据点 | 字符串长度 |
|---|---|
| 1,2,3 | 26 |
| 4,5,6 | 10000 |
| 7,8,9,10 | 1e6 |
问题分析
问题类似尺取。
要选出位置连续的且由26个大写字母组成的子串,定义这个子串的左边界 l ,右边界 r 。初始值都为0.
定义变量 tol ,记录已经选择的子串长度。
开始遍历字符串s,如果 s[r] 是 ‘?’ ,选中此字符,tol++,r++。
如果 s[r] 不是 ‘?’ ,则需要检查是否选中过这个字母。
为了方便检查,我们事先定义一个int型数组 b ,0-25分别代表A-Z。b[ s[r]-‘A’ ]不等于-1说明已经选择过这个字母。则把左边界 l 向前移动到这个上次选择这个字母的索引+1。同时更新 b ,把在 l 之前的字母都标记为未选择。tol的值也减去 l 前面的字母数量。
为了方便更新tol的值,定义一个数组 d ,0-25分别代表A-Z,记录选中此字母时已经选择的字母数量。
每选中一个字母,更新 b 为 r ,记录在字符串中的索引。tol++,更新 d 为tol,r++。
当tol=26,则说明结束,输出 l~r 的字符串即可。
为了保证最小字典序,没遇到一个’?’,就遍历b,输出一个没有选过的字母。
注意
一开始只过了4个点,因为在遇到一个选择过的字母s[r]时,窗口左边界移动时直接让他移动到了r。
代码实现
#include<iostream>
#include<string>
using namespace std;
string s;
char c[27];
int b[27],d[27];
int st=0,tol=0;
int main()
{
cin>>s;
int l = 0, r=0;
bool fin=false;
for(int i=0; i<26; i++)
d[i]=0,b[i]=-1;
while(r<s.size())
{
if(s[r]!='?')
{
int x=s[r]-'A';
if(b[x] != -1)
{
l=b[x]+1;
tol -= d[x];
int ji=d[x];
for(int i=0; i<26; i++)
{
if(d[i] < ji)
d[i] = 0;
else
d[i] -= ji;
if(b[i]<l)
b[i]=-1;
}
}
b[x] = r;//记录在字符串中的索引
tol++;
d[x] = tol;
r++;
}
else
{
tol++;
r++;
}
if(tol == 26)
{
fin = true;
break;
}
}
int t=0;
if(fin)
{
for(int i=0; i<26; i++)
if(b[i]==-1)
c[t]='A'+i, t++;
t=0;
for(int i=l; i<r; i++)
{
if(s[i]=='?')
{
printf("%c",c[t]);
t++;
}
else
printf("%c",s[i]);
}
printf("\n");
}
else
printf("-1\n");
return 0 ;
}
//AABCDEFGHIJKLMNOPQRSTUVW??MABCDEFGHIJKLZ
2240

被折叠的 条评论
为什么被折叠?



