原题链接: https://leetcode.com/problems/copy-list-with-random-pointer/
1. 题目介绍
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
给定一个链表,这个链表的每个节点都包含了一个额外的随机指针。这个随机指针可以指向任意节点或者null。
Return a deep copy of the list.
返回一个链表的深拷贝。
什么是链表的深拷贝呢?这要从链表的存储形式说起了。
内存分为两个空间,一个是堆内存,一个是栈内存。实例化的类都放在堆内存中,指向它们的引用(指针)存放在栈内存中。
比如:下面这一段代码
Node a = new Node(3,null,null);
Node b = a;
Node c = new Node(3,null,null);
Node(3,null,null) 经过实例化,存储在堆内存中。 a 存放在堆内存中,a 指向堆内存中Node(3,null,null) 那片空间。
这时候让 b = a,相当于a 、b 指向了同一块堆内存空间,b. val = a . val 。修改了a.val,也会改变 b.val .这是对a的浅拷贝。
如果这时候,在堆内存中新开辟一块空间,存储和 a 指向的Node(3,null,null) 一样的内容,并且这块新开辟的空间由 c 指向。a、c指向两个不同的空间。这时虽然 c. val = a . val。但是如果改变 c.val , a.val 是不会改变的。这是对 a 的深拷贝。
所以本题可以简单概括为,重新在堆内存中做一个和原有链表一模一样的链表,两者只是内容相同。修改其中一个链表,不会改变另外的链表。
Example 1:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
Note:
You must return the copy of the given head as a reference to the cloned list.
必须返回深拷贝的链表头节点引用。
2. 解题思路
本题的做法参考了题目中的 Hint 3、4:
We can avoid using extra space for old node —> new node mapping, by tweaking the original linked list. Simply interweave the nodes of the old and copied list.
For e.g.
Old List: A --> B --> C --> D
InterWeaved List: A --> A’ --> B --> B’ --> C --> C’ --> D --> D’
The interweaving is done using next pointers and we can make use of interweaved structure to get the correct reference nodes for random pointers.
具体做法是,首先让每个节点后面都接上一个自己的复制节点。然后串联起来所有的复制节点,就完成了对原链表的深拷贝。
实现代码
class Solution {
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
//让每个节点后面有一个和自己一样的复制节点
Node cur = head;
while(cur != null){
cur.next = new Node(cur.val , cur.next , cur.random);
cur = cur.next.next;
}
//让复制节点的 random 指向原来 random 的复制节点
cur = head;
while(cur != null ){
cur.next.random = ( cur.random == null ? null : cur.random.next);
cur = cur.next.next;
}
//恢复原来的链表,分离复制节点组成的深拷贝
cur = head;
Node res = head.next;
while(cur != null){
Node temp = cur.next;
cur.next = temp.next;
if (temp.next != null) {
temp.next = temp.next.next;
}
cur =cur.next;
}
return res;
}
}