题目
提供的Node:
static class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
题解
解法一:用hashMap很简单,key为原节点,value为副本节点,然后根据key的next和random,让value来拼成副本链表。
/**
* 使用哈希表,key是原链表的节点,value是copy的节点
* 然后一一拼接
* 最后返回的是map中key为head的值,它就是新链表的头节点
* @param head
* @return
*/
public static Node copyRandomList(Node head) {
if(head == null) {
return null;
}
Node cur = head;
// key是原链表的节点,value是copy的节点
HashMap<Node, Node> map = new HashMap<>();
while(cur != null) {
map.put(cur, new Node(cur.val));
// 移动
cur = cur.next;
}
// 拼接
cur = head;
while(cur != null) {
// 直接在map拼,map.get(cur)就是新链表的节点
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)
- 空间复杂度:一共存储N个节点,所以O(N)。
解法二:在原链表中的每个原节点的next添加它的副本节点,它的副本节点的next指向原先原节点的next。然后搞好副本节点的random,很简单,就是指向原节点的random的next。最后再把副本节点从原链表分离,拼成副本链表。不懂就看图:
代码:
/**
* 不用哈希表
* @param head
* @return
*/
public static Node copyRandomList(Node head) {
if(head == null) {
return null;
}
Node cur = head;
Node next = null;
Node copyNode = null;
// 先把克隆节点放在每一个旧节点后面
// 1->2
// 1->1'->2
while(cur != null) {
// 暂存
next = cur.next;
// 插入克隆节点
cur.next = new Node(cur.val);
// 接回去
cur.next.next = next;
// 移到下一个旧节点
cur = next;
}
// 先搞好random,有了上面的结构,让克隆节点指向克隆random很简单
// 旧节点的random的下一个节点,就是旧节点的克隆节点指向的random
cur = head;
while(cur != null) {
// 旧节点和克隆节点一对一对的处理
next = cur.next.next;
copyNode = cur.next;
copyNode.random = cur.random != null ? cur.random.next : null;
// 移动2个节点
cur = next;
}
// 把克隆节点从旧链表分离
// 克隆链表的头节点
Node copyNodeHead = head.next;
cur = head;
while(cur != null) {
next = cur.next.next;
copyNode = cur.next;
cur.next = next; // 旧节点接回旧节点
copyNode.next = next != null ? next.next : null; // 克隆节点接上克隆节点
cur = cur.next;
}
return copyNodeHead;
}
复杂度:
- 时间复杂度:O(N)
- 空间复杂度:如果不计算开辟副本节点带来的空间开销,那么就是O(1)