[编程题]字母交换

题目描述:
字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?

输入描述:

第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)

输出描述:

一个非负整数,表示操作之后,连续最长的相同字母数量。

示例:

输入
abcbaa 2
输出
2
说明
使2个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。
所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。

解析:
结合之前的题,现在应该明白读混合多种类的数据不需要直接整串读了,我们应该先把他们挑出来,归类,分成各字母数组再读取。

此后,对于各字母数组,假设都能聚拢,那应当选取其中一个字母为聚拢点,两旁的字母往中间移动,因此我们需要一个类似左右指针的东西确定移动的边界,在比较两旁的距离选较小的一边先聚拢。

代码:

#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

using namespace std;

int main()
{
	//读入s和n
	int n;
	string s;
	cin >> s >> n;

	//按字母归类存储每个字母出现的位置
	map<char, vector<int>> m;
	for(int i=0;i<s.size();i++)
	{
		char ch = s[i];
		m[ch].push_back(i);
	}

	//答案结果至少为1
	int ans = 1;

	//每个字母数组遍历
	for(int i=0;i<26;i++)
	{
		//当前字母为
		char ch = (char)('a' + i);

		//获取当前字母数组长度
		int size = 0;
		size = m[ch].size();

		//数组长度只有0或1可以直接跳过
		if(size<=1)
		{
			continue;
		}

		//字母数组每个位置陆续作为聚拢中心
		for(int j=0;j<size;j++)
		{
			//每次选新的聚拢中心应当更新可用步长和计数
			int feet = n;
			int count = 1;

			//备选的字母,数字为字母数组的下标
			int l_num = j - 1;
			int r_num = j + 1;

			//左右应该被移动到的位置
			int left = m[ch][j] - 1;
			int right = m[ch][j] + 1;

			//开始聚拢
			while (true)
			{
				//左右移动的距离
				//这里坑了我好几天才发现步长上限不是1000 UωU~~
				int dis_l = 9999999;
				int dis_r = 9999999;

				//当l_num处于数组中时,可选
				if(l_num>=0)
				{
					dis_l = left - m[ch][l_num];
				}
				//当l_num处于数组中时,可选
				if (r_num < size)
				{
					dis_r = m[ch][r_num] - right;
				}

				//当可用步长双方都不足时,则跳出循环
				if (feet < dis_l && feet < dis_r)
				{
					break;
				}

				//选距离小的
				if(dis_l<=dis_r)
				{
					//更新步长与计数
					feet -= dis_l;
					count++;

					//更新下一个备选位置和备选字母
					l_num--;
					left--;
				}
				else
				{
					//更新步长与计数
					feet -= dis_r;
					count++;

					//更新下一个备选位置和备选字母
					r_num++;
					right++;
				}

				//更新最大值
				ans = max(ans, count);
			}
		}
	}

	cout << ans << endl;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值