Merge k Sorted Lists
题目
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
分析
这道题目LeetCode给出的难度是hard
。如果不考虑复杂度,个人感觉这道题的难度达不到hard
。
这道题相比之前Merge Two Sorted Lists,难度有所上升。这道题要合并的是k
个有序链表。假设每个链表的长度都是m
,那么合并两个链表的时间复杂度是O(m)
。
其中一种解法就是参照之前合并两个有序链表的做法,不断取出k
个链表中的最小值,但是每次都得比较k
个元素,时间复杂度较高。
另一种解法是合并前两个链表为一个链表,然后不断地将新链表和下一个链表合并得到新链表。即:
ListNode result = lists[0];
for (int i = 1; i < lists.length; i++) {
result = mergeTwoLists(result, lists[i]);
}
return result;
但是该解法的时间复杂度也不是很理想。时间复杂度大概为 O ( k 2 ∗ m ) O(k^2*m) O(k2∗m)(合并最后两个链表的时间复杂度为 O ( k m ) O(km) O(km)而不是 O ( m ) O(m) O(m))。
二路归并解法:
该方法参照二路归并排序的思路。
将给出的k个链表每两个链表合并为一个新的链表。然后对新产生的所有链表重复该该合并操作直到剩下一个链表为止。剩下的那个链表就是最终的链表。
该方法的时间复杂度较为理想,大概是
O
(
m
∗
k
∗
l
o
g
k
)
O(m*k*logk)
O(m∗k∗logk)。
代码如下
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
private ListNode virtualNode = new ListNode(0); // 虚拟节点
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
ListNode result = null;
int tempLength = lists.length;
while (tempLength > 1) {
int j = tempLength / 2 + tempLength % 2;
for (int i = 0; i < tempLength / 2; i++) {
ListNode temp = mergeTwoLists(lists[i], lists[i + j]);
lists[i] = temp;
}
tempLength = j;
}
return lists[0];
}
// 合并两个有序链表的方法
private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newList = virtualNode;
ListNode tempNode = newList; // 临时节点
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
tempNode = tempNode.next = l1;
l1 = l1.next;
} else {
tempNode = tempNode.next = l2;
l2 = l2.next;
}
}
if (l1 == null) {
tempNode.next = l2;
} else {
tempNode.next = l1;
}
return newList.next;
}
}