csp m2 HRZ学英语

题意:

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

输入格式
输入只有一行,一个符合题目描述的字符串。
输出格式
输出只有一行,如果存在这样的子串,请输出,否则输出-1

样例输入1
AB??EFGHIJKLMNOPQRSTUVWXYZ
样例输出1
ABCDEFGHIJKLMNOPQRSTUVWXYZ
样例输入2
AABCDEFGHIJKLMNOPQRSTUVW??M
样例输出2
-1

在这里插入图片描述


思路:

题目为了得到第一个连续的26个大写字母串,我们可以维护一个区间,区间的左端点我们用“ l ”表示,表示在字符串中的位置,右端点即为我们遍历区间时的位置,这个区间有这些特点:里面的除“?”以外的字符都不重复;区间的长度小于等于26。

为了判断某个字符是否在区间内部,我们设立一个bool数组cha用来判断在或不在,同时我们还设立一个数组用来表示某元素在区间里时在字符串中的位置。

bool cha[26] = { false };
long long lo[26];

我们从字符串的首位开始遍历,若是遍历到"?",此时判断区间长度是否已经是26,若是则区间已确定跳出遍历,若不是则继续遍历下一个元素;当我们遍历到非“?”的字符时,则要判断是不是已经在区间内,若不在,则将cha里的对应元素设为true,记录位置到lo数组中;若是已经在,则我们需要“ l ”进行移动,移动到上一次出现这个字符的位置的后一个(因为保证区间内只能有一个他,就只能l向后移动),此时从上一个l的位置到上一次出现这个字符的位置的前一个元素已经全部从区间中移除了,我们需要将cha数组里的元素设为false。注意这时候一定要将lo的位置更新为这个元素现在的位置因为忘了这一步扣了60分

输出的时候如果字符串里面有“?”的话我们需要遍历cha数组,找到第一个为false的位置,输出他所对应的字符,这样才能满足字典序最小。


总结:

对于这种找到第一个满足某种条件的字符串,我们可以维护一个区间,通过移动区间的端点进行维护,注意到达目标时的判断条件。


代码:

#include<string>
#include<iostream>
using namespace std;

bool cha[26] = { false };
long long lo[26];

int main()
{
	string str;
	cin >> str;
	long long l = 0;
	long long r = -1;
	long long size = str.size();
	for (long long i = 0; i < size; i++)
	{
		if (str[i] == '?')
		{
			if ((i - l + 1) == 26)
			{
				r = i;
				break;
			}
			else continue;
		}

		if (cha[str[i] - 'A'] == true) //existed
		{
			for (long long m = l; m < lo[str[i] - 'A']; m++)
			{
				cha[str[m] - 'A'] = false;
			}
			l = lo[str[i] - 'A'] + 1; //l to 上一次出现的后面
			lo[str[i] - 'A'] = i;//lo重定位
		}
		else
		{
			cha[str[i] - 'A'] = true;
			lo[str[i] - 'A'] = i;
		}
		if ((i - l + 1) == 26)
		{
			r = i;
			break;
		}
	}

	if (r == -1)
	{
		cout << -1;
	}
	else
	{
		int now = 0;
		for (long long m = l; m <= r; m++)
		{
			if (str[m] != '?')cout << str[m];
			else
			{
				for (int p = now; p < 26; p++)
				{
					if (cha[p] == false)
					{
						cout << (char)(p + 'A');
						now = p + 1;
						break;
					}
				}
			}
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值