剑指offer 面试题26—复杂链表的复制

剑指offer 面试题26—复杂链表的复制_第1张图片

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


以下图为5个结点的复杂链表,实线表示m_pNext指针的指向,虚线表示m_pSibling指针的指向
剑指offer 面试题26—复杂链表的复制_第2张图片

解法一:

分两步

   1:遍历一遍链表,用m_pNext指针将链表连起来,O(n)

   2:假设原始链表中的某节点N的m_pSibling指向结点S,由于S的位置在链表上有可能在N的前面也可能在N的后面,所以要定位N的位置需要从原始链表的头结点开始找,假设从原始链表的头结点开始经过s步找到结点S,那么在复制链表上结点N的m_pSibling的S’,离复制链表的头结点的距离也是s,用这种办法我们就能为复制链表上的每个结点设置m_pSibling了对含有n个结点的链表,由于定位每个结点的m_pSibling都需要从链表头结点开始经过O(n)步才能找到,因此这种方法的总时间复杂度是O(n2)

         时间代价为O(n^2),空间代价为0


解法二:

    针对方法1中每次确定一个结点的m_pSibling指向效率较低,利用空间换取时间,同样分两步

    1:遍历一遍链表,用m_pNext指针将链表连起来的同时,将原链表中的结点N和相应复制结点N'建立哈希映射<N,N'>

    2:再次遍历一遍原链表,对于每一结点m通过哈希找到m',并在原链表中找到m的m_pSibling所指向结点,再次通过哈希查找找到m'的m_pSibling指针应指向的结点,并修改m'的m_pSibling指针   

  时间代价为O(n), 空间代价为O(n)


解法三:

     比较巧妙,只需遍历3次链表,时间代价为O(n),空间代价为0,分3步


    1:遍历一遍原始链表,复制结点N对应的N',将其插入到结点N的后面,如下图所示

剑指offer 面试题26—复杂链表的复制_第3张图片

   代码如下:

    void CloneNodes(ComplexListNode* pHead)  
    {  
        ComplexListNode* p = pHead;  
        while ( p )  
        {  
            ComplexListNode* pCloned = new ComplexListNode;  
            pCloned->m_nValue = p->m_nValue;  
            pCloned->m_pNext = p->m_pNext;  
            p->m_pNext = pCloned;  
            pCloned->m_pSibling = NULL;  
      
            p = p->m_pNext;  
        }  
    }  

   2:确定每个m_pSibling指针的指向,假设原始链表上的N的m_pSibling指向节点S,那么其对应复制出来的N'是N的m->pNext指向的节点,同样S'也是S的m->pNext指向的节点,

这就是我们在上一步中把每个结点复制出来的结点链接在原始结点后面的原因。有了这样的链接方式,我们就能在O(1)中就能找到每个结点的m_pSibling了。得到如下图结构

剑指offer 面试题26—复杂链表的复制_第4张图片

   代码如下:

    void ConnectSiblingNodes(ComplexListNode* pHead)  
    {  
        ComplexListNode* p = pHead;  
        ComplexListNode* pCloned = NULL; //记录当前要确定其m_pSibling的结点  
      
        while ( p )  
        {  
            pCloned = p->m_pNext;  
              
            if ( pCloned->m_pSibling )  
                pCloned->m_pSibling = p->m_pSibling->m_pNext;  
      
            p = pCloned->m_pNext;  
        }  
    }  

    3:再次遍历一遍,将原始链表和复制链表分开,奇数为原始链表,偶数为复制链表,得到如下图型

剑指offer 面试题26—复杂链表的复制_第5张图片

    代码如下:

    ComplexListNode* ReconnentNodes(ComplexListNode* pHead)  
    {  
        ComplexListNode* pNode = pHead;  
        ComplexListNode* pClonedHead = NULL;    //确定返回的头结点  
        ComplexListNode* pClonedNode = NULL;  
      
        //头结点特殊处理,边界条件判断  
        if ( pNode != NULL )  
        {  
            pClonedHead = pNode->m_pNext;  
            pClonedNode = pNode->m_pNext;  
      
            pNode->m_pNext = pClonedHead->m_pNext;  
            pNode = pNode->m_pNext;  
        }  
      
        while ( pNode )  
        {  
            pClonedNode->m_pNext = pNode->m_pNext;  
      
            pNode->m_pNext = pClonedNode->m_pNext;  
      
            pClonedNode = pClonedNode->m_pNext;  
              
            pNode = pNode->m_pNext;  
        }  
      
        return pClonedHead;  
    }  

   最终将上述3步合并,就是复制复杂链表的全过程:

    ComplexListNode* Clone(ComplexListNode* pHead)  
    {  
        CloneNodes(pHead);  
        ConnectSiblingNodes(pHead);  
          
        return ReconnentNodes(pHead);  
    }  





你可能感兴趣的:(复杂链表的复制,剑指offer,剑指offer,面试题26)