栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++优先队列、Java堆

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++优先队列、Java堆

优先队列实际上是堆

根节点的值比所有节点值都大,称为最大堆;

根节点的值比所有节点值都小,称为最小堆;

基本操作:

  • top 访问队头元素
  • empty 队列是否为空
  • size 返回队列内元素个数
  • push 插入元素到队尾 (并排序)
  • emplace 原地构造一个元素并插入队列
  • pop 弹出队头元素
  • swap 交换内容

第一种用法:

priority_queue q1;//默认从大到小排序,整数中元素大的优先级高 

第二种用法:

//升序队列 小顶堆
priority_queue ,greater > q;
//降序队列 大顶堆
priority_queue ,less >q;

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

第三种用法自定义:

struct cmp{
    bool operator()(pair m , pairn){
        return m.second > n.second;
    }
};
class Solution {
public:
    vector topKFrequent(vector& nums, int k) {
        
        priority_queue,vector>,cmp> q;
    }
};

简单例题:347. 前 K 个高频元素 - 力扣(LeetCode) (leetcode-cn.com)

 

基本思想:

        维护一个小顶堆,如果size() < k 则进入,如果size() == k 时,当堆顶小于当前次数大小,则弹出队头,该次数入队

struct cmp{
    bool operator()(pair m , pairn){
        return m.second > n.second;
    }
};
class Solution {
public:
    vector topKFrequent(vector& nums, int k) {

        int n = nums.size() , x = 0;
        if(n == 1) return nums;
        unordered_mapmap;
        for(auto x : nums)map[x]++;

        priority_queue,vector>,cmp> q;

        for(auto &[num,count] : map){
            if(q.size() == k){
                if(q.top().second < count){
                    q.pop();
                    q.push({num , count});
                }
            } else{
                q.push({num , count});
            }
        }
        vectorres;
        while (!q.empty()){
            res.emplace_back(q.top().first);
            q.pop();
        }
        return res;
    }
};

中等题目:1705. 吃苹果的最大数目 - 力扣(LeetCode) (leetcode-cn.com)

首先这道题是让你吃掉最多的苹果树,那么每天找最近过期的吃是最优解,别问我怎么知道

其次,既然是吃最近过期的那么,用map记录临期的最后一天和苹果个数,由于map的底层是红黑树,那么它本身就是默认升序的。分为两大块:1.在days天内,2.过期日期在days天外

class Solution {
public:
    int eatenApples(vector& apples, vector& days) {

        int ans = 0 ,  d = 0 ;
        map map;

        while (d < days.size() || !map.empty()){
            if(d < days.size()) map[days[d] + d -1] += apples[d];

            //尝试从map中取出一个最接近过期但是没有过期的苹果
            while (!map.empty()){
                if(map.begin()->first < d || map.begin()->second == 0) map.erase(map.begin()->first);
                else{
                    //如果找到了 我们就吃掉它
                    ans++;
                    //苹果数要减1
                    map.begin()->second--;
                    break;
                }
            }
            d++;
        }
        return ans;
    }
};

第二种方法:用优先队列

class Solution {
    public int eatenApples(int[] apples, int[] days) {

        //首先应该吃临近的过期食品,才能保证我吃的最多
        int ans = 0 , d = 0;
        //其次用小根堆记录过期时间和苹果个数
        PriorityQueue q = new PriorityQueue<>((a,b)->a[0]-b[0]); //升序为小根堆,默认以第一个元素升序

        while (d < days.length || !q.isEmpty()){

            //如果没到最后一天堆中已空,那么等待下一天长出苹果
            if(d < days.length) q.add(new int[]{days[d] + d -1 , apples[d]});

            //如果有过期苹果则删除
            while (!q.isEmpty()){
                if(q.peek()[0] < d || q.peek()[1] == 0) q.poll();
                else {
                    q.peek()[1]--;
                    ans++;
                    break;
                }
            }
            d++;
        }
        return ans;
    }
}

264. 丑数 II - 力扣(LeetCode) (leetcode-cn.com)

解法一:动态规划(三指针)由于每个丑数都有2,3,5组成,1除外,故利用三个指针p1 = 1,p2 = 1,p3 = 1,p1*2,p2*3,p3*5 , 将每次的最小值记录下来,如果等于p1*2则p1++,如果等于p2*2则p2++,如果等于p3*2则p3++,话不多说上代码

class Solution {
    public int nthUglyNumber(int n) {

        int[] dp = new int[n+10];
        dp[1] = 1;
        int p1 = 1 , p2 = 1 , p3 = 1;
        for(int i = 2 ; i <= n; i++){
            int num1 = dp[p1]*2 , num2 = dp[p2]*3 , num3 = dp[p3]*5;
            dp[i] = Math.min(Math.min(num1,num2) , num3);
            if(dp[i] == num1)p1++;
            if(dp[i] == num2)p2++;
            if(dp[i] == num3)p3++;
        }
        return dp[n];
    }
}

解法二:优先队列(小顶堆),由于后面的丑数能有前面的丑数乘2,3,5得到,1除外,由于会出现重复排序则利用map判断map集合中是否存在来决定是否入堆,利用堆的自然排序,每次取堆顶元素为第几个丑数,由于Java中的HashSet插入时可判断集合中是否存在比较方便,故Java判重

class Solution {
    public int nthUglyNumber(int n) {

        int[] arr = {2,3,5};
        Set set = new HashSet<>();

        PriorityQueue q = new PriorityQueue<>();
        set.add(1L);
        q.offer(1L);
        int ugly = 0;
        for(int i = 0 ; i < n; i++){
            long curr = q.poll();
            ugly = (int)curr;
            for(int x : arr){
                long next = curr*x;
                if(set.add(next)) q.offer(next);
            }
        }
        return ugly;
    }
}
class Solution {
public:
    int nthUglyNumber(int n) {

        vectorarr = {2,3,5};
        unordered_mapmap;
        priority_queue,greater>q;
        map[1]++;
        q.push(1);
        long ugly = 0;
        for(int i = 1 ; i <= n; i++){
            ugly = q.top();
            q.pop();
            for(int x : arr){
                long y = x *ugly;
                if(map[y] == 0){
                    map[y]++;
                    q.push(y);
                }
            }
        }
        return ugly;
    }
};

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/690005.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号