LeetCode刷题笔记——排序

桶排序:leetcode347(20230111)

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2

输出: [1,2]

示例 2:

输入: nums = [1], k = 1

输出: [1]

提示:

  • 1 <= nums.length <= 105

  • k 的取值范围是 [1, 数组中不相同的元素的个数]

  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。

Related Topics

  • 数组

  • 哈希表

  • 分治

  • 桶排序

  • 计数

  • 快速选择

  • 排序

  • 堆(优先队列)

解法1:使用两次桶排序

桶排序一般是O(n),符合题目要求小于O(nlogn)


#include<bits/stdc++.h>

using namespace std;
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //两遍桶排序
        map<int, int> counts;
        int max_count = 0;
        for (const int & num : nums) {
            max_count = max(max_count, ++counts[num]);
        }
        vector<vector<int> > buckets(max_count + 1);
        map<int,int>::iterator it;
        for (it=counts.begin();it!=counts.end();it++) {
            buckets[it->second].push_back(it->first);
        }
        vector<int> ans;
        for (int i = max_count; i >= 0 && ans.size() < k; --i) {
            for (const int & num : buckets[i]) {
                ans.push_back(num);
                if (ans.size() == k) {
                    break;
                }
            }
        }
        return ans;
    }
};

总结:

  1. 使用stl map来解决桶排序中空间浪费严重的问题

  1. 使用多遍桶排序将时间复杂度降低到O(nlogn)之下

  1. 学习map的遍历方法

解法2:使用堆(优先队列),建议使用c语言

维护一个大小为k的小顶堆,每次新元素进来就更新小顶堆

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> freq; // 统计词频
        for (auto& num : nums) ++freq[num];

        // 比较器
        auto pred = [](const auto& p1, const auto& p2)->bool {
            return p1.second > p2.second;
        };

        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(pred)> pq(pred);

        // 维护前k高的数字
        for (auto& p : freq) {
            pq.emplace(p);
            if (pq.size() > k) pq.pop();
        }

        vector<int> ans;
        while (!pq.empty()) { // 加入答案 并返回
            ans.emplace_back(pq.top().first);
            pq.pop();
        }
        return ans;
    }
};

总结:

  1. 复习stl优先队列的使用

  1. 要慎用stl,夏令营考试一般使用纯c

桶排序:leetcode451(20230112)

给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。

返回 已排序的字符串 。如果有多个答案,返回其中任何一个。

示例 1:

输入: s = "tree"

输出: "eert"

解释: 'e'出现两次,'r'和't'都只出现一次。

因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。

示例 2:

输入: s = "cccaaa"

输出: "cccaaa"

解释: 'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。

注意"cacaca"是不正确的,因为相同的字母必须放在一起。

示例 3:

输入: s = "Aabb"

输出: "bbAa"

解释: 此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。

注意'A'和'a'被认为是两种不同的字符。

提示:

  • 1 <= s.length <= 5 * 105

  • s 由大小写英文字母和数字组成

Related Topics

  • 哈希表

  • 字符串

  • 桶排序

  • 计数

  • 排序

  • 堆(优先队列)

方法一:两遍桶排序

class Solution {
public:
    char ans[500000];
    string frequencySort(string s) {
        vector<int> freq(128,0);
        int index=0;

        int max=0;
        for(int i=0;i<s.size();i++){
            int index=s[i];
            freq[index]++;
        }

        for(int i=0;i<128;i++){
            max= std::max(max,freq[i]);
        }
        vector<vector<int>> bucket(max+1);
        for(int i=0;i<128;i++){
            bucket[freq[i]].push_back(i);
        }

        for(int i=max;i>=0;i--){
            if(bucket[i].empty()){
                continue;
            }
            for(int j=0;j<bucket[i].size();j++){
                for(int k=0;k<i;k++){
                    char ch=bucket[i][j];
                    ans[index++]='\0'+bucket[i][j];
                }
            }
        }
        ans[index]='\0';
        string str=ans;
        return str;

    }
};

方法二:优先队列,更快

要注意优先队列的用法,以及pair比较时候默认比较第一个元素

class Solution {
public:
    char ans[500000];
    string frequencySort(string s) {
        priority_queue<pair<int,int>,vector<pair<int,int>>,less<pair<int,int> > > dict;
        vector<int> freq(128,0);
        int index=0;
        for(int i=0;i<s.size();i++){
            int idx=s[i];
            freq[idx]++;
        }
        for(int i=0;i<freq.size();i++){
            dict.push(make_pair(freq[i],i));
        }
        while (!dict.empty()){
            pair<int,int> tmp=dict.top();
            dict.pop();
            for(int i=0;i<tmp.first;i++){
                ans[index++]=tmp.second;
            }
        }
        ans[index]='\0';
        string str=ans;
        return str;
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值