LeetCode合并 k个升序链表

问题:

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

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

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]

输出:[1,1,2,3,4,4,5,6]

解释:链表数组如下:

javascript 复制代码
[
  1->4->5,
  1->3->4,
  2->6
]

将它们合并到一个有序链表中得到。

javascript 复制代码
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []

输出:[]

示例 3:

输入:lists = [[]]

输出:[]

解题思路

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

javascript 复制代码
/**
 * 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 包含以下链表:

javascript 复制代码
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 始终保持对链表头部的引用。

相关推荐
笑口常开xpr1 小时前
数 据 结 构 进 阶:哨 兵 位 的 头 结 点 如 何 简 化 链 表 操 作
数据结构·链表·哨兵位的头节点
dying_man8 小时前
LeetCode--24.两两交换链表中的结点
算法·leetcode
yours_Gabriel8 小时前
【力扣】2434.使用机器人打印字典序最小的字符串
算法·leetcode·贪心算法
GGBondlctrl9 小时前
【leetcode】递归,回溯思想 + 巧妙解法-解决“N皇后”,以及“解数独”题目
算法·leetcode·n皇后·有效的数独·解数独·映射思想·数学思想
凤年徐13 小时前
【数据结构初阶】单链表
c语言·开发语言·数据结构·c++·经验分享·笔记·链表
枫景Maple20 小时前
LeetCode 2297. 跳跃游戏 VIII(中等)
算法·leetcode
緈福的街口1 天前
【leetcode】3. 无重复字符的最长子串
算法·leetcode·职场和发展
小刘不想改BUG1 天前
LeetCode 70 爬楼梯(Java)
java·算法·leetcode