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