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.
假設存在這樣一個鏈表,在鏈表的每個節點中,除了記錄了自身值和指向下一個節點的指針,還有一個隨機指針指向鏈表中任意一個節點。如今要求深度複製這份鏈表,在不改變原鏈表內容的狀況下,建立一組新的對象,該組對象中的值和原鏈表中的值相同。node
由於任意節點指針的值在一遍遍歷中是沒法複製的。因此咱們能夠基本肯定至少須要兩次遍歷纔可以充分的複製鏈表。那麼在第一次遍歷的時候,咱們採用什麼樣的數據結構來記錄第一次遍歷的值呢?最直觀的思路是使用map,第一次遍歷時咱們訪問next指針,將當前對象和當前對象的複製對象做爲key-value值存入map中。第二次遍歷時,咱們能夠一邊調整複製對象的next指針,一邊調整複製對象的random指針,這兩個指針指向的都將是map中源對象的複製對象。因此能夠在兩次遍歷後完成任務。面試
public RandomListNode copyRandomList(RandomListNode head) { if(head==null) return null; Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); RandomListNode temp = head; while(temp!=null){ map.put(temp, new RandomListNode(temp.label)); temp = temp.next; } temp = head; while(temp!=null){ RandomListNode cur = map.get(temp); cur.next = map.get(temp.next); cur.random = map.get(temp.random); temp = temp.next; } return map.get(head); }
那麼咱們有沒有可能在不使用map的狀況下經過舊節點實現對新節點的檢索?答案是確定的。咱們能夠充分利用鏈表的特性來保存對新的複製節點的指針。第一圈遍歷時,咱們能夠將複製的節點插入至被複制的節點的後面。這樣咱們就能夠經過舊節點的next值找到新節點。在第二圈遍歷的時候,咱們能夠依次更新複製節點的random指針,將其指向新的複製節點。最後一圈遍歷,咱們調整next指針,恢復原鏈表和塑造新鏈表。微信
public RandomListNode copyRandomList2(RandomListNode head) { if(head==null) return null; RandomListNode current = head, copyHead = null, copyCurrent = null; while(current!=null){ RandomListNode temp = new RandomListNode(current.label); temp.next = current.next; current.next = temp; current = current.next.next; } current = head; while(current!=null){ if(current.random!=null){ current.next.random = current.random.next; } current = current.next.next; } current = head; copyCurrent = copyHead = head.next; head.next = head.next.next; while(current != null){ current.next = current.next.next; copyCurrent.next = copyCurrent.next.next; copyCurrent = copyCurrent.next; current = current.next; } return copyHead; }
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~數據結構