原题
767. 重构字符串
给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
示例 1:
输入: S = "aab"
输出: "aba"
示例 2:
输入: S = "aaab"
输出: ""
注意:
- S 只包含小写字母并且长度在[1, 500]区间内。
完整解题思路
初看该题时闹钟响起一声惊叹:卧槽,完蛋了,啥玩意儿,又不会了。然而我认为不能怎么轻易的就放弃,不然天天看题解,也甚是无趣… 遂思考了一阵,在 vscode 中写起了草稿,脑中有了个思路。
- 发现可以循环计算,使用 Map 存储键值对,计算每个字符出现的次数。
- 当出现最多的字符次数超过整体字符串长度半数 + 1 时,即不可能不出现相邻两字符不同的情况。
抓住这两点以后我以为自己已经解答出了这题,但是代码写起来看上去挺长的。嗯,这肯定是个垃圾解法,正确解法肯定代码一点点就搞定了,后续再随意拼一种结果出来就好了。
但是,当我写完上面两点逻辑之后,在拼后续结果的时候发现,妈呀,咋这么难拼… 然后陷入了沉思…
一会儿之后又有了思路:
- 先将整个 Map 内的 key 按照出现次数排序。嗯,看看有啥 Map 排序方法… 怎么一个 Map 排序方法都没有… 然后自己写了个简单的选择排序,获得了一个排好序的 key 数组。
- 排好序以后是不是从大到小,每个 key 各取一个即可获取到?尝试下… OK,提交报错,重来…
- 嗯… 那是不是每次拿两个,从大到小分别依次取最前面的两个就好了呢?试试,提交报错…此时一个小时过去… 我太菜了… 看看题解吧。
- 看完 Java 题解以后发现,原来题解也写了这么多代码… 诶,和我的思路就差一点点了,原来差的是每次取完两个都得排序一次,确保每次在头部的两个都是最多的,那得多耗费性能啊,时间复杂度肯定很高…答案竟然直接使用了 Java 的 PriorityQueue,无耻… 怪不得没有 JavaScript 解法!!!
- 提出排序方法,每次取完都排序一次,提交解决。OK,性能果然奇差无比,我真菜- -
总结
这次靠着自己的思考接近了终点,但是没有到达终点便是失败… 而且题解说了是贪心算法,我也没发现,自己回去再翻翻书看看贪心算法吧!
另一种解法今天暂时不看了,感觉脑细胞死的差不多了。
正经题解
- 先将每个字符的出现的次数存入 Map(题解是将其分为26个字母,每个字母占一个下标来存储出现次数)
- 获取出现最多次数的字符,判断其是否小于等于总长度的 (1/2 + 1),满足则表示有可能的组合,反之则没有
- 按照 Key 值出现的次数排序,循环每次获取最前面两个字符(题解是用 Java,直接使用 PriorityQueue,最优先队列,自定义排序规则,每次从队列中取出以后会自动排序,最前面的永远都是次数最多的)
- 每次获取完两个字符以后都重新排序,确保前面的两个字符都是当前 Map 中存在次数最多的
- 循环2个2个字符获取,直到取完所有字符
JavaScript 解法
var sort = (sortedKey, map) => {
for (let index = 0; index < sortedKey.length - 1; index++) {
for (let innerIndex = index + 1; innerIndex < sortedKey.length; innerIndex++) {
if (map.get(sortedKey[index]) < map.get(sortedKey[innerIndex])) {
let temp = sortedKey[index];
sortedKey[index] = sortedKey[innerIndex];
sortedKey[innerIndex] = temp;
}
}
}
return sortedKey;
}
/**
* @param {string} S
* @return {string}
*/
var reorganizeString = function(S) {
let result = '';
const map = new Map();
const splitedStr = S.split('');
for (let s of splitedStr) {
map.set(s, (map.get(s) || 0) + 1);
}
if (map.size > 0) {
let sortedKey = sort([...map.keys()], map);
let maxCount = map.get(sortedKey[0]);
if (Math.ceil(splitedStr.length / 2) >= maxCount) {
let end = false;
while (!end) {
let temp = '';
for (const key of sortedKey) {
if (map.get(key) > 0) {
temp += key;
map.set(key, map.get(key) - 1);
}
if (temp.length === 2) {
break;
}
}
if (temp.length === 0) {
end = true;
}
sortedKey = sort(sortedKey, map);
result += temp;
}
}
}
return result;
};
声明
题目来源于力扣,侵删。
本文讲述了如何通过贪心策略和Map数据结构解决字符串重构问题,涉及字符计数、频率排序及优先队列技巧。博主逐步解析思路转变,从初始的复杂解法到最终使用Java PriorityQueue优化。
1710

被折叠的 条评论
为什么被折叠?



