复制含有随机指针节点的链表

简介: 复制含有随机指针节点的链表

题目

一种特殊的单链表节点类描述如下:

class Node {
    int value;
    Node next;
    Node rand;
    Node(int val) {
        value = val ;
    }
}
复制代码

rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点,也可能指向null。给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。

【要求】时间复杂度O(N),额外空间复杂度0(1)

法一:Hash表拷贝链表

笔试中使用能帮助尽快解题

思路

  • 遍历原链表,采用一个Hash表,其key值放老结点的内存地址,value放入从老结点中复制得来的新结点内存地址,当结点遍历完毕后,所有的新旧结点均拷贝完毕;
  • 再次遍历原链表,每遍历一个结点,就得出他的rand和next指针,然后因为next指针和rand指针都是作为Hash表key存在,所以可以依据这个next和rand指针经由hash函数得出其对应新结点的所在地址(假设为N和R),再根据当前结点和哈希函数,得出当前结点的新结点,然后再设置新结点的next和rand指针分别指向N和R

复杂度

空间复杂度为O(N),时间复杂度为O(N)

public static Node copyListWithRand1(Node head){
    HashMap<Node, Node> map = new HashMap<Node, Node>();
    Node cur = head;
    while(cur != null){
        map.put(cur, new Node(cur.value));
        cur = cur.next;
    }
    cur = head;
    while(cur != null){
        // cur 老
        // map.get(cur) 新
        map.get(cur).next = map.get(cur.next);
        map.get(cur).rand = map.get(cur.rand);
        cur = cur.next;
    }
    return map.get(head);
}
复制代码

法二:利用新旧节点之间的位置关系

思路

利用新旧节点之间的位置关系而省略了方法一中的额外的hash表空间

步骤

  • 生成克隆节点:把克隆节点就直接放在老链表的下一个,然后克隆节点去串上老链表的下一个(克隆节点插在当前所遍历节点与下一个要遍历节点之间),遍历完成之后,老节点的rand指向保持不变,新节点的rand无指向,如下图:
    网络异常,图片无法展示
    |
  • 设置克隆节点的rand:遍历含有新老节点的链表,每次遍历到老节点时,能获取到rand,此时直接设置克隆节点的rand
  • 分离新老链表

复杂度

空间复杂度为O(1),时间复杂度为O(N)

public static Node copyListWithRand2(Node head){
    if(head == null){
        return null;
    }
    Node cur = head;
    Node next = null;
    // copy node and link to every node
    // 1->2
    // 1->1'->2
    while(cur != null){
        next = cur.next;
        cur.next = new Node(cur.value);
        cur.next.next = next;
        cur = next;
    }
    cur = head;
    Node curCopy = null;
    // set copy node rand
    // 1->1'->2->2'
    while(cur != null){
        next = cur.next.next;
        curCopy = cur.next;
        curCopy.rand = cur.rand != null ? cur.rand.next : null;
        cur = next;
    }
    Node res = head.next;
    cur = head;
    // split
    while(cur != null){
        next = cur.next.next;
        curCopy = cur.next;
        cur.next = next;
        curCopy.next = next != null ? next.next : null;
        cur = next;
    }
    return res
}
复制代码

相关LeetCode题

138. 复制带随机指针的链表

剑指 Offer 35. 复杂链表的复制



相关文章
|
4天前
|
算法
LeetCode第24题两两交换链表中的节点
这篇文章介绍了LeetCode第24题"两两交换链表中的节点"的解题方法,通过使用虚拟节点和前驱节点技巧,实现了链表中相邻节点的交换。
LeetCode第24题两两交换链表中的节点
|
13天前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
32 5
|
1月前
【数据结构OJ题】复制带随机指针的链表
力扣题目——复制带随机指针的链表
37 1
【数据结构OJ题】复制带随机指针的链表
|
13天前
|
Python
【Leetcode刷题Python】剑指 Offer 18. 删除链表的节点
Leetcode题目"剑指 Offer 18. 删除链表的节点"的Python解决方案,通过使用双指针法找到并删除链表中值为特定数值的节点,然后返回更新后的链表头节点。
24 4
|
15天前
|
Python
【Leetcode刷题Python】138. 复制带随机指针的链表
LeetCode上题目“138. 复制带随机指针的链表”的Python解决方案,包括两种方法:一种是在每个节点后复制一个新节点然后再分离出来形成新链表;另一种是构建一个字典来跟踪原始节点与其副本之间的映射关系,从而处理新链表的构建。
7 1
|
26天前
|
安全 云计算
云计算自旋锁问题之在线程安全地删除链表节点时,需要频繁加锁会影响性能如何解决
云计算自旋锁问题之在线程安全地删除链表节点时,需要频繁加锁会影响性能如何解决
29 2
|
2月前
|
算法
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
【数据结构与算法 刷题系列】求带环链表的入环节点(图文详解)
|
2月前
24. 两两交换链表中的节点
24. 两两交换链表中的节点
|
2月前
|
算法
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
|
2月前
|
存储
删除链表的节点
删除链表的节点
20 0