/**
* // Definition for a Node.
* function Node(val, next, random) {
* this.val = val;
* this.next = next;
* this.random = random;
* };
*/
/**
* @param {Node} head
* @return {Node}
*/
var copyRandomList = function(head) {
if(head == null) return head
// copy new node
let p0 = head
while(p0 != null) {
let nxt = p0.next
let newP0 = new Node(p0.val) // copy cur node's value
p0.next = newP0 // change next direction
p0.next.next = nxt == null ? null : nxt // new node links to next node
p0 = nxt // move cur node
}
// copy random points
let cur = head
while(cur != null) {
let nxtr = cur.next.next
let newcur = cur.next
newcur.random = cur.random == null ? null : cur.random.next
cur = nxtr
}
// split new linklist and old list
let newHead = head.next
// two points towards two list's headnode
cur = head
let newcur = head.next
while(cur != null) {
cur.next = cur.next.next
cur = cur.next
newcur.next = cur == null ? null : cur.next
newcur = newcur.next
}
return newHead
};
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head: return
hmap = {}
# 3. 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
cur = head
while cur:
hmap[cur] = Node(cur.val)
cur = cur.next
cur = head
# 4. 构建新节点的 next 和 random 指向
while cur:
hmap[cur].next = hmap.get(cur.next)
hmap[cur].random = hmap.get(cur.random)
cur = cur.next
# 5. 返回新链表的头节点
return hmap[head]
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if not head: return
# dict between old node and new node
hmap = {}
temp = head
while temp:
# first create the new node with the val
hmap[temp] = Node(temp.val)
temp = temp.next
temp = head
while temp:
# re-create the links and random
hmap[temp].next = hmap.get(temp.next)
hmap[temp].random = hmap.get(temp.random)
temp = temp.next
return hmap[head]
class Solution:
def copyRandomList(self, head: ‘Optional[Node]’) -> ‘Optional[Node]’:
if head None:
return None
cur = head
while cur:
cur.next = Node(cur.val, cur.next)
cur = cur.next.next
cur = head
while cur:
if cur.random:
cur.next.random = cur.random.next
cur = cur.next.next
cur = head.next
while(cur.next):
cur.next = cur.next.next
cur = cur.next
return head.next
class Solution {
public Node copyRandomList(Node head) {
return linkCopy(head);
}
// 方法二:old1 -> new1 -> old2 -> new2 -> ...;将原始节点和新链表的节点一一连接后,再进行拆分
private Node linkCopy(Node head) {
if (head == null) {
return head;
}
Node cur = head;
while (cur != null) {
Node tmp = new Node(cur.val);
tmp.next = cur.next;
cur.next = tmp;
cur = tmp.next;
}
// 对新节点的 random 进行复制
cur = head;
while (cur != null) {
if (cur.random != null) {
cur.next.random = cur.random.next;
}
cur = cur.next.next;
}
// 拆分链表
Node newHead = head.next;
Node newCur = newHead;
cur = head;
while (newCur != null && newCur.next != null) {
cur.next = cur.next.next;
newCur.next = newCur.next.next;
newCur = newCur.next;
cur = cur.next;
}
cur.next = null;
return newHead;
}
// 方法一:哈希表,记录原始节点 -> 新节点的映射关系
private Node hashCopy(Node head) {
if(head == null) {
return head;
}
HashMap<Node, Node> dic = new HashMap<>();
Node cur = head;
while(cur != null) {
dic.put(cur, new Node(cur.val));
cur = cur.next;
}
// 更新新链表的 next、random 指针
cur = head;
while(cur != null) {
dic.get(cur).next = (cur.next != null) ? dic.get(cur.next) : null;
dic.get(cur).random = (cur.random != null) ? dic.get(cur.random) : null;
cur = cur.next;
}
return dic.get(head);
}
}
思路:① 哈希表实现复杂链表的复制;② 使用合并 + 拆分的方式实现;
① 哈希表实现复杂链表的复制:使用一个哈希表记录原链表节点与复制后链表节点之间的映射,遍历原始链表时,为每个原始节点创建一个新节点,并将其存入到哈希表中;可以根据哈希表的映射关系,查找对应的节点,对新节点的 next、random 指针进行赋值;返回 head 对应的新链表的头节点。
时间复杂度:O(n),遍历了 2 次链表。
空间复杂度:O(n),使用了哈希表存储映射关系。
② 合并与拆分:将原始链表节点与复制链表节点合并成一个大的链表,形式如:old1->new1->old2->new2->old3->new3->... ;利用原始节点的 random 为新节点的 random 进行赋值;最后将大链表拆分为原始链表和复制链表,注意最后需要断开原始链表最后一个节点与新链表之间的连接;返回新链表的头节点。
时间复杂度:O(n),遍历了 3 次链表。
空间复杂度:O(1),只使用了常数级的额外空间。
共以下 46 个回答
“`java 在每一个节点的后面复制一个值一样的节点
class Solution {
public Node copyRandomList(Node head) {
if(head == null){
return null;
}
// 复制链表节点
Node cur = head;
while(cur != null){
Node next = cur.next;
cur.next = new Node(cur.val);
cur.next.next = next;
cur = next;
}
}
“`
时间复杂度O(N),额外空间复杂度为O(1)
解题思路:本题主要使用复制拆分思想,先将原链表每个结点后面复制一个新节点,再在这个新链表中表示新节点的新random指针,最后将其拆成原链表和新链表,难点在与如何写好复制和拆分的操作。
时间复杂度:O(n),空间复杂度:O(1)
用Map集合做的,时间和空间都是和O(n)
学到了,还能拆分链表
时间复杂度O(N),空间复杂度O(1)。
空间复杂度怎么会是O(1),肯定是O(n)啊,要复制一个链表的
哦我明白了,空间复杂度只算额外存储
看了题解才有的思路,太厉害了…惯性思维一直导致我在想怎么遍历一遍还能做到复制random,完全没想到map。
时间复杂度O(n)
空间复杂度O(1)
时间复杂度O(n)
空间复杂度O(n)
时间复杂度O(n)
空间复杂度O(n)
时间复杂度O(n)
空间复杂度O(1)
时间On 空间On
class Solution {
public Node copyRandomList(Node head) {
Node cur = head;
Map<Node, Node> map = new HashMap<>();
while(cur != null){
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
while(cur != null){
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
}
“`py
class Solution(object):
def copyRandomList(self, head):
if not head:
return
hmap={}
# 复制各个节点
cur=head
while cur:
hmap[cur]=Node(cur.val)
cur=cur.next
cur=head
# 构建新链表的next和random指向
while cur:
hmap[cur].next=hmap.get(cur.next)
hmap[cur].random=hmap.get(cur.random)
cur=cur.next
# 返回新链表的头节点
return hmap[head]
时间复杂度:O(N) 链表的长度为N
空间复杂度:O(N) 哈希表使用的额外空间
1、链表复制+拆分
时间复杂度0(n)、空间复杂度O(1)
2、通过HashMap来实现 先复制节点 再指定random
题解:先复制再拆分
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
}
*/
class Solution {
public Node copyRandomList(Node head) {
if (head null) {
return null;
}
Node cur = head;
Map<Node, Node> map = new HashMap<>();
while (cur != null) {
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
while (cur != null) {
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
return map.get(head);
}
}//主要是要记住思路
时间复杂度On
空间复杂度O1
哈希表
hmap使用线性大小的额外空间。拼接+拆分链表
拼接的好处是,旧当前节点的下一个就是新链表节点。random也是一样
hmap使用线性大小的额外空间。解决各种空指针花了好久
时间复杂度:O(n)
空间复杂度:O(1)
哈希表
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
}
*/
class Solution {
public Node copyRandomList(Node head) {
Node cur = head;
Map<Node, Node> map = new HashMap<>();
while(cur != null){
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
while(cur != null){
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),O(n)
“`c++mp;
Node* copyRandomList(Node* head) {
unordered_map
Node* p=head;
while(p){
mp[p]=new Node(p->val);
p=p->next;
}
p=head;
while(p){
mp[p]->next=mp[p->next];
mp[p]->random=mp[p->random];
p=p->next;
}
return mp[head];
}
“`
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
};
/
class Solution {
public:
Node copyRandomList(Node* head) {
std::unordered_map<Node,Node> mp;
for(auto p=head;p!=nullptr;p=p->next)
{
mp[p]=new Node(p->val);
}
};
空间复杂度O(n)
“`c++
class Solution {
public:
Node* copyRandomList(Node* head) {
if (!head) {
return nullptr;
}
Node* cur = head;
while (cur) {
Node* next = cur->next;
cur->next = new Node(cur->val);
cur->next->next = next;
cur = next;
}
};
//复制+拆分
“`
“`java
利用map构建源节点和新节点的映射关系,这样就可以迅速复制链表
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
}
*/
class Solution {
public Node copyRandomList(Node head) {
if(headnull) return null;
Node cur=head;
//建立原节点-新节点的映射关系
Map<Node,Node> map=new HashMap<>();
while(cur!=null){
map.put(cur,new Node(cur.val));
cur=cur.next;
}
//返回头节点再遍历一次
cur=head;
while(cur!=null){
map.get(cur).next=map.get(cur.next);
map.get(cur).random=map.get(cur.random);
cur=cur.next;
}
return map.get(head);
}
}
看视频学了一遍,自己画了图理清了思路,然后过了一个小时自己重新写了一遍
思路没问题,暂时可以说理解了,还是会有一些细节点的地方会写错
anyway,任何时候可以先判断一下头结点是不是就为null,先把这个if写出来
时间复杂度O(n),空间复杂度O(n)
不知道这个解法和递归的关系
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head nullptr){
return nullptr;
}
Node* cur = head;
while(cur!=nullptr){
Node* temp = new Node(cur->val);
temp->next = cur->next;
cur->next = temp;
cur = temp->next;
}
};
时间复杂度O(n),空间复杂度O(n)
class Solution {
public Node copyRandomList(Node head) {
Map<Node,Node> tmp=new HashMap<>(); //借用hashmap,将父子结点作为键值对存入到到mapNode中,利用这一绑定关系实现next的传递
Node cur=head;
while(cur!=null){
tmp.put(cur,new Node(cur.val));
cur=cur.next;
}
cur=head;
while(cur!=null){
tmp.get(cur).next=tmp.get(cur.next);
tmp.get(cur).random=tmp.get(cur.random);
cur=cur.next;
}
return tmp.get(head);
}
}
时间复杂度 O(n)
空间复杂度 O(n)
时间复杂度:O(n)
额外空间复杂度:O(1)
时间复杂度:O(n)
空间复杂度:O(n)
建立新旧节点的对应关系
先复制值,再创建链接和random部分
用hashmap来一一对应,然后再按顺序复制剩下的部分。
time O(n) space O(n)
这种办法可能空间不是最优解 但复制拆分感觉不如这个直白
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head NULL){
return head;
}
Node* p = head;
while(p){
Node* temp = p->next;
Node* q = new Node(p->val);
p->next = q;
q->next = temp;
p = temp;
}
p = head;
while(p){
Node* temp = p->next->next;
if(p->random){
p->next->random = p->random->next;
}
p = temp;
}
p = head;
Node* result = head->next;
while(p){
Node* temp = p->next->next;
if(temp){
p->next->next = temp->next;
}
p->next = temp;
p = temp;
}
return result;
}
};
思路:先复制相同值的新节点连接在原型之后,再处理random的指向,最后把原链表恢复,新链表断开提出返回。
时间复杂度O(N),空间复杂度O(1)。
class Solution:
def copyRandomList(self, head: ‘Optional[Node]’) -> ‘Optional[Node]’:
if head None:
return None
思路:在每个节点后复制原链表,再删除原来的
class Solution {
public:
Node* copyRandomList(Node* head) {
//1.如果链表是空链表,直接返回
if(head nullptr)
return nullptr;
//2.创建哈希表,存储复制节点
unordered_map<Node*, Node> NodeMap;
//3.进行复制操作
Node cur = head;
while(cur){
NodeMap[cur] = new Node(cur->val);
cur = cur->next;
}
//4.进行random指针和next指针的转移
cur = head;
while(cur){
NodeMap[cur]->next = NodeMap[cur->next];
NodeMap[cur]->random = NodeMap[cur->random];
cur = cur->next;
}
//5.返回链表头节点
return NodeMap[head];
}
};
时间o(n)
空间o(n)
//用一个哈希表来映射原节点和新节点,遍历两次,时间复杂度为O(N),空间复杂度O(n)
if(head null) {
return head;
}
时间o(n)
空间o(n)
a.代码及其思路
b.时间复杂度o(n),n为链表长度;空间复杂度o(n),哈希表需要额外n的常数空间;
思路:① 哈希表实现复杂链表的复制;② 使用合并 + 拆分的方式实现;
① 哈希表实现复杂链表的复制:使用一个哈希表记录原链表节点与复制后链表节点之间的映射,遍历原始链表时,为每个原始节点创建一个新节点,并将其存入到哈希表中;可以根据哈希表的映射关系,查找对应的节点,对新节点的
next、random指针进行赋值;返回head对应的新链表的头节点。时间复杂度:O(n),遍历了 2 次链表。
空间复杂度:O(n),使用了哈希表存储映射关系。
② 合并与拆分:将原始链表节点与复制链表节点合并成一个大的链表,形式如:
old1->new1->old2->new2->old3->new3->...;利用原始节点的random为新节点的random进行赋值;最后将大链表拆分为原始链表和复制链表,注意最后需要断开原始链表最后一个节点与新链表之间的连接;返回新链表的头节点。时间复杂度:O(n),遍历了 3 次链表。
空间复杂度:O(1),只使用了常数级的额外空间。
链表深拷贝:先构建新链表与原链表的关系,只插入数值,然后处理新链表的节点间的对应关系
public Node copyRandomList(Node head) {
if (head null) {
return head;
}
//将拷贝节点放到原节点后面,例如1->2->3这样的链表就变成了这样1->1′->2->2′->3->3′
for(Node cur = head, copy = null; cur != null; cur = cur.next.next){
copy = new Node(cur.val);
copy.next = cur.next;
cur.next = copy;
}
//把拷贝节点的random指针安排上
for(Node cur = head; cur != null; cur = cur.next.next){
if(cur.random != null){
cur.next.random = cur.random.next;
}
}
//分离拷贝节点和原节点1->1′->2->2′->3->3’,变成1->2->3和1′->2′->3’两个链表,后者就是答案
Node newHead = head.next;
for(Node cur = head, tmp = null; cur != null && cur.next != null;){
tmp = cur.next;
cur.next = tmp.next;
cur = tmp;
}
return newHead;
}
思路:首先复制节点接在原节点后,然后再分离
时间:O(n)
空间:O(n)
思路:使用 HashMap 建立一个 <oldNode, newNode> 。 首先不连接radom,建立一个与head 相同的链表 ans,并保存当前的<oldNode, newNode> 关系 。 建立完 ans 后 遍历一遍 ans,以连接radom。 通过查询 rem.get(head.random) 可以得到 当前newNode 所对应的 oldNode 的radom指向的oldNode 所对应的 newNode