2020.7.8编程练习

135 阅读2分钟

题目:剑指 Offer 35. 复杂链表的复制

不难看出题目的难点,由于是链表结构,所以无法直接访问复制出来的新节点。

方法一

对于每个新节点,遍历新链表来寻找对应的random节点,时间复杂度是O(n^2)。

方法二

由于方法一的时间主要花费再定位random节点上,可以在这方面着手去优化。可以讲解题分为两步,第一步仍然是复制原链表生成新链表,并将节点配对信息存储在哈希表中。这样就能以O(1)的时间找到random节点。同时也相当于是用空间换时间,因为我们需要一个O(n)大小的哈希表。

方法三(参考剑指offer解析)

将解题步骤分为三步,第一步仍然是复制原链表,但不同的是,将复制出来的节点链接在原节点之后,串成一个链表。

    void cloneNodes(Node* head){
        Node* cur = head;
        while(cur){
            Node* newNode = new Node(0);
            newNode->val = cur->val;
            newNode->next = cur->next;

            cur->next = newNode;
            cur = newNode->next;
        }
    }

第二步则是给新节点赋值random节点,由于整个链表是串行的,所以整体只需要O(N) 的时间。

    void connectRandomNodes(Node* head){
        Node* cur = head;
        while(cur){
            if(cur->random){
                cur->next->random = cur->random->next;
            }
            cur = cur->next->next;
        }
    }

第三步则是将链表分离为原链表和新链表。

    Node* reconnectNodes(Node* head){
        Node* cur = head;
        Node* cloneHead = NULL;
        Node* cloneCur = NULL;

        if(cur != NULL){
            cloneHead = cur->next;
            cloneCur = cur->next;
            cur->next = cloneCur->next;
            cur = cur->next;
        }
        while(cur){
            cloneCur->next = cur->next;
            cloneCur = cur->next;
            cur->next = cloneCur->next;
            cur = cur->next;
        }
        return cloneHead;
    }

最后将这三步串联起来形成题解。

    Node* copyRandomList(Node* head) {
        //首先复制链表中每个节点,并链接在每个原结点后
        cloneNodes(head);
        //再讲所有复制节点的random指针指向对应node
        connectRandomNodes(head);
        //最后再分割链表为两个
        return reconnectNodes(head);
    }

坑点

方法三的第三步里,因为循环的条件是原链表的cur指针是否为空,所以巧妙的使原链表的cur指针走在新链表cur指针的前面,可以减少对于边界情况null指针的判断。这样不仅简洁也增强了代码的鲁棒性。