合併兩個有序鏈表算法
將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是經過拼接給定的兩個鏈表的全部節點組成的。
示例:
輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4
合併K個排序鏈表數組
合併 k 個排序鏈表,返回合併後的排序鏈表。請分析和描述算法的複雜度。
示例:
輸入:
[
1->4->5,
1->3->4,
2->6
]
輸出: 1->1->2->3->4->4->5->6
從題目就能看出來 明顯是一道題,一道一道來。函數
首先題目給了鏈表節點構造函數this
/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /**
第一題仍是很簡單的,new一個新節點,而後不斷比較兩個參數鏈表的當前指向節點的值,而後新節點指向較小的那個,而後更新指針指向。常見的指針題,代碼以下指針
/** * @param {ListNode} l1 * @param {ListNode} l2 * @return {ListNode} */ var mergeTwoLists = function(l1, l2) { let head = result = new ListNode(null) while(l1 && l2) { if(l1.val < l2.val) { result.next = l1 l1 = l1.next } else { result.next = l2 l2 = l2.next } result = result.next } result.next = l1 || l2 return head.next };
先定義兩個指針指向同一個新節點來看成虛擬的頭,其中一個指針把鏈表串起來,另外一個用來看成返回值。
時間複雜度的話由於遍歷了兩個鏈表,因此是O(n + m)code
再看第二題,其實就是複雜版的上一題,第一反應是對鏈表數組循環調用上一題的函數,代碼也很簡單排序
var merge2Lists = function(l1, l2){ //... } for(var i = 1; i < lists.length; i++) { temp = merge2Lists(temp, lists[i]) }
時間複雜度是O(n^2)。leetcode
上面這種解法,簡單易懂,可是很明顯數組中的鏈表越靠前,遍歷的次數就越多,用分治的思想來考慮會更快,合併k個鏈表變成k/2個合併2個有序鏈表,再變k/4個...時間複雜度是O(nlogk)
代碼get
/** * @param {ListNode[]} lists * @return {ListNode} */ var mergeKLists = function(lists) { let n = lists.length if(!n) return null let merge = function(begin, end) { if(begin === end) return lists[begin] let mid = (begin + end) >> 1 let l1 = merge(begin, mid) let l2 = merge(mid + 1, end) return mergeTwoLists(l1, l2) } return merge(0, n - 1) };