LeetCode热题(JS版)- 23. 合并 K 个升序链表

69 阅读1分钟

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

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

示例 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

思路:数组二分,递归归并

这道题目可以用分治法来解决,具体来说,我们可以将链表数组分成两个子数组,分别递归地将它们合并成一个有序链表,然后再将这两个有序链表合并成一个有序链表。 为了方便起见,我们可以将链表数组的下标范围 [l,r][l, r] 定义为当前要合并的区间,然后递归地将它分成两个子区间 [l,m][l, m][m+1,r][m+1, r],其中 m=(l+r)/2m=\lfloor(l+r)/2\rfloor。然后递归地将两个子区间合并成一个有序链表,并返回合并后的链表头指针。 合并两个有序链表的过程可以使用迭代或递归来实现。这里我们使用迭代的方式来实现,具体来说,我们可以定义一个虚拟头节点 dummy,然后遍历两个链表,将它们的节点按照升序依次添加到 dummy 的后面,最后返回 dummy 的下一个节点即可。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

const mergeTwoLists = (l: ListNode | null, r: ListNode | null) => {
    const dummy = new ListNode();
    let p: ListNode | null = dummy;

    while(l && r) {
        if(l.val < r.val) {
            p.next = l;
            l = l.next
        } else {
            p.next = r;
            r = r.next
        }
        p = p.next;
    }

    p.next = l ? l : r;
    return dummy.next;
}

const merge = (lists: Array<ListNode | null>, start: number, end: number) => {
    if(start === end) return lists[start];// 奇数的中间

    const mid = Math.floor((end + start) / 2);
    const left = merge(lists, start, mid);
    const right = merge(lists, mid + 1, end);

    return mergeTwoLists(left, right)
}

function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
    if(!lists || !lists.length) return null;
    
    return merge(lists, 0, lists.length - 1)
};

image.png

总结

  • 时间复杂度 假设链表数组的长度为 kk,每个链表的平均长度为 nn。在递归过程中,每个链表节点最多被访问一次,因此时间复杂度为 O(knlogk)O(kn\log k)
  • 空间复杂度为 O(logk)O(\log k),即递归栈的深度。