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

相关推荐
杰九2 小时前
【算法题】46. 全排列-力扣(LeetCode)
算法·leetcode·深度优先·剪枝
manba_2 小时前
leetcode-560. 和为 K 的子数组
数据结构·算法·leetcode
liuyang-neu2 小时前
力扣 11.盛最多水的容器
算法·leetcode·职场和发展
忍界英雄2 小时前
LeetCode:2398. 预算内的最多机器人数目 双指针+单调队列,时间复杂度O(n)
算法·leetcode·机器人
Tisfy3 小时前
LeetCode 2398.预算内的最多机器人数目:滑动窗口+单调队列——思路清晰的一篇题解
算法·leetcode·机器人·题解·滑动窗口
.普通人3 小时前
c语言--力扣简单题目(回文链表)讲解
c语言·leetcode·链表
程序猿练习生3 小时前
C++速通LeetCode简单第18题-杨辉三角(全网唯一递归法)
c++·算法·leetcode
DdddJMs__1353 小时前
C语言 | Leetcode C语言题解之题409题最长回文串
c语言·leetcode·题解
学习使我变快乐6 小时前
C++:用类实现链表,队列,栈
开发语言·c++·链表
重生之我要进大厂7 小时前
LeetCode 876
java·开发语言·数据结构·算法·leetcode