力扣原题,链表面试题之复制带随机指针的链表

简介: 力扣原题,链表面试题之复制带随机指针的链表

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

public static class Node{
    public int value;
    public Node next;
    public Node rand;
    public Node(int v) {
      value=v;
    }
  }

rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节点,也可能指向null。给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。要求:时间复杂度O(N),额外空间复杂度O(1),注意,无环是指next方向上是无环的!!!

方法一(笔试用,最简单):在next方向上正常遍历一遍链表,遍历过程种将每个结点克隆存入HashMap<Node,Node>,表中的key是老结点,value是克隆的结点。就是人为构造一种对应关系,之后再遍历一遍链表,便可实现,具体看下面代码。但是这种方法在空间复杂度上没有做到O(1)

方法二(面试用):额外空间复杂度O(1),具体看代码

package com.harrison.class06;
import java.util.HashMap;
public class Code04_CopyListWithRandom {
  public static class Node {
    public int value;
    public Node next;
    public Node rand;
    public Node(int v) {
      value = v;
    }
  }
  public static Node copyRandomList1(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 (key)老结点 map.get(cur) (value)新结点
      map.get(cur).next = map.get(cur.next);
      map.get(cur).rand = map.get(cur.rand);
      cur = cur.next;
    }
    return map.get(head);
  }
  public static Node copyRandomList2(Node head) {
    if (head == null) {
      return null;
    }
    // 1 -> 2 -> 3 -> null
    // 1 -> 1' -> 2 -> 2' -> 3 -> 3' -> null
    Node cur = head;// 老结点
    Node next = null;// 老结点的下一个结点
    while (cur != null) {
      next = cur.next;// next记住老结点的下一个结点
      cur.next = new Node(cur.value);// 当前的老结点指向 复制自己的结点
      cur.next.next = next;// 复制的结点指向 next
      cur = next;
    }
    cur = head;
    Node copy = null;// 复制的结点
    // 依次设置 1' 2' 3' 的rand指针
    while (cur != null) {
      next = cur.next.next;// next 记住老结点的下一个结点
      copy = cur.next;// copy 来到(第一个)复制的结点
      // copy结点的rand指针指向 老结点的rand指针指向的结点的next指针
      copy.rand = cur.rand != null ? cur.rand.next : null;
      cur = next;// 当前结点往下跳
    }
    Node res = head.next;// 记住复制后的链表的头结点
    cur = head;
    // next方向上,把新老链表分离,rand方向不要动
    while (cur != null) {
      next = cur.next.next;// next 记住老结点的下一个结点
      copy = cur.next;// copy 来到(第一个)复制的结点
      // copy结点的next指针指向 下一个老结点的next指针
      copy.next = next != null ? next.next: null;
      cur = next;// 当前结点往下跳
    }
    return res;
  }
  public static void printLinkedList(Node node) {
    System.out.print("Linked List:");
    while (node != null) {
      System.out.print(node.value + " ");
      node = node.next;
    }
    System.out.println();
  }
  public static void main(String[] args) {
    Node head1 = new Node(7);
    head1.next = new Node(9);
    head1.next.next = new Node(1);
    head1.next.next.next = new Node(8);
    head1.next.next.next.next = new Node(5);
    head1.next.next.next.next.next = new Node(2);
    head1.next.next.next.next.next.next = new Node(5);
    printLinkedList(head1);
    //head1=copyRandomList1(head1);
    head1 = copyRandomList2(head1);
    printLinkedList(head1);
  }
}
相关文章
|
2月前
【bug记录】旋转链表与力扣报错:member access within null pointer of type ‘struct ListNode‘
【bug记录】旋转链表与力扣报错:member access within null pointer of type ‘struct ListNode‘
|
2月前
|
算法
LeetCode第24题两两交换链表中的节点
这篇文章介绍了LeetCode第24题"两两交换链表中的节点"的解题方法,通过使用虚拟节点和前驱节点技巧,实现了链表中相邻节点的交换。
LeetCode第24题两两交换链表中的节点
|
2月前
|
存储 算法
LeetCode第86题分隔链表
文章介绍了LeetCode第86题"分隔链表"的解法,通过创建两个新链表分别存储小于和大于等于给定值x的节点,然后合并这两个链表来解决问题,提供了一种简单易懂且操作原链表的解决方案。
LeetCode第86题分隔链表
|
2月前
|
存储 算法
LeetCode第83题删除排序链表中的重复元素
文章介绍了LeetCode第83题"删除排序链表中的重复元素"的解法,使用双指针技术在原链表上原地删除重复元素,提供了一种时间和空间效率都较高的解决方案。
LeetCode第83题删除排序链表中的重复元素
|
2月前
|
算法
LeetCode第23题合并 K 个升序链表
这篇文章介绍了LeetCode第23题"合并K个升序链表"的解题方法,使用分而治之的思想,通过递归合并链表的方式解决了这个难题。
LeetCode第23题合并 K 个升序链表
|
2月前
|
C++ 索引
leetcode 707.设计链表
本文提供了解决LeetCode 707题"设计链表"的C++实现,包括单链表的节点定义和类方法实现,如添加节点、获取节点值、删除节点等。
|
2月前
|
算法
LeetCode第92题反转链表 II
文章分享了LeetCode第92题"反转链表 II"的解法,通过使用四个指针来记录和更新反转链表段的头部、尾部以及前一个和后一个节点,提供了一种清晰且易于理解的解决方案。
LeetCode第92题反转链表 II
|
2月前
|
算法
LeetCode第21题合并两个有序链表
该文章介绍了 LeetCode 第 21 题合并两个有序链表的解法,通过创建新链表,依次比较两个链表的头节点值,将较小的值插入新链表,直至其中一个链表遍历完,再将另一个链表剩余部分接到新链表后面,实现合并。
LeetCode第21题合并两个有序链表
|
2月前
|
算法
LeetCode第19题删除链表的倒数第 N 个结点
该文章介绍了 LeetCode 第 19 题删除链表的倒数第 N 个结点的解法,通过使用快慢双指针,先将快指针移动 n 步,然后快慢指针一起遍历,直到快指针到达链尾,从而找到倒数第 N 个结点的前一个结点进行删除,同时总结了快慢指针可减少链表遍历次数的特点。
LeetCode第19题删除链表的倒数第 N 个结点
|
2月前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
46 0