zoukankan      html  css  js  c++  java
  • [LeetCode] 138. Copy List with Random Pointer(复制含有随机指针的链表)

    Description

    A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
    给定一个单链表,单链表的每个节点都有一个新增的随机指针,该指针会随机指向链表中的任何一个节点(或者 null)。

    Return a deep copy of the list.
    返回该链表的深拷贝

    The Linked List is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:
    输入/输出的链表表示为一个长度为 n 的节点数组,每个节点

    • val: an integer representing Node.val
      val:一个整数,表示 Node.val
    • random_index: the index of the node (range from 0 to n-1) where random pointer points to, or null if it does not point to any node.
      random_index:节点的下标(范围是 0n-1)表示该指针指向的节点,如果不指向任何节点,则以 null 表示。

    Examples

    Example 1

    Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
    Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]
    

    Example 2

    Input: head = [[3,null],[3,0],[3,null]]
    Output: [[3,null],[3,0],[3,null]]
    

    Example 3

    Input: head = []
    Output: []
    Explanation: Given linked list is empty (null pointer), so return null.
    

    Constraints

    • -10000 <= Node.val <= 10000
    • Node.random is null or pointing to a node in the linked list.
    • The number of nodes will not exceed 1000.

    Hints

    1. Just iterate the linked list and create copies of the nodes on the go. Since a node can be referenced from multiple nodes due to the random pointers, make sure you are not making multiple copies of the same node.

    2. You may want to use extra space to keep old node ---> new node mapping to prevent creating multiples copies of same node.

    3. We can avoid using extra space for old node ---> new node mapping, by tweaking the original linked list. Simply interweave the nodes of the old and copied list. For e.g.

      Old List: A --> B --> C --> D
      InterWeaved List: A --> A' --> B --> B' --> C --> C' --> D --> D'

    4. The interweaving is done using next pointers and we can make use of interweaved structure to get the correct reference nodes for random pointers.

    Solution

    含有随机指针的链表,它首先是个链表,我们肯定是有办法复制出这个链表的所有节点的,复制出来后,再处理随机指针就很容易了。只要建立一个从旧节点到新节点的映射,维护这个映射即可,代码如下:

    class Solution {
        fun copyRandomList(node: Node?): Node? {
            if (node == null) {
                return null
            }
            val oldToNew = hashMapOf<Node, Node>()
            // dummy 头节点,便于复制
            val dummy = Node(-1)
            var p = node
            var q: Node? = dummy
    
            // 第一次复制,复制出完整的链表结构
            while (p != null) {
                val newNode = Node(p.`val`)
                q?.next = newNode
                oldToNew[p] = newNode
                p = p.next
                q = q?.next
            }
    
            p = node
            q = dummy.next
            // 第二次复制,复制 random 结构
            while (p != null) {
                p.random?.let { q?.random = oldToNew[it] }
                p = p.next
                q = q?.next
            }
    
            return dummy.next
        }
    }
    

    如果所使用的语言没有 map 这样的数据结构支持,也可以试试提示 3 和 4 所说的常数额外空间的解法,代码如下:

    /**
     * Example:
     * var ti = Node(5)
     * var v = ti.`val`
     * Definition for a Node.
     * class Node(var `val`: Int) {
     *     var next: Node? = null
     *     var random: Node? = null
     * }
     */
    class Solution {
        fun copyRandomList(node: Node?): Node? {
            if (node == null) {
                return null
            }
            var p = node
            // 第一次遍历,复制链表结构
            // 确保每个原节点的后面是该节点的复制节点
            while (p != null) {
                val newNode = Node(p.`val`)
                newNode.next = p.next
                p.next = newNode
                p = p.next?.next
            }
    
            p = node
            var q = node.next
            // 第二次遍历,复制 random 指针
            // 原节点的 random 的 next 为 random 的复制节点
            while (p != null) {
                p.random?.let {
                    q?.random = it.next
                }
                p = p.next?.next
                q = q?.next?.next
            }
    
            val result = node.next
            p = node
            q = node.next
            // 第三次遍历,将复制节点从原节点中分离出来
            while (p != null) {
                p.next = q?.next
                q?.next = p.next?.next
                p = p.next
                q = q?.next
            }
    
            return result
        }
    }
    
  • 相关阅读:
    Android框架之路——OkGo的使用
    recyclerview23+出现多个item只显示第一个item的问题
    Spark MLlib回归算法LinearRegression
    Spark MLlib聚类KMeans
    Impala性能优化
    Impala通过JDBC方式访问
    Impala与HBase整合
    Impala数据处理(加载和存储)
    Impala SQL
    Impala储存与分区
  • 原文地址:https://www.cnblogs.com/zhongju/p/14078877.html
Copyright © 2011-2022 走看看