链表,复制带随机指针的链表
1. 题目描述
难易度:中等
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val
:一个表示Node.val
的整数。random_index
:随机指针指向的节点索引(范围从0
到n-1
);如果不指向任何节点,则为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]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
提示:
- -10000 <= Node.val <= 10000
Node.random
为空(null)或指向链表中的节点。- 节点数目不超过 1000 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer
2. 思路分析
- 以下代码所演示的解法,效率比较低:
- 首先创建新的链表,random域为null
- 第一次遍历链表得到random所指向的节点所对应的下标,保存在ArrayList中
- 第二次遍历,从ArrayList中取出下标找到对应的节点,将节点赋给本次操作节点的random域
- LeetCode题解中看到比较高效的解法:
- 创建一个HashMap:HashMap map=new HashMap()
- 第一次遍历时,HashMap的键为所对用节点cur,val为new Node(cur.val)
- 第二次遍历时,将键为cur所对应的值的next域赋值为map.get(cur.next)。即map.get(cur)=map.get(cur.next)
- 同样键为cur所对应的值的random域赋值为map.get(cur.random)
- 返回map.get(head)
3. 代码演示
import java.util.ArrayList;
/**
* @Description TODO
* @Author YunShuaiWei
* @Date 2020/5/8 21:12
* @Version
**/
public class Main {
}
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.next;
Node newHead = new Node(head.val);
Node tmp=newHead;
//遍历创建出新的链表
while (cur != null) {
tmp.next = new Node(cur.val);
cur = cur.next;
tmp=tmp.next;
}
cur = head;
ArrayList<Integer> index = new ArrayList<>();
//遍历得到cur的random域所指向的下标,存入ArrayList中
while (cur != null) {
Node r = cur.random;
int i = 0;
tmp = head;
while (tmp != r) {
i++;
tmp = tmp.next;
}
index.add(i);
cur = cur.next;
}
tmp = newHead;
cur = newHead;
//取出random所对应的下标,找到下标所对用的节点,将地址赋给tmp的random于
for (Integer i : index) {
while (i > 0) {
tmp = tmp.next;
i--;
}
cur.random = tmp;
cur = cur.next;
tmp = newHead;
}
return newHead;
}
}