算法题-复杂链表的复制

[编程题]复杂链表的复制

时间限制:1秒 空间限制:32768K

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

解法一:递归法

递归思想:把大问题转化若干子问题

此题转化为一个头结点和除去头结点剩余部分,剩余部分操作和原问题一致

Python解法

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
        # 返回 RandomListNode
    def Clone(self, headNode):
         # write code here
        if headNode is None: return
        theNewNode = RandomListNode(headNode.label)
        theNewNode.random = headNode.random
        theNewNode.next = self.Clone(headNode.next)
        return theNewNode

C++解法

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(pHead == NULL)
            return NULL;
                     unordered_map M;
        for(RandomListNode *p=pHead;p!=NULL;p=p->next)
            M[p] = new RandomListNode(p->label);

        for(RandomListNode *p=pHead;p!=NULL;p=p->next)
        {
            M[p]->next = M[p->next];
            M[p]->random = M[p->random];
        }
        return M[pHead];
    }
};

解法二:哈希表法,借助map空间换时间

利用空间节省时间,时间复杂度O(n)。
map关联

1.首先遍历一遍原链表,创建新链表(赋值label和next),用map关联对应结点(存储原节点指向对应新节点的指针);再遍历一遍,更新新链表的random指针。(注意map中应有NULL —-> NULL的映射)
2.不能改变原有链表
C++解法

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(pHead==NULL) return NULL;

        map m;
        RandomListNode* pHead1 = pHead;
        RandomListNode* pHead2 = new RandomListNode(pHead1->label);
        RandomListNode* newHead = pHead2;
        m[pHead1] = pHead2;
        while(pHead1){
            if(pHead1->next) pHead2->next = new RandomListNode(pHead1->next->label);
            else pHead2->next = NULL;
            pHead1 = pHead1->next;
            pHead2 = pHead2->next;
            m[pHead1] = pHead2;
        }

        pHead1 = pHead;
        pHead2 = newHead;
        while(pHead1){
            pHead2->random = m[pHead1->random];
            pHead1 = pHead1->next;
            pHead2 = pHead2->next;
        }
        return newHead;
    }
};
  1. 看到网上有人用multimap,思路基本相同遍历两边链表,第一遍用multimap映射对应关系到hashtable(存储原节点指向对应新节点的指针)不设置random指针,第二遍更新新链表的random指针.两个都能运行通过
    “`cpp
    class Solution {
    public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
    if(pHead==NULL)return NULL;
    //创建新链表的头结点
    RandomListNode *pCloneHead=new RandomListNode(pHead->label);
    pCloneHead->next=NULL;
    pCloneHead->random=NULL;
    //设置一个哈希map存储映射关系
    //由于不同结点的random可能指向同一个结点,所以用multimap而不是map
    unordered_multimap

2.也有人使用STL中的map来映射原来的地址和复制后的地址, 递归代码很精简 
```cpp
class Solution { 
public:
map< RandomListNode *, RandomListNode *> point_map;
    RandomListNode* Clone(RandomListNode* pHead){ 
        if(pHead == NULL) return NULL;
        RandomListNode* now = new RandomListNode(pHead->label);
        point_map[pHead] = now;//映射原来地址 到新地址
        now->next = Clone(pHead->next);
        now->random = point_map[pHead->random];
        return now;
    }
};




<div class="se-preview-section-delimiter">div>

Python解法

class Solution:
    def Clone(self, head):
        nodeList = []     #存放各个节点
        randomList = []   #存放各个节点指向的random节点。没有则为None
        labelList = []    #存放各个节点的值

        while head:
            randomList.append(head.random)
            nodeList.append(head)
            labelList.append(head.label)
            head = head.next
        #random节点的索引,如果没有则为1   
        labelIndexList = map(lambda c: nodeList.index(c) if c else -1, randomList)

        dummy = RandomListNode(0)
        pre = dummy
        #节点列表,只要把这些节点的random设置好,顺序串起来就ok了。
        nodeList=map(lambda c:RandomListNode(c),labelList)
        #把每个节点的random绑定好,根据对应的index来绑定
        for i in range(len(nodeList)):
            if labelIndexList[i]!=-1:
                nodeList[i].random=nodeList[labelIndexList[i]]
        for i in nodeList:
            pre.next=i
            pre=pre.next
        return dummy.next





class="se-preview-section-delimiter">div>

解法三:直接使用Python Copy包中的深度拷贝

import copy
class Solution:
    def Clone(self, pHead):
        chead=copy.deepcopy(pHead)
        return chead

直接赋值:其实就是对象的引用(别名)。

浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。

深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
参考:
文档-copy — Shallow and deep copy operations

Python 直接赋值、浅拷贝和深度拷贝解析

关于deepcopy这个博客也解释的很详细

Python-copy()与deepcopy()区别

你可能感兴趣的:(算法题-复杂链表的复制)