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

这道题目的关键在于,每个节点还包含一个随机节点,随机地指向链表中的一个节点。我们不但要深度拷贝所有原链表的节点,还需要准确地让拷贝链表中随机节点的对应关系和原链表保持一致。假如我们先拷贝原链表,然后查找源链表中的随机节点对应关系,借此来拷贝随机节点。那么每个查找每个对应关系都需要付出 O ( n ) O(n) O(n)的时间复杂度。拷贝整个链表的随机节点关系就需要 O ( n 2 ) O(n^2) O(n2)的时间复杂度。

哈希表

先把节点全部复制一遍,并且将原节点和拷贝后的节点一一对应存储再哈希表中。再遍历一遍源链表和拷贝链表,根据哈希表查找拷贝节点中每个随机节点对应的节点。

用哈希表,一个非常丑的写法。

class Solution {
    public Node copyRandomList(Node head) {
        if(head == null)
            return null;
        
        Node src = head;
        Node dstHead = new Node(src.val);
        HashMap<Node, Node> map = new HashMap();
        map.put(src, dstHead);

        Node dstPtr = dstHead;
        

        while(src.next != null){
            dstPtr.next = new Node(src.next.val);
            map.put(src.next, dstPtr.next);
            dstPtr = dstPtr.next;
            src = src.next;
        }
        
        dstPtr = dstHead;
        src = head;

        while(dstPtr != null){
            dstPtr.random = map.get(src.random);
            dstPtr = dstPtr.next;
            src = src.next;
        }

        return dstHead;
    }
}

来看看大佬的写法,多么漂亮。来源Krahets大神的题解。干净漂亮,太厉害了。

*/
class Solution {
    public Node copyRandomList(Node head) {
        Node src = head;
        HashMap<Node, Node> map = new HashMap();
        
        while(src != null){
            map.put(src, new Node(src.val));
            src = src.next;
        }
        src = head;
        
        while(src != null){
            map.get(src).next = map.get(src.next);
            map.get(src).random = map.get(src.random);
            src = src.next;
        }
        return map.get(head);
    }
}

还有一种原地置换的方法,折磨了我一个小时。大致分为三个步骤

  1. 拷贝,使得原链表每个元素重复一遍
  2. 修改random节点
  3. 将原链表和拷贝链表分开。
/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        if(head == null)
            return null;
        Node src = head;
        
        // 拷贝,使得链表每个元素重复一次
        while(src != null){
            Node temp = new Node(src.val);
            // temp.random = src.random;
            temp.next = src.next;
            src.next = temp;
            src = temp.next;
        }

        // 修改random节点
        src = head;
        while(src != null){
            if(src.random != null)
                src.next.random = src.random.next;
            src = src.next.next;
        }

        src = head.next;    
        Node res = head.next;     // 保存结果
        Node prev = head;   // 拆分得到原来链表
        while(src.next != null){
            // 注意,下面的语句不能写反,写反就GG了。
            prev.next = prev.next.next;
            src.next = src.next.next;
            src = src.next;
            prev = prev.next; 
        }

        prev.next = null;
        return res;
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值