说到底就是要把给出的链表完整拷贝一份。
如果仅仅需要拷贝正常的链表的话,只需要在循环中不断创建val和原始链表相同的节点并且将其连起来就行了。
加了这个random这个节点则较为复杂些。问题在于,random指向后是不连续的,这样在新的链表中没法遍历,说到底就是找不到指向的位置。
很直觉的想到给节点编上号,这样就能通过节点找位置,通过位置找节点了。
一开始的想法是建立两个Hashmap,
一个是<Node,Integer>,用于放原链表
一个是<Integer,Node>,用于放新的链表。
这样是因为原链表需要通过节点找序号,新链表需要通过序号找节点。
代码就写成了这样:
class Solution { public static Node copyRandomList(Node head) { HashMap<Node,Integer> hashMap1=new HashMap<Node,Integer>(); HashMap<Integer,Node> hashMap2=new HashMap<Integer,Node>(); int count=0; while(head!=null) { hashMap1.put(head,count); hashMap2.put(count,new Node(head.val)); if(count!=0) { hashMap2.get(count-1).next=hashMap2.get(count); } head=head.next; count++; } hashMap1.put(null,count+1); hashMap2.put(count+1,null); head=hashMap1.keySet().iterator().next(); count=0; while(head!=null) { Node no=hashMap2.get(hashMap1.get(head.random)); hashMap2.get(count).random=no; count=count+1; head=head.next; } System.out.println(hashMap2.containsValue(hashMap2.get(2).random)); return hashMap2.get(0); }
LeetCode中出现了奇怪的bug,判定所有的新节点中的random都是null,但我调试了不是这样的,所以我觉得应该是bug吧。
但看了一个解法恍然大悟,搞什么节点-序号,序号-节点。直接节点对节点存在hashmap中就好了嘛。重要的是找位置。
class Solution { public Node copyRandomList(Node head) { if(head==null) { return null; } //创建一个哈希表,key是原节点,value是新节点 Map<Node,Node> map = new HashMap<Node,Node>(); Node p = head; //将原节点和新节点放入哈希表中 while(p!=null) { Node newNode = new Node(p.val); map.put(p,newNode); p = p.next; } p = head; //遍历原链表,设置新节点的next和random while(p!=null) { Node newNode = map.get(p); //p是原节点,map.get(p)是对应的新节点,p.next是原节点的下一个 //map.get(p.next)是原节点下一个对应的新节点 if(p.next!=null) { newNode.next = map.get(p.next); } //p.random是原节点随机指向 //map.get(p.random)是原节点随机指向 对应的新节点 if(p.random!=null) { newNode.random = map.get(p.random); } p = p.next; } //返回头结点,即原节点对应的value(新节点) return map.get(head); } }
最优的解法则又进一步,反正重要的是位置,只要通过旧节点能找到对应的新节点就行,所以直接把新节点插在旧节点后面。
这样不用新建一个HashMap了,空间复杂度变为O1
class Solution { public Node copyRandomList(Node head) { if(head==null) { return null; } Node p = head; //第一步,在每个原节点后面创建一个新节点 //1->1'->2->2'->3->3' while(p!=null) { Node newNode = new Node(p.val); newNode.next = p.next; p.next = newNode; p = newNode.next; } p = head; //第二步,设置新节点的随机节点 while(p!=null) { if(p.random!=null) { p.next.random = p.random.next; } p = p.next.next; } Node dummy = new Node(-1); p = head; Node cur = dummy; //第三步,将两个链表分离 while(p!=null) { cur.next = p.next; cur = cur.next; p.next = cur.next; p = p.next; } return dummy.next; } }