[LeetCode] 138. Copy List with Random Pointer(複製含有隨機指標的連結串列)
-
Difficulty: Medium
-
Related Topics: Hash Table, Linked List
-
Link: https://leetcode.com/problems/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 ofn
nodes. 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
n-1
) where random pointer points to, ornull
if it does not point to any node.
random_index
:節點的下標(範圍是0
到n-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
-
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.
-
You may want to use extra space to keep old node ---> new node mapping to prevent creating multiples copies of same node.
-
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' -
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
}
}