給定一個鏈表,每一個節點包含一個額外增長的隨機指針,該指針能夠指向鏈表中的任何節點或空節點。java
要求返回這個鏈表的深拷貝。node
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.python
Return a deep copy of the list.bash
示例:數據結構
輸入:
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}
解釋:
節點 1 的值是 1,它的下一個指針和隨機指針都指向節點 2 。
節點 2 的值是 2,它的下一個指針指向 null,隨機指針指向它本身。
複製代碼
提示:dom
Note:學習
因爲須要考慮隨機指針,隨機指針指向的節點多是null,也多是鏈表的最後一個節點,深拷貝下,你不能將新鏈表的隨機指針指向原鏈表的節點,因此沒法一遍獲得新鏈表。spa
兩種解題方法,一種是拷貝全部節點,暫存在一種數據結構內,而後再遍歷一遍該數據結構,找到拷貝的節點,肯定隨機指針的指向。由於每一個節點都要找到隨機指針指向的節點,若是藉助 散列表(字典) 其查找複雜度爲 O(1) ,這樣能夠把總時間複雜度降到 O(n) ,因爲要暫存全部節點,其空間複雜度爲 O(n)。指針
另外一種解題方法是須要三次遍歷獲得結果,簡單來講就是先把每一個節點拷貝,並把拷貝節點鏈接到原節點後面,依次類推。肯定隨機節點的關係以後再拆分鏈表。是一種很巧妙的思路:code
原鏈表:1->2->3 複製每一個節點到原節點後面:1->1->2->2->3->3 複製隨機指針的指向關係 拆分鏈表:1->2->3, 1->2->3
複製隨機指針指向時,原節點的隨機節點下一個節點即爲新節點的隨機節點。假如原鏈表:1->2->3,節點1的隨機節點爲3,複製節點以後:1->1->2->2->3->3
咱們只需將新節點(原節點1的後一個節點1)指向原節點的隨機節點的後一個節點(原節點的隨機節點爲3,而複製以後隨機節點3的後一個節點依然爲3,但這個節點爲新節點),最後拆分鏈表(鏈表拆分不影響節點指向關係)。其時間複雜度爲 O(n),空間複雜度爲 O(1)。
Java:
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
HashMap<Node, Node> map = new HashMap<>();//藉助hashMap
Node newHead = new Node(0);//虛擬頭節點
Node cur = newHead;//指針指向當前節點
Node tmp;
while (head != null) {
if (map.containsKey(head)) {//查詢原節點是否已存在於map
tmp = map.get(head);//若是存在直接取value值
} else {
tmp = new Node(head.val);//不存在則新建一個值相同的節點
map.put(head, tmp);//存入map,key爲原節點,value爲新節點
}
cur.next = tmp;
if (head.random != null) {//原節點的隨機節點不爲空的狀況下
if (map.containsKey(head.random)) {//查詢該隨即節點是否已存在於map
tmp.random = map.get(head.random);//存在則直接將新節點的隨機指針指向其value值
} else {
tmp.random = new Node(head.random.val);//不存在則新建一個值相同的隨機節點
map.put(head.random, tmp.random);//存入map,key爲原節點的隨機節點,value爲新節點的隨機節點
}
}
head = head.next;//刷新原鏈表當前頭節點
cur = tmp;//即cur=cur.next,刷新新鏈表當前節點
}
return newHead.next;
}
}
複製代碼
Python3:
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head: return None
map = {}
newHead = Node(val=0, next=None, random=None)
cur = newHead
while head:
if head in map.keys():
tmp = map.get(head)
else:
tmp = Node(val=head.val, next=None, random=None)
map.setdefault(head, tmp)
cur.next = tmp
if head.random:
if head.random in map.keys():
tmp.random = map.get(head.random)
else:
tmp.random = Node(val=head.random.val, next=None, random=None)
map.setdefault(head.random, tmp.random)
head = head.next
cur = tmp
return newHead.next
複製代碼
Java:
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
//複製節點 1->2->3 ==> 1->1->1->2->2->3->3
Node cur = head;
while (cur != null) {
Node next = cur.next;
Node tmp = new Node(cur.val);
cur.next = tmp;
tmp.next = next;
cur = next;
}
//複製隨機指針
cur = head;
while (cur != null) {
//cur.next.random=>新節點的隨機節點 cur.random.next=>原節點的隨機節點的下一個節點
cur.next.random = cur.random == null ? null : cur.random.next;
cur = cur.next.next;//鏈表擴展一倍後確定是偶數位鏈表,因此能夠直接用cur.next.next
}
//分離節點
cur = head;
Node newHead = head.next;//新鏈表頭節點
while (cur != null) {
Node tmp = cur.next;
cur.next = tmp.next;
cur = cur.next;
tmp.next = cur == null ? null : cur.next;
}
return newHead;
}
}
複製代碼
Python3:
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head: return None
cur = head
while cur:
next = cur.next
tmp = Node(val=cur.val, next=next, random=None)
cur.next = tmp
cur = next
cur = head
while cur:
cur.next.random = cur.random.next if cur.random else None
cur = cur.next.next
cur = head
newHead = head.next
while cur:
tmp = cur.next
cur.next = tmp.next
cur = cur.next
tmp.next = cur.next if cur else None
return newHead
複製代碼
歡迎關注微.信公.衆號一塊兒學習:愛寫Bug