问题描述:
复制带随机指针的链表
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
示例:
输入: {"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1} 解释: 节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。 节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
基本思路:
- 思路很简单,显示不管所有随机节点,直接把链表复制,然后处理随机节点。唯一的难点是——之前链表的随机节点,指向的到底是我们新建链表的哪个节点——这个不为人知。
- 为了解决1中的问题,我们选择引入hash_map,建立映射,key是原来节点,value是复制的节点;这样我们就可以通过key的random指针,获得复制后实际对应的节点。
- 还有一个问题就是复制链表。。果然我对链表还是不太熟练,这里稍微总结一下怎么处理:
- 如果传入的参数是NULL,那就特殊情况特殊处理。
- 由于要返回头结点,所以头结点要单独开辟。
- 其他的还要两个指针,一个用来遍历原来的链表,另一个指向深拷贝链表的末尾。当然还需要一个新节点的指针。
- 然后该怎么做怎么做吧。
AC代码:
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node() {}
Node(int _val, Node* _next, Node* _random) {
val = _val;
next = _next;
random = _random;
}
};
*/
class Solution {
public:
Node* copyRandomList(Node* head) {
// 考虑特殊情况(head->next为空的情况)
if (!head) return NULL;
if (!head->next && head->random == head) {
auto ret = new Node(head->val, NULL, NULL);
ret->random = ret;
}
if (!head->next && head->random == NULL) {
return new Node(head->val, NULL, NULL);
}
unordered_map<Node*, Node*> hash_map; // 利用hash_map来建立节点之间的联系
// 进行节点的复制
auto p = head->next;
auto prev = new Node(head->val, NULL, NULL);
auto ret = prev; // 返回的头结点
hash_map[head] = prev; // 初始化第一个节点
while (p) {
auto new_node = new Node(p->val, NULL, NULL);
hash_map[p] = new_node; // 更新hash_map
prev->next = new_node;
prev = prev->next;
p = p->next;
}
// 获得random指针的值
auto p1 = head;
auto p2 = ret;
while (p1) {
p2->random = hash_map[p1->random];
p1 = p1->next;
p2 = p2->next;
}
return ret;
}
};