2020年2月4日牛客寒假训练赛1

G- eli和字符串

题目描述:
eli拿到了一个仅由小写字母组成的字符串。
她想截取一段连续子串,这个子串包含至少 个相同的某个字母。
她想知道,子串的长度最小值是多少?
注:所谓连续子串,指字符串删除头部和尾部的部分字符(也可以不删除)剩下的字符串。例如:对于字符串"arcaea”而言,“arc”、“rcae”都是其子串。而“car”、“aa”则不是它的子串。

解法:比赛时想记录每个字符对应下标然后从头到尾两层循环一遍的,提交超时了,赛后就看了看大佬的做法,用队列来做,因为队列可以先进先出。这里学到了以后设定int型的最大值时用0x3f3f3f3f好

#include<iostream>
#include<queue>
#include<cstdio>
#include<string>
using namespace std;
queue<int>a[30];
int last[30]={0},ans=0x3f3f3f3f,n,k;
int main()
{
	string s;
	scanf("%d%d",&n,&k);
	cin>>s;
	for(int i=0;i<s.length();i++)
	{
		int id=s[i]-'a';//id用于记录对应字母在字母表中的顺序-1
		last[id]=i;
		a[id].push(i);
		if(a[id].size()>=k)//一满足不小于K了就会进入循环,所以last[id]用来记录最近出现的字母在字符串的位置
		{
			ans=min(ans,last[id]-a[id].front());
			a[id].pop();
		}
	}
	if(ans==0x3f3f3f3f)
	ans=-1;
	else//由于减完后字母对应的Id比正常少1,这里加上,比如a:1,代码减完是:0
	ans++;
printf("%d",ans); 
}

H-nozomi和字符串

题目要求及数据:
在这里插入图片描述

解法:贪心的想一想操作一定是对连续的0或者1进行操作的,否则不是最优解。比如101010,若操作次数k=2,那么必然是将第一个0和第二个0翻转变成1,得到111110;而不是将第一个0和第三个0变成1,得到111011,操作要么全变0要么全变1,两种情况都写一下,注意的是端点要赋个值

代码:

#include<bits/stdc++.h>
using namespace std;
string s;
vector<int>v0,v1;       //v0存字符'0'的坐标位置,v1存字符'1'的坐标位置
int main(){
 
    int n,k,i,j;
    cin>>n>>k;
    cin>>s;
    v0.push_back(-1); 
    v1.push_back(-1);
    for(i=0;i<n;i++){
        if(s[i]=='0')v0.push_back(i);
        else v1.push_back(i);
    }
    v0.push_back(n);
    v1.push_back(n);
    int ma=0;
    if(v0.size()-2<=k)ma=n;//减2是因为上面自己加了个-1、n,目的是为了让下面的[j+1]、[i-1]有对应的值 
    else{
        for(i=1,j=k;j<v0.size()-1;i++,j++){
            ma=max(ma,v0[j+1]-v0[i-1]-1);//第i个0到第j个0改变为1之后,连续相同字符的子串最大长度应当为第j+1个0所在的位置减去第i-1个0所在的位置减1
        }
    }
    if(v1.size()-2<=k)ma=n;
    else{
        for(i=1,j=k;j<v1.size()-1;i++,j++){
            ma=max(ma,v1[j+1]-v1[i-1]-1);
        }
    }
    cout<<ma;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值