题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4
思路
采用分治合并的思想解决
- 首先写一个方法合并两个链表
- 将数组中的链表进行配对(两个一组):第一轮合并以后, k 个链表被合并成了 k/2个链表,平均长度为2n/k,然后是k/4个链表, k/8个链表等等;如下图所示:
代码
/**
* 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) {
return merge(lists,0,lists.length-1);
}
//将一个数组中的多个链表划分为多个组(每个组两个链表),这些组分别进行合并
/*
lists:需要合并的链表数组
first:当前链表数组最左边的下标(如:0)
last:当前链表数组最右边的下标(如:lists.length-1)
*/
public ListNode merge(ListNode[] lists,int first,int last){
//如果最左边的下标到底最右边(证明已经得到需要合并的两个链表中的其中一个链表)
if(first == last){
return lists[first];
}
//如果最左边大于最右边下标(证明此时是匹配不上两个链表,所以只能为null)
if(first > last){
return null;
}
//>> :右移运算符,num >> 1,相当于num除以2
int mid = (first+last) >> 1;
//进行递归运算
return mergeTwoLists(merge(lists,first,mid),merge(lists,mid+1,last));
}
//合并两个链表的方法
public ListNode mergeTwoLists(ListNode a,ListNode b){
//如果a为空,则把整个b以后的元素全部合并(b为空同理)
if(a==null || b==null){
return a!=null ? a : b;
}
//初始化一个节点值为0的空节点head来保存合并之后链表的头部
ListNode head = new ListNode(0);
//将tail指向head...
ListNode tail = head,aPtr=a,bPtr=b;
//当aPtr和bPtr都不为空时退出循环
while(aPtr!=null && bPtr!=null){
//如果aPtr当前的值小于bPtr,则将aPtr的值赋予tail
if(aPtr.val < bPtr.val){
//将aPtr的值赋予taail
tail.next = aPtr;
//aPtr往后移动一位
aPtr = aPtr.next;
}else{//与if里面的类似
tail.next = bPtr;
bPtr = bPtr.next;
}
//将当前tail的内容指向下一个结点
tail = tail.next;
}
//最后两个链表中会剩下一个值(有一个链表不为空),将该值赋予当前tail的下一个结点
tail.next = (aPtr!=null ? aPtr : bPtr);
//将head返回,去除头节点的内容后
return head.next;
}
}
代码说明
见注释。。。