给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
我的思路:
random指针会出现两种情况:
1.指向的节点还没创建
2.指向的节点创建过了
建个map保存下来之前遍历过的原链表节点,当新链表的节点需要random指向之前的节点时使用
由于本题在复制的过程中存在random需要指向的节点不存在,所以需要额外再用个map保存一下
等待新链表创建了之后再找到之前的节点指向
代码如下:
public Node copyRandomList(Node head) { Map<Node,Node> map = new HashMap<>();//不用链表是因为想创建的时候就能创建,不会积压多个相同的节点 Map<Node, ArrayList<Node>> map2 = new HashMap<>();//链表是因为需要记录下来之前想创建random但是没创建成功的所有节点 Node res = new Node(0); Node resHead = res; while (head != null){ Node newHead = new Node(head.val); res.next = newHead; map.put(head, newHead); if (head.random != null){ if (map2.containsKey(head.random)){ map2.get(head.random).add(newHead); }else{ map2.put(head.random, new ArrayList<Node>(){{add(newHead);}}); } } if (map2.containsKey(head.random)){ map2.get(head.random).add(newHead); } if (map.containsKey(head.random)){ newHead.random = map.get(head.random); } if (map2.containsKey(head)){ ArrayList<Node> list = map2.get(head); for (Node node : list) { node.random = newHead; } } head = head.next; res = res.next; } return resHead.next; }
结果:
官方给出的方法一是回溯+哈希表,相当于是遍历了两次
代码如下:
class Solution {
Map<Node, Node> cachedNode = new HashMap<Node, Node>();
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
if (!cachedNode.containsKey(head)) {
Node headNew = new Node(head.val);
cachedNode.put(head, headNew);
headNew.next = copyRandomList(head.next);
headNew.random = copyRandomList(head.random);
}
return cachedNode.get(head);
}
}
方法二省去了哈希表,将该链表中的每一个节点拆分为两个相连的节点
如:A-B-C,拆分为A-A'-B-B'-C-C'
这样,我们可以直接找到每一个拷贝节点 S' 的随机指针应当指向的节点,即为其原节点 S的随机指针指向的节点 T的后继节点 T',即
nodeNew.random = node.random.next
最后拆分即可
代码如下:
class Solution {
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
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 nodeNew = node.next;
nodeNew.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;
}
}