1. 程式人生 > 實用技巧 >[LeetCode] 138. Copy List with Random Pointer(複製含有隨機指標的連結串列)

[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 adeep copyof the list.
返回該連結串列的深拷貝

The Linked List is represented in the input/output as a list ofnnodes. Each node is represented as a pair of[val, random_index]where:
輸入/輸出的連結串列表示為一個長度為 n 的節點陣列,每個節點

  • val: an integer representingNode.val
    val:一個整數,表示 Node.val
  • random_index: the index of the node (range from0
    ton-1) where random pointer points to, ornullif 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.randomis 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
    }
}