WEEK8 csp模拟 B - HRZ学英语

B - HRZ学英语

题目描述

瑞神今年大三了,他在寒假学会了英文的26个字母,所以他很兴奋!于是他让他的朋友TT考考他,TT想 到了一个考瑞神的好问题:给定一个字符串,从里面寻找连续的26个大写字母并输出!但是转念一想, 这样太便宜瑞神了,所以他加大了难度:现在给定一个字符串,字符串中包括26个大写字母和特殊字 符’?’,特殊字符’?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字 母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现 的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果 不存在,输出-1! 这下HRZ蒙圈了,他刚学会26个字母,这对他来说太难了,所以他来求助你,请你帮 他解决这个问题,报酬是可以帮你打守望先锋。
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二 个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排 在前。例如

AB??EFGHIJKLMNOPQRSTUVWXYZ 

ABCDEFGHIJKLMNOPQRSTUVWXYZ 
ABDCEFGHIJKLMNOPQRSTUVWXYZ

上面两种填法,都可以构成26个字母,但是我们要求字典序最小,只能取前者。
注意,题目要求的是 第一个出现的,字典序最小的!

Input

输入只有一行,一个符合题目描述的字符串

Output

输出只有一行,如果存在这样的子串,请输出,否则输出-1

Sample Input 1

ABC??FGHIJK???OPQR?TUVWXY?

Sample Output 1

ABCDEFGHIJKLMNOPQRSTUVWXYZ

Sample Input 2

AABCDEFGHIJKLMNOPQRSTUVW??M

Sample Output 2

-1

Note

时间限制1s
空间限制64mb
数据点字符串长度
1,2,326
4,5,6104
7,8,9,10106

题解

用类似尺取的方法,有一个左指针和右指针,区间内长度为26,每次移动一格。用长度为26的letter数组来记录目前区间中分别含有26个字母的个数,用wenhao来记录目前区间中含有’?‘的个数。
一开始取前26个字母,并计算出这26个字母中的letter数组和wenhao,并判断这26个字母能否符合要求。不符合则r和l右移,进入循环。进入while循环后,先将l-1处的字母在letter数组或wenhao中删除,再将r处的字母计入letter数组或wenhao。然后判断这26个字母能否符合要求。不符合则r和l右移,进入下一次循环。循环直至r>n时结束。
判断某26个字母是否符合要求时,判断letter数组中是否所有元素小于1即可。若满足这个条件,需要将最小序列输出。输出时,首先循环letter数组,将letter数组中为0的元素插入数组v中(这段字符串中没有这个元素,这些元素的顺序可变);然后对v排序,使字典序小的元素在前;然后循环l到r区域,输出相应字母,’?'处有序输出相应的v数组中的元素。一旦判断成功后,输出后直接结束程序即可。运行到程序末尾则证明没有符合要求的元素,输出-1。

代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
char a[1000100];
int letter[26];
int wenhao=0;
vector<int>v;
int main(int argc, char** argv) {
	scanf("%s",a);
	memset(letter,0,sizeof(letter));
	int n=strlen(a);
	//计算前26个 
	int l=0,r=25;
	for(int i=0;i<26;i++){
		if(a[i]=='?'){wenhao++;continue;}
		letter[a[i]-'A']++;
	}
	//判断前26个
	bool suc=1; 
	for(int i=0;i<26;i++){
		if(letter[i]>1){suc=0;break;}
	}
	if(!suc){l++;r++;}
	else{//成功 
		for(int i=0;i<26;i++){
			if(letter[i]==0){
				v.push_back(i);
			}
		}
		sort(v.begin(),v.end());
		int tot=0;
		for(int i=l;i<=r;i++){
			if(a[i]=='?'){
				printf("%c",'A'+v[tot++]);
			}else{
				printf("%c",a[i]);
			}
		}
		printf("\n");
		return 0;
	}
	while(r<n){
		//计算 
		if(a[l-1]=='?'){wenhao--;}
		else{letter[a[l-1]-'A']--;}
		if(a[r]=='?'){wenhao++;}
		else{letter[a[r]-'A']++;}
		//检查 判断 
		suc=1;
		for(int i=0;i<26;i++){
			if(letter[i]>1){suc=0;break;}
		}
		if(!suc){l++;r++;}
		else{//成功
			for(int i=0;i<26;i++){
				if(letter[i]==0){
					v.push_back(i);
				}
			}
			sort(v.begin(),v.end());
			int tot=0;
			for(int i=l;i<=r;i++){
				if(a[i]=='?'){
					printf("%c",'A'+v[tot++]);
				}else{
					printf("%c",a[i]);
				}
			}
			printf("\n");
			return 0;
		}
	}
	printf("-1\n");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值