题目:
给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少为 k。
所有输入的字符串都由小写字母组成,如果找不到距离至少为 k 的重排结果,请返回一个空字符串 ""。
示例 1:
输入: s = "aabbcc", k = 3
输出: "abcabc"
解释: 相同的字母在新的字符串中间隔至少 3 个单位距离。
示例 2:
输入: s = "aaabc", k = 3
输出: ""
解释: 没有办法找到可能的重排结果。
示例 3:
输入: s = "aaadbbcc", k = 2
输出: "abacabcd"
解释: 相同的字母在新的字符串中间隔至少 2 个单位距离。
解答:
贪心法,每次尽量取频次大的字母加入结果。
先统计每个字母出现的次数,存入map
然后把所有的[字母:频次]存入最大堆
每次从最大堆中取k个最大频次的字母,加入结果字符串。然后相应频次减一后再放回最大堆。
最终要么堆为空,则成功。如果堆中剩下不到k个字母,那么只能取一次(即字符串结尾,因为后面没有其他元素了),否则失败。
1 class Solution { 2 public: 3 string rearrangeString(string s, int k) { 4 if(k==0){ 5 return s; 6 } 7 vector<int> cnt(26,0); 8 for(char& c:s){ 9 cnt[c-'a']+=1; 10 } 11 priority_queue<pair<int,char>> max_heap; 12 for(int i=0;i<26;++i){ 13 if(cnt[i]>0){ 14 max_heap.push(make_pair(cnt[i],'a'+i)); 15 } 16 } 17 string res; 18 while(res.size()<s.size()){ 19 vector<pair<int,char>> tmp; 20 int min_len=min(k,int(max_heap.size())); 21 for(int i=0;i<min_len;++i){ 22 auto cur=max_heap.top(); 23 max_heap.pop(); 24 res+=cur.second; 25 if(--cur.first>0){ 26 tmp.push_back(cur); 27 } 28 } 29 if(min_len<k and res.size()!=s.size()){ 30 return ""; 31 } 32 for(auto& pai:tmp){ 33 max_heap.push(pai); 34 } 35 } 36 return res; 37 } 38 };
时间O(n log n),空间O(n)