LeetCode Copy List with Random Pointer
/** * Definition for singly-linked list with a random pointer. * struct RandomListNode { * int label; * RandomListNode *next, *random; * RandomListNode(int x) : label(x), next(NULL), random(NULL) {} * }; */ class Solution { public: RandomListNode *copyRandomList(RandomListNode *head) { if (head == NULL) return NULL; unordered_map<RandomListNode*, RandomListNode*> p2p; RandomListNode* newhead = new RandomListNode(head->label); newhead->random = head->random; p2p.insert(pair<RandomListNode*, RandomListNode*>(head, newhead)); RandomListNode* tail = newhead; head = head->next; while (head != NULL) { RandomListNode* item = new RandomListNode(head->label); item->random = head->random; p2p.insert(pair<RandomListNode*, RandomListNode*>(head, item)); tail->next = item; tail = item; head = head->next; } tail = newhead; while (tail != NULL) { if (tail->random != NULL) { tail->random = p2p.find(tail->random)->second; } tail = tail->next; } return newhead; } };
因为random指针的指向是随机的,自己没想出什么不用map的方法。map存储的是旧对象地址(key)-相应的新对象的地址(value)。这样在第一次遍历原链表时进行链表复制,并对每个对象建立旧地址到新地址的映射,暂时直接复制random字段的值。然后进行第二次链表遍历,这回是对刚刚建立的新链表,如果发现其random字段不为NULL,则它存储了一个对象的旧地址值,因为我们已经有了所有对象的旧-新地址映射表,所以很方便的能够查找到该指针指向的对象的新地址值。这样链表的深拷贝就完成了。
- unordered_map 无序的,hash实现,O(1),C++11中才有,要加编译选项-std=c++11
- map 有序的,树实现,O(logn)
的确这题可能数据量不是很大用unordered_map比map快不了多少。
后来网上找的一个更巧妙的算法,一些方法就是要对原始结构进行修改(好像有不使用额外的栈/递/队列归遍历树,另外leetcode上的另一题Reorder List 也是如此),本题的详细过程解释见参考[2]。
自己也写一个作为练习,最后重新分出新旧两个链表节点重新拼接的过程怎么写简洁点还是需要考虑一下。
// 2. without a map RandomListNode *_copyRandomList(RandomListNode *head) { if (head == NULL) return NULL; RandomListNode* item = new RandomListNode(head->label); item->random = head->random; item->next = head->next; head->next = item; RandomListNode* tail = item->next; while (tail != NULL) { item = new RandomListNode(tail->label); item->random = tail->random; item->next = tail->next; tail->next = item; tail = item->next; } tail = head; while (tail != NULL) { tail = tail->next; if (tail->random != NULL) tail->random = tail->random->next; tail = tail->next; } RandomListNode* newhead = head->next; RandomListNode* oldtail = head; tail = newhead; while (tail->next != NULL) { oldtail->next = tail->next; oldtail = tail->next; tail->next = oldtail->next; tail = oldtail->next; } oldtail->next = NULL; return newhead; }
速度上比原先的使用map版本快了70ms左右(从提交的结果来看)
参考:
[1] zhuli哥的题解 http://www.cnblogs.com/zhuli19901106/p/3518026.html
[2] 另外一篇比较详细的题解 http://www.cnblogs.com/TenosDoIt/p/3387000.html