每日一题 - 剑指 Offer 35. 复杂链表的复制
题目信息
-
时间: 2019-06-28
-
题目链接:Leetcode
-
tag: 链表
-
难易程度:中等
-
题目描述:
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
提示
1.-10000 <= Node.val <= 10000
2.Node.random为null或指向链表中的节点
3.节点数目不超过1000
解题思路
本题难点
本题的意思是复制一个链表并返回,这个链表与一般链表不同的是多了一个 random
指针。
具体思路
这个复制过程可以分成两步:第一步是复制原始链表上的每个节点,并用next指针相连; 第二步是设置每个节点的random指针。
- 复制节点:将原始链表的任意节点 N复制为新节点N',再把N'连接到 N的后面。即如果原始链表为A->B->C->D 则复制过后为A->A'->B->B'->C->C'->D->D'
- 建立random连接: 如果原始链表上的节点 N 的random指针指向节点S,则它对应的复制节点N'的random指针指向节点S的复制节点S',也就是当前节点S的下一个节点。
- 拆分链表:把这个长链表拆分成两个链表,把奇数位置的节点连接起来就是原始链表,把偶数位置的节点连接起来就是复制出来的链表。
代码
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if(head == null){
return null;
}
//插入新节点
Node cur = head;
while(cur != null){
Node clone = new Node(cur.val);
clone.next = cur.next;
cur.next = clone;
cur = clone.next;
}
//建立random链接
cur = head;
while(cur != null){
Node clone = cur.next;
if(cur.random != null){
clone.random = cur.random.next;
}
cur = clone.next;
}
//拆分
cur = head;
Node cloneHead = head.next;
while(cur.next != null){
Node next = cur.next;
cur.next = next.next;
cur = next;
}
return cloneHead;
}
}
复杂度分析:
- 时间复杂度 O(N) : 链表长度为N,遍历所需时间。
- 空间复杂度 O(1) :没有使用额外的空间保存已保存的节点。
其他优秀解答
解题思路
1.创建HashMap
2.复制结点值
3.复制指向(next,random)
代码
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution { //HashMap实现
public Node copyRandomList(Node head) {
HashMap<Node,Node> map = new HashMap<>(); //创建HashMap集合
Node cur=head;
//复制结点值
while(cur!=null){
//存储put:<key,value1>
map.put(cur,new Node(cur.val)); //顺序遍历,存储老结点和新结点(先存储新创建的结点值)
cur=cur.next;
}
//复制结点指向
cur = head;
while(cur!=null){
//得到get:<key>.value2,3
map.get(cur).next = map.get(cur.next); //新结点next指向同旧结点的next指向
map.get(cur).random = map.get(cur.random); //新结点random指向同旧结点的random指向
cur = cur.next;
}
//返回复制的链表
return map.get(head);
}
}