剑指offer(二十五)-复杂链表的复制

示例:

输入:{1,2,3,4,5,3,5,#,2,#}

输出:{1,2,3,4,5,3,5,#,2,#}

解析:我们将链表分为两段,前半部分{1,2,3,4,5}为ListNode,后半部分{3,5,#,2,#}是随机指针域表示。

以上示例前半部分可以表示链表为的ListNode:1->2->3->4->5

后半部分,3,5,#,2,#分别的表示为

1的位置指向3,2的位置指向5,3的位置指向null,4的位置指向2,5的位置指向null

如下图:

第一种解法,借助一个辅助工具,借助一个map,第一次循环遍历链表,将每个节点和节点的复制值作为key和value放进map里面。第二次遍历链表,将每个节点都作为key去map中查询节点,获得当前节点的 random,并且复制给当前复制节点的random指针。代码如下

public RandomListNode firstClone(RandomListNode pHead) {
        if(null == pHead){
            return null;
        }
        HashMap<RandomListNode, RandomListNode> map = new HashMap<>();
        RandomListNode randomListNode = new RandomListNode(pHead.label);
        RandomListNode head = pHead;
        RandomListNode cloneHead = randomListNode;
        map.put(head,cloneHead);
        while (null != head.next){
            cloneHead.next = new RandomListNode(head.next.label);
            head = head.next;
            cloneHead = cloneHead.next;
            map.put(head,cloneHead);
        }
        head = pHead;
        cloneHead = randomListNode;
        while (null != cloneHead){
            cloneHead.random = map.get(head.random);
            head = head.next;
            cloneHead = cloneHead.next;
        }
        return randomListNode;
    }

第二种解法,简称双节点解法,顾名思义,就是在复制节点的时候,将复制节点放在当前节点的后面,复制节点random就是当前节点random,这样操作之后,就是每个节点都存在双份,结果按奇或偶拆分链表即可。结合代码画个图给大家,方便大家,也方便自己加强理解,代码如下

while (null != head){

        RandomListNode node = new RandomListNode(head.label);

        node.next = head.next;

        head.next = node;

        head = node.next;

    }

上面这段代码执行以后,如下图

while (null != head && null != head.next){
        if(null != head.random){
            head.next.random = head.random.next;
        }
        //因为每个节点后面跟了一个复制节点,所以需要跳两级
        head = head.next.next;
    }

 上面这段代码执行之后,如下图

 while (null != head && null != head.next){
        head.next = head.next.next;
        if(null == head.next){
            result.next = null;
        }else {
            result.next = head.next.next;
        }
        result = result.next;
        head = head.next;
    }

 此代码就是对处理过的链表进行拆分,如下图

 完整代码如下

 public RandomListNode secondClone(RandomListNode pHead) {
        if (null == pHead) {
            return null;
        }
        RandomListNode head = pHead;
        while (null != head){
            RandomListNode node = new RandomListNode(head.label);
            node.next = head.next;
            head.next = node;
            head = node.next;
        }
        head = pHead;
        while (null != head && null != head.next){
            if(null != head.random){
                head.next.random = head.random.next;
            }
            //因为每个节点后面跟了一个复制节点,所以需要跳两级
            head = head.next.next;
        }
        RandomListNode resultHead = pHead.next;
        head = pHead;
        RandomListNode result = resultHead;
        //拆分链表
        while (null != head && null != head.next){
            head.next = head.next.next;
            if(null == head.next){
                result.next = null;
            }else {
                result.next = head.next.next;
            }
            result = result.next;
            head = head.next;
        }
        return resultHead;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值