难度:中等
目录
一、问题描述
这里直接采用LeetCode上面的描述。
如果字符串中不含有任何 'aaa'
,'bbb'
或 'ccc'
这样的字符串作为子串,那么该字符串就是一个「快乐字符串」。
给你三个整数 a,b ,c,请你返回 任意一个 满足下列全部条件的字符串 s:
- s 是一个尽可能长的快乐字符串。
- s 中 最多 有 a 个字母 'a'、b 个字母 'b'、c 个字母 'c' 。
- s 中只含有 'a'、'b' 、'c' 三种字母。
如果不存在这样的字符串 s ,请返回一个空字符串 ""。
下面给出示例:
提示:
0 <= a, b, c <= 100
a + b + c > 0
二、思路
1、解题思路
题目中说明了,不能允许重复的三个相同的字符连续出现,那么我们要优先使用数量最多的字符来进行排列。使用 贪心策略。
在这里我们有两种方法来挑选最多的字符:
- 每次根据数目,对字符进行排序
- 使用 优先队列 会自动排序
我这里使用 优先队列 + 贪心策略 :
- 每次都选择 字符数量最多 的进行排列
- 如果 连续出现两个相同的字符 ,那么取字符数量 次多 的进行排列
重复操作,直至队列为空为止。
这里采用的优先队列结构如下:
- priority_queue<pair<int,char>> pq;
- int 为 char 字符的个;
- 这里 char 分别为字符 'a'、'b'、'c'。
2、极端情况判断
- 这里在将第一多数量的字符出队后,如果 不存在 次多数量的字符,那么取 队头 元素时会溢出。
3、解决极端情况
- 在对 次多 数量的字符 取队头元素之前,要进行判断。如果此时队列是空,那么应该结束循环,因为再向字符串尾部添加字符,就会出现连续三个相同的字符,则不符合题意。
三、解题
1、代码实现
class Solution {
public:
string longestDiverseString(int a, int b, int c) {
//默认 大堆顶 优先
priority_queue<pair<int,char>> pq;
//优先队列存放三个 pair
if(a){
pq.push({a,'a'});
}
if(b){
pq.push({b,'b'});
}
if(c){
pq.push({c,'c'});
}
string ans = "";
while(!pq.empty()){
pair<int,char> firstMax = pq.top();
pq.pop();
const int ansLength = ans.size();
//如果是两个连续的 元素 那么 准备入队第二多的元素
if(ansLength >= 2 and ans[ansLength-1] == firstMax.second and ans[ansLength-2] == firstMax.second){
//这里判断一下 取完了最多的元素 还有没有元素在队列里面 否则 下面会越界
if(pq.empty()){
break;
}
pair<int,char> secondMax = pq.top();
pq.pop();
ans.push_back(secondMax.second);
secondMax.first -= 1;
//第二多的元素还有的话,再次入队
if(secondMax.first){
pq.push(secondMax);
}
//没有使用的 第一多的 元素重新入队
pq.push(firstMax);
}
//否则 直接入队最多的元素
else{
ans.push_back(firstMax.second);
firstMax.first -= 1;
// 第一多的元素 如果还有的话 再次入队
if(firstMax.first){
pq.push(firstMax);
}
}
}
return ans;
}
};
2、时间复杂度 and 空间复杂度
时间复杂度:,a、b、c 分别为字符个数,这里 C 为 3 即字母个数,为入队后排序的时间复杂度。
空间复杂度:
四、总结
使用 贪心策略,每次都找最优解,这里的最优解也就是 对 最多 和 次多 的字符 进行排列,符合要求,直至全部排列完,或者剩下一种最多的字符 结束。
再排列之前,每次都要根据字符数目,进行排序。理解这题能够稍微理解一些 贪心思想,这里使用 优先队列 ,也能够学习到优先队列的使用,分为 升序队列 和 降序队列 (默认为 升序队列)。