题⽬描述
输⼊⼀个复杂链表(每个节点中有节点值,以及两个指针,⼀个指向下⼀个节点,另⼀个特殊指针random 指向⼀个随机节点),请对此链表进⾏深拷⻉,并返回拷⻉后的头结点。(注意,输出结果中请不要返回参数中的节点引⽤,否则判题程序会直接返回空)
思路及解答
哈希表映射
使用哈希表存储原节点和新节点的映射关系:
- 第一次遍历:创建所有新节点,并建立原节点到新节点的映射
- 第二次遍历:根据映射关系设置新节点的next和random指针
- 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),需要存储所有节点的映射关系
节点插入拆分法
通过在原链表中插入新节点来避免使用额外空间:
- 节点复制插入:在每个原节点后面插入一个复制的新节点
- 设置random指针:新节点的random指向原节点random的下一个节点
- 链表拆分:将混合链表拆分为原链表和新链表
- 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),只使用固定数量的指针变量
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |