一、前言
前段时间在leetcode刷到一道复制带随机指针的链表的题目(网址在这),我用的是很傻的方法过的,看了评论区后发现有个很好的方法,我用他的思路自己实现了一下。因为感觉很妙,所以记录一下他这种方法。
二、题目详情
原题网址链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer
以下是复制的题目:
- 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
- 要求返回这个链表的 深拷贝。
- 我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
- val:一个表示 Node.val 的整数。
- random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
三、思路
1、我开始的做法
用一个数组记录每个节点的random指针指向的节点的位置,第1个节点的位置记录在数组位置1。
如下图:
位置1存储的数字是第1个节点的随机节点在链表中的位置,位置2存储的数字是第2个节点的随即节点在链表中的位置,以此类推,数字为0代表随机节点指向null。
这种做法实现后时间复杂度挺大的,还很复杂,也不是我想讲的。
2、优秀的做法
① 思路
原先的链表,这里没画出随机指针:
- 先把所有克隆的节点挂到原节点的后面。
- 再把克隆(copy)节点的random的节点赋值。因为画起来比较麻烦,因此就用字来讲:
- 遍历当前链表,遍历的节点都不是克隆(copy)的节点,而是原节点。
- 通过当前节点,找到它的随机节点,然后把这个随机节点后面那个节点(当前随机节点的克隆节点)赋值给当前节点的下一个节点(当前节点的克隆节点),这里就完成了random指针的赋值了。
- 分离两个链表。
四、第二种思路的代码实现
public class Solution1 {
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
// 1.先把所有克隆的节点挂到原节点的后面
// 当前节点
Node cur = head;
// 克隆的新节点
Node clone;
while (cur != null) {
// 创建一个新节点
clone = new Node(cur.val);
// 插入克隆的节点
clone.next = cur.next;
cur.next = clone;
cur = clone.next;
}
// 2.再把克隆节点的random的节点赋值
cur = head;
while (cur != null) {
if (cur.random != null) {
cur.next.random = cur.random.next;
}
cur = cur.next.next;
}
// 3.分离链表
Node newHair = new Node(0);
Node newCur = newHair;
cur = head;
while (cur != null) {
newCur.next = cur.next;
cur.next = cur.next.next;
newCur = newCur.next;
cur = cur.next;
}
return newHair.next;
}
}