问题描述;
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法一:
暴力求解,遍历K个链表,找到其中头结点最小的那个,将该节点插到合并链表的尾部,该节点后移。重复上述工作直到数组中k个排序链表都为null。
实现代码如下:
public ListNode mergeKLists(ListNode[] lists) {
ListNode head = new ListNode(-1);
ListNode cur = head;
boolean flag = true;//当所有的结点都遍历完成后 置为false
while(flag){
flag = false;
int minValue = Integer.MAX_VALUE;
for(int i = 0; i < lists.length; i++){
if(lists[i] == null){
continue;
}
flag = true;
minValue = lists[i].val < minValue ? lists[i].val : minValue;
}
for(int i = 0; i < lists.length; i++){
if(lists[i] == null){
continue;
}
if(minValue == lists[i].val){
cur.next = lists[i];
lists[i] = lists[i].next;
cur = cur.next;
}
}
}
return head.next;
}
假设每个链表长度为N,则上述方法的时间复杂度为O(k*k* N),由于总共K*N个元素,每个元素都需要经过K轮循环。
解法二:
使用归并排序的思想,将lists数组中的链表两两合并,如此最终剩下一个大链表。为了避免开辟新空间,总是将当前数组的两端依次合并,并将结果保存在前面的位置上。该方式下每个节点不需要比较K次,只需log(K)即可。因此时间复杂度降为O(log(k) * k * N)
实现代码如下:
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = new ListNode(-1);
ListNode cur = head;
ListNode cur1 = l1;
ListNode cur2 = l2;
while(cur1 != null && cur2 != null){
if(cur1.val < cur2.val){
cur.next = cur1;
cur1 = cur1.next;
}else{
cur.next = cur2;
cur2 = cur2.next;
}
cur = cur.next;
}
if(cur1 != null){
cur.next = cur1;
}else{
cur.next = cur2;
}
return head.next;
}
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0){
return null;
}
for(int end = lists.length - 1; end > 0; end = end / 2){
step(lists, 0, end);
}
return lists[0];
}
public void step(ListNode[] lists, int start, int end){
while(start < end){
lists[start] = mergeTwoLists(lists[start], lists[end]);
start++;
end--;
}
}