题解-今日头条2018校招后端方向(第四批)

原题链接

链接:https://www.nowcoder.net/questionTerminal/fcd645af2750401588d9e92aea05d630

有一个仅包含’a’和’b’两种字符的字符串s,长度为n,每次操作可以把一个字符做一次转换(把一个’a’设置为’b’,或者把一个’b’置成’a’);但是操作的次数有上限m,问在有限的操作数范围内,能够得到最大连续的相同字符的子串的长度是多少。

输入描述:
第一行两个整数 n , m (1<=m<=n<=50000),第二行为长度为n且只包含’a’和’b’的字符串s。
输出描述:
输出在操作次数不超过 m 的情况下,能够得到的 最大连续 全’a’子串或全’b’子串的长度。
示例:

输入

8 1
aabaabaa

输出

5

说明

把第一个 'b' 或者第二个 'b' 置成 'a',可得到长度为 5 的全 'a' 子串。

————————————   分界线————————————————

分析:

该字符串非 a 即 b 也就是说在区间 l~r之间把所有字符变为 a 所需的步骤数是 该区间内 b 的数量。反之亦然.
用数组 count[i] 表示 字符串中位置区间 0~i 包含的 a 的个数
则 区间 l~r 的 a 的个数为 count[r]-count[l-1]
b 的个数用 a 的个数算出 即 区间 l~r 的 b 的个数为 r+1-count[r]-(l+1-1-count[l-1])=r+1-count[r]-l+count[l-1]

在区间 l~r 的 a 和 b 的个数已知的情况下
若 区间长度step内的 a 的个数 <= m 则 可以通过 m 个步骤 产生 长度为step的字符串 b
若 区间长度step内的 b 的个数 <= m 则 可以通过 m 个步骤 产生 长度为step的字符串 a

归纳为 :若 区间长度step内的 b 或 a 的个数 <= m 则 可以通过 m 个步骤 产生 长度为step的字符串

这样  就可以直接计算出一个字符串长度(区间长度step)是否可行,因此不需要进行递推,可以直接进行二分搜索,得到最大长度。
检查一个长度step是否可行的时间复杂度为O(n),二分搜索的时间复杂度为O(log n)。
因此,该方法总的时间复杂度为 O(n*log n) 


代码:


#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int count[50005];
int n,m;
int ans=0;

//检查当前区间长度(step)是否能在 m 个步骤内实现全 a 或 全 b 
bool func(int step){
    for(int i=0;i+step<n;i++){
        if(m>=step+1-(count[i+step]-count[i-1]))return true;	//检查 a  公式 m>=区间内 b 的个数 
		if(m>=count[i+step]-count[i-1])return true;	//检查 b  公式: m>=区间内 a 的个数 
    }
    return false;
}
 
 
int main(){
    cin>>n>>m;
    string str;
    cin>>str;
    //输入并计算出 count 数组 
    int sum=0;
    for(int i=0;i<str.size();i++){
        if(str[i]=='a')count[i]=++sum;
        else count[i]=sum;
    }
 
    //二分搜索最大区间值 
	int l=0,r=n-1,mid; 
    while(l<r){
        mid=l+(r-l)/2;
        if(func(mid)){
            l=mid+1;
        }else r=mid;
    }
    ans=max(ans,l);
     
    cout<<ans<<endl;
    return 0;
     
}


扫描二维码关注公众号,回复: 2958662 查看本文章

猜你喜欢

转载自blog.csdn.net/bobbymly/article/details/79267864
今日推荐