輸入:k個有序鏈表lists
輸出:一個有序鏈表
規則:將這個k個有序鏈表合併成一個有序鏈表
分析:在鏈表中合併兩個有序鏈表爲一個有序鏈表是基本功。最開始的直覺是我們可以將lists[0]和lists[1]合併得到 result,result再和lists[2]合併,一直 到最後合併完成。這個每個節點 都要和其他鏈表中的一個節點比較,所以時間複雜度是O(k*n)。n是所有節點的個數總和。
public ListNode mergeKLists(ListNode[] lists) {
ListNode mergeHead = new ListNode(0);
ListNode node = mergeHead;
while(true){
ListNode minHead = null;
int idx = -1;
for (int i=0;i<lists.length;i++) {
if (lists[i] != null) {
if(minHead == null || minHead.val> lists[i].val){
minHead = lists[i];
idx = i;
}
}
}
if(minHead==null){
break;
}
lists[idx] = lists[idx].next;
node.next = new ListNode(minHead.val);
node = node.next;
}
return mergeHead.next;
}
分析2:可以使用堆排序解決上面的比較問題。在堆中維護的是每個鏈表 表頭元素。移除最小的節點,插入鏈表中的下一個節點。時間複雜度O(nlogk)。
public ListNode mergeKLists(ListNode[] lists) {
ListNode dummy = new ListNode(-1);
ListNode current = dummy;
PriorityQueue<ListNode> heap = new PriorityQueue<ListNode>(new Comparator<ListNode>(){
public int compare(ListNode i1,ListNode i2){
return i1.val-i2.val;
}
});
//把頭節點放進去
for(ListNode node: lists){
if(node!=null){
heap.offer(node);
}
}
while(!heap.isEmpty()){
ListNode node = heap.poll();
if(node.next != null){
heap.offer(node.next);
}
current.next = node;
current = current.next;
}
return dummy.next;
}
分析3:使用分治法。先解決lists[0]和lists[1],lists[2]和lists[3]…,合併完成只剩下。下一輪解決lists[0]和lists[2],lists[4]和lists[6]…,合併完成剩下…一直到最後只剩下lists[0],就是結果。
public ListNode mergeKLists(ListNode[] lists) {
for(int interval =1 ;interval<lists.length; interval=interval*2){
for(int j = 0;j+interval<lists.length;j = j + 2*interval){
lists[j] = mergeTwoLists(lists[j],lists[j+interval]);
}
}
return lists.length>0?lists[0]:null;
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1);
ListNode currentNode = dummy;
while(l1!=null && l2!=null){
if(l1.val > l2.val){
currentNode.next = l2;
l2 = l2.next;
}else{
currentNode.next = l1;
l1 = l1.next;
}
currentNode = currentNode.next;
}
while(l1!=null){
currentNode.next = l1;
l1 = l1.next;
currentNode = currentNode.next;
}
while(l2!=null){
currentNode.next = l2;
l2 = l2.next;
currentNode = currentNode.next;
}
return dummy.next;
}
複雜度分析。最外層循環有次。mergeTwoLists函數的時間複雜度是n=兩個列表節點個數的和。最後合起來是O(nlogk)。這裏的n是所有鏈表節點個數和。