1. 题目来源
2. 题目说明
3. 题目解析
方法一:贪心+构造+巧妙解法
这个问题其实正面考虑比较麻烦的。在此利用贪心的去构造会能直观简单点,下面谈谈构造策略:
- 首先很直观的能够想到,若有多个字符,我们尽可能两两的将其放到一起,用另一个字母对其进行间隔。但是这对条件的判断以及特殊输入情况来讲就很麻烦,一度不知道如何去判断
- 换一种构造策略,我们首先不考虑连续输出两字符,先考虑输出一个字符,那么一定是符合题意并且是最长的,那么可能会剩余一些字母,并且肯定已经有部分字母已经被用完了。这样我们就先构造出了 连续不相同的字符串
- 接着我们将剩余字母向字符串进行回填,即若剩余字母
a
,就将字符串中单个的a
扩充成两个a
,这样也是肯定满足要求的并且还是最长的
即先填一个字符,若字符还有剩余,那么就将字符补充为两个,这样一定是合法且最长的。
在此贪心的进行构造,每次尝试进行构造时肯定是从当前字母个数最多的开始填充,这样才能构造出最长的连续字符串,一个排序函数就可以了。
在进行回填的时候,循环遍历字符串,并查看字符串每一位是否还有剩余字符,若仍存在剩余字符就填充一个进去,这样遍历完毕字符串就是满足题意的最长字符串了。很秒的思想!
构造方法多种多样,前几位大佬真的很快…
参见代码如下:
// 执行用时 :4 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :6.5 MB, 在所有 C++ 提交中击败了100.00%的用户
int cnt[4], idx[4];
inline bool cmp(int a, int b) {return cnt[a] > cnt[b];}
class Solution {
public:
char help(int x) {
if (x == 1) return 'a';
if (x == 2) return 'b';
return 'c';
}
string longestDiverseString(int a, int b, int c) {
vector<int> vt; vt.push_back(0);
cnt[1] = a, cnt[2] = b, cnt[3] = c;
idx[1] = 1, idx[2] = 2, idx[3] = 3;
bool flag = true;
while (flag) {
sort(idx + 1, idx + 4, cmp);
flag = false;
for (int i = 1; i <= 3 and flag == false; ++i) {
int c = idx[i];
if (vt.back() != c and cnt[c] > 0) {
--cnt[c];
vt.push_back(c);
flag = true;
}
}
}
int len = vt.size();
string ans = "";
for (int i = 1; i < len; ++i) {
ans += help(vt[i]);
if (cnt[vt[i]] > 0) {
ans += help(vt[i]);
--cnt[vt[i]];
}
}
return ans;
}
};