Leetcode_767_重构字符串_贪心

11/30

Leetcode_767_重构字符串_贪心

算法

假设
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;
	}
};
上一篇:【DB笔试面试767】在Oracle中,OGG的命令接口是哪个?


下一篇:如何在lambda表达式域中使用局部变量?