Leecode-138. 复制带随机指针的链表(击败100%用户,通俗易懂)

题目描述

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的 深拷贝。

我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。

示例 1:

在这里插入图片描述
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:

在这里插入图片描述

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:

在这里插入图片描述

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:

输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

提示:

-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

方法一:
1、首先考虑边界,当head为空时,不用拷贝,直接返回head。
2、如果不考虑random指针,复制一个链表很简单,可以新建一个newHead引用,然后依次遍历原链表,然后对于每一个节点,用其值新建节点,并依次将这些节点链接在新的链表newHead上。
3、在本题中,对于每个节点还存在一个随机指向另一个节点的指向信息需要拷贝。在前面所述的拷贝操作中,可以将新链表的节点引用依次存放在一个数组中,就可通过访问数组下标来快速的获得新链表中各个节点的引用,对于新链表的每个节点,如果我们知道了旧链表中random指向节点的位置index,那么让每个节点根据位置信息,指向刚刚所建立的数组中的元素,即可完成深拷贝。
4、为了获取旧链表中指定节点的位置,可以从头遍历链表并维护一个位置index,遍历一个节点,index++,当前节点为所要寻找节点,返回index。
针对每一个节点在获取random的位置信息时,最坏的时间复杂度是O(n),即遍历整个链表,时间复杂度O(n2)

方法一实现代码(Java):


/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

class Solution {
    public int findIndex(Node head,Node fn)
    {
        Node temp=head;
        int index=0;
        while(temp!=null&&fn!=temp)
        {
            index++;
            temp=temp.next;
        }
        return index;
    }
    public Node copyRandomList(Node head) {
        if(head==null)
        {
            return head;
        }
        Node newHead=new Node(head.val);
        Node p1=head.next;
        Node p2=newHead;
        List<Node> nodes=new ArrayList<Node>();
        nodes.add(newHead);
  
        while(p1!=null)//不考虑随机节点下复制
        {
            Node node=new Node(p1.val);
            p2.next=node;
            nodes.add(node);
            p2=p2.next;
            p1=p1.next;
        }
        p2=newHead;
        p1=head;
        while(p2!=null)
        {
            Node node=p1.random;
            if(node!=null)
            {
                int index=findIndex(head,node);
                p2.random=nodes.get(index);
            }
            p1=p1.next;
            p2=p2.next;
        }
        return newHead;
    }
}

在这里插入图片描述

方法二:由上图可以发现,这种方法效率很低。方法一存在一个问题,针对每一个节点,在复制节点的random信息时,为了获取特定节点的位置信息时,需要去从头遍历节点,其实在遍历过程,针对该特定节点之前节点的位置信息,我们已经获得,但是下次需要这些信息时,我们需要再次重复计算,所以在整个计算过程造成了大量的资源浪费。如果将这些位置信息保存下来,就会大大的提高程序的运行速度。
故方法二中,我采用hashmap<Node,Integer>,在第一次不考虑随机节点遍历时,就记录下原始链表中各个节点的位置信息:
HashMap<Node,Integer> map=new HashMap<>();
map.put(node,index)
然后利用map的get方法就可以快速的获取原始链表指定节点的位置信息,且不会造成重复运算。
方法二实现代码(Java)

class Solution {
    public Node copyRandomList(Node head) {
        if(head==null)
        {
            return head;
        }

        Node newHead=new Node(head.val);
        Node p1=head.next;
        Node p2=newHead;
        List<Node> nodes=new ArrayList<Node>();
        HashMap<Node,Integer> map=new HashMap<>();
        nodes.add(newHead);
        int index=0;
        map.put(head,index);
        while(p1!=null)
        {
            index++;
            map.put(p1,index);//记录原始链表的位置信息
            Node node=new Node(p1.val);
            p2.next=node;
            nodes.add(node);
            p2=p2.next;
            p1=p1.next;
        }
        p2=newHead;
        p1=head;
        while(p2!=null)
        {
            Node node=p1.random;
            if(node!=null)
            {
                p2.random=nodes.get(map.get(node));
            }
            p1=p1.next;
            p2=p2.next;
        }
        return newHead;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值