解法一(HashMap)
/*
// 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;
}
//通过hashmap来进行复制保存
Map<Node, Node> map = new HashMap<Node, Node>();
//用newHead去遍历
Node newHead = head;
while (newHead != null) {
//如果HashMap没有当前节点,那么就进行复制,并且查找复制的节点是通过本来的节点映射得到
if (!map.containsKey(newHead)) {
Node copyNode = new Node(newHead.val);
//映射两者
map.put(newHead, copyNode);
}
//如果当前节点的Random不为空且该Random节点不在HashMap中,则复制Random
if (newHead.random != null) {
Node random = newHead.random;
if (!map.containsKey(random)) {
Node copyRandom = new Node(random.val);
//建立映射
map.put(random, copyRandom);
}
//复制后的节点的random指针也该指向这个random节点
map.get(newHead).random = map.get(random);
}
//下一个
newHead = newHead.next;
}
//上面这个while循环只是复制完了所有的节点,并且建立了节点与random节点之间的联系,但是链表的next还未建立联系
newHead = head;
while (newHead != null) {
Node next = newHead.next;
map.get(newHead).next = map.get(next);
newHead = newHead.next;
}
return map.get(head);
}
}
搭配图片理解算法过程
1指向3的指针即random指针
第一个while完成后,复制的链表就变成了这样
第二个while循环完成后就成功了
优点
使用HashMap进行复制和建立映射很方便。
缺点
由于要用HashMap来存储映射关系,所以空间消耗更多了,空间复杂度为O(n),
如果我们有另外一种方式来映射,就可以省去HashMap这种空间消耗了
解法二
图片理解
之前我们使用键值在HashMap中来获取复制的节点,现在我们就用原节点的next域来获取复制的节点,这种方式不存在映射空间的消耗
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
//复制原节点
copy(head);
//并建立random节点的联系
copyRandom(head);
//上面两步完成后就是上图的效果了,上图差了一个random线。
//拆开后返回
return split(head);
}
//建立图示想要的next即为复制节点的链表
public 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;
}
}
//建立Random的联系
public void copyRandom(Node head) {
Node node = head;
while(node != null && node.next != null) {
if (node.random != null) {
//next节点即为复制后的节点,例如1‘,让它的random去指向复制后的random
node.next.random = node.random.next;
}
//一次性跳两个,因为不需要去遍历复制的节点
node = node.next.next;
}
}
//拆开图示链表,分开为两个一样的链表
public 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;
}