一、題目描述
給你一個鏈表數組,每個鏈表都已經按升序排列。
請你將所有鏈表合并到一個升序鏈表中,返回合并后的鏈表。
示例 1:
輸入:lists = [[1,4,5],[1,3,4],[2,6]]
輸出:[1,1,2,3,4,4,5,6]
解釋:鏈表數組如下:
[
1->4->5,
1->3->4,
2->6
]
將它們合并到一個有序鏈表中得到。
1->1->2->3->4->4->5->6
示例 2:
輸入:lists = []
輸出:[]
示例 3:
輸入:lists = [[]]
輸出:[]
二、解題思路
分治思想
- 將大問題劃分為兩個到多個子問題
- 子問題可以繼續拆分成更小的子問題,直到能夠簡單求解
- 如有必要,將子問題的解進行合并,得到原始問題的解
分而治之,分到區間內只有一個鏈表,合并區間;所以問題就轉化為了合并兩個有序鏈表。
2.1 合并兩個有序鏈表
leetcode21.合并兩個有序鏈表
將兩個升序鏈表合并為一個新的 升序 鏈表并返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。
思路
遞歸函數返回
- 更小的那個鏈表節點,并把它剩余節點與另一個鏈表再次遞歸
- 返回之前更新此節點的 next(原本的next需要更新為歸回來的那個更小的鏈表節點)
代碼實現
/**
* Leetcode21: 合并兩個有序鏈表【遞歸】
* @param list1
* @param list2
* @return
*/
public static ListNode mergeTwoSortedListsRecursion(ListNode list1, ListNode list2) {
if (list1 == null) {
return list2;
}
if (list2 == null) {
return list1;
}
if (list1.val < list2.val) {
ListNode listNode = mergeTwoSortedListsRecursion(list1.next, list2);
list1.next = listNode;
return list1;
} else {
ListNode listNode = mergeTwoSortedListsRecursion(list1, list2.next);
list2.next = listNode;
return list2;
}
}
遞歸執行流程
遞歸合并兩個有序鏈表.png
2.2 把k個鏈表依次拆解
/**
* 合并k個升序鏈表
* @param lists
* @return
*/
public static ListNode mergeKListsRecursion(ListNode[] lists) {
if (lists == null) {
return null;
}
return split(lists, 0, lists.length - 1);
}
/**
* 把k個鏈表依次拆解,拆到只剩下一個,兩兩合并
* @param lists
* @param i
* @param j
* @return
*/
public static ListNode split(ListNode[] lists,int i,int j) {
// 拆到數組中只剩下一個元素時終止遞歸 此時i和j重合
if (i == j) {
return lists[i];
}
int mid = (i+j) >>> 1;
ListNode left = split(lists, i, mid);
ListNode right = split(lists, mid+1, j);
//合并后的鏈表
ListNode listNode = mergeTwoSortedListsRecursion(left, right);
return listNode;
}
拆解鏈表遞歸執行流程
鏈表拆分遞歸流程.png