767. 重构字符串
给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
示例 1:
输入: S = "aab"
输出: "aba"
示例 2:
输入: S = "aaab"
输出: ""
注意:
S 只包含小写字母并且长度在[1, 500]区间内。
今天不怎么有精神,所以最开始搞的时候方向错了。我选择的是广搜和深搜,一顿错做猛如虎,发现超时。
看了题解是堆排序和插入法,果断选择插入法,不过堆排序还是要搞得,所以就标记了“重要”。
记录一下自己做错的过程。
- 深搜是最不合适的方法,我还研究了半天
- 广搜也不行,一样的,搜索这道题目根本就是最费劲不讨好的方式
- 插入法很好,我的思路是这样的
a. 创建一个和字符串 S 一样大小的字符串 ans
b. 使用 map 统计字符串 S 出现的字符和频率
c. 将频率最高的字符放入到字符串 ans 的偶位置
d. 频率最高的用完,用次之,依次进行
e.字符串 ans 中的偶数位置放完,再放置奇数位置
我觉得我的描述很清晰,实际上,我在很刻意的做这件事,可以的训练自己的逻辑。今天在写深搜的时候,那个递归让我写的很痛苦,因为我觉得我根本做不到写代码之前,就在脑海中打理好我该怎么去写,这是一个很糟糕的习惯。这种代码越写越糟糕。
我的插入法中间也有肯多小坑。
4. map 的排序是针对 key,我把这个给忘了,我习惯使用了排好顺序的map,然后错误也是很明显。也就是map提供的排序是针对字符而不是频率
5. map 是不存在对 value 的排序 ,所以我觉得 pair+vector 太麻烦,所以自己定义了一个struct
6. 偶数位置放完之后,放置奇数位置的时候,需要继续从最高频率开始,而不是最低频率,这样是为了避免重复,如果奇数位置从最低频率开始,那么字符串ans的末尾位置很有可能最高频率相邻。
7. 为空的条件是 最高频率 < (字符串 ans 长度 + 1) / 2
8. 需要在运算符号两边留下足够的空格用于运算
这个是这样算的:
假设字符串长度 len, 最高频率为 a,其他频率为 b,满足不相邻的要求:
那么最高频率的最大值为: a <= b + 1
2a <= a + b + 1
a <= (len+1) / 2
一切的逻辑需要用数学表现出来,这也是我想要的能力:
typedef struct {
char ch;
int num;
}Map;
bool cmp(Map a, Map b) {
return a.num > b.num;
}
class Solution {
public:
string reorganizeString(string S) {
int len = S.size();
map<char, int> maps;
for (int i = 0; i < len; i++)
maps[S[i]]++;
vector<Map> count;
for (map<char, int>::iterator it = maps.begin(); it != maps.end(); it++) {
Map tmp;
tmp.ch = it->first;
tmp.num = it->second;
count.push_back(tmp);
}
sort(count.begin(), count.end(), cmp);
if ( count.begin()->num > (len+1)/ 2 )
return "";
string ans = S;
vector<Map>::iterator it = count.begin();
//填充偶数位
for (int i = 0; i < len; i += 2) {
if (it->num == 0)
it++;
ans[i] = it->ch;
it->num--;
}
//填充奇数位
for (int i = 1; i < len; i += 2) {
if (it->num == 0)
it++;
ans[i] = it->ch;
it->num--;
}
return ans;
}
};
u1s1, 我觉得我代码写的还是相当精炼的。