[路飞]_程序员必刷力扣题: 合并K个升序链表

197 阅读1分钟

「这是我参与12月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

合并K个升序链表

力扣链接

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 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 = [[]]
输出: []

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i] 按 升序 排列
  • lists[i].length 的总和不超过 10^4

递归分治 合并

思路

  • 需要一个两个合并链表的函数mergeTwoList
  • 将数组中的链表两两合并
  • 处理边界值,lists没有值的时候返回null

mergeTwoList合并链表函数通过不断比较两链表的首节点大小,来找出当前最小节点,将最小节点拼接在新节点末尾,当一个链表完全拼接完毕后,剩余链表直接拼接在新链表后方,返回新链表的next

merge函数用来合并lists的第l位到第r位的链表,只要l!==r就会进行二分,继续递归调用merge,然后在最后用mergeTwoList来合并两个结果得到合并后的链表

var mergeTwoList = function (a, b) {
    if (!a || !b) {
        return a ? a : b
    }
    var node1 = a
    var node2 = b
    var newHead = new ListNode('head')
    var last = newHead
    while (node1 && node2) {
        if (node1.val < node2.val) {
            last = last.next = node1
            node1 = node1.next
        } else {
            last = last.next = node2
            node2 = node2.next
        }
    }
    last.next = node1 ? node1 : node2
    return newHead.next
}
var merge = function(lists,l,r){
    if(l===r) return lists[l]
    if(l>r) return null
    var mid = (l+r)>>1
    return mergeTwoList(merge(lists,l,mid),merge(lists,mid+1,r))
} 
var mergeKLists = function (lists) {
     return merge(lists,0,lists.length-1)
};

队列分治 合并

思路

上面通过递归来合并,这里我们也可以通过队列来合并

  • 把lists本身当做一个队列
  • 处理边界,len为0的时候直接返回null
  • 如果len>1,证明至少两个链表,分别从lists头部取出前两个节点进行合并,将合并结果push到lists尾部
  • 最后lists中只会剩下一个链表 返回lists[0]
var mergeTwoList = function (a, b) {
    ...
}
var mergeKLists = function (lists) {
    if (lists.length === 0return null
    while (lists.length > 1) {
        var node1 = lists.shift()
        var node2 = lists.shift()
        lists.push(mergeTwoList(node1, node2))
    }
    return lists[0]
};