复杂链表的复制

剑指 Offer 35. 复杂链表的复制

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

分析

注意这个题,主要是考察的深复制,并且所有结点的random结点其实都是指向的原来已创建出来的结点

方法1 哈希表

先不考虑randow指针,使用哈希的方式,建立原始链表和新创建结点的一一映射。

class Solution {
public:
    Node* copyRandomList(Node* head) {
        //使用字典建立原始链表和新链表结点的映射
        map dic;
        Node* cur = head;
        while(cur){
            dic[cur] = new Node(cur->val);
            cur = cur->next;
        }
        cur = head;
        while(cur){
            dic[cur]->next = dic[cur->next];
            dic[cur]->random = dic[cur->random];
            cur = cur->next;
        }
        return dic[head];
        
    }
};

方法2 就地复制

不使用哈希的方式。初始还是先不考虑random结点。
主要分为三步:

  • 在原始的链表的每一个结点的后面插入一个节点
  • 根据复制结点的前一个原始结点的random结点来指定复制结点的randow结点。因为每一个复制结点是原始结点的next结点,所以每一个复制结点的randow结点也是其相对应的原始结点的next结点。
  • 指定好randow结点之后,然后开始分割两个链表
class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(!head) return head;
        //为原始的链表添加复制结点
        Node* cur = head;
        while(cur){
            //链表中插入节点的时候,先保留当前结点的下一个节点
            Node* nxt = cur->next;
            Node* node = new Node(cur->val);
            cur->next = node;
            node->next = nxt;
            cur = nxt;
        }

        //指定复制链表链表节点的random结点
        cur = head;
        while(cur){
            Node* copyNode = cur->next;

            //需要判断random是否为空
            if(cur->random){
                copyNode->random = cur->random->next;
            }else{
                copyNode->random = NULL;
            }
            cur = copyNode->next;
        }
        //分割链表
        cur = head;
        Node* copyHead = cur->next;
        Node* copyNode = cur->next;
        cur->next = copyNode->next;
        cur = cur->next;
        //注意此处在分割两个链表的时候,要让拷贝结点在前,原始链表结点在后,否则会出现空指针异常
        while(cur){
            copyNode->next = cur->next;
            cur->next = cur->next->next;
            cur = cur->next;
            copyNode = copyNode->next;
        }
        return copyHead;     
    }
};

为了防止在分割链链表的时候出现先出现空指针异常,使得复制结点无法获得后继,那么上面的解法在循环中每一步都是让原始结点在后,复制结点在前,如果要使得复制结点在后的话,那么就要在原始结点为空的时候,及时判空,退出。即写法如下:

//分割链表
        cur = head;
        Node* copyHead = cur->next;
        Node* copyNode = cur->next;
        while(cur){         
            cur->next = cur->next->next;
            cur = cur->next;
            if(!cur){
                copyNode->next = NULL;
                break;
            }
            copyNode->next = cur->next;
            copyNode = copyNode->next;
        }
        return copyHead;  

你可能感兴趣的:(leetcode题解)