三、桶排序
先看定义:
桶排序会进行两次排序,一次将所有元素分配到不同的桶中,一次针对每个桶排序或再次排序所有元素。
练习题:
1)
力扣https://leetcode.cn/problems/top-k-frequent-elements/这道题就是非常典型的桶排序,先将每个元素分配到桶(统计每个元素的出现频次),再根据频次排序每个桶。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int,int> mp;
for(auto n:nums){
mp[n]++;
}
vector<pair<int,int>> vt(mp.begin(), mp.end());
sort(vt.begin(), vt.end(), [&](pair<int,int>& a, pair<int,int>& b){
return a.second>b.second;
});
vector<int> res(k,0);
for(int i=0;i<k;i++){
res[i] = vt[i].first;
}
return res;
}
};
2)
力扣https://leetcode.cn/problems/sort-characters-by-frequency/这道题也是桶排序,可以用和上一道题一样的方法排序,也可以在第二次排序时以递归方式继续使用桶排序。
为了不重复,这题解法用的后者。
class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> mp;
int max_count = 0;
for(auto c:s){
max_count = max(max_count, ++mp[c]);
}
vector<vector<char>> vt(max_count+1);
for(auto m:mp){
vt[m.second].push_back(m.first);
}
string res = "";
for(int i=max_count;i>0;i--){
if(vt[i].size()){
for(auto v:vt[i]){
for(int j=0;j<i;j++){
res += v;
}
}
}
}
return res;
}
};
四、多路排序
力扣https://leetcode.cn/problems/sort-colors/这道题要有意义,那肯定是一遍遍历,那就考虑到同时给0,1,2三类元素排序。
解题思路:用三个指针,两个分别指向有序的0,2区间,另一个遍历整个数组,遇到0,与指向0区间的指针交换值,遇到2,与指向2区间的指针交换。(当然,指向2区间的指针换成指向1区间也是可以的)
需要注意的细节是遍历指针与2区间指针交换后,指向的值可能为0,所有不能直接自增。
代码:
class Solution {
public:
void sortColors(vector<int>& nums) {
int left = 0, right = 0, end = nums.size()-1;
while(right<=end){
if(nums[right]==0)
swap(nums[left++], nums[right++]);
else if(nums[right]==2)
swap(nums[end--], nums[right]);
else
right++;
}
}
};