剑指offer 复杂链表的复制

牛客链接
普通链表的深拷贝只需要通过遍历原链表一次就能实现,但是题目给出的复杂链表多了random指针,会跳跃性的指向任意节点,这让我们无法通过一次遍历解决这个问题。

利用HashMap建立映射

提前存储新节点对应哪个原节点,这样就能够找到新节点的random指针应该指向哪(指向原节点的random指针指向的节点的对应新节点)。

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
import java.util.HashMap;
public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        if (pHead == null) return null;
        // 1. 建立<原节点, 新节点>的映射
        HashMap<RandomListNode, RandomListNode> map = new HashMap<>();
        RandomListNode cur = pHead;
        while (cur != null) {
            map.put(cur, new RandomListNode(cur.label));
            cur = cur.next;
        }
        // 2. 根据映射关系,设置每个节点的两个指针
        cur = pHead;
        while (cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(pHead);
    }
}

需要遍历链表两次O(n),且需要建立辅助map,O(n)。

不使用额外空间

看注释。

/*
// 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;
        // 不使用辅助空间map
        // 1. 将原始链表构造成A->A'->B->B'->...的形式
        Node cur = head;
        while (cur != null) {
            Node newNode = new Node(cur.val);
            newNode.next = cur.next;
            cur.next = newNode;
            cur = cur.next.next;
        }
        // 2. 设置新节点(A', B', C', ...)的random指针(主要目的)
        // 跟Map异曲同工,Map是保存映射关系,而这个直接就让两个对应的节点挨着,方便找到自己的random
        cur = head;
        while (cur != null) {
            // ×空指针判断
            if (cur.random != null)
                cur.next.random = cur.random.next;
            cur = cur.next.next;
        }
        // 3. 将这个组合链表拆分开来,奇数位置是原始链表,偶数位置是新链表(从1开始)
        Node pre = head;
        cur = head.next;
        Node newHead = head.next;
        while (cur.next != null) {
            pre.next = pre.next.next;
            cur.next = cur.next.next;
            pre = pre.next;
            cur = cur.next;
        }
        // 此时pre.next仍然连接到cur,需要设置为pre.next.next即为null
        pre.next = null; 
        return newHead;
    }
}

不使用额外空间,时间复杂度仍然为O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值