1、题目描述
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
2、思路分析
方法一:回溯+哈希(虽然我也没太看懂哪里体现出了回溯的思想)
这里我倒是没看出回溯提现在哪里,更多的应该是一个递归的思想,首先对于当前节点进行拷贝,然后利用递归对于当前节点的后继节点和随机节点进行拷贝,最后将拷贝完成的新节点返回,即是拷贝完成的链表。
具体实现步骤如下:
- 利用哈希表存储新节点的创建情况,原来节点作为键,新节点为value
- 检查「当前节点的后继节点」和「当前节点的随机指针指向的节点」的创建情况。如果这两个节点中的任何一个节点的新节点没有被创建,我们都立刻递归地进行创建
- 当我们拷贝完成,回溯到当前层时,我们即可完成当前节点的指针赋值
- 注意一个节点可能被多个其他节点指向,因此我们可能递归地多次尝试拷贝某个节点,为了防止重复拷贝,我们需要首先检查当前节点是否被拷贝过,如果已经拷贝过,我们可以直接从哈希表中取出拷贝后的节点的指针并返回即可。
方法二:迭代+节点拆分
可以将链表中的每一个节点拆分成两个相邻的节点,例如对于链表A->B->C,可以将其拆分成A->A'->B->B'->C->C',其中任意一个节点S,S'代表其拷贝节点。
然后我们就可以找到S'节点的随机指针应该指向的节点,是原节点S的随机指针指向的节点T的后继节点T',需要注意的是原节点的随机指针可能为空。
当我们完成了拷贝节点的随机指针的赋值,我们只需要将这个链表按照原节点与拷贝节点的种类进行拆分即可,只需要遍历一次。同样需要注意最后一个拷贝节点的后继节点为空,我们需要特别判断这种情况。
3、代码实现
回溯方法实现
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
Map<Node,Node> map = new HashMap<>();
public Node copyRandomList(Node head) {
if(head == null){
return head;
}
if(!map.containsKey(head)){
Node headNew = new Node(head.val);
map.put(head,headNew);
headNew.next = copyRandomList(head.next);
headNew.random = copyRandomList(head.random);
}
return map.get(head);
}
}
节点拆分方法实现
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if(head == null){
return head;
}
for(Node node = head;node != null;node = node.next.next){
Node nodeNew = new Node(node.val);
nodeNew.next = node.next;
node.next = nodeNew;
}
for(Node node = head;node != null;node = node.next.next){
Node nodetemp = node.next;
nodetemp.random = (node.random != null) ? node.random.next : null;
}
Node headNew = head.next;
for(Node node = head;node != null;node = node.next){
Node nodeNew = node.next;
node.next = node.next.next;
nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
}
return headNew;
}
}