LeetCode 23 Merge k Sorted Lists (Tag:Linked List Difficulty:Hard)

165 阅读2分钟

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

前言

关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!

题目描述

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

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

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

链接:leetcode-cn.com/problems/me…

题解

这道题目是一道典型的分治题目。首先要理解什么是分治策略,看一下概念。

分治策略是:对于一个规模为 n 的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为 k 个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。

知道了分治法的概念之后,再加上 leetcode 21合并两个有序链表的前提,所以这道合并 k 个有序链表的题目就是将这 k 个链表分解为多个 2 个有序链表合并的问题。分解的方法是通过递归,每次将链表分为两部分,最后将这两部分合成一个有序链表。

递归终止条件是,长度为 0, 1, 2 的时候,都可以返回一个链表。

具体代码如下,时间复杂度为 O(kn×logk)

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
var mergeKLists = function(lists) {
    const n = lists.length
    if (n === 0) return null
    if (n === 1) return lists[0]
    if (n === 2) return merge2List(lists[0], lists[1])
    let mid = Math.floor(n / 2)
    let list1 = mergeKLists(lists.slice(0, mid))
    let list2 = mergeKLists(lists.slice(mid))
    return merge2List(list1, list2)
    
};

var merge2List = (list1, list2) => {
    let head = new ListNode(0)
    let point = head
    while (list1 && list2) {
        if (list1.val < list2.val) {
            point.next = list1
            list1 = list1.next
        } else {
            point.next = list2
            list2 = list2.next
        }
        point = point.next
    }
    if (list1) point.next = list1
    if (list2) point.next = list2
    return head.next
}