LeetCode合并 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 = [[]]
输出:[]

解题思路

将所有值放进数组中排序,再新造ListNode

/**
 * 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 list = [];
    // 遍历所有链表
    for (let i = 0; i < lists.length; i++) {
        let node = lists[i];
        // 遍历链表并收集值
        while (node) {
            list.push(node.val);
            node = node.next;
        }
    }
    // 排序所有值
    list.sort((a, b) => a - b);
    // 创建结果链表的头节点
    const res = new ListNode();
    // 使用哑节点简化链表构建过程
    let now = res;
    // 构建排序后的链表
    for (let i = 0; i < list.length; i++) {
        now.next = new ListNode(list[i]);
        now = now.next;
    }
    // 返回合并和排序后的链表的头节点
    return res.next;
};

代码解释:

这段代码通过嵌套循环遍历了 lists 数组中的每个链表。lists 数组包含了 k 个链表,每个链表由 ListNode 对象组成。以下是遍历过程的详细解释

1.初始化外部循环:
使用 for 循环初始化索引 i,从 0 开始,直到 lists.length(即 k),因为 lists 数组的长度表示链表的数量。

2.获取当前链表:
在每次迭代中,lists[i] 获取 lists 数组中第 i 个链表的引用。

3.初始化内部循环:
let node = lists[i] 声明了一个变量 node,它指向当前链表的头节点。

4.遍历当前链表:
使用 while 循环遍历当前链表。循环条件是 node 不为 null,即链表尚未到达末尾。

5.收集节点值:
while 循环内部,node.val 获取当前节点的值,并将其添加到 list 数组中:list.push(node.val)

6.移动到下一个节点:
node = node.next 将 node 指针移动到链表的下一个节点。

7.继续遍历:
如果 node 仍然不是 null,则继续循环,重复步骤 5 和 6。

8.完成当前链表的遍历:
nodenull 时,while 循环结束,表示当前链表已遍历完毕。

9.移动到下一个链表:
for 循环的下一次迭代将 i 增加,并将 node 重置为下一个链表的头节点。

10.完成所有链表的遍历:
i 达到 lists.length 时,for 循环结束,表示所有链表都已遍历完毕。
示例:

假设 lists 包含以下链表:

lists[0]: 1 -> 3 -> 5
lists[1]: 2 -> 4
lists[2]: 6

遍历过程如下:

i = 0: node 从 1 遍历到 5,将值推入 list
i = 1: node 从 2 遍历到 4,将值推入 list
i = 2: node 从 6 开始,将其值推入 list
最终,list 数组包含所有链表的值 [1, 3, 5, 2, 4, 6]

这种嵌套循环的方法确保了所有 k 个链表中的所有节点都被访问并收集其值。

在这个 mergeKLists 函数中,res 是一个新创建的 ListNode 实例,用作合并后链表的头节点。然而,这个头节点最初是空的,它的 next 指针被初始化为 nullnow 指针用于在构建新链表的过程中遍历链表并添加新的节点。

解释 resnow

  • res 是合并后链表的头节点,但在初始化时,res.nextnull
  • now 是一个辅助指针,用于在链表构建过程中指向当前正在操作的节点。

构建链表的过程:
1.首先,创建一个空的头节点 res
2.使用 now 指针从 res 开始,逐个添加新节点到链表中。
3.在每次迭代中,将 now.next 设置为一个包含当前值的新 ListNode,然后将 now 移动到这个新节点。

为什么返回 res.next 而不是 now.next:
在链表构建的最后,now 指针位于链表的末尾(最后一个节点)。如果返回 now.next,这将返回链表的最后一个节点之后的 null 指针,这不是链表的有效部分。
res 是链表的头节点,即使在迭代过程中 now 移动了,res 始终指向链表的开始。因此,res.next 是链表的第一个有效节点,这是我们想要返回的。

总结:
返回 res.next 是因为我们想要返回合并后链表的头节点,它是链表的第一个有效节点。now 指针仅用于遍历和构建链表,而 res 始终保持对链表头部的引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值