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;
}
};