题意描述:
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
解题思路:
Alice: 我想起来你以前反转链表的做法了。
Bob: 你是说先把所有节点的值都存起来,然后排序,然后再重新塞到 原来的链表里面。
Alice: 对啊,不过这里面没有现成的链表可以填充啊 ?
Bob: 那就把那 k 个链表首尾相连呗,反正节点的数量对得上,最后返回头结点就是了。
Alice: emm, 这样的时间复杂度应该是O(n * log n) + O(n)
, 然后空间复杂度应该是 O(n)
,空间复杂度有点高诶。
Bob: 那就直接合并 k 个有序链表吧, 每次从所有的链表头 找到值最小的那一个,接上去,然后一直接下去就好了。
Alice: 时间复杂度呢 ?
Bob: 时间复杂度应该是O(k N)
k
是链表个数,N
是节点个数。不过空间复杂度倒是很小, O(1)
。
Alice: 你说这两个方法哪个更快呀 ?
Bob: 当然是 O(n log n)
啊,一般而言,空间复杂度越高,时间复杂度就会稍微低一些。空间换时间嘛。
Alice: 😎😎
代码:
Python 方法一: 使用库函数和辅助数组排序,时间复杂度O(n * log n),空间复杂度 O(n)。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
data = []
headAndTails = []
for head in lists:
if head == None:
# 有空链表直接跳过
continue
headAndTails.append(head)
node = head
while node.next != None:
data.extend([node.val])
node = node.next
data.extend([node.val])
headAndTails.append(node)
for x in range(1, len(headAndTails)-1, 2):
# 将lists中的链表首尾相连
headAndTails[x].next = headAndTails[x+1]
if len(headAndTails) == 0:
return None
data.sort()
# 排序
node = headAndTails[0]
for x in data:
# 将排序后的结果填充回链表
node.val = x
node = node.next
return headAndTails[0]
Java 方法一: ArrayList 排序外部数组,时间复杂度O(n*log n) 空间复杂度 O(n)。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode node = new ListNode(0);
int tot = 0;
List<ListNode> headAndTails = new ArrayList<ListNode>();
List<Integer> data = new ArrayList<Integer>();
for(int i=0; i<lists.length; ++i){
if(lists[i] == null){ // 跳过空链表
continue;
}
node = lists[i];
headAndTails.add(node);
while(node.next != null){
data.add(node.val);
node = node.next;
}
data.add(node.val);
headAndTails.add(node);
}
if(headAndTails.size() == 0){ // lists 中的链表全是空链表
return null;
}
for(int i=1; i<headAndTails.size()-1; i+=2){ // 将lists中的链表尾首相连
headAndTails.get(i).next = headAndTails.get(i+1);
}
Collections.sort(data); // 排序外部数组
node = headAndTails.get(0); // 将排序后的结果填充进链表
for(int i=0; i<data.size(); ++i){
node.val = data.get(i);
node = node.next;
}
return headAndTails.get(0);
}
}
Python 方法二: 直接合并 =》超时。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
head = ListNode(0);
tot = 0
# 统计节点总数
for node in lists:
while node != None:
tot += 1
node = node.next
# 合并所有链表节点
cnt = 0
node = head
while cnt < tot:
node.next = self.getNextNode(lists)
node = node.next
cnt += 1
return head.next
def getNextNode(self, lists):
minValue = 2 ** 31 - 1
minNode = None
for node in lists:
if node != None and node.val < minValue:
minValue = node.val
minNode = node
for x in range(len(lists)):
if lists[x] != None and lists[x] == minNode:
lists[x] = lists[x].next
break
return minNode
Java 方法二: 直接合并,时间复杂度O(n^2),空间复杂度O(1)。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int tot = 0;
ListNode head = new ListNode(0);
ListNode node = new ListNode(0);
// 统计节点总个数
for(int i=0; i<lists.length; ++i){
node = lists[i];
while(node != null){
tot += 1;
node = node.next;
}
}
//System.out.println(lists.length);
node = head;
int cnt = 0;
while(cnt < tot){
node.next = get(lists);
node = node.next;
cnt += 1;
}
return head.next;
}
public ListNode get(ListNode[] lists){
int minValue = Integer.MAX_VALUE;
ListNode retNode = null;
for(int i=0; i<lists.length; ++i){
if(lists[i] != null && lists[i].val < minValue){
minValue = lists[i].val;
retNode = lists[i];
}
}
for(int i=0; i<lists.length; ++i){
if(lists[i] != null && lists[i] == retNode){
lists[i] = lists[i].next;
break;
}
}
return retNode;
}
}
易错点:
- 一些测试样例:
[[1,4,5],[1,3,4],[2,6]]
[[1,4,5],[],[2,6]]
[[],[],[2,6]]
[[],[]]
[[1],[2]]
- 答案:
[1,1,2,3,4,4,5,6]
[1,2,4,5,6]
[2,6]
[]
[1,2]
总结: