劍指Offer_#35_複雜連結串列的複製
阿新 • • 發佈:2020-07-09
劍指Offer_#35_複雜連結串列的複製
劍指offerContents
題目
請實現 copyRandomList 函式,複製一個複雜連結串列。在複雜連結串列中,每個節點除了有一個 next 指標指向下一個節點,還有一個 random 指標指向連結串列中的任意節點或者 null。
例如:
提示:
- -10000 <= Node.val <= 10000
- Node.random 為空(null)或指向連結串列中的節點。
- 節點數目不超過 1000 。
思路分析
方法1:雜湊表
- 構建雜湊表
沿著next
指標,逐個遍歷舊連結串列節點,克隆出一個新連結串列節點。向雜湊表新增<舊節點,新節點>
的鍵值對。 - 構造新連結串列
從頭節點開始,遍歷舊連結串列節點,然後通過雜湊表獲得舊節點所對應的新節點,以及舊節點的next
節點/random
節點所對應的新節點。設定每個新節點的next
和random
。
方法2:原地修改連結串列
- 在每個節點後克隆一個新節點
- 設定新節點的
random
指標,指向應該指向的位置 - 修改
next
指標,將拷貝的連結串列分離出來
圖解
解答
解答1:雜湊表
class Solution {
public Node copyRandomList(Node head) {
HashMap<Node,Node> map = new HashMap<>();
Node cur = head;
while(cur != null){
map.put(cur,new Node(cur.val));
cur = cur.next;
}
cur = head;
while(cur != null){
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
}
複雜度分析
時間複雜度O(n)
空間複雜度O(n)
解答2:原地修改連結串列
class Solution {
public Node copyRandomList(Node head) {
CloneNodes(head);
ConnectRandomNodes(head);
return ReconnectNodes(head);
}
//在每個原節點之後增加一個克隆的節點
public void CloneNodes(Node head){
Node cur = head;
while(cur != null){
Node cloned = new Node(cur.val);
cloned.next = cur.next;
cur.next = cloned;
cur = cloned.next;
}
}
//設定每個新節點的random指標
public void ConnectRandomNodes(Node head){
Node cur = head;
while(cur != null){
//當前節點的下一個節點是克隆節點
Node cloned = cur.next;
if(cur.random != null) cloned.random = cur.random.next;
//每次迭代,指標移動兩個節點
cur = cloned.next;
}
}
//將拷貝的連結串列拆分出來
public Node ReconnectNodes(Node head){
//cur指標指向舊連結串列的節點
Node cur = head;
//ERROR:必須對cloneNode和cloneHead在if之外進行初始化,否則可能不被初始化
//clonedNode是新連結串列的指標
Node clonedNode = null;
//clonedHead是新連結串列頭節點
Node clonedHead = null;
if(cur != null){
clonedHead = cur.next;
clonedNode = clonedHead;
//cur指標先走一步,這樣才方便連線克隆的節點
cur.next = clonedNode.next;
cur = cur.next;
}
//cur非null,那麼cloneNode一定也非null
while(cur != null){
//連線到下個克隆節點
clonedNode.next = cur.next;
//更新cloneNode指標
clonedNode = clonedNode.next;
//連線到下箇舊連結串列節點
cur.next = clonedNode.next;
//更新cur指標
cur = cur.next;
}
return clonedHead;
}
}
複雜度分析
時間複雜度O(n)
空間複雜度O(1)
TIP:避免連結串列迭代中的空指標異常
比較容易出現的問題是空指標異常,防止這個異常的方式就是增加一個條件判斷。具體舉例說明:
- 因為要訪問
cur.random.next
,所以必須保證cur.random
不是null
if(cur.random != null) cloned.random = cur.random.next;
- 因為要訪問cur.next,所以必須保證
cur
不是null
if(cur != null){
clonedHead = cur.next;
clonedNode = clonedHead;
//cur指標先走一步,這樣才方便連線克隆的節點
cur.next = clonedNode.next;
cur = cur.next;
}
也就是說,每次些連結串列迴圈的程式碼,一定要注意迴圈過程中,*.next
或者*.val
之類的語句,一定要再其之前增加條件判斷語句if(* != null)