题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
解题思路
这道题有三种解法。
第一种是先拷贝节点,用next连接起来。之后从头开始遍历节点,对每个节点根据random值去寻找节点,再做连接。时间复杂度为O(n²)。
第二种是使用哈希表,通过哈希表来对应拷贝前后的两个复杂链表,这样一来,就可以通过原链表的random作为键,取到新链表的random应该指向的结点。
第三种是对链表进行拓展,第一次遍历时在每个结点之后创建拷贝结点,第二次遍历时根据兄弟结点,连接上random结点,第三次遍历时则将两倍长度的链表拆开,取得复制链表。时间复杂度为O(n)。见下图:
Code
// 解法二 哈希表
/*function RandomListNode(x){
this.label = x;
this.next = null;
this.random = null;
}*/
function Clone(pHead)
{
// write code here
if(!pHead) return null;
const map=new Map();
let p,p2;
p=pHead;
p2=new RandomListNode(pHead.label);
const pHead2=p2;
map.set(p,p2);
while(p){
if(p.next) p2.next=new RandomListNode(p.next.label);
else p2.next=null;
p=p.next;
p2=p2.next;
map.set(p,p2);
}
p=pHead;
p2=pHead2;
while(p){
p2.random=map.get(p.random);
p=p.next;
p2=p2.next;
}
return pHead2;
}
// 解法三 拓展链表
/*function RandomListNode(x){
this.label = x;
this.next = null;
this.random = null;
}*/
function Clone(pHead)
{
// write code here
cloneNodes(pHead);
connectRandom(pHead);
return reconnectNodes(pHead);
}
function cloneNodes(pHead) {
// 复制链表
let pNode = pHead;
while (pNode) {
const newNode = new RandomListNode(pNode.label);
newNode.next = pNode.next;
pNode.next = newNode;
pNode = newNode.next;
}
}
function connectRandom(pHead) {
// 设置random指针
let pNode = pHead;
while (pNode) {
if (pNode.random) {
pNode.next.random = pNode.random.next;
}
pNode = pNode.next.next;
}
}
function reconnectNodes(pHead) {
// 拆开链表
let pNode = pHead;
let newNodeHead = null,
newNode = null;
if (pNode) {
newNodeHead = newNode = pNode.next;
pNode.next = newNode.next;
pNode = newNode.next;
}
while (pNode) {
newNode.next = pNode.next;
newNode = newNode.next;
pNode.next = newNode.next;
pNode = pNode.next;
}
return newNodeHead;
}
运行环境:JavaScript (V8 6.0.0)
运行时间:17ms
占用内存:5432k