A -> B -> C
我们可以采用一个 三步走策略 来完成深拷贝:
-
克隆节点并插入原链表
在每个原节点后面插入一个新节点,得到:A -> A' -> B -> B' -> C -> C' -
复制 random 指针
对于原链表中的每个节点,如果A.random = C,那么它的克隆节点A'应该指向C'。
利用cur.next就能找到克隆节点,进而把random正确指过去。 -
拆分链表
把原链表和新链表分开:- 原链表恢复为:
A -> B -> C - 新链表得到:
A' -> B' -> C'
- 原链表恢复为:
这样,新链表就被成功构造出来了。
var copyRandomList = function (head) {
if (!head) return null;
let cur = head;
// A -> A' -> B -> B' -> C -> C'
while (cur) {
let clone = new Node(cur.val);
clone.next = cur.next;
cur.next = clone;
cur = clone.next;
}
// random point
cur = head;
while (cur) {
if (cur.random) {
cur.next.random = cur.random.next; // A' = C'
}
cur = cur.next.next; // A' -> B'
}
// split
cur = head;
let cloneHead = cur.next;
while (cur) {
let clone = cur.next;
cur.next = clone.next;
if (clone.next) {
clone.next = clone.next.next;
}
cur = cur.next;
}
return cloneHead;
};
复杂度分析
- 时间复杂度:O(n),三次遍历链表
- 空间复杂度:O(1),不需要额外的数据结构(相比哈希表法更优雅)