一、题目要求
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 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]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
二、使用HashMap的解法
public class Solution {
public Node copyRandomList(Node head) {
if (head == null) {
return head;
}
HashMap<Node, Node> hashMap = new HashMap<Node, Node>();
Node newNode = head;
while (newNode != null) {
if (!hashMap.containsKey(newNode)) {
Node node = new Node(newNode.val);
hashMap.put(newNode, node);
}
if (newNode.random != null) {
Node random = newNode.random;
if (!hashMap.containsKey(random)) {
Node node = new Node(random.val);
hashMap.put(random, node);
}
hashMap.get(newNode).random = hashMap.get(random);
}
newNode = newNode.next;
}
newNode = head;
while (newNode.next != null) {
hashMap.get(newNode).next = hashMap.get(newNode.next);
newNode = newNode.next;
}
return hashMap.get(head);
}
}
三、使用添加节点的解法
public class Solution {
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
copy(head);
copyRandom(head);
return split(head);
}
private Node split(Node head) {
Node result = head.next;
Node move = head.next;
while (head != null && head.next != null) {
head.next = head.next.next;
head = head.next;
if (move != null && move.next != null) {
move.next = move.next.next;
move = move.next;
}
}
return result;
}
private void copyRandom(Node head) {
Node node = head;
while (node != null && node.next != null) {
if (node.random != null) {
node.next.random = node.random.next;
}
node = node.next.next;
}
}
private void copy(Node head) {
Node node = head;
while (node != null) {
Node copy = new Node(node.val);
copy.next = node.next;
node.next = copy;
node = copy.next;
}
}
}
四、测试用例
public class Test {
public static void main(String[] args) {
// 空链表测试
Node empty = null;
Node emptyNode1 = Solution1.copyRandomList(empty);
Node emptyNode2 = Solution2.copyRandomList(empty);
System.out.println("空链表测试:");
System.out.println("方法1:");
show(emptyNode1);
System.out.println("方法2:");
show(emptyNode2);
// 一个节点链表测试
Node one = new Node(1);
one.next = null;
one.random = null;
Node oneNode1 = Solution1.copyRandomList(one);
Node oneNode2 = Solution2.copyRandomList(one);
System.out.println("一个节点链表测试:");
System.out.println("方法1:");
show(oneNode1);
System.out.println("方法2:");
show(oneNode2);
// 两个节点链表测试
Node two = new Node(1);
two.next = new Node(2);
two.random = null;
two.next.random = two;
Node twoNode1 = Solution1.copyRandomList(two);
Node twoNode2 = Solution2.copyRandomList(two);
System.out.println("两个节点链表测试:");
System.out.println("方法1:");
show(twoNode1);
System.out.println("方法2:");
show(twoNode2);
// 正常链表测试
Node list = new Node(1);
list.next = new Node(2);
list.next.next = new Node(3);
list.next.next.next = new Node(4);
list.random = list.next.next;
list.next.random = list;
list.next.next.random = null;
list.next.next.next.random = list.next;
Node listNode1 = Solution1.copyRandomList(list);
Node listNode2 = Solution2.copyRandomList(list);
System.out.println("正常链表测试:");
System.out.println("方法1:");
show(listNode1);
System.out.println("方法2:");
show(listNode2);
}
private static void show(Node node) {
while (node != null) {
System.out.println("数值:" + node.val);
if (node.next != null) {
System.out.println("下一节点数值:" + node.next.val);
} else {
System.out.println("下一节点数值:" + null);
}
if (node.random != null) {
System.out.println("随机节点数值:" + node.random.val);
} else {
System.out.println("随机节点数值:" + null);
}
node = node.next;
}
}
}
五、流程图
(一)、使用HashMap的流程图
1、初始状态
2、开始复制节点
3、复制节点结束
4、赋值next节点
(二)、添加节点的流程图
1、初始状态
2、创建第一个复制节点
3、第一个复制节点添加完毕
4、复制节点添加完毕
5、复制节点random指针赋值完毕