zoukankan      html  css  js  c++  java
  • (剑指Offer)面试题26:复杂链表的复制

    题目:

    请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。

    在复杂链表中,每个结点除了有一个pNext指针指向下一个结点之外,还有一个pSibling指向链表中的任意结点或者NULL。

    结点的定义如下:

    struct ComplexListNode{
        int val;
        ComplexListNode* pNext;
        ComplexListNode* pSibling;
    };
    

    思路:

    方法1:

    复制原始链表上的每一个结点,并通过pNext连接起来;然后再设置每个结点的pSibling指针。

    假设原始链表中某个结点N的pSibling指针指向结点S,那么就需要从头到尾遍历查找结点S,如果从原始链表的头指针开始,经过m步之后达到结点S,那么在复制链表中的结点N'的pSibling指针指向的结点也是距离复制链表s步的结点。通过这种办法就可以为复制链表上的每个结点设置pSibling指针。

    时间复杂度:O(N^2)

    方法2:

    方法1是通过链表查找来得到pSibling指针所指向的结点,实际上我们可以通过空间换取时间,将原始链表和复制链表的结点通过哈希表对应起来,这样查找的时间就从O(N)变为O(1)。具体如下:

    复制原始链表上的每个结点N创建N',然后把这些创建出来的结点用pNext连接起来。同时把<N,N'>的配对信息方法一个哈希表中;然后设置复制链表中的每个结点的pSibling指针,如果原始链表中结点N的pSibling指向结点S,那么在复制链表中,对应的N'应该指向S'。

    时间复杂度:O(N)

    方法3:

    在不使用辅助空间的情况下实现O(N)的时间效率。

    第一步:根据原始链表的每个结点N创建对应的N',然后将N‘通过pNext接到N的后面;

    第二步:设置复制出来的结点的pSibling。假设原始链表上的N的pSibling指向结点S,那么其对应复制出来的N'是N->pNext指向的结点,同样S'也是结点S->pNext指向的结点。

    第三步:把长链表拆分成两个链表,把奇数位置的结点用pNext连接起来的就是原始链表,把偶数位置的结点通过pNext连接起来的就是复制链表。

    代码:

    1、Hash方法:

    struct ComplexListNode{
        int val;
        ComplexListNode* pNext;
        ComplexListNode* pSibling;
        ComplexListNode():val(0),pNext(NULL),pSibling(NULL){};
    };
    
    typedef std::map<ComplexListNode*,ComplexListNode*> MAP;
    
    ComplexListNode* CloneNodes(ComplexListNode* pHead,MAP &hashNode){
        ComplexListNode* pNode=new ComplexListNode();
        ComplexListNode* p=pNode;
        ComplexListNode* tmp;
    
        while(pHead!=NULL){
            tmp=new ComplexListNode();
            tmp->val=pHead->val;
            p->pNext=tmp;
            hashNode[pHead]=tmp;
            pHead=pHead->pNext;
            p=p->pNext;
        }
        return pNode->pNext;
    }
    
    void SetSiblings(ComplexListNode* pHead,ComplexListNode* pCopy,MAP &hashNode){
        while(pCopy!=NULL){
            pCopy->pSibling=hashNode[pHead->pSibling];
            pCopy=pCopy->pNext;
            pHead=pHead->pNext;
        }
    }
    
    ComplexListNode* ComplexListCopy(ComplexListNode* pHead){
        ComplexListNode* pCopy;
        MAP hashNode;
        pCopy=CloneNodes(pHead,hashNode);
        SetSiblings(pHead,pCopy,hashNode);
        return pCopy;
    }
    

    2、复制连接方法:

    #include <iostream>
    
    using namespace std;
    
    struct ComplexListNode{
        int val;
        ComplexListNode* pNext;
        ComplexListNode* pSibling;
        ComplexListNode(int x):val(x),pNext(NULL),pSibling(NULL){};
    };
    
    void CloneNodes(ComplexListNode* pHead){
        ComplexListNode* pNode=pHead;
        ComplexListNode* pCloned;
        while(pNode!=NULL){
            pCloned=new ComplexListNode(pNode->val);
            pNode->pNext=pCloned;
            pCloned->pNext=pNode->pNext;
            pNode=pCloned->pNext;
        }
    }
    
    void ConnectSiblingNodes(ComplexListNode* pHead){
        ComplexListNode* pNode=pHead;
        ComplexListNode* pCloned;
        while(pNode!=NULL){
            pCloned=pNode->pNext;
            if(pNode->pSibling!=NULL){
                pCloned->pSibling=pNode->pSibling->pNext;
            }
            pNode=pCloned->pNext;
        }
    }
    
    ComplexListNode* ReconnectNodes(ComplexListNode* pHead){
        ComplexListNode* pNode=pHead;
        ComplexListNode* pClonedHead=NULL;
        ComplexListNode* pClonedNode=NULL;
    
        if(pNode!=NULL){
            pClonedHead=pClonedNode=pNode->pNext;
            pNode->pNext=pClonedNode->pNext;
            pNode=pNode->pNext;
        }
        while(pNode!=NULL){
            pClonedNode->pNext=pNode->pNext;
            pClonedNode=pClonedNode->pNext;
            pNode->pNext=pClonedNode->pNext;
            pNode=pNode->pNext;
        }
        return pClonedHead;
    }
    
    ComplexListNode* Clone(ComplexListNode* pHead){
        CloneNodes(pHead);
        ConnectSiblingNodes(pHead);
        return ReconnectNodes(pHead);
    }

    在线测试OJ:

    http://www.nowcoder.com/books/coding-interviews/f836b2c43afc4b35ad6adc41ec941dba?rp=1

    AC代码:

    /*
    struct RandomListNode {
        int label;
        struct RandomListNode *next, *random;
        RandomListNode(int x) :
                label(x), next(NULL), random(NULL) {
        }
    };
    */
    class Solution {
    public:
        typedef std::map<RandomListNode*,RandomListNode*> MAP;
        RandomListNode* CloneNextNode(RandomListNode* pHead,MAP &hashNode){
            RandomListNode* pCopy=new RandomListNode(0);
            RandomListNode* p=pCopy;
            RandomListNode* tmp;
            while(pHead!=NULL){
                tmp=new RandomListNode(pHead->label);
                p->next=tmp;
                hashNode[pHead]=tmp;
                p=p->next;
                pHead=pHead->next;
            }
            return pCopy->next;
        }
    
        void setRandomNode(RandomListNode* pHead,RandomListNode* pCopy,MAP &hashNode){
            while(pCopy!=NULL){
                pCopy->random=hashNode[pHead->random];
                pCopy=pCopy->next;
                pHead=pHead->next;
            }
        }
    
        RandomListNode* Clone(RandomListNode* pHead)
        {
            RandomListNode* pCopy;
            MAP hashNode;
            pCopy=CloneNextNode(pHead,hashNode);
            setRandomNode(pHead,pCopy,hashNode);
            return pCopy;
        }
    };
    
    /*
    struct RandomListNode {
        int label;
        struct RandomListNode *next, *random;
        RandomListNode(int x) :
                label(x), next(NULL), random(NULL) {
        }
    };
    */
    class Solution {
    public:
        RandomListNode* Clone(RandomListNode* pHead)
        {
            CloneNodes(pHead);
            CloneRandom(pHead);
            return ReConnectNodes(pHead);
        }
        
        void CloneNodes(RandomListNode* pHead){
            RandomListNode* pCloned;
            while(pHead!=NULL){
                pCloned=new RandomListNode(pHead->label);
                pCloned->next=pHead->next;
                pHead->next=pCloned;
                pHead=pCloned->next;
            }
        }
        
        void CloneRandom(RandomListNode* pHead){
            RandomListNode* pCloned;
            while(pHead!=NULL){
                pCloned=pHead->next;
                if(pHead->random!=NULL){
                    pCloned->random=pHead->random->next;
                }
                pHead=pCloned->next;
            }
        }
        
        RandomListNode* ReConnectNodes(RandomListNode* pHead){
            RandomListNode* pClonedHead=NULL;
            RandomListNode* pClonedNode=NULL;
            RandomListNode* pNode=pHead;
            
            if(pNode!=NULL){
                pClonedHead=pClonedNode=pNode->next;
                pNode->next=pClonedNode->next;
                pNode=pNode->next;
            }
            
            while(pNode!=NULL){
                pClonedNode->next=pNode->next;
                pClonedNode=pClonedNode->next;
                pNode->next=pClonedNode->next;
                pNode=pNode->next;
            }
            return pClonedHead;
        }
    };
  • 相关阅读:
    类似-Xms、-Xmn这些参数的含义:
    类似-Xms、-Xmn这些参数的含义:
    类似-Xms、-Xmn这些参数的含义:
    类似-Xms、-Xmn这些参数的含义:
    Java 虚拟机是如何判定两个 Java 类是相同的?
    Java 虚拟机是如何判定两个 Java 类是相同的?
    Java 虚拟机是如何判定两个 Java 类是相同的?
    Java 虚拟机是如何判定两个 Java 类是相同的?
    互联网支付系统整体架构详解
    DTO
  • 原文地址:https://www.cnblogs.com/AndyJee/p/4654545.html
Copyright © 2011-2022 走看看