《剑指offer》刷题——【分解让复杂问题简单化】面试题35:复杂链表的复制(java实现)
一、题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针
指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中
的节点引用,否则判题程序会直接返回空)
二、题目分析
在复杂链表的节点中,除了有指向下一个节点的指针(实线箭头),还有指向任意节点的指针(虚线箭头)
方法一:普通方法 O(n^2)
- (1)复制原始链表上的每一个节点,并用m_pNext链接起来
- (2)设置每个节点的 m_pSibling指针(每一个需要从链表头开始经过O(n)步才能找到)
方法二、借助辅助空间的O(n)解法
- (1)复制原始链表上的每一个节点N创建N,并用m_pNext链接起来;并将<N, N`> 的配对信息放到一个哈希表中
- (2)设置复制链表上每一个m_pSibling(==由于有了哈希表,可以用O(1)的时间根据s找到s`)
方法三、不借助辅助空间的O(n)解法
- 根据原始链表的每个节点创建对应的N^(把N ^ 链接在N的后面)
- 设置复制出来的节点的m_pSibling(把N^ 的m_pSibling指向N的m_pSibling)
- 把长链表拆分成两个链表:奇数位置的节点用pNext链接起来就是原始链表,偶数位置则是复制链表
三、代码实现
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
//复制原始链表
CloneNodes(pHead);
//设置随机链接
ConnectSiblingNodes(pHead);
//拆分链表
return ReconnectNodes(pHead);
}
/**
* 1.复制原始链表的任意节点N并创建新节点N`,再把N`链接到N的后面
*/
public void CloneNodes(RandomListNode pHead){
RandomListNode node = pHead;//链表指针
//遍历原始链表
while(node != null){
//新建一个节点
RandomListNode cloned = new RandomListNode(node.label);
//复制节点
//cloned.label = node.label;
cloned.next = node.next;
cloned.random = null;
//并将复制节点链接在原始节点之后
node.next = cloned;
//更改下一个遍历到的节点,为复制节点的下一节点
node = cloned.next;
}
}
/**
* 2. 设置复制出来的节点的random
*/
public void ConnectSiblingNodes(RandomListNode pHead){
//遍历
RandomListNode node = pHead;
while(node != null){
RandomListNode cloned = node.next;
//若遍历到的节点有random指向
if(node.random != null){
//则复制节点的random即为原始节点的random的下一节点
cloned.random = node.random.next;
}
//更改下一个遍历到的节点,为复制节点的下一节点
node = cloned.next;
}
}
/**
* 3. 把长表拆分成两个链表,奇数位为原始链表,偶数位为复制链表
*/
public RandomListNode ReconnectNodes(RandomListNode pHead){
RandomListNode node = pHead;//原始链表指针
RandomListNode clonedHead = null; //复制链表头指针
RandomListNode clonedNode = null; //复制链表指针
//若链表不为空
if(node != null){
clonedHead = clonedNode = node.next;//初始化复制链表头指针 指针
node.next = clonedNode.next;//将奇数节点的下一节点指向偶数节点的下一节点
node = node.next; //遍历指针后移
}
//循环拆分奇偶位
while(node != null){
//复制链接
clonedNode.next = node.next;
clonedNode = clonedNode.next;
//原始链表连接
node.next = clonedNode.next;
//遍历节点后移
node = node.next;
}
//返回复制链表的头指针
return clonedHead
}
}