25、复杂链表的复制 好题,是好题不错
题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
1、第一种方法,在节点后复制一个节点,然后再分离开这方法超级棒,太麻烦了,不建议用这种方法
/* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomListNode(int x) : label(x), next(NULL), random(NULL) { } }; */ class Solution { public: //复制原始链表的任一节点N并创建新节点N',再把N'链接到N的后边 void CloneNodes(RandomListNode* pHead) { RandomListNode* pNode = pHead; while (pNode != nullptr) { RandomListNode* pCloned = new RandomListNode(pNode->label); pCloned->next = pNode->next; pNode->next = pCloned; pNode = pCloned->next; } } //如果原始链表上的节点N的random指向S,则对应的复制节点N'的random指向S的下一个节点S' void ConnectRandomNodes(RandomListNode* pHead) { RandomListNode* pNode = pHead; while (pNode != nullptr) { RandomListNode* pCloned = pNode->next; if (pNode->random != nullptr) pCloned->random = pNode->random->next; pNode = pCloned->next; } } //把得到的链表拆成两个链表,奇数位置上的结点组成原始链表,偶数位置上的结点组成复制出来的链表 RandomListNode* ReConnectNodes(RandomListNode* pHead) { RandomListNode* pNode = pHead; RandomListNode* pClonedHead = nullptr; RandomListNode* pClonedNode = nullptr; //初始化 if (pNode != nullptr) { pClonedHead = pNode->next; pClonedNode = pNode->next; pNode->next = pClonedNode->next; pNode = pNode->next; } //循环 while (pNode != nullptr) { pClonedNode->next = pNode->next; pClonedNode = pClonedNode->next; pNode->next = pClonedNode->next; pNode = pNode->next; } return pClonedHead; } //三步合一 RandomListNode* Clone(RandomListNode* pHead) { CloneNodes(pHead); ConnectRandomNodes(pHead); return ReConnectNodes(pHead); } };
自己在力扣上复现第一种做法,有很多要注意的地方
https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/
执行用时:24 ms, 在所有 C++ 提交中击败了21.10%的用户
内存消耗:11.1 MB, 在所有 C++ 提交中击败了100.00%的用户
class Node { public: int val; Node* next; Node* random; Node(int _val) { val = _val; next = NULL; random = NULL; } }; class Solution { public: void copyList(Node* head) { Node* node = head; while (node != nullptr) { Node* temp = new Node(node->val); temp->next = node->next; node->next = temp; node = temp->next; } } void connectRandomNodeList(Node* head) { Node* node = head; Node* copyNode = head->next; while (node != nullptr) { if (node->random != nullptr) //每当你要进行赋值的时候都要注意进行非空判断 copyNode->random = node->random->next; node = copyNode->next; if (node != nullptr) //每当你要进行赋值的时候都要注意进行非空判断 copyNode = node->next; } } Node* reCopyList(Node* head) { Node* node = head; Node* copyNode = head->next; Node* copyNodeHead = head->next; while (node != nullptr) { node->next = copyNode->next; node = node->next; if (node != nullptr)//每当你要进行赋值的时候都要注意进行非空判断 copyNode->next = node->next; copyNode = copyNode->next; } return copyNodeHead; } Node* copyRandomList(Node* head) { if (head == nullptr) return nullptr; copyList(head); connectRandomNodeList(head); return reCopyList(head); } };
2、哈希表的做法,其实更简单一下啊
RandomListNode* Clone(RandomListNode* pHead) { if (pHead == nullptr) { return nullptr; } std::unordered_map<RandomListNode*, RandomListNode*> hash_map; for (RandomListNode* p = pHead; p != nullptr; p = p->next) { hash_map[p] = new RandomListNode(p->label); } for (RandomListNode* p = pHead; p != nullptr; p = p->next) { hash_map[p]->next = hash_map[p->next];//这里要注意是 unmp[p->next] 千万注意,好好想想 hash_map[p]->random = hash_map[p->random];//下同 } return hash_map[pHead]; }
在力扣上复现了一遍
执行用时:20 ms, 在所有 C++ 提交中击败了49.48%的用户
内存消耗:11.4 MB, 在所有 C++ 提交中击败了100.00%的用户
Node* copyRandomList(Node* head) { if (head == nullptr) return nullptr; unordered_map<Node*, Node*> unmp; for (Node* p = head; p != nullptr;p=p->next) { unmp[p] = new Node(p->val); } for (Node* p = head; p != nullptr; p = p->next) { unmp[p]->next = unmp[p->next];//这里要注意是 unmp[p->next] 千万注意,好好想想 unmp[p]->random = unmp[p->random];//下同 } return unmp[head]; }
3、哈希表的递归写法
struct RandomListNode { int label; struct RandomListNode* next, * random; RandomListNode(int x) : label(x), next(NULL), random(NULL) { } }; class Solution { public: unordered_map<RandomListNode*, RandomListNode*> unmp; RandomListNode* Clone(RandomListNode* pHead) { if (pHead == NULL) return NULL; RandomListNode* head = new RandomListNode(pHead->label); unmp[pHead] = head; head->next = Clone(pHead->next); //在这里递归是关键,保证所有节点都已生成,放入map head->random = NULL; if (pHead->random!=nullptr) head->random = unmp[pHead->random]; //查找map中对应节点 return head; } };
力扣上复现做法
执行用时:24 ms, 在所有 C++ 提交中击败了21.10%的用户
内存消耗:11.5 MB, 在所有 C++ 提交中击败了100.00%的用户
class Node { public: int val; Node* next; Node* random; Node(int _val) { val = _val; next = NULL; random = NULL; } }; class Solution { public: unordered_map<Node*, Node*> unmp; Node* copyRandomList(Node* head) { if (head == NULL) return NULL; Node* newHead = new Node(head->val); unmp[head] = newHead; newHead->next = copyRandomList(head->next); //在这里递归是关键,保证所有节点都已生成,放入map newHead->random = NULL; if (head->random != nullptr) newHead->random = unmp[head->random]; //查找map中对应节点 return newHead; } };
二刷:
1、哈希表递归写法
运行时间:3ms 占用内存:520k
class Solution { public: //关键是保存住映射关系,可以说是哈希表和链表的组合吧 unordered_map<RandomListNode*,RandomListNode*> unmp; RandomListNode* Clone(RandomListNode* pHead) { if(pHead == nullptr) return nullptr; RandomListNode* newHead = new RandomListNode(pHead->label); unmp[pHead] = newHead;//这里需要保存的是 pHead -》 newHead 的映射关系,必须在这里保存 newHead->next = Clone(pHead->next);//到这一步,其实所有的点已经全部生成了 newHead->random = nullptr;//其实默认已经是nullptr了,有没有这一步其实没什么关系 if(pHead->random != nullptr) newHead->random = unmp[pHead->random];//这一步,真的是灵魂所在了 return newHead; } };
2、哈希表迭代写法
运行时间:2ms 占用内存:492k
/* 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(pHead == nullptr) return nullptr; unordered_map<RandomListNode*,RandomListNode*> unmp; for( auto p = pHead; p != nullptr; p=p->next){ unmp[p] = new RandomListNode(p->label); } for( auto p = pHead; p != nullptr; p=p->next){ unmp[p]->next = unmp[p->next]; unmp[p]->random = unmp[p->random]; } return unmp[pHead]; } };
美女帅哥们如果觉得写的还行,有点用的话麻烦点个赞或者留个言支持一下阿秀~
如果觉得狗屁不通,直接留言开喷就完事了。