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

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

题目

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

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. 复杂链表的复制



相关文章
|
1月前
链表指针的传参,传值和传地址
本文讨论了链表操作中指针传参的问题,特别是指针的传值与传地址的区别,并提供了修正代码,以确保链表插入操作能正确地修改指针指向的地址。
16 1
链表指针的传参,传值和传地址
|
1月前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
17 0
LeetCode第二十四题(两两交换链表中的节点)
|
1月前
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
40 0
Leetcode第十九题(删除链表的倒数第N个节点)
|
1月前
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
46 0
|
1月前
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
17 0
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
22 0
|
3月前
|
算法
LeetCode第24题两两交换链表中的节点
这篇文章介绍了LeetCode第24题"两两交换链表中的节点"的解题方法,通过使用虚拟节点和前驱节点技巧,实现了链表中相邻节点的交换。
LeetCode第24题两两交换链表中的节点
10_填充每个节点的下一个右侧节点指针
10_填充每个节点的下一个右侧节点指针
05_删除链表的倒数第N个节点
05_删除链表的倒数第N个节点
04_两两交换链表中的节点
04_两两交换链表中的节点