JZ35:复杂链表的复制

题目链接JZ35: 复杂链表的复制
题目描述:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。
在这里插入图片描述
深拷贝和浅拷贝的区别 参考链接
数据类型分为基本数据类型和引用数据类型,基本数据类型的数据直接存储在栈中,引用数据类型 存储的是该对象在栈中的引用,真实的数据存放在堆内存中。
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝:会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会影响到原对象。

题目分析:
哈希法:将旧结点和新结点的映射关系存储到hash表中,方便后续查找。这样新链表和旧链表每个结点的指向就有了关联。两次循环链表,先创建结点复制label,再修改 random 和 next 指针的指向。最后返回头结点的映射。
时间复杂度:O(n) 遍历链表和哈希表
空间复杂度:O(n) 创建一个哈希表存储结点地址映射
在这里插入图片描述

import java.util.HashMap;
import java.util.Map;
public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        //哈希表法
        if(pHead==null){
            return null;
        }
        RandomListNode cur = pHead;
        HashMap<RandomListNode,RandomListNode> map = new HashMap<>();
        //将原结点和复制结点进行映射,存储在hashmap中
        while(cur!=null){
            RandomListNode copyNode = new RandomListNode(cur.label); //创建新结点并赋值
            map.put(cur,copyNode);
            cur = cur.next;
        }
        //让cur重新指回头结点,再次遍历链表,修改指针指向
        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);
    }
}

链表拼接、拆分。看题解一位大佬讲解滴,妙~啊。将复制结点链接到原结点的后面,组成一条链表,再去更改新结点的random指针,使用双指针法更改链表的next指针,拆分旧链表和新链表。理解代码!
时间复杂度:O(n) 遍历三次链表
空间复杂度:O(1) 常数个链表指针变量
在这里插入图片描述

public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if(pHead==null){
            return pHead;
        }
        RandomListNode cur = pHead;
        //将copyNode链接到链表结点的后面
        while(cur!=null){
            RandomListNode copyNode = new RandomListNode(cur.label);
            copyNode.next = cur.next;
            cur.next = copyNode;
            cur = copyNode.next;
        }
        //修改随机指针
        cur = pHead; //记录原链表结点
        RandomListNode pre = pHead.next; //记录复制链表结点
        while(cur!=null){
            //处理随机结点为null的情况
            pre.random = (cur.random==null)?null:cur.random.next;
            //判空指针
            if(cur.next!=null){
                cur = cur.next.next;
            }
            if(pre.next!=null){
                pre = pre.next.next;
            }
        }
        //过河拆桥(拆分两个链表使它们分别称为两个独立的链表)
        cur = pHead;
        pre = pHead.next;
        RandomListNode ret = pHead.next;
        while(cur!=null){
            if(cur.next!=null){
                cur.next = cur.next.next;
            }
            if(pre.next!=null){
                pre.next = pre.next.next;
            }
            cur = cur.next;
            pre = pre.next;
        }
        return ret;
    }
}

总结:哈希映射是比较好理解的做法,容易想明白;但是当我看见法二时有被惊艳到,并且空间复杂度为O(1),重在理解吧,至少掌握其中以一种方法吧!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值