剑指offer专项突击版第20天

剑指 Offer II 059. 数据流的第 K 大数值

小顶堆

  • 第k大就等同于,序列升序后倒数第k个数。
  • 容易发现,倒数第k个之前的数都用不到了,那么我们可以扔掉那些没用的,然后保持插入后序列仍然有序即可。
  • 由于这里add会操作 1 0 4 10^4 104 次,所以需要较小的时间复杂度,容易想到使用堆结构(大小保持为<= k k k ),或者multiset。
class KthLargest {
public:
    int k = 0;
    priority_queue<int,vector<int>,greater<int>> heap;
    KthLargest(int k, vector<int>& nums) {
        for(int num: nums) heap.push(num);
        this->k = k;
    }
    
    int add(int val) {
        heap.push(val);
        while(heap.size() > k) heap.pop();
        return heap.top();
    }
};

剑指 Offer II 060. 出现频率最高的 k 个数字

方法一、使用哈希表记录次数,然后遍历哈希表让堆来维护前 k k k 大,时间复杂度就为 O ( N l o g k ) O(Nlogk) O(Nlogk)

class Solution {
public:
    typedef pair<int,int> PII;
    unordered_map<int,int> cnts;
    static bool cmp(const PII &a, const PII &b) {
        return a.second > b.second;
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        for(int num: nums) {
            cnts[num]++;
        }
        //自定义排序规则
        priority_queue<PII,vector<PII>,decltype(&cmp)> heap(cmp);
        for(auto p: cnts) {
            if(heap.size() == k) { //保持堆大小不大于k
                if(heap.top().second < p.second) {
                    heap.pop();
                    heap.emplace(p);
                }
            } else heap.emplace(p);
        }
        vector<int> res;
        while(heap.size()) {
            res.emplace_back(heap.top().first);
            heap.pop();
        }
        return res;
    }
};

方法二、使用哈希表记录次数,然后再排序取出前k大的数即可。时间 O ( N l o g N ) O(NlogN) O(NlogN)

class Solution {
public:
    unordered_map<int,int> cnts;
    static bool cmp(const pair<int,int> &a, const pair<int,int> &b) {
        return a.second > b.second;
    }
    vector<int> topKFrequent(vector<int>& nums, int k) {
        int maxx = 0;
        for(int num: nums) {
            cnts[num]++;
        }
        vector<pair<int,int>> ls;
        for(auto p: cnts) {
            ls.emplace_back(p);
        }
        sort(ls.begin(),ls.end(),cmp);
        ls.erase(ls.begin()+k,ls.end());
        vector<int> res;
        for(auto num: ls) res.emplace_back(num.first);
        return res;
    }
};

剑指 Offer II 061. 和最小的 k 个数对

  • 容易想到一个方法:暴力出所有数对,然后排序取前 k k k 小,时间复杂度是 O ( N 2 ) O(N^2) O(N2) 在这里会超时。
  • 仔细思考会发现, n u m s 1 [ 0 ] + n u m s 2 [ 0 ] nums1[0]+nums2[0] nums1[0]+nums2[0] 一定是最小的,然后接下第二小肯定是它们其中之一: n u m s 1 [ 0 ] + n u m s 2 [ 1 ] nums1[0]+nums2[1] nums1[0]+nums2[1] n u m s 1 [ 1 ] + n u m s 2 [ 0 ] nums1[1]+nums2[0] nums1[1]+nums2[0] ,以此类推,这样我们就不用遍历出所有数对了只需利用规律找出前几个即可,这里需要用小顶堆来维护数对间的关系。

在这里插入图片描述

class Solution {
public:
    typedef pair<int,int> PII;
    vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
        auto cmp = [&nums1,&nums2](const PII &a, const PII &b) {
            return nums1[a.first]+nums2[a.second] > nums1[b.first]+nums2[b.second];
        };

        int n = nums1.size();
        int m = nums2.size();
        priority_queue<PII,vector<PII>,decltype(cmp)> heap(cmp);
        for(int i = 0; i < min(k,n); i++) {
            heap.emplace(i,0);
        }
        vector<vector<int>> res;
        while(k-- && heap.size()) {
            auto [x,y] = heap.top();
            heap.pop();
            res.push_back({nums1[x],nums2[y]});
            if(y+1 < m) heap.emplace(x,y+1);
        }
        return res;
    }
};

参考:https://leetcode.cn/problems/qn8gGX/solution/he-zui-xiao-de-k-ge-shu-dui-by-leetcode-eoce6/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值