题目名称

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null

示例 1: 35- ☆☆☆(四解法)复杂链表的复制 - 图1 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

哈希表

思路

由题意知,对于该链表的赋值,难点在于链表random节点的复制, 需要构建源节点和复制节点之间的映射关系,才可以得到复制random节点。
利用哈希表的查询特点,考虑构建 原链表节点新链表对应节点 的键值对映射关系,再遍历构建新链表各节点的 nextrandom 引用指向即可。

算法

  • 初始化:unordered_map;
  • 在新空间中构建节点,并在哈希表中存储【源节点,复制节点】的映射关系
  • 构建复制空间的random节点:

    • copyNode=umap[orgNode]
    • copyNode->random=umap[orgNode->random]

      实现

      1. Node* copyRandomList(Node* head){
      2. unordered_map<Node*,Node*> umap;
      3. //构建复制空间节点
      4. Node* cur=head;
      5. while(cur!=nullptr){
      6. Node* node=new Node(cur->val);
      7. umap.insert(make_pair(cur,node));
      8. cur=cur->next;
      9. }
      10. //构建复制空间节点的关系
      11. cur=head;
      12. while(cur!=nullptr){
      13. umap[cur]->next=umap[cur->next];
      14. umap[cur]->random=umap[cur->random];
      15. cur=cur->next;
      16. }
      17. return umap[head];
      18. }

      复杂度分析

  • 时间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图2

  • 空间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图3

❤❤❤拼接+拆分

思路

考虑构建 原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> …… 的拼接链表,如此便可在访问原节点的 random 指向节点的同时找到新对应新节点的 random 指向节点.

算法

  1. 复制各节点,实现拼接
  2. 构建复制空间中中新节点的random
    • 源节点为cur,复制节点为copy=cur->next;则copy->random=cur->random->next;
  3. 拆分原节点和复制节点
    • cur->next=copy->next;cur=cur->next;
    • copy->next=cur->next;copy=copy->next;

      实现

      1. Node* copyRandomList(Node* head) {
      2. Node* cur=head;
      3. if(head==NULL) return cur;
      4. Node* next=cur->next;
      5. //拼接
      6. while(cur!=NULL){
      7. Node* node = new Node(cur->val);
      8. cur->next=node;
      9. node->next=next;
      10. cur=next;
      11. if(cur!=NULL) next=cur->next;
      12. }
      13. //构建复制节点的random关系
      14. cur=head;
      15. Node* ansCur=cur->next;
      16. while(cur!=NULL){
      17. if(cur->random!=NULL) ansCur->random=cur->random->next;
      18. cur=ansCur->next;
      19. if(cur!=NULL) ansCur=cur->next;
      20. }
      21. //拆分
      22. cur=head;
      23. copy=cur->next;
      24. Node* ans=head->next;
      25. while(cur!=NULL){
      26. cur->next=copy->next;
      27. cur=cur->next;
      28. if(cur!=NULL) copy->next=cur->next;
      29. copy=copy->next;
      30. }
      31. return ans;
      32. }

      复杂度分析

  • 时间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图43次遍历,时间复杂度为35- ☆☆☆(四解法)复杂链表的复制 - 图5
  • 空间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图6

图的基本单元是 顶点,顶点之间的关联关系称为 边,我们可以将此链表看成一个图:

需要实现原节点与复制节点之间的映射关系

image.png由于图的遍历方式有深度优先搜索和广度优先搜索,同样地,对于此链表也可以使用深度优先搜索和广度优先搜索两种方法进行遍历。

DFS

实现

  1. def copyRandomList(self, head: 'Node') -> 'Node':
  2. def dfs(head):
  3. if not head: return
  4. if head in visited:
  5. return visited[head]
  6. #创建新节点
  7. copy=Node(head.val,None,None)
  8. visited[head]=copy
  9. copy.next=dfs(head.next);
  10. copy.random=dfs(head.random);
  11. return copy;
  12. visited={}
  13. return dfs(head)

复杂度分析

  • 时间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图8
  • 空间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图9

    BFS

    实现

    1. Node* copyRandomList(Node* head) {
    2. if(!head) return NULL;
    3. unordered_map<Node*,Node*> umap;
    4. queue<Node*> q;
    5. Node* copy=new Node(head->val);
    6. q.push(head);
    7. umap[head]=copy;
    8. while(!q.empty()){
    9. Node* cur=q.front();
    10. q.pop();
    11. if(cur->next!=NULL && umap.find(cur->next)==umap.end()){
    12. umap[cur->next]=new Node(cur->next->val);
    13. q.push(cur->next);
    14. }
    15. if(cur->random!=NULL && umap.find(cur->random)==umap.end()){
    16. umap[cur->random]=new Node(cur->random->val);
    17. q.push(cur->random);
    18. }
    19. umap[cur]->next=umap[cur->next];
    20. umap[cur]->random=umap[cur->random];
    21. }
    22. return umap[head];
    23. }

    复杂度分析

  • 时间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图10

  • 空间复杂度:35- ☆☆☆(四解法)复杂链表的复制 - 图11

题目标题难度划分

星级 题目难度
简单
☆☆ 中等
☆☆☆ 困难

算法掌握难度程度划分

星级 掌握难度
普通
经典,易掌握
❤❤ 经典,略难掌握
❤❤❤ 困难