给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
示例:
输入:
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}
解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
我的思路:
说实话吧,第一眼我连题都没看懂,我读了好久题目。后来才发现,就是它给你一个节点,然后叫你构建一个跟这个头结点一模一样的链表处理,不能直接返回原节点,会被判为作弊。
我的思路很简单,取巧,走捷径,既然他不让你返回原节点,那我更改一下原节点的val值可不可以?其实你不用担心更改了原节点的val值会不会影响判题,我可以告诉你,不会,它肯定还有一个一模一样的链表用来判题。至于为啥要更改原节点的val值呢,且听我慢慢分析。
每个节点包含一个随机指针,这个随机指针是最棘手的地方,我一开始想的是我直接用一个数组把每个随机节点的地址值存起来不就完了?到时候再赋值到我自己建立的节点的 random 里不就行了?后来一想不对啊,我存的是别人已经创建好的节点的地址值,不是指向我自己创建的节点,所以没用。
于是,第一步,遍历他给我的节点,按照前后顺序,从第一个到最后一个,同时我弄了一个数组,遍历节点的同时一边创建节点并把我创建的节点放入数组中(现在暂不处理随机节点)。第二步,我也是遍历一遍节点,我把每个节点的value值修改成他们自己的序号(这是重点),比如1号节点的value值改成1,代表它是第几个节点,相当于编个号,也对应我前面第一步所创建的数组的下标,1号节点的下标就是1,0号节点的下标就是0。(注意啊,我修改的是原节点,就是题目要求我们拷贝的那个节点,不是我创建的节点)(实际上我第一步跟第二步是一起做的)
之后就好弄了,现在就能用到我前面修改的value值了,我把我创建的链表跟题目提供给我的链表一起遍历,当发现题目给我的某个节点拥有随机指针的时候,我就看看这个随机指针指向的节点的value值,这个value值就是数组节点的下标,random 指向这个节点即可。
代码:
class Solution {
public:
Node* copyRandomList(Node* head) {
if (head == NULL)return NULL;
vector<Node*> v;//用来存储我创建的节点,顺序跟题目给我的节点一样
int k = 0;//计数
Node* l = head;//临时用来遍历的节点
while (l)
{
Node* temp = new Node(l->val, NULL, NULL);//我创建的节点
v.push_back(temp);//把我创建的节点放入数组中
l->val = k;//修改题目给我的节点的value值,改成当前节点数组的节点下标
k++;
l = l->next;
}
l = head;//临时遍历的节点
k = 0;//计数
while (l)
{
if (l->random != NULL)
{
v[k]->random = v[l->random->val];//当前节点保存的随机节点
}
l = l->next;
if (k + 1 < v.size())v[k]->next = v[k + 1];//当前节点指向下一个节点
k++;
}
return v[0];
}
};