链表问题_复杂链表的复制

题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
分析:这个题目说白了也就是实现这个类的拷贝构造函数,具体的有三种方法提供:
1、直观的解法,把复制过程分成两步:第一步是复制原始链表上的每个节点,并且用next连接起来;第二步,设置每个节点的random指针。对于第一步遍历一遍即可解决,花费O(n)的时间,但是对于第二步来说,每个指针的random指针都有可能指向当前节点的前面,由于为单向链表,所以我们不得不重头遍历来确定random,因此需要花费O(n^2)的时间,所以总的时间效率为O(n^2)。具体的实现如下:

struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
        label(x), next(NULL), random(NULL) {}
};

/*第一种方法,直观的解法,首先赋值每个节点,然后连接next,最后连接random,总的花费O(n^2)*/
RandomListNode* CloneNodes(RandomListNode*phead)
{
    if (!phead)
        return NULL;
    //第一步复制每个节点,并且进行连接,同时构造出对应的


    RandomListNode*pclone_head = new RandomListNode(phead->label);
    pclone_head->next = NULL;
    pclone_head->random = NULL;


    RandomListNode*pnode = phead->next;
    RandomListNode*pclone_node = pclone_head;

    while (pnode)
    {
        RandomListNode*pclone = new RandomListNode(pnode->label);
        pclone->next = NULL;
        pclone->random = NULL;

        pclone_node->next = pclone;
        pclone_node = pclone;

        pnode = pnode->next;
    }

//第二步确定random指针
    pnode = phead;
    pclone_node = pclone_head;
    while (pnode)
    {
        if (pnode->random)
        {
            RandomListNode* pnode1 = phead;
            RandomListNode* pclone_node1 = pclone_head;
            while (pnode1!=pnode->random)
            {
                pnode1 = pnode1->next;
                pclone_node1 = pclone_node1->next;
            }
            pclone_node->random = pclone_node1;
        }
        pnode = pnode->next;
        pclone_node = pclone_node->next;
    }

    return pclone_head;
}

2、这一种方法还是分为两步,第一步任然是复制原始链表上的每个节点,但是在复制的同时我们把配对关系放在一个哈希表中< N,N’ >。第二步,确定random,此时我们有了哈希表,即可以花费O(1)的时间就可以确定random,即总的时间为O(n)。相当于用空间换取了时间,具体的实现如下:

struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
        label(x), next(NULL), random(NULL) {}
};
//第二种方法使用一个哈希表存储对应的关系,这样在找random节点时,只需要O(1)时间,相当于用空间换时间,总体的时间复杂度为O(n)
RandomListNode* CloneNodes(RandomListNode*phead)
{
    if (!phead)
        return NULL;
    //第一步复制每个节点,并且进行连接,同时构造出对应的map
    map<RandomListNode*, RandomListNode*> search_map;

    RandomListNode*pclone_head = new RandomListNode(phead->label);
    pclone_head->next = NULL;
    pclone_head->random = NULL;

    search_map[phead] = pclone_head;

    RandomListNode*pnode = phead->next;
    RandomListNode*pclone_node = pclone_head;

    while (pnode)
    {
        RandomListNode*pclone = new RandomListNode(pnode->label);
        pclone->next = NULL;
        pclone->random = NULL;

        pclone_node->next = pclone;
        pclone_node = pclone;

        search_map[pnode] = pclone;

        pnode = pnode->next;
    }


    //在map中查找对应的random
    pnode = phead;
    pclone_node = pclone_head;
    while (pnode)
    {
        if (pnode->random)
            pclone_node->random = search_map[pnode->random];
        pnode = pnode->next;
        pclone_node = pclone_node->next;
    }

    return pclone_head;
}

3、这一种方法比较巧妙,可以不用辅助空间,但是时间效率任然是O(n),具体分为三步:第一步,复制每个节点,但是此时把复制的节点连接在被复制的节点之后;第二步,确定random节点,由于在第一步,已经把每个复制的节点连接在原节点之后,所以此时复制节点的random就为,原节点的random的下一个,只需要花费O(1)的时间就可以确定random;第三步,把链表按奇偶拆分成两个链表,就可以得到,复制的链表。具体的实现如下:

struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
        label(x), next(NULL), random(NULL) {}
};

/*第三种方法:复制每个节点,并且将其连接在被复制的节点之后,这样复制节点的random就为被复制节点random之后的那个节点,不需要额外的空间即可以达到O(n)*/
RandomListNode* CloneNodes(RandomListNode*phead)
{
    Clone(phead);
    randomClone(phead);
    return reconnectnode(phead);
}

//复制每个节点并且把它连在原节点之后
void Clone(RandomListNode* phead)
{
    RandomListNode*pnode = phead;
    while (pnode)
    {
        RandomListNode*pclone = new RandomListNode(pnode->label);
        pclone->random = NULL;

        pclone->next = pnode->next;
        pnode->next = pclone;
        pnode = pclone->next;
    }
}

//连接复制节点的random,即为被复制节点的random的下一个
void randomClone(RandomListNode* phead)
{
    RandomListNode*pnode = phead;
    while (pnode)
    {
        if (pnode->random)
        {
            pnode->next->random = pnode->random->next;
        }
        pnode = pnode->next->next;
    }
}

//按奇偶分开
RandomListNode* reconnectnode(RandomListNode*phead)
{
    RandomListNode* pclone_head = NULL;
    RandomListNode* pclone_node = NULL;
    RandomListNode* pnode = phead;
    if (pnode)
    {
        pclone_head = pnode->next;
        pclone_node = pclone_head;

    }

    while (pnode)
    {
        pnode->next = pclone_node->next;
        pnode = pnode->next;
        pclone_node->next = pnode->next;
        pclone_node = pclone_node->next;
    }
    return pclone_head;
}

猜你喜欢

转载自blog.csdn.net/xc13212777631/article/details/80833984
今日推荐