剑指Offer35-复杂链表的复制
题目描述
/**
* @Author: PlusHuang
* @Date: 2021/11/30 23:04
* @Theme:
* @Description:
* 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,
每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
结果示例
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
输入:head = [] 输出:[] 解释:给定的链表为空(空指针),因此返回 null。
代码示例及详细解释
/*
// 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 currentNode = head;
//在原链表的每一个节点,复制一个和前面界面一样的节点
while(currentNode != null){
//复制一个当前节点
Node node = new Node(currentNode.val);
//新节点的后面是当前节点的下一个节点
node.next = currentNode.next;
//将新节点插入当当前节点后
currentNode.next = node;
//当前节点继续往下移,注意不是currentNode = currentNode.next,因为已经插入了新节点,应该是node.next
currentNode = node.next;
}
//为新增的每个节点设置随机属性
currentNode = head;//重新回到链表头
//遍历每一个原节点
while(currentNode != null){
if(currentNode.random != null){
//如果当前节点随机属性不为空,将其邻接节点(也就是其复制的节点)设置随机节点
currentNode.next.random = currentNode.random.next;//注意这里要加.next,是要将新节点的random属性设置好
}
//遍历源节点,隔着一个
currentNode = currentNode.next.next;
}
//将新旧节点一一拆分,新节点连接成的新链表就是原链表的复制链表
currentNode = head.next;
Node preNode = head;
Node result = head.next;
while (currentNode.next != null) {
preNode.next = preNode.next.next;
currentNode.next = currentNode.next.next;
preNode = preNode.next;
currentNode = currentNode.next;
}
preNode.next = null; // 将 原链表的最后一个节点 的 next指针,重新指向null
return result;
}
}
解题思路和收获的启示
就是碰到这种题目,如果是单纯普通的链表复制,那就直接遍历复制就好了,但是由于此题非常特殊,存在随机属性,直接遍历复制的话咱们只能知道随机属性节点的是哪个,但是因为不清楚这个节点在链表的哪个位置,只知道它是什么不是到位置我们是无法将复制的新节点成功地连接起来的。可以想到地解决办法就是依赖于原链表,依靠原链表地固有的节点顺序来进行复制,进而我们想到了可以在原链表上每个节点后面复制节点,再把random属性按照源节点一样设置好。最后形成地链表是九新交替链表,只需要再对其进行分离即可。
以后遇到此类链表赋值问题,只需要遵守两项原则,一般都可以解决:
- 一般链表,直接遍历复制
- 特殊链表,存在各种指向,可以依靠原链表地固有顺序,在原链表上进行复制。这些就不用特意去考虑链表各种乱七八糟地指向了。