声明:题目来源:力扣(LeetCode)
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。要求返回这个链表的深度拷贝
题目链接:复制带随机指针的链表
示例:
输出一个拷贝的链表,应满足第一个节点的随机指针指向第二个节点,第二个节点的随机指针指向它自己。
本题的关键在于随机指针的拷贝问题——仅复制单链表的值着实简单,一路 next 遍历一遍即可。然而这个随机指针却不好判断,由于链表不具有随机访问的能力,因此我们也不能知道这个随机指针到底指向了哪个节点(除非一个个穷举)。再加上链表节点地址的任意性,我们也不能使用地址差来确定随机指针指向的节点,那要怎么确定随机指针到底指向了哪个节点呢?下面给出了两种解题思路:
题解1:先不管 random 的指向,先简单复制一下原链表,我们就得到了一个等长的、节点值与原链表相同的新链表。
接着再确定 random 的指向。要想知道 random 具体指向哪个节点,只能通过访问 random 所指向的节点确定,那么访问了 random 所指向的节点之后(这里假定 random 的指向不为空),要如何确定这个节点是链表中的哪个节点?那就需要我们在这之前,先给链表的所有节点做个标记,而这个标记,我们只能存在原链表的节点值 val 当中。因此,在进行复制随机指针的操作之前,再遍历一遍原链表,将原链表的节点值按顺序依次编号,例:
这样,我们通过原链表的随机指针 random 访问到某节点,再根据该节点的值就可以确定它在链表中的位置了,我们复制过来的链表,也就可以根据原链表的这个值来确定某一个节点的 random 应该指向哪个位置的节点,从而实现深度拷贝。
但是这个算法有一个缺点就是时间复杂度依赖于随机指针的指向,有时候可能会耗费很多时间。
下面给出这种解法的C++代码(题目没有提供C语言环境,只能写C++代码了,不过还是C语言的语法):
class Solution {
public:
//给节点编号
void Number(Node* head){
int i = 0;
for(;head;++i){
head->val = i;
head = head->next;
}
}
//将节点移动 d 个位置
Node* MoveNode(Node* node, int d){
while(d