問題:
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.
Return a deep copy of the list.
結點的定義如下:
/**
* Definition for singly-linked list with a random pointer.
* class RandomListNode {
* int label;
* RandomListNode next, random;
* RandomListNode(int x) { this.label = x; }
* };
*/
原來的鏈表的結構如下圖所示:
注意一點,random的指針可以指向后面的結點,也可以指向前面的結點。
這里提供兩種解法:
方法1:用hash表存儲結點信息,時間O(2n),空間O(n)
第一次遍歷原鏈表,並構建random為null的新鏈表,於此同時在hash表中存儲原結點和新結點的地址信息,原結點地址為key,新結點地址為value,即map<原結點地址,新結點地址>
第二次遍歷原鏈表,對於random不為空的結點,可以根據random的值,在hash表中找到random指向的節點對應的新結點的地址,再以此給新結點random賦值即可。
方法2:先改變原鏈表的結構,在恢復,時間O(2n),空間O(1)
這個方法需要3次遍歷,
第一次,構建新鏈表的結點,random為null,並且用原來鏈表節點的next指向對應的新結點,新結點的next指向原鏈表的下一個結點,如圖所示:
第二次,給新節點的random賦值,
p = head; while(p!=null){ if(p.random != null){ p.next.random = p.random.next; } p = p.next.next; }
第三次,恢復原鏈表和新鏈表的鏈表結構。
head2 = head.next; p = head; while(p!=null){ p2 = p.next; p.next = p2.next; if (p2.next != null) p2.next = p2.next.next; p = p.next; }
方法2的完整代碼:
public class Solution { public RandomListNode copyRandomList(RandomListNode head) { if(head == null)return null; RandomListNode head2,p2,p = head; while(p!=null){ RandomListNode n = new RandomListNode(p.label); n.next = p.next; p.next = n; p = n.next; } p = head; while(p!=null){ if(p.random != null){ p.next.random = p.random.next; } p = p.next.next; } head2 = head.next; p = head; while(p!=null){ p2 = p.next; p.next = p2.next; if (p2.next != null) p2.next = p2.next.next; p = p.next; } return head2; } }