算法通关村第14关【白银】| 堆的经典问题

1.数组中的第k个最大元素

思路:

  • 最直观的就是选择法,遍历一k次找到第k大的数
  • 之前使用快速排序的思想每次找出一个位置,会超时
  • 这里使用堆(优先队列),找最大用小堆,找最小用大堆。

例如找第k大的数,新建一个空间为k的最小优先队列,只要比当前优先队列最小值大就替换进去,这样全部的数遍历一遍,里面留下的就是前k大的数了,其他的全被替换出去了,并且队头是第k最大的。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>(k);
        for(int n : nums){
            if(pq.size()<k){
                pq.offer(n);
            }else{
                if(n>pq.peek()){
                    pq.poll();
                    pq.offer(n);
                }
            }
        }
        return pq.peek();
    }
}

2.堆排序原理

  1. 构建最大堆(Max Heap):首先,将待排序的元素构建成一个最大堆。最大堆是一个满足堆性质的二叉树,即每个节点的值都大于或等于其子节点的值,根节点是堆中的最大元素。

    构建最大堆的过程:从数组中的最后一个非叶子节点开始,逐个向前处理每个节点,将当前节点与其子节点比较并进行交换,直到整个数组构建成一个最大堆。
  2. 排序:一旦构建了最大堆,最大元素就位于堆的根节点(数组的第一个元素)。将根节点(最大元素)与数组中的最后一个元素交换,然后将数组的大小减1,将根节点下沉到适当位置,以保持剩余元素的最大堆性质。重复这个过程,直到整个数组有序。

 堆排序的时间复杂度为O(n * log n),其中n是待排序数组的元素数量。由于堆排序是一种原地排序算法,不需要额外的辅助空间,因此它在空间复杂度上表现较好。堆排序的稳定性取决于在构建最大堆时是否采用稳定的下沉方法,通常情况下是不稳定的排序算法。

3.合并k个升序链表

思路:题目要求从小到大排序构造一个新的链表,这里要保证每次加入的元素是当前最小的,使用优先队列构造小根堆。将ListNode数组第一个元素加入队列,每次取出队头然后加入取出的元素的下一个。

PriorityQueue详解可以看 PriorityQueue初始化和方法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists.length == 0){
            return null;
        }
        ListNode head = new ListNode(-1);
        PriorityQueue<ListNode> q = new PriorityQueue<>(lists.length,(a,b)->a.val-b.val);
        for(int i = 0;i<lists.length;i++){
            if(lists[i] == null) continue;
            q.add(lists[i]);
        }
        ListNode tail = head;
        while(!q.isEmpty()){
            tail.next = q.poll();
            tail = tail.next;
            if(tail.next!=null){
                q.offer(tail.next);
            }
        }
        return head.next;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值