215. 数组中的第K个最大元素 - 力扣(LeetCode)
给定整数数组 nums
和整数 k
,请返回数组中第 **k**
个最大的元素。
请注意,你需要找的是数组排序后的第 k
个最大的元素,而不是第 k
个不同的元素。
你必须设计并实现时间复杂度为 O(n)
的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
提示:
1 <= k <= nums.length <= 105
-104 <= nums[i] <= 104
第 K 个最大元素,就是在数组排序以后,后 K 个元素中最小的元素。因此,我们可以维护一个有 K 个元素的小根堆:
public int findKthLargest(int[] nums, int k)
{
//创建一个容量为 k 的小根堆
PriorityQueue<Integer> minHeap = new PriorityQueue<>(k);
//将前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]);
}
}
//返回堆顶元素,即第k大元素
return minHeap.peek();
}
注:PriorityQueue
中元素的默认排序是升序排序。这意味着队列头部的元素(堆顶元素)将是最小的元素。如果需要改变排序顺序,例如创建大根堆,可以通过传递一个比较器Comparator.reverseOrder()
来实现降序排列。
找第K大用小根堆,找第K小用大根堆。
就本题来说:
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
将所有节点放入小根堆
public static ListNode mergeKLists(ListNode[] lists)
{
//创建一个小根堆,并设置比较器(这是必须的,不能采用默认的升序)
PriorityQueue<ListNode> minHeap = new PriorityQueue<>((ListNode a,ListNode b)->(a.val - b.val));
//将所有节点放入小根堆
for(ListNode list : lists)
{
while(list != null)
{
minHeap.offer(list);
list = list.next;
}
}
//答案链表的虚拟头结点
ListNode dummy = new ListNode(-1);
//尾插法,保证升序
ListNode tail = dummy;
while (!minHeap.isEmpty())
{
tail.next = minHeap.poll();
tail = tail.next;
}
tail.next = null; //手动截断,否则会在输出方法中陷入死循环
return dummy.next;
}
先将每个链表的头节点放入小根堆,出来一个再放入下一个,这样可以维持一个小堆,减少堆的自我排序时间,也将原先的空间复杂度O(N)
优化到O(k)
public static ListNode mergeKLists_2(ListNode[] lists)
{
//创建一个小根堆,并设置比较器(这是必须的,不能采用默认的升序)
PriorityQueue<ListNode> minHeap = new PriorityQueue<>((ListNode a,ListNode b)->(a.val - b.val));
//先将每个链表的头节点放入小根堆
for(ListNode list : lists)
if (list != null)
minHeap.offer(list);
//答案链表的虚拟头结点
ListNode dummy = new ListNode(-1);
//尾插法,保证升序
ListNode tail = dummy;
while (!minHeap.isEmpty())
{
ListNode node = minHeap.poll();
tail.next = node;
tail = tail.next;
//把剩下的结点放入小根堆
if(node.next != null)
minHeap.offer(node.next);
}
tail.next = null; //手动截断,否则会在输出方法中陷入死循环
return dummy.next;
}