给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。
若可行,输出任意可行的结果。若不可行,返回空字符串。
leetcode
解题思路:
- 首先想想什么样的情况下不能构成可行的字符串,就像植树问题,最大的相同的字符个数一定小于字符串长度加一再除以二,如果超了就肯定会相邻。
- 所以,我们在枚举输出的时候,只要剩下需要输出的字符串一直满足这个条件,就一直能够产生合法的答案。当我们每次输出数量最大的两个字符串的时候,就能够让原来的字符串一直满足条件了。你想嘛,如果每次都输出数量的了,那么数量大的不就肯定会超过半数了。
这里利用了优先队列,让数量多的字符排在对头。
class Solution {
public String reorganizeString(String s) {
int n = s.length();
if(n < 2) return s;
// 通过数组对字符串的字符进行计数
int[] cnt = new int[26];
int maxCnt = 0;
for(char c : s.toCharArray()) {
cnt[c - 'a'] ++;
}
for(int i : cnt) {
maxCnt = Math.max(maxCnt, i);
}
if(maxCnt > (n + 1) / 2) return "";
// 构造优先队列
PriorityQueue<Character> q = new PriorityQueue<>((a, b) -> cnt[b - 'a'] - cnt[a - 'a']);
// 填入优先队列
for(int i = 0; i < 26; i++) {
if(cnt[i] > 0) q.offer((char)(i + 'a'));
}
StringBuilder res = new StringBuilder();
while(q.size() > 1) {
// 每次提取两个数量最多的字符
char a = q.poll();
char b = q.poll();
res.append(a);
res.append(b);
cnt[a - 'a'] --;
cnt[b - 'a'] --;
if(cnt[a - 'a'] > 0) q.offer(a);
if(cnt[b - 'a'] > 0) q.offer(b);
}
// 最后可能还剩下一个
if(q.size() > 0) res.append(q.poll());
return res.toString();
}
}