题目
剑指 Offer 35. 复杂链表的复制
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
分析:
这题难点就在于如何去复制节点的random指针,你直接去拷贝一个random,会面临不知道random是否有创建。
那么想知道random是否有创建,可以用一个哈希表来存一个当前节点与拷贝节点的映射。
思路1:
哈希表+迭代
- 先遍历原链表,复制所有的节点,并存入哈希表,key是原节点,value是复制的节点,next和random先都暂时复制为null
- 再遍历原链表,为复制的节点去赋值next和random指针,指针的来源就是,【原节点所指向的next和random节点,在hash表里映射对应的复制的节点】
具体代码如下:
/**
* @param {Node} head
* @return {Node}
*/
var copyRandomList = function(head) {
let cur = head;
let hashMap = new Map();
while(cur){
hashMap.set(cur,new Node(cur.val,null,null));
cur = cur.next;
}
cur = head;
while(cur){
hashMap.get(cur).next = cur.next ? hashMap.get(cur.next) : null;
hashMap.get(cur).random = cur.random ? hashMap.get(cur.random) : null;
cur = cur.next;
}
return hashMap.get(head);
}
思路2:
拼接+剪切
复制一套链接节点,让后让新旧节点依次交错的排列在一起,那么我们访问找新节点random的时候,可以去找新节点的前一个原节点random的next
- 遍历原链表,遍历每一个节点的时候,复制一个新节点,然后将新节点放在原节点后,即cur.next = newNode,newNode.next = cur.next.next;
- 遍历原链表,将原节点的random所指向节点的next复制给新节点,也即cur.next.random = cur.random.next,这里要做一下cur.random非空判断
- 遍历原链表,将新旧链表的链接切断。
代码如下:
/**
* @param {Node} head
* @return {Node}
*/
var copyRandomList = function(head) {
if(head==null)return head;
let cur = head;
while(cur){
let tmp = new Node(cur.val,null,null);
tmp.next = cur.next;
cur.next = tmp;
cur = cur.next.next;
}
cur = head;
while(cur){
cur.next.random = cur.random ? cur.random.next : null;
cur = cur.next.next;
}
cur = head.next;
let pre = head,res = head.next;
while(cur.next){
pre.next = pre.next.next;
cur.next = cur.next.next;
pre = pre.next;
cur = cur.next;
}
pre.next = null;
return res
}
思路3:
哈希表+递归
这个方法由于有递归,稍微难理解一点,但是最简洁的。
- 定义递归函数,入参是原节点和哈希表,出参是新节点
- 判断入参的这个原节点,是否有创建新节点,有则直接返回,没有则开始创建
- 复制这个原节点的创建一个新节点,nex和random先赋值null,并以原节点为key,新节点为value存入哈希表
- 为这个新节点复制next指针,值为递归调用自身去哈希表里寻找或者创造。
- 为这个新节点复制random指针,值为递归调用自身去哈希表里寻找或者创造。
大家可以自己写个简单的demo一步一步去消化一下
代码如下:
/**
* @param {Node} head
* @return {Node}
*/
var copyRandomList = function(head,cacheNode = new Map()) {
if(head==null)return head;
if(!cacheNode.get(head)){
cacheNode.set(head,{val:head.val})
cacheNode.get(head).next = copyRandomList(head.next,cacheNode)
cacheNode.get(head).random = copyRandomList(head.random,cacheNode)
}
return cacheNode.get(head);
}