交换次数
IT产业人才需求节节攀升。业内巨头百度、阿里巴巴、腾讯(简称BAT)在某海滩进行招聘活动。
招聘部门一字排开。由于是自由抢占席位,三大公司的席位随机交错在一起,形如:ABABTATT,这使得应聘者十分别扭。
于是,管理部门要求招聘方进行必要的交换位置,使得每个集团的席位都挨在一起。即最后形如:BBAAATTT 这样的形状,当然,也可能是:AAABBTTT 等。
现在,假设每次只能交换2个席位,并且知道现在的席位分布,
你的任务是计算:要使每个集团的招聘席位都挨在一起需要至少进行多少次交换动作。
输入:是一行n个字符(只含有字母B、A或T),表示现在的席位分布。n<=10^4
输出:交换次数
样例输入:TABTABBTTTT
样例输出:3
来源:2018年蓝桥杯第九届决赛真题
看标签以为是一道水题结果没想到给卡住了。
思路
因为输入字符串只含有字母B、A、T,所以我们最后可以交换的结果有6种。也就是这三个字母的全排列,以样例为例如下:
AABBBTTTTTT
AATTTTTTBBB
BBBAATTTTTT
BBBTTTTTTAA
TTTTTTAABBB TTTTTTBBBAA
接下来,我们用字符串去匹配六种结果字符串,要注意将待交换字符串分为三段,如果结果字符串是BBB、AA、TTTTTT,那么待交换字符串为TAB、TA、BBTTTT。
(注意这里不能直接一一匹配然后把不匹配的数量÷2当作交换次数,如果是只有两种字母这种做法是正确的。但是我们这里有三种,所以必须想办法如何转换。)
我们定义b、a、t为字符串内字母出现的次数。则对于样例b=3、a=2、t=6。
我们还定义Ab、At、Ba、Bt。Ab是待交换字符串的A段(即TA)出现B的数量,TA内没有B,所以Ab=0。其他同理。
TAB TA BBTTTT
B段 A段 T段
现在我们把B段里的A、T都交换到A、T段。即Ba + Bt。
交换的优先原则是B段里的A优先交换A段里的B。我们下面考虑两种交换情况下A区多出T的个数:
1.B段里的A不够用,即(Ba < Ab),B区的A都交换到A区还不能换完A区的B。所以我们需要将B区的T交换A区的B。即A区多出的T为Ab-Ba个。
2.B段里的A够用,即(Ba >= Ab),B区的A交换到A区还有剩余,剩下的A交换到T区,但这个过程B区和A区只会发生A与B的交换,B区的T不会交换到A区。即A区多出T的个数为0。为了方便编程我们记为Ab-Ab。
在B区的A、T交换完成后,A区T的个数就是 交换前A区T的个数At 和 交换后多出来T的个数Ab-min(Ba,Ab)。
所以sum = Ba + Bt + At + Ab - min(Ab,Ba)
代码里是把A段里的B、T都交换到B、T段。
代码
#include<iostream>
#include<cstring>
using namespace std;
string s;
const int INF = 0x3f3f3f3f;
int func(string s,char A,char B,char C){
int a=0,b=0,c=0;
int Abc=0,Ab=0,Ba=0,Bc=0,res;
int i,j;
for(i=0;i<s.size();i++){
if(s[i]==A)a++;
if(s[i]==B)b++;
if(s[i]==C)c++; } for(i=0;i<a;i++){ if(s[i]!=A)Abc++; if(s[i]==B)Ab++; } for(i=a;i<a+b;i++){ if(s[i]==A)Ba++; if(s[i]==C)Bc++; } res = Abc + Bc + Ba - min(Ba,Ab); return res; } int main(){ while(cin>>s){ int min=INF; int res; char c[][4]={"BAT","ATB","TBA","BTA","ABT","TAB"}; for(int i=0;i<6;i++){ res=func(s,c[i][0],c[i][1],c[i][2]); if(res<min)min=res; } cout<<min<<endl; } return 0; }