2182. 构造限制重复的字符串
难度 : 中等
题目大意:
给你一个字符串
s
和一个整数repeatLimit
,用s
中的字符构造一个新字符串repeatLimitedString
,使任何字母 连续 出现的次数都不超过repeatLimit
次。你不必使用s
中的全部字符。返回 字典序最大的
repeatLimitedString
。如果在字符串
a
和b
不同的第一个位置,字符串a
中的字母在字母表中出现时间比字符串b
对应的字母晚,则认为字符串a
比字符串b
字典序更大 。如果字符串中前min(a.length, b.length)
个字符都相同,那么较长的字符串字典序更大。提示:
1 <= repeatLimit <= s.length <= 105
s
由小写英文字母组成
输入:s = "cczazcc", repeatLimit = 3
输出:"zzcccac"
解释:使用 s 中的所有字符来构造 repeatLimitedString "zzcccac"。
字母 'a' 连续出现至多 1 次。
字母 'c' 连续出现至多 3 次。
字母 'z' 连续出现至多 2 次。
因此,没有字母连续出现超过 repeatLimit 次,字符串是一个有效的 repeatLimitedString 。
该字符串是字典序最大的 repeatLimitedString ,所以返回 "zzcccac" 。
注意,尽管 "zzcccca" 字典序更大,但字母 'c' 连续出现超过 3 次,所以它不是一个有效的 repeatLimitedString 。
分析
首先肯定是要思考构造方法, 怎么构造呢?先分析要求是什么, 字典序最大,也就是说字符串构造出来的字符串要尽量的长,在最长的条件下,尽可能将ASCII码大的放在前面,这里要用到贪心的思想,字典序要尽可能大,我们可以将s
从大到小排序,怎么保证合理呢, 如果连续的字符的数量没有超过repeatLimit
那么就不用管,如果超过了就要用另外一个字符来将这两个字符隔开,怎么选能保证字典序最大呢,当然是选排序后s
的第二个不一样的字符了,思路有了,代码用堆来实现,C++
中是优先队列
贪心 + 优先队列
class Solution {
public:
using PII = pair<char, int>;
string repeatLimitedString(string s, int repeatLimit) {
int n = s.size();
priority_queue<PII> q;
unordered_map<char, int> cnt;
for (char c : s) cnt[c] ++;
for (auto p : cnt) q.push(p);
string res;
while (q.size()) {
auto t = q.top(); q.pop();
int x = min(repeatLimit, t.second);
res += string(x, t.first);
if (q.empty()) break;
t.second -= x;
if (!t.second) continue;
if (x == repeatLimit && q.size()) {
auto tt = q.top(); q.pop();
res += tt.first;
tt.second -= 1;
if (tt.second) q.push(tt);
}
q.push(t);
}
return res;
}
};
结束了