重排列一个字符串,使相邻字母不同
sol:
注意到如果一个字母出现的次数超过一半,就不可能了。
接下来使用贪心的思路;
构造:每次选择次数最大的且与上次字母不同的加在字符串后,可以通过优先队列维护次数字母的次数
public String reorganizeString(String S) {
int[] cnt = new int[26];
for (char ch : S.toCharArray()) cnt[ch -'a']++;
//校验
int maxCnt = 0;
for (int x : cnt) maxCnt = Math.max(maxCnt, x);
if (maxCnt > (1 + S.length()) / 2) return "";
//优先队列,次数大的字母先出队
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[1] - a[1]);
for (int i = 0; i < cnt.length; i++) {
if (cnt[i] == 0) continue;
pq.offer(new int[]{i, cnt[i]});
}
int last = -1;
StringBuilder sb = new StringBuilder();
while (!pq.isEmpty()) {
int[] first = pq.poll();
if (first[0] != last) {
sb.append((char)(first[0] + 'a'));
last = first[0];
if (first[1] > 1) pq.offer(new int[]{first[0], first[1] - 1});
} else {
int[] second = pq.poll();
sb.append((char)(second[0] + 'a'));
last = second[0];
if (second[1] > 1) pq.offer(new int[]{second[0], second[1] - 1});
pq.offer(first);
}
}
return sb.toString();
}
另一种解法:先填充偶数位置的,再填充奇数位置的.
public String reorganizeString(String S) {
int[] cnt = new int[26];
for (char ch : S.toCharArray()) cnt[ch - 'a']++;
//校验
int maxCnt = 0;
int index = -1;
for (int i = 0; i < cnt.length; i++) {
if (cnt[i] > maxCnt) {
maxCnt = cnt[i];
index = i;
}
}
if (maxCnt > (1 + S.length()) / 2) return "";
char[] res = new char[S.length()];
int idx = 0;
while (cnt[index]-- > 0) {
res[idx] = (char) (index + 'a');
idx += 2;
}
for (int i = 0; i < cnt.length; i++) {
while (cnt[i]-- > 0) {
if (idx >= res.length) idx = 1;
res[idx] = (char) ('a' + i);
idx += 2;
}
}
return String.valueOf(res);
}