剑指Offer-题35(Java版):复杂链表的复制

参考自:《剑指Offer——名企面试官精讲典型编程题》

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

主要思路
分三步:
第一步:复制每个旧节点,使得新节点A’在旧节点A后面(A ->A’ ->B)。
第二步:根据旧节点的额外节点,设置新节点对应的额外节点。其中,新额外节点 = 旧额外节点的下一个节点。
第三步:拆分前两步生成的链表成2个链表,使得新节点和旧节点分离。每次旧节点移动2步,新节点就是旧节点的前一个节点和后一个节点,然后连接新节点和它的下一个节点。
例如:
A ->A’ ->B ->B’ ->C ->C’
A’.next = B.next(其中B.next 即为B’)

关键点:分步,先复制后拆分

时间复杂度:O(n)

public class CloneLinkedList
{
    public static void main(String[] args)
    {
        RandomListNode head = getTestData();
        RandomListNode newHead = clone(head);
        while (newHead != null)
        {
            if (newHead.random != null)
            {
                System.out.printf("节点值:%s  额外节点值:%s", newHead.label, newHead.random.label);
            } else
            {
                System.out.printf("节点值:%s", newHead.label);
            }
            System.out.println();
            newHead = newHead.next;
        }
    }

    private static RandomListNode getTestData()
    {
        RandomListNode head = new RandomListNode(1);
        RandomListNode head2 = new RandomListNode(2);
        RandomListNode head3 = new RandomListNode(3);
        RandomListNode head4 = new RandomListNode(4);
        head.next = head2;
        head2.next = head3;
        head3.next = head4;
        head2.random = head4;  //额外节点
        return head;
    }

    private static RandomListNode clone(RandomListNode pHead)
    {
        cloneNodes(pHead);
        connectSibling(pHead);
        return reconnectNode(pHead);
    }

    //复制每个旧节点
    private static void cloneNodes(RandomListNode pHead)
    {
        RandomListNode oldNode = pHead;
        //复制每个旧节点,使得新节点A'在旧节点A后面
        //A ->A' ->B
        while (oldNode != null)
        {
            RandomListNode newNode = new RandomListNode(oldNode.label);
            RandomListNode oldNext = oldNode.next;
            newNode.next = oldNext;
            oldNode.next = newNode;
            oldNode = oldNext;
        }
    }

    //设置新节点的额外节点
    private static void connectSibling(RandomListNode pHead)
    {
        RandomListNode oldNode = pHead;
        //根据旧节点的额外节点,设置新节点对应的额外节点。
        while (oldNode != null)
        {
            RandomListNode newNode = oldNode.next;
            RandomListNode oldRandom = oldNode.random;  //旧节点指向的额外节点
            if (oldRandom != null)
            {
                //新额外节点 = 旧额外节点的下一个节点
                newNode.random = oldRandom.next;
            }
            oldNode = newNode.next;
        }
    }

    /**
     * 长链表拆成新旧2个链表
     *
     * @param pHead
     * @return
     */
    private static RandomListNode reconnectNode(RandomListNode pHead)
    {
        RandomListNode oldNode = pHead;
        RandomListNode newHead = null;
        RandomListNode newNode = null;
        //获取头指针
        if (pHead != null)
        {
            newHead = pHead.next;
            newNode = newHead;
            oldNode = newNode.next;
        }
        while (oldNode != null)
        {
            RandomListNode newNext = oldNode.next;
            //连接新节点的下一个节点
            newNode.next = newNext;
            newNode = newNext;
            //旧节点移动2步
            if (newNext == null) break;
            oldNode = newNext.next;
        }
        return newHead;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37862405/article/details/80287260
今日推荐