Skip to content
Branch: master
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
..
Failed to load latest commit information.
README.md
solve.cpp

README.md

Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

Solution

关键问题是当拷贝random指针时有可能节点还没有生成。因此自然想到random指针先不理它。

于是我们先拷贝所有节点,即完成链表的deep copy, 但是random指针如何更新呢?

我们可以第二次扫描把把每个节点的一一映射关系放在map中,比如p为原始链表节点,q为新的链表的节点,p1->q1, p2->q2

第三次扫描更新random指针,根据p节点的random,在map中找到对应q的random, 比如p1->random == p3, 则 q1->random == map[p3] == q3

这样需要O(n)的空间。

有没有更优的方法?

我们可以先在原地插入相同的节点,形成一个新的链表,比如1->2->3,变成1->1'->2->2'->3->3', 而random指针指向原来的值,即若random(1) == 3, 则random(1') == 3.

然后更新random,此时只需要更新第偶数个节点random指向下一个节点即可,即random(p') = random(p')->next

第三步,需要把拷贝的节点从原来的链表分离出来即可

总结出来,需要以下三步:

  • 原地插入拷贝,random指向原来的节点
RandomListNode *copyInPlace(RandomListNode *head)
{
	if (head == nullptr)
		return nullptr;
	RandomListNode *p = head;
	while (p) {
		RandomListNode *t = new RandomListNode(p->label);
		t->next = p->next;
		t->random = p->random;
		p->next = t;
		p = p->next->next;
	}
	return head;
}
  • 更新random指针,把第偶数个节点的random指向原来的下一个节点
RandomListNode *updateRandomPointer(RandomListNode *head)
{
	if (head == nullptr)
		return nullptr;
	RandomListNode *p = head->next;
	while (p) {
		if (p->random)
			p->random = p->random->next;
		if (p->next == nullptr) // 最后一个节点next指针为null
			break;
		else
			p = p->next->next;
	}
	return head;
}
  • 从原来的链表中分离开,返回复制的节点
RandomListNode *breakDown(RandomListNode *head)
{
	if (head == nullptr)
		return nullptr;
	RandomListNode *head1 = head, *head2 = head->next;
	RandomListNode *p = head1, *q = head2;
	while (p && q) {
		p->next = p->next->next;
		if (q->next) // 最后一个节点指向null
			q->next = q->next->next;
		p = p->next;
		q = q->next;
	}
	return head2;
}

最后代码为:

RandomListNode *copyRandomList(RandomListNode *head)
{
	copyInPlace(head);
	updateRandomPointer(head); // 不能和breakdown一起,原因是随机指针可能指向前面的节点
	return breakDown(head);
}

需要注意的是最后一个节点指向为null的情况,即p->next->next,注意最后一个节点的p->next为null,因此会出现段错误.

You can’t perform that action at this time.