题目
解题思路
本题可使用贪心算法解决。s
中最多有a
个字母’a’、b
个字母’b’、c
个字母’c’,也即三个字符的剩余可使用数为a
,b
,c
。我们使用贪心策略,每次都优先将剩余可使用数最多的字符插入快乐字符串末尾,同时更新该字符的剩余可使用数,直至连续使用一个字符两次,改用剩余可用次数次多的字符。原因是题目中规定出现三个连续字符的字符串不是快乐字符串。于是我们使用一个数组存储每个字符的信息,包括剩余可使用数,当前连续使用次数,以及字符本身。每次选字符都更新数组中的信息,并按剩余可使用数从小到大进行排序,这样方便每次选择剩余可使用数最多或次多字符。重复选字符过程直至无字符可用,这就包括所有字符都用完或者只剩一种字符并且当前连续使用次数已经达到两次。
代码
class Solution {
public:
struct Temp{
int count;//本字符剩余可使用数
char word;//本字符
int countS;//本字符当前连续出现次数
};
string longestDiverseString(int a, int b, int c) {
string ans;//存答案
vector<Temp> words = {{a,'a',0},{b,'b',0},{c,'c',0}};//存储可使用字符及相关信息
while(words[0].count != 0 || words[1].count != 0 || words[2].count != 0){//当可使用字符有剩余
//每轮判断前先按照字符剩余可使用数将数组排序
sort(words.begin(),words.end(),[](const Temp& t1, const Temp& t2){return t1.count<t2.count;});
//mySort(words);
if(words[2].count != 0 && words[2].countS != 2){//优先使用剩余可使用数最多字符
//如果本字符可用,将其他字符的连续出现数置为0
words[0].countS = 0;
words[1].countS = 0;
ans += words[2].word;//添加本字符到答案字符串末尾
++words[2].countS;//本字符当前连续使用数加一
--words[2].count;//本字符剩余可使用数减一
}
else{//如果剩余可使用数最多的字符不可用,比如已经连续使用两次了
if(words[1].count != 0 && words[1].countS != 2){//则判断剩余可使用数次多字符是否可使用
//若可使用,执行与第一个if分支类似操作
words[0].countS = 0;
words[2].countS = 0;
ans += words[1].word;
++words[1].countS;
--words[1].count;
}
else break;//如果剩余可使用数最多和次多字符都不可用,则说明无字符可用,退出循环
}
}//返回答案
return ans;
}
void mySort(vector<Temp>& words){
for(int i = 0; i < 3; ++i){
int min = i;
for(int j = i + 1; j < 3; ++j){
if(words[j].count<words[min].count) min = j;
}
swap(words[i],words[min]);
}
}
};
复杂度分析
时间复杂度: O(a+b+c)
。选字符过程最多进行a+b+c
次,并且每次选字符耗时都是常数时间,包括排序。
空间复杂度: O(1)
。数组存储字符信息也是常数空间的,毕竟就三种字符。