剑指offer-25、复杂链表的复制

题⽬描述

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

思路及解答

哈希表映射

使用哈希表存储原节点和新节点的映射关系:

  1. 第一次遍历:创建所有新节点,并建立原节点到新节点的映射
  2. 第二次遍历:根据映射关系设置新节点的nextrandom指针
public class Solution {
 public Node copyRandomList(Node head) {
 if (head == null) {
 return null;
 }
 
 // 创建哈希表存储原节点到新节点的映射
 HashMap<Node, Node> map = new HashMap<>();
 Node current = head;
 
 // 第一次遍历:创建所有新节点并建立映射
 while (current != null) {
 map.put(current, new Node(current.val));
 current = current.next;
 }
 
 // 第二次遍历:设置新节点的next和random指针
 current = head;
 while (current != null) {
 Node newNode = map.get(current);
 newNode.next = map.get(current.next);
 newNode.random = map.get(current.random);
 current = current.next;
 }
 
 return map.get(head);
 }
}
class Node {
 int val;
 Node next;
 Node random;
 
 public Node(int val) {
 this.val = val;
 this.next = null;
 this.random = null;
 }
}
  • 时间复杂度​:O(n),两次遍历链表
  • 空间复杂度​:O(n),需要存储所有节点的映射关系

节点插入拆分法

通过在原链表中插入新节点来避免使用额外空间:

  1. 节点复制插入​:在每个原节点后面插入一个复制的新节点
  2. 设置random指针​:新节点的random指向原节点random的下一个节点
  3. 链表拆分​:将混合链表拆分为原链表和新链表
public class Solution {
 public Node copyRandomList(Node head) {
 if (head == null) {
 return null;
 }
 
 // 第一步:在每个节点后面插入复制的节点
 Node current = head;
 while (current != null) {
 Node newNode = new Node(current.val);
 newNode.next = current.next;
 current.next = newNode;
 current = newNode.next;
 }
 
 // 第二步:设置复制节点的random指针
 current = head;
 while (current != null) {
 if (current.random != null) {
 current.next.random = current.random.next;
 }
 current = current.next.next;
 }
 
 // 第三步:拆分链表
 Node newHead = head.next;
 current = head;
 while (current != null) {
 Node temp = current.next;
 current.next = temp.next;
 if (temp.next != null) {
 temp.next = temp.next.next;
 }
 current = current.next;
 }
 
 return newHead;
 }
}
  • 时间复杂度​:O(n),三次遍历链表
  • 空间复杂度​:O(1),只使用固定数量的指针变量
作者:程序员Seven原文地址:https://www.cnblogs.com/seven97-top/p/19054746

%s 个评论

要回复文章请先登录注册