链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
提示:
-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。
这道题画个图会比较好理解,做法就是在原链表中,在每个结点的后面复制一个与它相同的结点。然后,让复制的结点的random指针和被复制的结点的一样。再将原链表和复制链表分离开来。
写了两个版本的代码,区别在于一个用的while循环,一个用的for循环,用for循环会比较简洁。还有就是在分离操作的时候,一个用了双指针,有点繁琐,但是很好想啦。其实用一个指针就可以完成分离操作,但要定义一个dummy虚拟头结点。
c++代码如下:
1 class Solution { 2 public: 3 Node* copyRandomList(Node* head) { 4 if(!head) return head; 5 auto p = head; 6 while(p){ 7 auto q = new Node(p->val); 8 q->next = p->next; 9 p->next = q; 10 p = q->next; 11 } 12 auto k = head; 13 while(k){ 14 if(k->random) k->next->random = k->random->next; 15 k = k->next->next; 16 } 17 auto copy = head->next; 18 auto a = head, b = head->next->next; 19 while(b){ 20 a->next->next = b->next; 21 a->next = b; 22 a = b; 23 b = b->next->next; 24 } 25 a->next = b; 26 return copy; 27 } 28 };
更简洁、更妙的解法如下:
1 class Solution { 2 public: 3 Node* copyRandomList(Node* head) { 4 if(!head) return head; 5 for(auto p = head; p; p = p->next->next){ 6 auto q = new Node(p->val); 7 q->next = p->next; 8 p->next = q; 9 } 10 11 for(auto k = head; k; k = k->next->next){ 12 if(k->random) k->next->random = k->random->next; 13 } 14 auto dummy = new Node(-1); 15 auto cur = dummy; 16 for(auto p = head; p;p = p->next){ 17 cur->next = p->next; 18 p->next = cur->next->next; 19 cur = cur->next; 20 } 21 22 return dummy->next; 23 } 24 };