首页 > 代码库 > 【leetcode】Copy List with Random Pointer

【leetcode】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.


 

好麻烦的链表题T_T

首先说一下深拷贝和浅拷贝的区别,参考这篇博文:http://www.cnblogs.com/BlueTzar/articles/1223313.html

深拷贝:在拷贝过程中,为新的变量申请新的空间,所以原来的变量不存在时,拷贝得到的变量还可以使用。

浅拷贝:在拷贝过程中,不为新变量申请新的空间,只是把原来变量的地址给新的变量,原来的变量不存在时,拷贝得到变量也不能使用了。

所以在题目中,要做到两点,第一原来的链表不能改变;第二,拷贝得到的链表要有自己完全独立的内存空间,而不是只是指向原来的链表。


 

解题思路思路参考:http://www.cnblogs.com/lautsie/p/3259724.html

但是这个博客有个bug,就是恢复原来链表的next指针和建立新链表的random和next指针是不能同时进行的。因为有可能有如下情况:

在建立3‘的random指针的时候通过3‘当前的random指针找到3,又通过3的random指针找到1,但是如果1的next指针已经被改为指向2,而不再是1‘,那么就没办法找到3‘真正的random指针1‘了,所以恢复原来链表的next指针,只能在新链表完全建立好以后进行。那么就需要一个结构来存储原来链表的next指针信息,这里采用一个map:oldlistnext保存。

所以算法分为3个循环:

第一个循环,建立新的链表,并且把新链表中各个节点的random指针指向原来链表对应的节点,原来链表的next指针指向新链表的对应节点,如下图所示:

图中橙色是原来链表的next指针,绿色是新建链表的random指针,蓝色虚线表示新建链表的next指针。

第二个循环,恢复新建链表的next和random指针:new_list_p->next = new_list_p->next->next;new_list_p->random = new_list_p->random->random->next;如下图所示:

第三个循环,恢复原来链表的next指针,old_list_p->next = oldlistnext[old_list_p],如下图所示:

当然,上述过程中要注意各种边界情况的考虑。

代码如下:

 1 class Solution {
 2 public:
 3     RandomListNode *copyRandomList(RandomListNode *head) {
 4         if(head == NULL)
 5             return NULL;
 6 
 7         RandomListNode* old_list_p = head;
 8         RandomListNode* new_list_p;
 9         bool has_head = 0;
10         std::map<RandomListNode *,RandomListNode *> oldlistnext;
11 
12         //建立新的链表
13         while(old_list_p != NULL){
14             RandomListNode* temp= (struct RandomListNode*)malloc(sizeof(struct RandomListNode));
15             if(has_head == 0){
16                 new_list_p = temp;
17                 has_head = 1;
18             }
19             oldlistnext.insert(std::map<RandomListNode*,RandomListNode*>::value_type(old_list_p, old_list_p->next));
20 
21             temp->label = old_list_p->label;
22             temp->next = old_list_p->next;
23             temp->random = old_list_p;
24             old_list_p->next = temp;
25 
26             old_list_p = temp->next;
27         }
28 
29         RandomListNode* h = new_list_p;
30         old_list_p = head;
31 
32         //恢复新建链表的next和random指针
33         while(new_list_p != NULL){
34             if(new_list_p->random->random != NULL){
35                 new_list_p->random = new_list_p->random->random->next;
36             }
37             else
38                 new_list_p->random = NULL;
39 
40             if(new_list_p->next != NULL)
41                 new_list_p->next = new_list_p->next->next;
42             else
43                 new_list_p->next = NULL;
44 
45             new_list_p = new_list_p->next;
46 
47         }
48 
49         old_list_p = head;
50         
51         //恢复原来链表的next指针
52         for(int i = 1;i <= oldlistnext.size();i++){
53             old_list_p->next = oldlistnext[old_list_p];
54             old_list_p = old_list_p->next;
55         }
56 
57         return h;
58     }
59 };