在《堆结构青铜挑战》笔记中,我们以画图的方式详细的剖析了堆创建,插入和删除过程。该篇文章主要针对堆经典问题进行总结,关键在于分析如何利用堆的特性解决这些问题。
1.在数组中找第K大的元素
题目见LeetCode215,描述为:给定整数数组nums和整数k,返回数组中第k个最大元素!
先前,我们已经使用了快速排序方式,通过一轮快排将数组变成有序元素,再通过数组下标找到第K大的元素。
但是,如果题目进行变式:以链表的形式给定n个数字和整数k,返回n个数字中第k个最大元素。快速排序策略就失效了!有什么更加优异的方式找到数组中第k个最大元素嘛?答:堆结构!
我的分析:如果想找到数组中第K大的元素,可以将数组“定性”的划分为两部分:较大的数和较小的数(保持较大的数部分容量为K,其余部分都是较小的数),我们只需要在较大的数字中找到最小的数字,该数字就是第K大的数!
理解分析后,如何将堆结构应用在上述思路分析中呢?答:创建一个大小为K的小根堆,利用小根堆筛选出数组中较大的数,筛选完毕后堆顶元素就是第K大元素!
厘清思路,直接上代码!
public static int myFindKthLargest(int[] nums, int k) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
//保持小根堆的大小为k
for (int i = 0; i < k; i++) {
minHeap.add(nums[i]);
}
for (int i = k; i < nums.length; i++) {
if(nums[i] > minHeap.peek()){
minHeap.poll();
minHeap.offer(nums[i]);
}
}
return minHeap.peek();
}
变式问题:在数组中找第K小的元素
我的分析:找第k小的数字,就是将数组“定性”的分成:较小的数和较大的数(保持较小的数部分容量为K),只需要在较小的数字中找到最大的数字,该数字就是第K小的数!
即,创建一个大小为K的大根堆,利用大根堆筛选出数组中较小的数,筛选完毕后堆顶元素就是第K小元素!(当元素大于大根堆堆顶时,该元素被筛除,当元素小于大根堆堆顶时,该元素保留,这样可以保证大根堆维护了数组中较小的数部分,代码也应该呼之欲出了!)
总结:
1.K多大就建立多大固定大小的堆;
2.找最大用小堆,找最小用大堆;
3.只有比堆顶更大(小)的元素才让进入堆。
2.堆排序
堆排序原理和堆查找原理正好相反,排序:升序用小堆,降序用大堆。
3.合并K个排序链表
题目见LeetCode23,描述为:给定一个链表数组,每个链表数组都已经按照升序排序,将链表合并到一个升序链表中,返回合并后的链表。
我的分析:合并链表的时候,需要比较对多条链表中较小的节点,将较小的节点插入合并链表表尾。
关键在于,如何找到多条链表中最小的节点?答:小根堆,具体来说是使用小根堆维护多条链表的头节点,选取最小的节点插入合并链表的表尾,由于是链表结构,因此需要将最小节点所归属的链表的下一个节点加入堆中,如下图所示:
比如:现在存在3条链表[1,4,5] [2,7,9] [3,6],起初小根堆维护了1、2、3个链表的表头,然后将最小的节点1加入到合并链表中。此时,需要比较的是4、2、3这三个节点,因此需要将4加入到堆中。
厘清思路,直接上代码!
public static ListNode mergeKLists(ListNode[] lists){
if(lists == null || lists.length == 0) return null;
//创建小根堆
PriorityQueue<ListNode> q = new PriorityQueue<>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
});
for (int i = 0; i < lists.length; i++) {
if(lists[i]!=null){
q.add(lists[i]);
}
}
ListNode dummy = new ListNode(-1);
ListNode tail = dummy;
while(!q.isEmpty()){
tail.next = q.poll();
tail = tail.next;
if(tail.next != null){
q.add(tail.next);
}
}
return dummy.next;
}
OK,《算法通关村第十四关——堆结构白银挑战笔记》结束,喜欢的朋友三联加关注!关注鱼市带给你不一样的算法小感悟!(幻听)
再次,感谢鱼骨头教官的学习路线!鱼皮的宣传!小y的陪伴!ok,拜拜,第十四关第三幕见!