先来看题:
示例1:
示例2:
思考:
通过观察题目,我们会发现这个题有两种解法:
1.哈希表(不推荐)
具体代码如下:
//哈希表解法
public class Solution {
public Node copyRandomList(Node head) {
//先判空
if(head == null){
return null;
}
//创建一个HashMap
Map<Node,Node> map = new HashMap<>();
for(Node cur = head; cur != null; cur = cur.next){
//将原节点拷贝一份放到集合中(这时只有val值相同)
map.put(cur,new Node(cur.val));
}
for(Node cur = head; cur != null;cur = cur.next){
//通过next值将所有拷贝的节点连接到一起
map.get(cur).next = map.get(cur.next);
//拷贝原节点中random的值
map.get(cur).random = map.get(cur.random);
}
//返回原节点作为键时所对应的新链表的头节点
return map.get(head);
}
}
LeetCode上测试:
第二种解法就是:原地修改解法(推荐)
相较于哈希表,我感觉这种解法更能体现我们的代码能力,所以我也推荐用此方法。
原理:
大体结构:
详细步骤:
具体代码:
class Solution {
public Node copyRandomList(Node head) {
//先判空链表
if (head == null) {
return null;
}
//不直接使用head,备份一个cur
Node cur = head;
//遍历链表
while (cur != null) {
//创建一个新节点,使它的val值与原节点的val值相等
Node node = new Node(cur.val);
//将新节点连接到原节点后面
node.next = cur.next;
cur.next = node;
//处理下一个原节点
cur = cur.next.next;
}
//重置一下cur
cur = head;
//遍历
while (cur != null) {
//判断一下原节点的random是不是null
//不是,就进行处理
//由于新创建节点的random值默认是null,所以不用管
if (cur.random != null) {
//不是,就将原节点的random指向也拷贝到新节点的random中
//这里需要注意:
//cur.random是原节点的值,新节点不能直接指向
//所以只能指向那个原节点的拷贝节点
//在上面我们就已经将每个拷贝节点放到了每个原节点的后面
cur.next.random = cur.random.next;
}
//处理下一个
cur = cur.next.next;
}
//存放新链表的头节点
Node copyHead = head.next;
cur = head;
//拷贝一份用来循环遍历
Node copyCur = head.next;
while (cur != null) {
//连接原链表
cur.next = cur.next.next;
cur = cur.next;
//判断是不是尾结点
if (copyCur.next != null) {
//不是,继续连接新链表
copyCur.next = copyCur.next.next;
copyCur = copyCur.next;
}
}
//返回新链表的头节点
return copyHead;
}
}
LeetCode上测试:
总结:
方法有两种,哈希表与原地修改法没有谁一定好,谁一定坏,但是一般在面试中还是推荐用原地修改法。