题目描述:
请实现函数ComplexListNode* Clone(ComplexListNode* Head),复制一个复杂链表,在复杂链表中,每个节点除了有一个_next指针指向下一个外,还有一个Sibling指针指向链表中的任意节点或者nullptr。
节点类型
struct ComplexListNode
{
int _data;
ComplexListNode* _next;
ComplexListNode* _Sibling
}
第一直觉的思路是:
- 复制原链表的节点,用_next连接
- 设置每个节点的Sibling指针
由于找每个节点的Sibling指针都要遍历一次原链表,故这种思路的时间复杂度为O(N2)。
思考一下,上面这种思路的时间复杂度之所以高,是因为每次找Sibling指针都要遍历链表,所以很耗时,稍加思索就可以想到如何在查找上优化,没错,就是哈希表。
可以将原链表的Sibling指针存入一个哈希表中,这样每次查找就是O(1)的复杂度,这样,整个过程的时间复杂度就是O(N),不过哈希表需要额外的空间复杂度开销。
这里介绍剑指offer上的思路,在不需要额外空间复杂度的情况下,依然是O(N)的时间复杂度。
算法的思路:
第一步: 根据原链表中的每个节点N创建对应的复制节点N’,然后将N‘连接在N后面
此步骤代码:
void CloneNode(ComplexListNode* Head)
{
ComplexListNode* node = Head;
while(node){
ComplexListNode* Cloned = new ComplexListNode();
Cloned->_data = node->_data;
Cloned->_next = node->_next;
Cloned->_Sibling = nullptr;
//克隆出的节点连在原节点后面
node->_next = Cloned;
node = Clone->_next;
}
}
第二步:设置复制出来的节点的Sibling。假定原链表中N的Sibling指向S,那么其对应复制出来的N’是N的_next指向的节点同理,S’也是S的_next指向的节点。故如下:
完成第二步的代码
void ConnectSiblingNodes(ComplexListNode* Head)
{
ComplexListNode* node = Head;
while(node){
ComplexListNode* Cloned = node->_next;
if(node->_Sibling){
Cloned->_Sibling = node->_Sibling->_next;
}
node = Cloned->_next;
}
}
第三步:整个链表现在奇数位为原始链表的节点,偶数位是复制出来的节点,拆分成两个链表即可。
完成此步骤的代码:
ComplexListNode* ReConnectNodes(ComplexListNode* Head)
{
ComplexListNode* node = Head;
ComplexListNode* ClonedHead = nullptr;
ComplexListNode* Clonednode = nullptr;
if(node){
ClonedHead = Clonednode = node->_next;
node = Clonenode->_next;
node = node->_next;
}
while(node){
Clonednode->_next = node->_next;
Clonednode = Clonednode->_next;
node->_next = Clonednode->_next;
node = node->_next;
}
return ClonedHead;
}
然后这三步合起来即可:
ComplexListNode* Clone(ComplexListNode *Head)
{
CloneNodes(Head);
ConnectSibling(Head);
return ReConnectNodes(Head);
}