【算法】复杂链表的复制

先上题目

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

RandomListNode类
public class RandomListNode {
    int label;//节点值
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}

思路

两种解题思路,第一种使用map来保存新旧两个链表,第二种是先把链表复制一遍,然后再拆分成两个。

1、map方法

用map存放新旧两个链表,由于复制链表有一个random指针指向随机节点,因此当我们追踪某个节点的next时,可能这个next是之前某个节点的random,已经被存入map中了,所以就不用再存入,了解这种情况后代码看起来就比较清晰了。上代码

public class Clone {
    private static RandomListNode solution(RandomListNode pHead){
        //判空
        if (pHead == null)  return null;

        //用来存放两个链表的map,key为旧链表,value为新链表
        Map<RandomListNode, RandomListNode> map = new HashMap<>();
        //新链表的头
        RandomListNode newHead = new RandomListNode(pHead.label);
        //追踪旧链表的指针
        RandomListNode point = pHead;
        //追踪新链表的指针
        RandomListNode newPoint = newHead;

        while (point!=null){
            //追踪next
            if (point.next!=null && map.containsKey(point.next)){
                newPoint.next = map.get(point.next);
            }else {
                //先判断next是否存在
                if (point.next!=null){
                    //这里要生成一个新的节点,否则直接temp=point.next的话next节点的next信息也带在其中,题目就没有意义了
                    RandomListNode temp = new RandomListNode(point.next.label);
                    map.put(point.next, temp);
                    newPoint.next=temp;
                }
            }

            //追踪random
            if (point.random!=null && map.containsKey(point.random)){
                newPoint.random = map.get(point.random);
            }else {
                //先判断random是否存在
                if (point.random!=null){
                    //同样要生成新节点
                    RandomListNode temp = new RandomListNode(point.random.label);
                    newPoint.random = temp;
                    map.put(point.random, temp);
                }
            }
            //两个指针都指向下一个
            point = point.next;
            newPoint = newPoint.next;
        }
        return newHead;
    }
}
2、复制解法

1、先将链表每个节点复制一次,复制出来的节点插到原节点的后边
2、遍历链表,给复制出来的节点赋上random
3、将链表拆分成两个
如果理解不了可以自己画个图,这里第3步只举了一个while循环
在这里插入图片描述

private static RandomListNode solution(RandomListNode pHead){
        //判空
        if (pHead == null)  return null;

        //用来追踪的指针
        RandomListNode point = pHead;
        //新链表的头,最后返回用到
        RandomListNode newHead = null;

        //1、复制链表
        while (point!=null){
            //克隆出当前节点
            RandomListNode cloneNode = new RandomListNode(point.label);
            //把下一个节点提取出来
            RandomListNode next = point.next;
            //将克隆出来的节点插入
            point.next = cloneNode;
            cloneNode.next=next;
            //指向下一个节点
            point=next;
        }

        //指针回到头结点
        point = pHead;

        //2、遍历链表,给复制出来的链表插上random
        while (point!=null){
            if (point.random!=null){
                //这里有个坑,一开始没注意到困惑了很久
                //注意这里的point.next.random要指向point.random.next!!, 这个next不能掉,否则就带有random节点的信息了。跟map解法中要生成新的节点一个道理
                point.next.random = point.random.next;
            }else {
                point.next.random = null;
            }
            point = point.next.next;
        }

        //指针回到头结点
        point = pHead;

        //3、拆分两个链表
        newHead = pHead.next;
        while (point!=null){
            //属于新链表的节点
            RandomListNode cloneNode = point.next;
            //属于旧链表的节点,cloneNode.next就是他原本的下一个节点
            point.next = cloneNode.next;
            //这里要进行判空,否则会报错
            cloneNode.next = cloneNode.next==null? null : cloneNode.next.next;
            point = point.next;
        }

        return newHead;

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值