Leetcode_767_重构字符串_贪心

本文介绍了一种通过堆数据结构解决字符串重组问题的方法,当字符串满足特定条件时,可以按规则重新组织字符以最大化重复字符的使用。算法首先找出最频繁字符及其数量,然后利用堆结构合并字符,确保每个重复字符后至少有一个字符。

11/30

在这里插入图片描述

算法

假设
n为字符串长度
maxnum为字符串中出现最多次的字符的出现次数
X字符为字符串中出现最多次的字符

以出现最多次的字符X为分隔
将其余各个字符插入X后方
每个X字符后插入一个字符,然后将下一个字符插入下一个X后
最后一个X字符插完,再回到第一个X字符后面再插入。
所以 除了最后一个X字符后可以为空,其他X字符后必须有至少一个字符。
所以只要(n + 1) / 2 >= maxnum则必定有解
可以将这种分隔抽象为堆
最后将堆合并即可
class Solution
{
public:
	struct A
	{
		int num;
		char ch;
	} a[27];
	static bool cmp(A a, A b)
	{
		if (a.num == b.num)
			return a.ch < b.ch;
		return a.num > b.num;
	}
	string reorganizeString(string S)
	{
		//字符串中出现最多次的字符的出现次数
		int maxnum = 0;
		//字符串的长度
		int n = S.size();
		for (int i = 0; i <= 25; i++)
			a[i].ch = 'a' + i;
		for (int i = 0; i < n; i++)
			maxnum = max(maxnum, ++a[S[i] - 'a'].num);
		if ((n + 1) / 2 < maxnum)
			return "";
		//放置maxnum个堆,每个堆的初始元素为字符串中出现最多次的字母,最后再加
		string stack[maxnum];
		sort(a, a + 25, cmp);
		//字符的起始下标指针,因为最多次字母已经用完了,所以从第二多的字母开始用
		int charst = 1;
		//字符的终止下标指针
		int charend = 0;
		//堆的起始下标指针
		int stackst = 0;
		//找到charend
		for (int i = 1; i <= 25; i++)
		{
			if (a[i].num != 0)
				charend = i;
			else
				break;
		}
		//减去使用最大字母的个数
		n -= maxnum;
		//以全部字母使用完为终止条件
		while (n != 0)
		{
			//维护字符的尾指针
			while(a[charend].num==0)
				charend--;
			//如果该字母用完了,找下个字母
			while (a[charst].num == 0)
			{
				charst++;
				//如果找完了
				if (charst > charend)
				{
					//从第一个再开始重新找起
					charst = 1;
					while (a[charst].num == 0)
						charst++;
					break;
				}
			}
			//使用这个字符
			a[charst].num--;
			//总字符数-1
			n--;
			//将这个字符加入对应的堆
			stack[stackst] += a[charst].ch;
			//如果每个堆都放了一个字符的话,再重新从第一个堆开始放
			if (stackst == maxnum - 1)
				stackst = 0;
			else
				stackst++;
		}
		string ans;
		//将堆合并
		for (int i = 0; i < maxnum; i++)
			ans += a[0].ch + stack[i];
		return ans;
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值