题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
哈希表解法
由于复杂链表的节点label是唯一的,因此可以使用哈希表, 将label作为键值,node作为value,每次添加next或者random节点时先判断哈希表中是否已存在该label对应的节点,若存在,则返回该节点,若不存在则新建一个节点并添加到哈希表中。这种解法相当于用空间换时间,只需遍历一次链表即可
import java.util.HashMap;
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if (pHead == null)
return null;
RandomListNode head, tail;
HashMap<Integer, RandomListNode> hashMap = new HashMap<>();
int label = pHead.label;
RandomListNode next, random;
head = new RandomListNode(label);
tail = head;
hashMap.put(label, tail);
while (pHead != null) {
next = pHead.next;
random = pHead.random;
RandomListNode tmp;
if (next != null) {
if (hashMap.containsKey(next.label))
tmp = hashMap.get(next.label);
else {
tmp = new RandomListNode(next.label);
hashMap.put(next.label, tmp);
}
} else {
tmp = null;
}
tail.next = tmp;
if (random != null) {
if (hashMap.containsKey(random.label))
tmp = hashMap.get(random.label);
else {
tmp = new RandomListNode(random.label);
hashMap.put(random.label, tmp);
}
} else {
tmp = null;
}
tail.random = tmp;
tail = tail.next;
pHead = pHead.next;
}
return head;
}
}
三步法
- 先在原链表的基础上复制链表,即在每个节点后插入克隆的节点,例如:
1-2-3-4-5
插入克隆节点后变成1-1-2-2-3-3-4-4-5-5
- 这一步根据原链表的random设置克隆链表的random指向
- 最后将两个链表拆分,即设置两个链表的next指向
public static RandomListNode Clone(RandomListNode pHead) {
if (pHead == null)
return null;
RandomListNode now = pHead;
// 在每个节点后插入克隆节点
while (now != null) {
RandomListNode cloneNode, tmpNext;
cloneNode = new RandomListNode(now.label);
tmpNext = now.next;
now.next = cloneNode;
cloneNode.next = tmpNext;
now = now.next.next;
}
// 设置random节点
now = pHead;
while (now != null) {
now.next.random = now.random == null ? null : now.random.next;
now = now.next.next;
}
// 拆分链表
RandomListNode head = pHead.next;
now = pHead;
while (now != null) {
RandomListNode tmpNext = now.next;
now.next = tmpNext.next;
tmpNext.next = tmpNext.next == null ? null : tmpNext.next.next;
now = now.next;
}
return head;
}