剑指offer之面试题35:复杂链表的复制

复杂链表的复制

1、题目

请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。在复杂链表中,每个节点除了有一个m_pNext指针指向下一个节点,还有一个m_pSibling指针指向链表中的任意节点或者nullptr。节点的C++定义如下:

struct ComplexListNode
{
    int                 m_nValue;
    ComplexListNode* m_pNext;
    ComplexListNode* m_pSibling;
};

输入参数:原始链表的头指针pHead

输出结果:复制链表的头指针pClonedHead

2、解题

这道题的关键在于拆分复杂问题让其简单化,复制一个复杂链表共有三种方法。

法一:

  • 步骤
    • 复制链表上的每个节点,并链接起来
    • 设置每个节点的m_pSibling指针,所要定位的位置从原始链表的头节点开始找
  • 时间复杂度:O(n^2)

法二:

  • 步骤
    • 复制链表上的每个节点,并链接起来。同时将m_pSibling指针的配对信息放在一个哈希表中
    • 设置每个节点的m_pSibling指针,从哈希表中以O(1)时间找到即可
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

法三:

  • 步骤
    • 复制链表上的每个节点,将每个克隆节点放在原始节点的后面。
    • 设置克隆节点的m_pSibling指针
    • 将这个长链表拆分成两个链表,一个是原始链表,一个就是复制链表
    • 在一个总的函数中调用上述的三个步骤(函数),最后返回复制链表的头指针pClonedHead
  • 时间复杂度:O(n)
  • 空间复杂度:不需要额外的空间

Gjb88x.png

3、代码

这里采用第三种方法

//在原始节点后面克隆一个新节点
void CloneNodes(ComplexListNode* pHead) {
    ComplexListNode* pNode = pHead;

    while (pNode != nullptr) {
        //初始化克隆节点,分配内存
        ComplexListNode* pCloned = new ComplexListNode();
        pCloned->m_nValue = pNode->m_nValue;
        pCloned->m_pNext = pNode->m_pNext;
        pCloned->m_pSibling = nullptr;
        //原始节点向前移动
        pNode->m_pNext = pCloned;
        pNode = pCloned->m_pNext;
    }
}
//给克隆处的新节点的m_pSibling指针赋值
void ConnectSiblingNodes(ComplexListNode* pHead) {
    ComplexListNode* pNode = pHead;

    while (pNode != nullptr) {
        ComplexListNode* pCloned = pNode->m_pNext;
        //若原始节点的>m_pSibling指针为空,直接跳过即可
        if (pNode->m_pSibling != nullptr) {
            pCloned->m_pSibling = pNode->m_pSibling->m_pNext;
        }
        pNode = pCloned->m_pNext;
    }
}
//从一个链表中分离出两个链表
ComplexListNode* ReconnectNodes(ComplexListNode* pHead) {
    ComplexListNode* pNode = pHead;
    ComplexListNode* pClonedHead = nullptr;
    ComplexListNode* pClonedNode = nullptr;
    //先找到头节点再说
    if (pNode != nullptr) {
        pClonedHead = pClonedNode = pNode->m_pNext;
        //头节点赋值后,原始节点记得向前移动
        pNode->m_pNext = pClonedNode->m_pNext;
        pNode = pNode->m_pNext;
    }
    while (pNode != nullptr) {
        //只有下一个原始节点存在,克隆节点才能继续前进
        pClonedNode->m_pNext = pNode->m_pNext;
        pClonedNode = pClonedNode->m_pNext;
        //而后原始节点继续前进
        pNode->m_pNext = pClonedNode->m_pNext;
        pNode = pNode->m_pNext;
    }
    return pClonedHead;
}

ComplexListNode* Clone(ComplexListNode* pHead) {
	CloneNodes(pHead);
	ConnectSiblingNodes(pHead);

	return ReconnectNodes(pHead);
}
4、注意点
  • 在给克隆节点的m_pSibling指针赋值时,若原始节点的>m_pSibling指针为空,记得直接跳过即可
  • 从一个链表中分离出两个链表的时候,需要先给复制链表的头指针赋值,再进行分离操作
  • 分离时的步骤为:(此时pNode在pClonedNode之前)
    • 先判空pNode,只有下一个原始节点pNode存在时,克隆节点pClonedNode才能继续前进
    • 而后原始节点pNode继续前进,始终保持在pClonedNode的前面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值