首页 > 代码库 > Copy List with Random Pointer

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.

思路:本题要求复制链表,因为每个元素存在一个随机指针,所以使问题变得稍微复杂一些。

方法1:首先,遍历链表,复制当前节点,并将当前节点的地址和新节点的地址映射存入map中;然后,再次遍历链表,通过查找map,找到当前节点及其next和random指针对应的新节点的地址,并修改当前节点对应新节点的next和random字段。

 1 class Solution { 2 public: 3     RandomListNode *copyRandomList( RandomListNode *head ) { 4         if( !head ) { return 0; } 5         unordered_map<RandomListNode*,RandomListNode*> addrMap; 6         RandomListNode *curr = head; 7         while( curr ) { 8             addrMap[curr] = new RandomListNode( curr->label ); 9             curr = curr->next;10         }11         curr = head;12         while( curr ) {13             RandomListNode *newCurr = addrMap[curr];14             if( curr->next ) { newCurr->next = addrMap[curr->next]; }15             if( curr->random ) { newCurr->random = addrMap[curr->random]; }16             curr = curr->next;17         }18         return addrMap[head];19     }20 };

上述方法为完成复制,对每个节点可能需要对map进行3次查找。

方法2:与方法1类似,也使用map记录原始节点和新节点的地址映射关系。不同之处在于,第一次遍历时,已经完成了对正常链表的复制,但新节点的random字段与原始节点相同。因此,第二次遍历时,通过查找map修改新节点的random字段。

 1 class Solution { 2 public: 3     RandomListNode *copyRandomList( RandomListNode *head ) { 4         if( head == 0 ) { return 0; } 5         map<RandomListNode*,RandomListNode*> addrMap; 6         RandomListNode *newhead = new RandomListNode(head->label), *node = newhead; 7         node->random = head->random; addrMap[head] = node; 8         while( head->next ) { 9             head = head->next;10             node->next = new RandomListNode(head->label);11             node = node->next;12             node->random = head->random;13             addrMap[head] = node;14         }15         node = newhead;16         while( node ) {17             if( node->random ) {18                 node->random = addrMap[node->random];19             }20             node = node->next;21         }22         return newhead;23     }24 };

该方法相比方法1,对每个节点只需要对map进行1次查找。但其第一次遍历的循环体较方法1要复杂。方法1和方法2都需要使用map记录原始节点和新节点的地址映射。

方法3:通过三次遍历,完成复制过程,不需要使用map存储地址映射关系。

第一次遍历,通过将原始节点的random字段指向新节点的地址,同时将其random字段的原始值存储在新节点的label字段中,以实现原始节点和新节点的映射。这使得我们可以通过原始节点的random字段找到其对应的新节点,这与使用map建立地址映射关系作用相同。

第二次遍历,通过上述映射关系,修改新节点的random字段和next字段,使其指向对应的新节点。

第三次遍历,修改新节点的label字段,同时恢复原始节点的random字段。

 1 class Solution { 2 public: 3     RandomListNode *copyRandomList( RandomListNode *head ) { 4         if( head == 0 ) { return 0; } 5         RandomListNode *node = head; 6         // first loop: new all nodes. 7         while( node ) { 8             RandomListNode *newNode = new RandomListNode( (int)node->random ); 9             node->random = newNode;10             node = node->next;11         }12         // second loop: assign random and next pointer.13         node = head;14         while( node ) {15             RandomListNode *newNode = node->random;16             RandomListNode *random = (RandomListNode*)newNode->label;17             if( random ) {18                 newNode->random = random->random;19             }20             if( node->next ) {21                 newNode->next = node->next->random;22             }23             node = node->next;24         }25         // third loop: recover ramdom pointer and copy label.26         node = head;27         RandomListNode *newHead = head->random;28         while( node ) {29             RandomListNode *newNode = node->random;30             node->random = (RandomListNode*)newNode->label;31             newNode->label = node->label;32             node = node->next;33         }34         return newHead;35     }36 };