「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。
每日刷题第50天 2021.02.20
6014. 构造限制重复的字符串
- leetcode原题链接:leetcode-cn.com/problems/co…
- 难度:中等
- 方法:贪心、优先队列
题目
-
给你一个字符串 s 和一个整数 repeatLimit ,用 s 中的字符构造一个新字符串 repeatLimitedString ,使任何字母 连续 出现的次数都不超过 repeatLimit 次。你不必使用 s 中的全部字符。
-
返回 字典序最大的 repeatLimitedString 。
-
如果在字符串 a 和 b 不同的第一个位置,字符串 a 中的字母在字母表中出现时间比字符串 b 对应的字母晚,则认为字符串 a 比字符串 b 字典序更大 。如果字符串中前 min(a.length, b.length) 个字符都相同,那么较长的字符串字典序更大。
示例
- 示例1
输入:s = "cczazcc", repeatLimit = 3
输出:"zzcccac"
解释:使用 s 中的所有字符来构造 repeatLimitedString "zzcccac"。
字母 'a' 连续出现至多 1 次。
字母 'c' 连续出现至多 3 次。
字母 'z' 连续出现至多 2 次。
因此,没有字母连续出现超过 repeatLimit 次,字符串是一个有效的 repeatLimitedString 。
该字符串是字典序最大的 repeatLimitedString ,所以返回 "zzcccac" 。
注意,尽管 "zzcccca" 字典序更大,但字母 'c' 连续出现超过 3 次,所以它不是一个有效的 repeatLimitedString 。
- 示例2
输入:s = "aababab", repeatLimit = 2
输出:"bbabaa"
解释:
使用 s 中的一些字符来构造 repeatLimitedString "bbabaa"。
字母 'a' 连续出现至多 2 次。
字母 'b' 连续出现至多 2 次。
因此,没有字母连续出现超过 repeatLimit 次,字符串是一个有效的 repeatLimitedString 。
该字符串是字典序最大的 repeatLimitedString ,所以返回 "bbabaa" 。
注意,尽管 "bbabaaa" 字典序更大,但字母 'a' 连续出现超过 2 次,所以它不是一个有效的 repeatLimitedString 。
提示
1 <= repeatLimit <= s.length <= 105s由小写英文字母组成
解法
解题思路
- 贪心的思路
- 记录几个方法:'a'.charCodeAt()和String.fromCharCode()方法
- 'a'.charCodeAt(),将字母转换为字典序数值
- String.fromCharCode(value)将值转换为字母
- map集合:map.set(s[i], (map.get(s[i]) || 0) + 1)
- 数组的解构:let arr = [...map.keys()].sort().reverse()
- 总结: 使用数组记录的不好的地方,就是其中会包含很多0的情况,易出错。因此可以转化思路,用map集合记录,而后将map集合转换为数组,再进行排序。
- 具体来说:
- 字典序大的字符数有剩余,且结果字符串结尾不为此字符的就加上此字符的最小重复数,字符;
- 字典序大的字符数有剩余,且结果字符串结尾为此字符的就加上后面字符的一个隔开;
- 直到字符用完或唯一能用的字符为结果字符结尾的字符。
延伸(快慢指针)
- 字典序大的字符数有剩余,且结果字符串结尾不为此字符的就加上此字符的最小重复数,字符;
- 字典序大的字符数有剩余,且结果字符串结尾为此字符的就加上后面字符的一个隔开;
- 直到字符用完或唯一能用的字符为结果字符结尾的字符
/**
* @param {string} s
* @param {number} repeatLimit
* @return {string}
*/
var repeatLimitedString = function(s, repeatLimit) {
let len = s.length;
if(len == 1) return s;
s = s.split('');
let compare = function (template) {
return template.sort((a,b) => b[0] - a[0]);
}
let charArr = new Array(26).fill(0);
let a = 'a'.charCodeAt();
// let indexArr = new Array(26);
for(let i = 0; i < len; i++) {
let tempt = s[i].charCodeAt() - a;
charArr[tempt]++;
}
// 预处理数据
// console.log(charArr);
let index = charArr.length - 1;
let ans = '';
let next;
let flag = false;
while(true){
// while(charArr[index] != 0){
// 找到当前字典序最大,且不为0
if(charArr[index] <= repeatLimit){
for(let j = 0; j < charArr[index]; j++){
ans += String.fromCharCode(index + a);
}
charArr[index] = 0;
flag = true;
}else if(charArr[index] > repeatLimit){
for(let j = 0; j < repeatLimit; j++){
ans += String.fromCharCode(index + a);
}
charArr[index] -= repeatLimit;
if(index == 0) return ans;
next = index - 1;
while(charArr[next] == 0){
next--;
if(next == -1) return ans;
}
ans += String.fromCharCode(next + a);
charArr[next]--;
}
// 确保下一次遍历的是有长度的
// 需不需要找下一个
if(charArr[index] == 0) {
// 当前最大的已经排完,需要找次小的
// 需要找到一个不为0的长度
// 如果是直接剪完的,就不存在next
if(flag) {
while(charArr[index] == 0){
index--;
if(index == -1) return ans;
}
// console.log(index);
}else {
while(charArr[next] == 0){
next--;
if(next == -1) return ans;
}
index = next;
}
}
// }
}
};