Little-Prince

导航

138. 复制带随机指针的链表

138. 复制带随机指针的链表

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
深拷贝指源对象和拷贝对象相互独立,其中任何一个对象的改动都不会对另一个对象造成影响。在进行赋值之前,为指针类型的数据成员另辟一个独立的内存空间,实现真正内容上的拷贝。
 
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

 val:一个表示 Node.val 的整数。
 random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
 
 
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
 
思路:
1.从 head 节点开始遍历链表。首先创造新的 head 拷贝节点,并将该新建节点的引用也放入已访问字典中。
2.random 指针
如果当前节点 i 的 random 指针指向一个节点 j 且节点 j 已经被拷贝过,我们将直接使用已访问字典中该节点的引用而不会新建节点。
如果当前节点 i 的 random 指针指向的节点 j 还没有被拷贝过,我们就对 j 节点创建对应的新节点,并把它放入已访问节点字典中。
 
3.next 指针
如果当前节点 i 的 next 指针指向的节点 j 在已访问字典中已有拷贝,我们直接使用它的拷贝节点。
如果当前节点 i 的next 指针指向的节点 j 还没有被访问过,我们创建一个对应节点的拷贝,并放入已访问字典。
 
4.我们重复步骤 2 和步骤 3 ,直到我们到达链表的结尾。
 
时间复杂度 o(n), 空间复杂度 o(n)。
代码:
/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        Node *old_node, *new_node, *head_new;
        if(!head)
            return head;
        unordered_map<Node*,Node*> m;
        old_node = head;
        new_node = new Node(old_node->val);
        m[old_node] = new_node;
        head_new = new_node;

        while(old_node)
        {
             if(old_node->random)
                new_node->random = copy(m, old_node->random);
            if(old_node->next) 
                new_node->next = copy(m, old_node->next);
           
            old_node = old_node->next;
            new_node = new_node->next;
            
        
          
        }

       return head_new;



        
    }

    Node *copy(unordered_map<Node*, Node*> &m, Node *old_node1)
    {

        unordered_map<Node*, Node*>::iterator it = m.find(old_node1);
        Node *new_node1;
        if(it!=m.end())
        {
            return it->second;
        }
        else
        {
            new_node1 = new Node(old_node1->val);
            m[old_node1] = new_node1;
            return new_node1;
        }
    }
};

 

思路:

1.遍历原来的链表并拷贝每一个节点,将拷贝节点放在原来节点的旁边,创造出一个旧节点和新节点交错的链表。

2.迭代这个新旧节点交错的链表,并用旧节点的 random 指针去更新对应新节点的 random 指针。比方说, B 的 random 指针指向 A ,意味着 B' 的 random 指针指向 A' 。

3.现在 random 指针已经被赋值给正确的节点, next 指针也需要被正确赋值,以便将新的节点正确链接同时将旧节点重新正确链接。即拆分新旧两个链表。
 
代码:
/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head==NULL)
            return head;

        Node *old_node, *new_node, *new_head;
        old_node = head;
        while(old_node)
        {
            new_node = new Node(old_node->val);
            new_node->next = old_node->next;
            old_node->next = new_node;
            old_node = new_node->next;
        }

        old_node = head;
        
        while(old_node)
        {
            new_node = old_node->next;
            if(old_node->random)
            new_node->random = old_node->random->next;
            old_node = old_node->next->next;
        }

        old_node = head;
        new_node = head->next;
        new_head = new_node;

        while(old_node)
        {
            old_node->next = old_node->next->next;
            if(new_node->next)
            new_node->next = new_node->next->next;
            old_node = old_node->next;
            new_node = new_node->next;
        }
        return new_head;


        
    }
};

 

posted on 2020-07-29 21:33  Little-Prince  阅读(149)  评论(0)    收藏  举报