https://leetcode-cn.com/problems/merge-k-sorted-lists/
这道题的前置题目是合并两个排序链表 https://leetcode-cn.com/problems/merge-two-sorted-lists/
- 暴力法
将所有链表合并后排序
时间复杂度O(NlogN) N= 总节点数量
空间复杂度O(N)
- 归并
基于合并两个排序链表,我们可以做到循环依次合并两个链表,将问题转换为合并两个排序链表k-1次;
由于每次合并前后,被合并链表和所得链表的结构(有序性)不变,因此可以采用分治、归并的方式,对每两个链表进行合并,再将合并后的结果继续按此逻辑每两个相合并
时间复杂度:O(NlogK)
举例图示:
0 1 2 3 4 5 6
01 23 45 6
0123 456
0123456
我的代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 1) return lists[0];
int distance = 1;
int sumDistance = 0;
ListNode head = null;
while (condition(distance, lists.length)) {
for (int i = 0; i < lists.length; i += (distance + 1 + sumDistance)) {
if (i + distance < lists.length) {
head = mergeTwoLists(lists[i], lists[i + distance]);
lists[i] = head;
}
}
sumDistance += distance;
distance *= 2;
}
return head;
}
boolean condition(int distance, int length) {
//distance = 最后一次合并结果 * 2 ,所以临界值判断需要除以2
//由于两两合并,所以一旦超过一半必然归并完成
return length % 2 == 0 ? (distance / 2) < length / 2 : (distance / 2) < (length + 1) / 2 ;
}
ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0);
ListNode preHead = res;
ListNode cur1 = l1;
ListNode cur2 = l2;
while (cur1 != null || cur2 != null) {
if (cur1 != null && cur2 != null) {
if (cur1.val > cur2.val) {
res.next = new ListNode(cur2.val);
cur2 = cur2.next;
} else {
res.next = new ListNode(cur1.val);
cur1 = cur1.next;
}
} else if (cur1 == null && cur2 != null) {
res.next = new ListNode(cur2.val);
cur2 = cur2.next;
} else if (cur2 == null && cur1 != null) {
res.next = new ListNode(cur1.val);
cur1 = cur1.next;
}
res = res.next;
}
return preHead.next;
}
}
改进思路:
由于我的实现需要计算每次合并的两个链表的下标,这个过程比较麻烦;看了其他解答后,发现这样一种解决方式
/**
* 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 len = lists.length;
if (len == 0) {
return null;
}
// 将n个链表以中间为对称,合并,即合并
while(len>1) {
for (int i=0; i<len/2; i++) {
lists[i] = mergeTwoListsForK(lists[i], lists[len-1-i]);
}
len = (len+1)/2;
}
return lists[0];
}
private ListNode mergeTwoListsForK(ListNode l1, ListNode l2) {
ListNode head = new ListNode(-1);
ListNode p = head;
while(l1 != null && l2 != null) {
if (l1.val < l2.val) {
p.next = l1;
l1 = l1.next;
} else {
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
if (l1 != null) {
p.next = l1;
} else if (l2 != null) {
p.next = l2;
}
return head.next;
}
}
这个思路更方便解答,省却了计算偏移的过程
0 1 2 3 4 5 6
06 15 24 3
063 1524
0631524