返回

轻轻松松搞定LeetCode第138题:复制带随机指针的链表

前端

征服 LeetCode 第 138 题:揭秘「复制带随机指针的链表」的神秘面纱

导言

探索 LeetCode 第 138 题,我们将踏上一段深入理解复制包含随机指针的链表的迷人旅程。这条道路上,我们将携手共进,发掘这一编程难题中的奥秘,并掌握一种高效、优雅的解决方案。

原地克隆:精妙绝伦的解决方案

破解第 138 题的关键在于 「原地克隆」 法。这种方法以其精妙的策略和高效的性能,在众多的解题方案中脱颖而出。

1. 插入克隆节点:复制的初始步骤

旅程伊始,我们将沿着原始链表穿梭,在每个原始节点后面巧妙地插入其克隆节点。这一步为后续的操作奠定了坚实的基础。

// 插入克隆节点
let current = head;
while (current) {
  let next = current.next;
  current.next = new Node(current.val, null, null);
  current.next.next = next;
  current = next;
}

2. 修正随机指针:赋予克隆生命

有了克隆节点,下一步便是赋予它们生命,也就是修正它们指向的随机节点。我们沿着链表游走,逐一将克隆节点的随机指针指向原始链表中对应的随机节点的克隆节点。

// 修正随机指针
current = head;
while (current) {
  if (current.random) {
    current.next.random = current.random.next;
  }
  current = current.next.next;
}

3. 拆分链表:完成杰作

最后,我们巧妙地将克隆链表和原始链表拆分,完成这幅杰作。克隆链表将成为最终的答案,而原始链表将回归其原貌。

// 拆分链表
dummy = new Node(0, null, null);
current = dummy;
originalCurrent = head;
clonedCurrent = head.next;

while (originalCurrent) {
  current.next = originalCurrent;
  originalCurrent = originalCurrent.next;
  current = current.next;

  current.next = clonedCurrent;
  clonedCurrent = clonedCurrent.next;
  current = current.next;
}

// 返回克隆链表的头结点
return dummy.next;

总结:从难题到解决方案

通过「原地克隆」法,我们巧妙地解决了 LeetCode 第 138 题中复制带随机指针的链表的难题。这一方法以其高效和优雅,展示了编程艺术的魅力。愿这趟探索之旅,启迪你的编程思维,助力你征服更多编程难题。

常见问题解答

1. 克隆链表和原始链表有什么区别?

克隆链表是一个新创建的链表,它的结构与原始链表完全相同,但节点是不同的。原始链表保持不变。

2. 「原地克隆」法的时间复杂度和空间复杂度是多少?

「原地克隆」法的时间复杂度为 O(n),其中 n 是链表的长度。空间复杂度为 O(1),因为我们没有使用额外的空间来存储中间结果。

3. 随机指针的目的是什么?

随机指针将链表中的节点与链表中的另一个随机节点连接起来。它为链表添加了额外的复杂性,使得复制变得更具挑战性。

4. 这种方法适用于所有类型的链表吗?

是的,这种方法适用于所有类型的链表,包括带有循环和自相交的链表。

5. 有没有替代的解决方法?

除了「原地克隆」法,还可以使用哈希表或深度复制等方法来复制带随机指针的链表。然而,这些方法通常需要额外的空间或更复杂的操作。