目录
题目要求
字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?
输入描述:
第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)
输出描述:
一个非负整数,表示操作之后,连续最长的相同字母数量。
示例1
输入
abcbaa 2
输出
2
说明
使3个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。
解题思路
动态规划:使用方阵dp[i][j],表示在str[x[i]]到str[x[j]]之间的所有此字母移动到相邻位置需要的最小交换次数。
首先,对于任一字母,任意依次出现的两个字母,移动到相邻位置,需要的最小交换次数,是他们下标之差减一。即:dp[i][i+1]=(x[i+1]-x[i])-1。
进一步,对于任一字母,任意两次出现的两个字母,移动到相邻位置,需要的最小交换次数,显然也是他们下标之差减一。即:dp[i][i+k]=(x[i+k]-x[i])-1。
最终,对于任一字母,任意两次出现的两个字母及其之间的所有此字母,移动到相邻的位置,需要的最小交换次数,是其之间的所有此字母移动到相邻位置所需要的最小交换次数,加上两头两个字母移动到相邻位置所需要的最小交换次数,再减去两头两个字母之间此字母的个数。即:dp[left][right]=dp[left+1][right-1]+(x[right]-x[left]-1)-(right-left-1)。
找到这个规律后,遍历从'a'~'z'每个字母,就能较为快速的计算出至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同了。
代码及其超级详细注解如下:
代码
#include <iostream>
#include<vector>
#include<stdlib.h>
using namespace std;
int m;
string str;
/*此函数用来计算字符串中的某个字母,
在最多m次交换后,此字母连续的最大长度*/
int maxi(vector<int>& x){
//此字母出现的次数
int n=x.size();
/*创建方阵,其中dp[i][j]表示在str[x[i]]到str[x[j]]
之间的所有此字母移动到相邻位置需要的最小交换次数*/
int dp[n][n];
//初始化方阵为0
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
dp[i][j]=0;
}
}
for(int i=0;i<n-1;i++){
/*初始化方阵,即:依次出现的两个字符串变为相邻,
需要的最少交换次数是此字符的下标之差减一*/
dp[i][i+1]=(x[i+1]-x[i])-1;
}
//k表示步长
for(int k=2;k<n;k++){
//用i遍历所有字母
for(int i=0;i<n-k;i++){
//第i次出现,第i+k次出现
int left=i,right=i+k;
dp[left][right]=dp[left+1][right-1]+(x[right]-x[left]-1)-(right-left-1);
/*使得第left次出现到第right次出现之间的所有此字母连续所需要的最小
交换次数,等于第left+1次出现到第right-1次出现之间的所有此字母连续
所需要的最小交换次数,加上第left次出现和第right次出现移动到一起所
需要的交换次数,再减去此字母在这两次出现之间出现的次数*/
}
}
int max=1;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(dp[i][j]<=m&&(j-i+1)>max){
//遍历方阵找出经过小于等于m次交换,此字母连续的最大长度
max=j-i+1;
}
}
}
/*for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;*/
return max;
}
int main()
{
cin >> str >> m;
//为每个字母创建一个容器,依次存放其出现在字符串中的下标
vector< vector<int> > a(26);
//初始化每个字母的位置容器
for(int i=0;i<str.length();i++){
a[str[i]-'a'].push_back(i);
}
int max=0;
//遍历每个字母,找出所有字母,经过小于等于m次交换后,此字母连续的最大长度
for(int i=0;i<26;i++){
if(maxi(a[i])>max) max=maxi(a[i]);
}
cout<<max<<endl;
return 0;
}