以下提供三种方法
方法1 :先将所有结点copy一份,再遍历原链表,将next,random之类的指向还原
方法2 :dfs法,有点类似方法1,但只遍历原链表一遍
方法3 :迭代 + 节点拆分
/**
* Definition for a Node.
* class Node {
* public $val = null;
* public $next = null;
* public $random = null;
* function __construct($val = 0) {
* $this->val = $val;
* $this->next = null;
* $this->random = null;
* }
* }
*/
class Solution {
/**
* @param Node $head
* @return Node
*/
function copyRandomList($head) {
if (is_null($head)) {
return $head;
}
$h = $head;
$nodeArr = [];
while ($h) {
$nodeArr[spl_object_id($h)] = new ListNode($h->val);
$h = $h->next;
}
$t = $head;
$headNode = new ListNode(0);
$headNode->next = $nodeArr[spl_object_id($t)];
while ($t) {
$newNode = $nodeArr[spl_object_id($t)];
if (is_null($t->next)) {
$newNode->next = null;
} else {
$newNode->next = $nodeArr[spl_object_id($t->next)];
}
if (is_null($t->random)) {
$newNode->random = null;
} else {
$newNode->random = $nodeArr[spl_obj_id($t->random)];
}
$t = $t->next;
}
return $headNode->next;
}
function copyRandomListV2($head) {
static $nodeArr = [];
if (is_null($head)) {
return null;
}
if (!array_key_exists(spl_object_id($head), $nodeArr)) {
$newNode = new ListNode($head->val);
$nodeArr[spl_object_id($head)] = $newNode;
$newNode->next = $this->copyRandomListV2($head->next);
$newNode->random = $this->copyRandomListV2($head->random);
}
return $nodeArr[spl_object_id($head)];
}
function copyRandomListV3($head) {
if (is_null($head)) {
return null;
}
$h = $head;
while ($h) {
$newNode = new ListNode($h->val);
$newNode->next = $h->next;
$h->next = $newNode;
$h = $h->next->next;
}
$h = $head;
while ($h && $h->next) {
$newNode = $h->next;
$newNode->random = $h->random ? $h->random->next : null;
$h = $h->next->next;
}
$res = $head->next;
$h = $head;
while ($h) {
$newNode = $h->next;
if ($newNode->next) {
$h->next = $newNode->next;
$newNode->next = $newNode->next->next;
} else {
$newNode->next = null;
$h->next = null;
}
$h = $h->next;
}
return $res;
}
}