剑指offer——复杂链表的复制(Java)

题目:
请实现函数 public Node clone(Node pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个Next指针指向下一个结点外,还有一个random指向链表中的任意结点或者NULL。结点的定义如下:

public class Node {
    public int val;
    public Node next;
    public Node random;
    public Node (int val){
        this.val = val;
    }
}

在这里插入图片描述
上图是一个包含四个复杂结点的复杂链表,实现代表next指针,虚线代表random指针。

第一思路
复杂链表的复制可以分为两个部分,第一步就是将全部结点复制,并用next指针链接起来,第二布是把每个结点的random指针指向它对应的复制结点。这样的话第一步的事件复杂度为便利一次单链表的时间复杂度即为:O(n),第二部则需要首先便利每一个random指针,找到其指向的对应位置,然后便利复制结点找到当前random应该指向的位置,这样的话时间复杂度为O(n2),这样的话整个复制算法的时间复杂度为O(n2)。
优化思路
我们可以在复制结点的时候把,A和A`以key和value来存储进一个Map中,这样在寻找random指向位置的时候就可以通过Map.get()方法来直接获取到复制结点的random应该指向的结点。不过这样做事以O(n)的空间来换取了O(n)的时间。
代码实现

 public static Node cloneNode(Node pHead){
        if (pHead == null){
            return null;
        }
        HashMap<Node,Node> nodeHashMap = new HashMap<>();
        Node pCloneHead = new Node(pHead.val);
        Node pNode = pHead;
        Node pCloneNode = pCloneHead;
        nodeHashMap.put(pNode,pCloneNode);
        while (pNode.next != null){
            pCloneNode.next = new Node(pNode.next.val);
            pNode = pNode.next;
            pCloneNode = pCloneNode.next;
            nodeHashMap.put(pNode, pCloneNode);
        }
        pNode = pHead;
        pCloneNode = pCloneHead;
        while (pCloneNode != null){
            pCloneNode.random = nodeHashMap.get(pNode.random);
            pNode = pNode.next;
            pCloneNode = pCloneNode.next;
        }
        return pCloneHead;
    }

总结
通过HashMap的特性,来以O(n)的空间复杂度来换取了O(N2)的时间复杂度变为O(n)。

最优解法
不用O(n)的空间复杂度来实现O(n)的时间效率。

第一步:让仍然是根据原始链表的每个结点N创建对应的N’。不过我们把N’链接在N的后面。

第二步:设置复制出来的结点的random 。原始链表上的A的random 指向结点C,那么其对应复制出来的A’是A的next指向的结点,同样C’也是C的m_pNext指向的结点。即A’ = A.next,A’.random = A.random .next;故像这样就可以把每个结点的random 设置完毕。

第三步:将这个长链表中源节点删除掉,这样便得到了复制后的复杂链表。

代码实现

    //在每个结点后添加其复制后的结点
    public static void clone(Node pHead){
        Node pNode = pHead;
        while (pNode != null){

            Node pClone = new Node(pNode.val);
            if(pNode.next != null){
                pClone.next = pNode.next;
                pClone.random = null;

                pNode.next = pClone;
                pNode = pClone.next;
            }else {
                pNode.next = pClone;
               break;
            }

        }
    }
    //设置每个结点的random(注:m_pSibling为空结点不做修改)
    public static void random(Node pHead){
        Node pNode = pHead;
        while (pNode != null){
            Node pClone = pNode.next;
            if(pNode.random != null){
                pClone.random = pNode.random.next;
            }
                pNode = pClone.next;
        }
    }
    //拆分链表
    public static Node del(Node pHead){
        Node pNode = pHead;
        Node pCloneHead = null;
        Node pCloneNode = null;
        if (pNode != null){
            pCloneHead = pCloneNode = pNode.next;
            pNode.next = pCloneNode.next;
            pNode = pNode.next;
        }
        while (pNode != null){
            pCloneNode.next = pNode.next;
            pCloneNode = pCloneNode.next;
            pNode.next = pCloneNode.next;
            pNode = pNode.next;
        }
        return pCloneHead;
    }
    public static Node zhenghe(Node pHead){
        clone(pHead);
        random(pHead);
        return del(pHead);
    }

总结
这个复制算法通过三次便利便将复制后的复杂链表得到了,这样的时间复杂度为O(n);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值