Java最优队列PriorityQueue自定义排序规则

PriorityQueue

Java自带的最优队列,其内部实现方法是一个小顶堆二叉树。最小的节点永远在上方,小顶堆在做前K个这类问题是有比全部排序好的效果。O(Klogn) k<n而整体快排也有O(nlogn)的时间复杂度,所以PriorityQueue是我们必须掌握的一种数据结构。

LeetCode 5556. 可以到达的最远建筑

给你一个整数数组 heights ,表示建筑物的高度。另有一些砖块 bricks 和梯子 ladders 。

你从建筑物 0 开始旅程,不断向后面的建筑物移动,期间可能会用到砖块或梯子。

当从建筑物 i 移动到建筑物 i+1(下标 从 0 开始 )时:

如果当前建筑物的高度 大于或等于 下一建筑物的高度,则不需要梯子或砖块
如果当前建筑的高度 小于 下一个建筑的高度,您可以使用 一架梯子 或 (h[i+1] - h[i]) 个砖块
如果以最佳方式使用给定的梯子和砖块,返回你可以到达的最远建筑物的下标(下标 从 0 开始 )。

示例 1:

输入:heights = [4,2,7,6,9,14,12], bricks = 5, ladders = 1
输出:4
解释:从建筑物 0 出发,你可以按此方案完成旅程:

  • 不使用砖块或梯子到达建筑物 1 ,因为 4 >= 2
  • 使用 5 个砖块到达建筑物 2 。你必须使用砖块或梯子,因为 2 < 7
  • 不使用砖块或梯子到达建筑物 3 ,因为 7 >= 6
  • 使用唯一的梯子到达建筑物 4 。你必须使用砖块或梯子,因为 6 < 9
    无法越过建筑物 4 ,因为没有更多砖块或梯子。
    示例 2:

输入:heights = [4,12,2,7,3,18,20,3,19], bricks = 10, ladders = 2
输出:7
示例 3:

输入:heights = [14,3,19,3], bricks = 17, ladders = 0
输出:3

提示:

1 <= heights.length <= 105
1 <= heights[i] <= 106
0 <= bricks <= 109
0 <= ladders <= heights.length
力扣5556

第一次思路(递归)

每一步取使用梯子和砖块两者最优方法

class Solution {
    public int furthestBuilding(int[] heights, int bricks, int ladders) {
        return DFS(heights, bricks, ladders, 0);
    }

    public int DFS(int[] heights, int bicks, int ladders, int i) {
    	//如果梯子或砖块用超了,直接返回
        if (ladders<0||bicks < 0) {
            return i - 1;
        }if (i == heights.length - 1) {
            return i;
        }
        int now = heights[i + 1] - heights[i];
        if (now <= 0) {
        	//如果这个建筑高度大于下一块建筑,可以直接跳过去
            return DFS(heights, bicks, ladders, i + 1);
        } else {
        	//比较两种选择的最优解。
            int a = DFS(heights, bicks, ladders - 1, i + 1);
            int b = DFS(heights, bicks - now, ladders, i + 1);
            return Math.max(a,b);
        }
    }
}

在这里插入图片描述

这个方法思路没问题,就是太复杂了。以下是我看题解结合自己百度学到的新方法。

优先队列+贪心

创建一个小顶堆,小顶堆我简单介绍一下。它可以每次返回一组数中最小的数,他是一个二叉树,上面的节点数值比较小。每次可以返回数顶的节点。Java里自带的小顶堆是PriorityQueue,我们只需讲高度差最大的用梯子,其他都用砖块,代码特别的巧妙实现如下:

public int furthestBuilding(int[] heights, int bricks, int ladders) {
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        int n = heights.length;
        for (int i = 0; i < n - 1; i++) {
            int a = heights[i + 1] - heights[i];
            if (a > 0) {
                pq.offer(a);
                if (pq.size() > ladders) {
                    bricks -= pq.poll();
                }
                if (bricks < 0) {
                    return i;
                }
            }
        }
        return  n - 1;
    }

在这里插入图片描述

LeetCode 373. 查找和最小的K对数字

这道题中,我们只需要把优先队列的排列规则自定义就行,在PriorityQuery的构造函数中传入一个自定义的Comparator,实现对每个集合中的前两个值的和比较。

public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        PriorityQueue<List<Integer>> priorityQueue = new PriorityQueue<>(new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                int sumO1 = o1.get(0) + o1.get(1);
                int sumO2 = o2.get(0) + o2.get(1);
                return sumO1-sumO2;
            }
        });
        for (int i = 0; i < nums1.length; i++) {
            for (int j = 0; j < nums2.length; j++) {
                List<Integer> list=new ArrayList<Integer>();
                list.add(nums1[i]);
                list.add(nums2[j]);
                priorityQueue.add(list);
            }
        }
        List<List<Integer>> lists=new ArrayList<>();
        while(k-->0){
            List<Integer> list=priorityQueue.poll();
            if(list==null){
                continue;
            }
            lists.add(list);
        }
        return lists;
    }
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值