原题:
构造限制重复的字符串 - 力扣 (LeetCode) 竞赛 (leetcode-cn.com)
周赛第三题,完成的速度不算快。主要原因是没有第一时间想到解决方案,都是在过程中思考和推导。说白了还是不熟?????
考虑过:
1.先统计然后按字典序最大的在先不管最大限制次数的情况下组成一个字符串。比如
输入:s = "cczazcc", repeatLimit = 3
那么排序后最大的字符串就是zzcccca。但是此时cccc超过了最大重复次数。
我的思路是能不能用滑动窗口来考察上面这个没限制的字符串然后在滑动的过程中解决限制次数的问题。
2.因为需要构造字典序最大的字符串,所以是不是可以用单调栈来排序
前面两种思路的过程中都注意到一个事情:就是总是需要把一个“次大”的字符提上去,于是在想这一步应该是绕不过去了。于是就直接用 贪心+模拟来做就是了
比赛时通过的代码:
class Pair implements Comparable<Pair> {
Character c;
Integer cnt;
@Override
public int compareTo(Pair o) {
return o.c - this.c;
}
}
public String repeatLimitedString(String s, int repeatLimit) {
Map<Character, Integer> cntMap = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
cntMap.put(c, cntMap.getOrDefault(c, 0) + 1);
}
PriorityQueue<Pair> pq = new PriorityQueue<>();
for (Map.Entry<Character, Integer> entry : cntMap.entrySet()) {
Pair p = new Pair();
p.c = entry.getKey();
p.cnt = entry.getValue();
pq.add(p);
}
StringBuilder sb = new StringBuilder();
while (!pq.isEmpty()) {
Pair p = pq.poll();
for (int i = 0; i < Math.min(repeatLimit, p.cnt); i++) {
sb.append(p.c);
}
int leftCnt = p.cnt - repeatLimit;
if (leftCnt <= 0) { // 当前的最大的character 全加完了
continue;
} else { // 需要找一个次小的垫进去隔开
if (pq.isEmpty()) {
break;
}
Pair secondP = pq.poll();
sb.append(secondP.c);
p.cnt = leftCnt;
secondP.cnt = secondP.cnt - 1;
pq.add(p);
// 这里有可能次大的那一个已经用完了,就不用在添加进去
if (secondP.cnt > 0) {
pq.add(secondP);
}
}
}
return sb.toString();
}