文章

LeetCode138 链表的深度拷贝

LeetCode138 链表的深度拷贝

题目

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。 要求返回这个链表的深拷贝。 示例: 在这里插入图片描述 输入: {“$id”:”1”,”next”:{“$id”:”2”,”next”:null,”random”:{“$ref”:”2”},”val”:2},”random”:{“$ref”:”2”},”val”:1} 解释: 节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。 节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。

这个题目有一定难度的,难度在于随机指针。这个指针域该怎么复制是一个很重要的问题。 深度拷贝:原链表和新链表不互相影响,可以随意更改。 这个题目可以用 map 来计算,主要是存储随机指针之间的逻辑关系,map 中存储的是地址和节点 ID 的映射。 难点有两点: 1.随机指针指向了哪一个节点? 2.这个节点的地址是多少? 而用 map 就是为了解决这两点的。

我自己的思路:首先存储随机指针指向的 ID,然后新建新的指针,顺便保存值和指针以及随机指针三个参数,返回新的指针。

写代码发现行不通,不知道该怎么写,存储随机指针以及保存其他的指针都好写,但是怎么新建新指针和将新指针的 next 域、random 域和原来的联系起来,这里不知道怎么写。

这里我的思路是有问题的,原因是我没有想清楚该做什么。我的思路是保存随机指针指向的 ID,这一步保存 ID 是对的,但是随机指针不对,这里保存的应该是新链表中的指针,而不是旧链表,同理,新建新的指针时,值可以保存,但是 next 指针和随机指针不能一次性保存的。

正确的方法,应该是,根据原链表的长度建立新链表,仅仅将值域的值赋值,next 域和 random 域暂时不用管,并且将新节点存放到 vector 中,然后保存旧节点的地址对应的 id。

然后再次遍历旧节点,连接新节点的 next 域,然后由于 map 中保存的是旧节点的地址,所以对旧节点的 random 域取地址,该地址一定在 map 中,且对应的 key 值即为指向的 id,结合该 id 在 vector 中索引,即可得到新节点中的 random 指针的地址。 最终代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Node* copyRandomList(Node* head)
{
	std::map<Node*, int > node_map;
	std::vector<Node*> node_vec;
	Node* ptr = head;
	int i = 0;
	while (ptr)
	{
		node_vec.push_back(new Node(ptr->val));
		//记录ptr 和ID的映射
		node_map[ptr] = i++;
		ptr = ptr->next;
	}

	node_vec.push_back(0);
	ptr = head;
	i = 0;
	while (ptr)
	{
		node_vec[i]->next = node_vec[i + 1];
		if (ptr->random!=NULL)
		{
			int id = node_map[ptr->random];//get ID
			node_vec[i]->random = node_vec[id];
		}
		ptr = ptr->next;
		i++;
	}
	return node_vec[0];
}
本文由作者按照 CC BY 4.0 进行授权