一.按照词频求
参考:https://blog.youkuaiyun.com/qq_26410101/article/details/82108011
https://blog.youkuaiyun.com/qq_38595487/article/details/79977315 (公式里少写了括号)
个人理解:
(1)先找出现次数最多的字母,假设为A,出现m次,要求字母间隔大于n。那么先将A按照给定间隔排好后的长度为(m-1)*(n+1) + 1
,(m-1)是因为m个A之间有(m-1)块空格。(n+1)是因为每块空格长度为n,在加上字母A,一共n+1,最后一个+1是最后一个字母A。比如字母A出现3次,间隔为2,则A排好后为
A _ _ A _ _ A
(2)接下来排的时候只需要依次将频率小的字母插入这些空格中,注意插的时候要先插满第二位的空格,再插第三位的空格,以此类推,且频率高的字母先插。
(3)上面说的是大部分情况,但是还会出现两种特殊情况:
1.最大频率的字母不止一个,比如A,B都出现了3次,则此时A,B排好后为AB _ _ AB _ _ AB
会发现此时长度多了一个长度(最后一个B的长度),因此此时的总长度应该为(m-1)*(n+1)+count
,count为最大频率的字母个数,在这里为2。上面的(1)可以认为是count=1的一个特例
2.当中间所有的空格都被填满了还没有插入所有元素,此时需要将剩余元素依次插入到每块的后面去(这样可以保证彼此间的间隔大于n,相当于是拓宽了部分块的间隔),比如AAABBCCD 先得到ABCABCA
,此时还有一个D没有插入,则插到每个块后面去,得到ABCDABCA
,此时会发现其实这个长度就是原数组的长度。
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
unordered_map<char,int>mp; //值为字母,键为出现的次数
int count = 0;
for(auto e : tasks)
{
mp[e]++; //记录每个字母的次数
count = max(count, mp[e]); //记录出现最多的次数
}
int ans = (count-1)*(n+1); //第(1)种情况
for(auto e : mp) if(e.second == count) ans++;//第(3)-1的情况,第一种中的+1是在这里加的
return max((int)tasks.size(), ans); //第(3)-2的情况
}
};
二优先队列(没看)
https://leetcode.com/problems/task-scheduler/discuss/104493/C%2B%2B-Java-Clean-Code-Priority-Queue
上面的博客有解析