题意:我们可以进行一个操作,一次删除一个或多个字符,但删除的字符不可以相邻
求对所给字符我们要进行最少几次从而形成相同字符组成的串串(且最长)
解:
当我们想要使得两个字符靠近,先要看她两之间隔着几个无关字符,假设隔了N个,那么由于每次删除的字符不能相邻(至少也要隔一个),所以最少通过log2(N)+1次来消除她们之间的无关字符。
又因为总共最多也才26个字母,我们可以对每个字母判断一遍(最少几次使得字符串中的该字母靠在一起)
如何判断最少几次使得字符串中的该字母靠在一起呢?
找出最大的相邻(理论上相邻,就是第一个a和第二个a,第二个a和第三个a之间的距离这个意思的相邻)该字母之间的字符个数。如果能把隔最远的两个相邻该字母靠近,那么其他的就一定能消除。所以就能得到得到该字母串的最小次数。
再求出每个字母串中的最小操作次数就是我们需要的答案。
这里我们进行了一个转换,就是用一个二维数组的一维存储当前字符是谁(通过-'a'换成0~26数字),用它的二维(也就相当于每一行)存储该字母出现的下标。
遍历一遍就可以完成这个操作:
然后我们通过每个字母存储的下标逐个计算长度,找组内最大长度,组间最小操作次数即可。
所以该题:
#include<bits/stdc++.h>
using namespace std;
int t,l,n,ans,maxl;
string s;
int main()
{
cin>>t;
while(t--)
{
cin>>s;
n=s.size();
vector<int> a[30];//二维数组
for(int i=0; i<n; i++)
a[s[i]-'a'].push_back(i);//记录每个字符的下标到对于数组中
ans=n;//结果
for(int i=0; i<26; i++)
{
l=-1;
maxl=0;//组内最长
a[i].push_back(n);
for(int j=0; j<a[i].size(); j++)
{
int len = a[i][j]-l-1;
if(len>=1)
{
int lens=log2(len)+1;
maxl=max(maxl,lens);
}
l=a[i][j];
}
ans=min(ans,maxl);
}
cout<<ans<<endl;//取最小操作数
}
return 0;
}