/**
* 思路:如果s长度小于2,直接返回s,假设字符串s的长度为n。
* n为偶数,如果字符串中的某个字符数量超过 n/2 则肯定会存在相邻的字符。
* n为奇数,如果字符串中的某个字符的数量超过 (n+1)/ 2 ,肯定会存在相邻的字符。
* 因为n为偶数时 (n+1)/2等于n/2,所以可以合并上面的两个情况。
* 然后构建优先队列,优先队列是使用堆实现的,然后构建大顶堆。
* 每次从优先队列取出出现次数最多的两个字符加入到结果中,
* 然后将次数不为0 的字符再重新添加到优先队列中。
* @auther start
* @create 2024-01-12 14:34
*/
public class L767 {
public String reorganizeString(String s) {
int len = s.length();
if (len < 2) return s;
int[] count = new int[26];
int maxCount = 0;
//统计字符出现次数
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
count[c - 'a']++;
//出现最多的字符次数
maxCount = Math.max(maxCount, count[c - 'a']);
}
//肯定有相邻字符出现的情况
if (maxCount > (len + 1) / 2) {
return "";
}
//构建优先队列
PriorityQueue<Character> queue = new PriorityQueue<>(new Comparator<Character>() {
@Override
//构建大顶堆
public int compare(Character o1, Character o2) {
return count[o2 - 'a'] - count[o1 - 'a'];
}
});
//添加字符到优先队列中
for (char c = 'a'; c <= 'z'; c++) {
if (count[c - 'a'] > 0) {
queue.offer(c);
}
}
StringBuffer res = new StringBuffer();
while (queue.size() > 1) {
//取出优先队列中的两个字符
char c1 = queue.poll();
char c2 = queue.poll();
//添加到结果中
res.append(c1);
res.append(c2);
int idx1 = c1 - 'a', idx2 = c2 - 'a';
//这两个字符数量减一
count[idx1]--;
count[idx2]--;
//判断这两个字符的数量是否大于1,大于1重新加入到优先队列中
if (count[idx1] > 0)
queue.offer(c1);
if (count[idx2] > 0)
queue.offer(c2);
}
//字符串长度为奇数的情况,取出最后一个字符
if (queue.size() > 0) {
res.append(queue.poll());
}
return res.toString();
}
}