[LeetCode] 767. Reorganize String 重构字符串
Given a string S, check if the letters can be rearranged so that two characters that are adjacent to each other are not the same.
If possible, output any possible result. If not possible, return the empty string.
Example 1:
Input: S = "aab"
Output: "aba"
Example 2:
Input: S = "aaab"
Output: ""
Note:
Swill consist of lowercase letters and have length in range[1, 500].
这道题给了一个字符串,让我们重构这个字符串,使得相同的字符不会相邻,如果无法做到,就返回空串,题目中的例子很好的说明了这一点。如果先不考虑代码实现,让你来手动重构的话,该怎么做呢?其实就是把相同的字符分开。比如例子1中,两个a相邻了,所以把第二个a和后面的b交换位置,这样分开了相同的字符,就是最终答案了。再来看一个例子,比如 "aaabbc",当发现第二个字符也是 ‘a’ 的时候,就需要往后遍历找到第一个不是 ‘a’ 的字符,即 ‘b’,然后交换 ‘a’ 和 ‘b’ 即可,然后继续往后面进行同样的处理,当无法找到不同的字符后就返回空串。这种方法对有序的字符串S是可以的,虽然题目给的两个例子中字符串S都是有序的,实际上不一定是有序的。所以博主最先的想法是给数组排序呗,但是博主的这个解法跪在了这个例子上 "vvvlo",我们发现排序后就变成 "lovvv",这样上面提到的解法就跪了。其实这里次数出现多的字符串需要在前面,这样才好交换嘛。那么还是要统计每个字符串出现的次数啊,这里使用 HashMap 来建立字母和其出现次数之间的映射。由于希望次数多的字符排前面,可以使用一个最大堆,C++ 中就是优先队列 Priority Queue,将次数当做排序的 key,把次数和其对应的字母组成一个 pair,放进最大堆中自动排序。这里其实有个剪枝的 trick,如果某个字母出现的频率大于总长度的一半了,那么必然会有两个相邻的字母出现。这里博主就不证明了,感觉有点像抽屉原理。所以在将映射对加入优先队列时,先判断下次数,超过总长度一半了的话直接返回空串就行了。
好,最大堆建立好以后,此时难道还是应该使用上面所说的交换的方法吗?其实直接构建新的字符串要更加简单一些。接下来,每次从优先队列中取队首的两个映射对儿处理,因为要拆开相同的字母,这两个映射对儿肯定是不同的字母,可以将其放在一起,之后需要将两个映射对儿中的次数自减1,如果还有多余的字母,即减1后的次数仍大于0的话,将其再放回最大堆。由于是两个两个取的,所以最后 while 循环退出后,有可能优先队列中还剩下了一个映射对儿,此时将其加入结果 res 即可。而且这个多余的映射对儿一定只有一个字母了,因为提前判断过各个字母的出现次数是否小于等于总长度的一半,按这种机制来取字母,不可能会剩下多余一个的相同的字母,参见代码如下:
解法一:
class Solution {
public:
string reorganizeString(string S) {
string res = "";
unordered_map<char, int> m;
priority_queue<pair<int, char>> q;
for (char c : S) ++m[c];
for (auto a : m) {
if (a.second > (S.size() + ) / ) return "";
q.push({a.second, a.first});
}
while (q.size() >= ) {
auto t1 = q.top(); q.pop();
auto t2 = q.top(); q.pop();
res.push_back(t1.second);
res.push_back(t2.second);
if (--t1.first > ) q.push(t1);
if (--t2.first > ) q.push(t2);
}
if (q.size() > ) res.push_back(q.top().second);
return res;
}
};
下面这种解法的原理和上面的很类似,就是写法上很秀,堪比陈独秀。这里使用了一个长度为 26 的一位数组 cnt 来代替上面的 HashMap 进行统计字母的出现次数,然后比较秀的一点是,把上面的映射对儿压缩成了一个整数,做法是将次数乘以了 100,再加上当前字母在一位数字中的位置坐标i,这样一个整数就同时 encode 了次数和对应字母的信息了,而且之后 decode 也很方便。数组 cnt 更新好了后,需要排个序,这一步就是模拟上面解法中最大堆的自动排序功能。不过这里是数字小的在前面,即先处理出现次数少的字母。这里除了和上面一样检测次数不能大于总长度的一半的操作外,还有一个小 trick,就是构建字符串的时候,是从第二个位置开始的。这里构建的字符串是直接对原字符串S进行修改的,因为 cnt 数组建立了之后,字符串S就没啥用了。用一个变量 idx 来表示当前更新字母的位置,初始化为1,表示要从第二个位置开始更新。因为出现次数最多的字母一定要占据第一个位置才行,这就是留出第一个位置的原因。这里很叼的一点,就是隔位更新,这样能保证相同的字母不相邻,而且当 idx 越界后,拉回到起始位置0,这就有点遍历循环数组的感觉。举个栗子来说吧,比如 "aaabbc",更新顺序为:
_ c _ _ _ _
_ c _ b _ _
_ c _ b _ b
a c _ b _ b
a c a b _ b
a c a b a b
解法二:
class Solution {
public:
string reorganizeString(string S) {
int n = S.size(), idx = ;
vector<int> cnt(, );
for (char c : S) cnt[c - 'a'] += ;
for (int i = ; i < ; ++i) cnt[i] += i;
sort(cnt.begin(), cnt.end());
for (int num : cnt) {
int t = num / ;
char ch = 'a' + (num % );
if (t > (n + ) / ) return "";
for (int i = ; i < t; ++i) {
if (idx >= n) idx = ;
S[idx] = ch;
idx += ;
}
}
return S;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/767
类似题目:
Rearrange String k Distance Apart
参考资料:
https://leetcode.com/problems/reorganize-string/
https://leetcode.com/problems/reorganize-string/discuss/113440/Java-solution-PriorityQueue
https://leetcode.com/problems/reorganize-string/discuss/113427/C%2B%2B-Greedy-sort-O(N)
https://leetcode.com/problems/reorganize-string/discuss/232469/Java-No-Sort-O(N)-0ms-beat-100
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] 767. Reorganize String 重构字符串的更多相关文章
- [LeetCode] Reorganize String 重构字符串
Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...
- LeetCode - 767. Reorganize String
Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...
- [leetcode]Weekly Contest 68 (767. Reorganize String&&769. Max Chunks To Make Sorted&&768. Max Chunks To Make Sorted II)
766. Toeplitz Matrix 第一题不说,贼麻瓜,好久没以比赛的状态写题,这个题浪费了快40分钟,我真是...... 767. Reorganize String 就是给你一个字符串,能不 ...
- 767. Reorganize String - LeetCode
Question 767. Reorganize String Solution 题目大意: 给一个字符串,将字符按如下规则排序,相邻两个字符一同,如果相同返回空串否则返回排序后的串. 思路: 首先找 ...
- 767. Reorganize String
Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...
- 【LeetCode】767. Reorganize String 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.me/ 题目地址:https://leetcode.com/problems/reorganiz ...
- LeetCode 344. Reverse String(反转字符串)
题目描述 LeetCode 344. 反转字符串 请编写一个函数,其功能是将输入的字符串反转过来. 示例 输入: s = "hello" 返回: "olleh" ...
- [LeetCode] 394. Decode String 解码字符串
Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where ...
- [LeetCode] 87. Scramble String 搅乱字符串
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrin ...
随机推荐
- kudu 查看元数据信息
package com.lala.lala.pipe.dbinfo import org.apache.kudu.client.KuduClient import com.lala.lala.comm ...
- COMP 2406 – F19
COMP 2406 – F19 – A4 Due Friday, November 22nd at 11:59 PMAssignment 4 Trivia Quiz BuilderSubmit a s ...
- 奥展项目笔记06--js弹出框、对话框、提示框、弹窗总结
JS的三种最常见的对话框: //====================== JS最常用三种弹出对话框 ======================== //弹出对话框并输出一段提示信息 functi ...
- 图片服务器FastDFS的安装及使用
FastDFS介绍 FastDFS是用c语言编写的一款开源的分布式文件系统.FastDFS为互联网量身定制,充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标,使用FastDFS ...
- MySQL for OPS 04:存储引擎
写在前面的话 在使用 Linux 的时候,可以经常听到有关文件系统 FS(File System)的东西,MySQL 也有属于自己类似的东西,那就是存储引擎.之前在创建数据表的时候,在 Create ...
- 搭建 Frp 来远程内网 Windows 和 Linux 机子
魏刘宏 2019 年 5 月 19 日 一.使用一键脚本搭建服务端 Frp 这个内网穿透项目的官方地址为 https://github.com/fatedier/frp ,不过我们今天搭建服务端时不直 ...
- aspx.designer.cs没有自动生成代码(没有自动注册)
遇到这个问题的最大可能是:aspx页面存在bug. 比如说我的主页是从项目里的别的页面复制过来的,但是少复制了一些引用,页面就存在bug,导致aspx.designer.cs没有自动生成代码. 解决方 ...
- 回忆C++
内联函数 内联函数适用于函数较为短小的情况. 内联函数存在的意义是:提高程序运行效率. 内联函数的缺点:如果一个内联函数太长且频繁调用,会导致生成的可执行程序较大. 静态链接库会被嵌入到生成的可执行程 ...
- Vue笔记--同局域网下访问本地项目
正常开发中有时间提测比较麻烦.通常让测试小姐姐连接开发本地开启的服务器访问本地项目(在同一局域网下). 其实一般项目IDE已经实现这些功能例如webstorm和vscode,有时候需要单独配置下. 但 ...
- python如何通过windows命令行运行一个python程序文件?
python如何通过windows命令行运行一个python程序文件? cmd 进入到py文件对应目录下或者直接在上面的文件地址栏输入cmd,敲入回车 定位到对应的目录下 输入python xxx.p ...