[LeetCode] 767. Reorganize String
Given a string s
, rearrange the characters of s
so that any two adjacent characters are not the same.
Return any possible rearrangement of s
or return ""
if not possible.
Example 1:
Input: s = "aab" Output: "aba"
Example 2:
Input: s = "aaab" Output: ""
Constraints:
1 <= s.length <= 500
s
consists of lowercase English letters.
重构字符串。
给定一个字符串
s
,检查是否能重新排布其中的字母,使得两相邻的字符不同。返回
s
的任意可能的重新排列。若不可行,返回空字符串""
。
影子题358。思路是 priority queue + hashmap。hashmap 存的是每个字符和他们出现的次数;priority queue 存的是 hashmap 的 entry,但是是一个按照字符出现次数来排序的一个 maxheap,也就是说出现次数越多的字符会在 heap 顶端。先遍历一遍 input,存入字符和他们各自出现的次数之后,也同时把每个 hashmap entry 存入 pq。有一个 corner cases 是在遍历 input 字符串的时候,如果有任何一个字符的出现次数大于 input 的一半则返回空字符串,因为一定无法满足题意。corner case 处理完之后就开始从 pq 往外弹出元素。先弹出一个,记为 first,判断如果上一个被 attach 的字符也是 first 的话则再弹出一个 second 字符。加了哪个字符,就对其 mapvalue-- 并判断是否需要再加回 maxheap,直到 pq 为空。
时间O(nlogn)
空间O(n)
Java实现
1 class Solution { 2 public String reorganizeString(String s) { 3 int n = s.length(); 4 HashMap<Character, Integer> map = new HashMap<>(); 5 for (char c : s.toCharArray()) { 6 int count = map.getOrDefault(c, 0) + 1; 7 // impossible 8 if (count > (n + 1) / 2) { 9 return ""; 10 } 11 map.put(c, count); 12 } 13 14 PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> b[1] - a[1]); 15 for (char c : map.keySet()) { 16 queue.offer(new int[] { c, map.get(c) }); 17 } 18 19 StringBuilder sb = new StringBuilder(); 20 while (!queue.isEmpty()) { 21 int[] first = queue.poll(); 22 if (sb.length() == 0 || first[0] != sb.charAt(sb.length() - 1)) { 23 sb.append((char) first[0]); 24 if (--first[1] > 0) { 25 queue.offer(first); 26 } 27 } else { 28 int[] second = queue.poll(); 29 sb.append((char) second[0]); 30 if (--second[1] > 0) { 31 queue.offer(second); 32 } 33 queue.offer(first); 34 } 35 } 36 return sb.toString(); 37 } 38 }
另一种做法是创建一个 hashmap 先记录每个字母出现的频率,再创建一个跟 input 字符串等长的数组开始往里面放字母。首先放出现次数最多的字母,并且放的时候,每两个字母之间隔开一个位置,类似 [0, 2, 4, 6...] 这样的放置方法。出现次数最多的字母处理完之后,其他的字母也是隔开一个位置这样的方式,放入数组剩下的位置里面。为什么出现次数最多的字母是一个比较特殊的情形是因为最极端的情况,出现次数最多的字母有可能占据 input 长度的一半,而占据 input 长度的一半也就意味着是没法按照题目要求重构的。
时间O(n)
空间O(n)
Java实现
1 class Solution { 2 public String reorganizeString(String S) { 3 int[] hash = new int[26]; 4 for (int i = 0; i < S.length(); i++) { 5 hash[S.charAt(i) - 'a']++; 6 } 7 int max = 0; 8 int letter = 0; 9 for (int i = 0; i < hash.length; i++) { 10 if (hash[i] > max) { 11 max = hash[i]; 12 letter = i; 13 } 14 } 15 // corner case 16 if (max > (S.length() + 1) / 2) { 17 return ""; 18 } 19 char[] res = new char[S.length()]; 20 int index = 0; 21 while (hash[letter] > 0) { 22 res[index] = (char) (letter + 'a'); 23 index += 2; 24 hash[letter]--; 25 } 26 for (int i = 0; i < hash.length; i++) { 27 while (hash[i] > 0) { 28 if (index >= res.length) { 29 index = 1; 30 } 31 res[index] = (char) (i + 'a'); 32 index += 2; 33 hash[i]--; 34 } 35 } 36 return String.valueOf(res); 37 } 38 }
相关题目