Author: Zhai Tianbao Steven
Copyright notice: the copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source
Title Description:
Enter a complex linked list (each node has a node value and two pointers, one pointing to the next node and the other special pointer random pointing to a random node). Please make a deep copy of this linked list and return the copied head node. (Note: please do not return the node reference in the parameter in the output result, otherwise the problem determination program will directly return null). The following figure is a complex linked list with 5 nodes. The solid arrow in the figure represents the next pointer and the dotted arrow represents the random pointer. For simplicity, the pointer pointing to null is not drawn.
Example:
Input: {1,2,3,4,5,3,5, #, 2, #}
Output: {1,2,3,4,5,3,5, #, 2, #}
Analysis: we divide the linked list into two segments. The first half {1,2,3,4,5} is a ListNode, and the second half {3,5, #, 2, #} is a random pointer field representation.
The first half of the above example can represent LISTNODES with a linked list: 1 - > 2 - > 3 - > 4 - > 5
The second half, 3, 5, #, 2, # are represented as
The position of 1 points to 3, the position of 2 points to 5, the position of 3 points to null, the position of 4 points to 2, and the position of 5 points to null
As shown below:
Example:
Input:
{1,2,3,4,5,3,5,#,2,#}
Return value:
{1,2,3,4,5,3,5,#,2,#}
Problem solving ideas:
This topic examines the use of linked lists of data structures. There are two common solutions to this problem.
- Hash table. Create a mapping table with hash map, establish sentry to prevent the front pointer from being empty, pre is used to build a new linked list, and cur is used to traverse the original linked list; Traverse the storage mapping relationship, just as the second node of the original linked list corresponds to the second node of the new linked list, one-to-one correspondence, which is a bit like "shadow imitation"; After the mapping is completed, the hash table is traversed. Value corresponds to the new linked list, key corresponds to the original linked list, and the random of value equals m [key - > Random], which is equivalent to connecting the random of the new linked list according to the random of the original linked list (note that the key - > Random here points to the node of the original linked list, and m [key - > Random] is the node pointing to the new linked list); delete the sentry, and the new linked list is copied.
- Linked list splitting method. Traverse the linked list for the first time, and create a node behind each node to form a combined linked list; Traverse the combined linked list for the second time, and connect the random of the new linked list node to the next of the original linked list node random to realize synchronous connection; Traverse the combined linked list for the third time and split it. Connecting the pointer next to the next of next is equivalent to splitting the combined linked list into the original linked list and the new linked list. At this time, the new linked list has been completed.
Test code:
Solution 1: hash table
/* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomListNode(int x) : label(x), next(NULL), random(NULL) { } }; */ class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { // If it is blank, return if(!pHead) return pHead; // Create hash map unordered_map<RandomListNode*, RandomListNode*> m; // Set up a sentry to prevent the front pointer from being empty RandomListNode* sentry=new RandomListNode(0); // Establish pointers to sentinels and headers RandomListNode* pre=sentry,*cur=pHead; // Traversal storage mapping while(cur) { RandomListNode* temp = new RandomListNode(cur->label); pre->next = temp; m[cur] = temp; pre = pre->next; cur = cur->next; } // Traverse the hash table and connect the random of the new table with the random relationship of the original table for(auto&[key,value]:m) { value->random=key->random==NULL?NULL:m[key->random]; } // Delete Sentinel delete sentry; return m[pHead]; } };
Solution 2: linked list splitting
class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { // If it is blank, return if(!pHead) return pHead; // Traversal linked list RandomListNode* cur = pHead; // A copy node is created after each node while(cur){ RandomListNode* tmp = new RandomListNode(cur->label); tmp->next = cur->next; cur->next = tmp; cur = tmp->next; } // Traverse the combined linked list and connect the next of the random of the original linked list with the random of the new linked list node RandomListNode *old = pHead, *clone = pHead->next, *ret = pHead->next; while(old){ clone->random = old->random == NULL ? NULL : old->random->next; // Handle random pointers to copy nodes if(old->next) old = old->next->next; // Note the special null pointer if(clone->next) clone = clone->next->next; } // Traverse again, split, interval split, and tear down the original linked list and the new linked list old = pHead, clone = pHead->next; while(old){ // Split linked list if(old->next) old->next = old->next->next; if(clone->next) clone->next = clone->next->next; old = old->next; clone = clone->next; } return ret; } };