今天分享的题目虽然是LeetCode hard 难度但是如果你看过一遍 他就变中等了,如果你实现两遍,它就变简单了。面试再也不怕这道高频题了。真希望遇到所有的hard题目都跟这题一样。
23. 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入: [ 1->4->5, 1->3->4, 2->6 ]
思路 :
- 每次遍历找出所有元素中最小的元素 ,可以使用使用hash结构快速获得某个链表的头部节点
- 创建一个大小固定的队列,将每个头结点放入到队列中,不断从队列中获取最小的元素,转换一下这不是就是最大堆。让出队元素的下一个元素添加进入最大堆中。
- 合并k个排序列表跟合并两个链表没有本质区别,只不过链表数量变多,借鉴归并排序的思想,不断合并两个有序列表
方法1
省略
方法2——最大堆
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> queue=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){
continue;
}
queue.add(lists[i]);
}
ListNode head=new ListNode(0);
ListNode res=head;
while(!queue.isEmpty()){
ListNode out=queue.poll();
if(out.next!=null){
queue.add(out.next);
}
head.next=out;
head=out;
}
return res.next;
}
}
对于java8 可以在比较器部分进行部分代码优化
如:
Queue<ListNode> heap = new PriorityQueue((l1, l2) -> l1.val - l2.val);
方法3——分治思想
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists==null||lists.length==0){
return null;
}
return merge(lists,0,lists.length-1);
}
private ListNode merge(ListNode[]lists,int left,int right){
if(left==right){
return lists[left];
}
int mid=left+(right-left)/2;
ListNode l1=merge(lists,left,mid);
ListNode l2=merge(lists,mid+1,right);
return mergeTwoLists(l1,l2);
}
private ListNode mergeTwoLists(ListNode l1,ListNode l2){
if(l1==null){
return l2;
}
if(l2==null){
return l1;
}
if(l1.val<l2.val){
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}
else{
l2.next=mergeTwoLists(l1,l2.next);
return l2;
}
}
}