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

题目

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

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

示例 1:
在这里插入图片描述
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:
在这里插入图片描述
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

示例 3:
在这里插入图片描述
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]

示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

分析

题目要求把原链表复制一份出来,难点在于节点不仅有next域,还有random域,而random的指向并不是顺序的,所以需要一些技巧

思路1 - 节点副本
在每个结点后面复制出一个节点副本,并对新的节点维护random关系,依次将节点副本连接起来,即为新链表。

需要遍历一遍链表,时间复杂度是 O ( n ) O(n) O(n)

思路2 - 哈希
如前所述,此题难点在于random的指向并不是顺序的,所以顺次访问结点时,可能结点的random指针指向一个还不存在的节点,所以应该在访问前创建好节点,由此可知,创建节点的顺序并不是链表的节点顺序。

可以使用哈希表建立新链表与旧链表节点之间的映射,key为旧链表节点,value为对应的新链表节点,遍历链表时,如果节点的哈希值不存在或者其random节点的哈希值不存在,则创建新节点,否则说明该结点已创建,只要维护next和random关系就好。这样就能综合考虑原节点次序以及random节点次序,合理创建新的节点。

同样需要遍历一遍链表,时间复杂度是 O ( n ) O(n) O(n)

代码实现(cpp)

思路1 - 节点副本 O ( n ) O(n) O(n)

class Solution {
public:
    Node* copyRandomList(Node* head) {
        Node* cur = head;
        
        // 每个结点复制出一个新节点
        while (cur) {
            Node* tmp = cur->next;
            Node* copy = new Node(cur->val);
            cur->next = copy;
            copy->next = tmp;

            cur = tmp;
        }

        // 维护random关系
        cur = head;
        while (cur) {
            if (cur->random != nullptr) cur->next->random = cur->random->next;
            cur = cur->next->next;
        }

        Node* res = new Node(-1);
        Node* p = res; //新链接当前节点
        cur = head;
        while (cur) {
            p->next = cur->next;
            p = p->next;
            cur->next = cur->next->next;  //恢复原链表
            cur = cur->next;
        }
        
        return res->next;
    }
};

思路2 - 哈希 O ( n ) O(n) O(n)

class Solution {
public:
    Node* copyRandomList(Node* head) {
        unordered_map<Node*, Node*> mp;
        Node* res = new Node(-1);
        Node* cur = head; // 遍历旧链表的指针
        Node* p = res; // 新链表当前节点
        mp[nullptr] = nullptr; //因为某些节点的random节点可能是空,防止访问出错

        while (cur) {
            if (!mp.count(cur)) mp[cur] = new Node(cur->val); //复制出一个新节点
            if (!mp.count(cur->random)) mp[cur->random] = new Node(cur->random->val);  // 复制出其random节点
            
            p->next = mp[cur];
            p->next->random = mp[cur->random];

            p = p->next;
            cur = cur->next;
        }

        return res->next;
    }
};

总结

这两种做法的时间复杂度都是 O ( n ) O(n) O(n),应该还可以优化,之后再更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值