劍指Offer——複雜鏈表的複製

題目描述

輸入一個複雜鏈表(每個節點中有節點值,以及兩個指針,一個指向下一個節點,另一個特殊指針指向任意一個節點),返回結果爲複製後複雜鏈表的head。(注意,輸出結果中請不要返回參數中的節點引用,否則判題程序會直接返回空)

概念

複雜鏈表示例:


方法一

可以分爲兩步來完成:

1、複製原始鏈表上的每一個結點,並用next鏈接起來;

2、設置每個結點的random 指針:由於鏈表中節點的random指針指向的節點可能在該節點之前,也可能在該節點之後,需要從頭到尾的遍歷鏈表來進行查找,然後連接起來,所以時間複雜度是O(N^2)。

方法二

方法一的時間花費主要在定位結點的random上,故我們可以對此優化:用空間換時間。方法還是可以分爲兩步:

1、複製原始鏈表上的每一個結點,並用next鏈接起來,同時創建一個map映射表:<N,N'>(原始結點,複製的結點),將兩個鏈表中的節點映射起來,從而便於後續random指針的設置。

2、設置每個結點的random 指針:由於已經使用map結構將兩個鏈表中的節點進行了映射,可以很方便的找到random指針應該指向的節點。用O(n)的空間消耗把時間複雜度由O(N^2)降到了O(n)。

對應的代碼如下:

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if( pHead == NULL )
            return NULL;
        unordered_map<RandomListNode*,RandomListNode*> record;
        RandomListNode* res = new RandomListNode(pHead->label);
        RandomListNode* p1 = pHead->next;
        RandomListNode* p2 = res;
        while( p1 )
        {
            RandomListNode* temp = new RandomListNode(p1->label);
            p2->next = temp;
            record.insert( make_pair(p1,temp) );
            p1 = p1->next;
            p2 = temp;
        }
        p1 = pHead;
        p2 = res;
        while( p1 )
        {
            if( p1->random )
                p2->random = record[p1->random];
            p1 = p1->next;
            p2 = p2->next;
        }
        return res;
    }
};

方法三

方法可以分爲三步,以下圖中的鏈表爲例:


1、複製原始鏈表上的每一個結點N,創建對應的N’,並把N’放在N之後。如下圖:


2、設置每個結點的random 指針。如果原始鏈表上的結點N的random指向S,則對應的複製結點N’(即節點N的next)的random指向S’(節點S的next)。如下圖:

3、將長鏈表拆分成兩個鏈表:把奇數位置的結點用pNext連接起來的就是原始鏈表,把偶數位置的結點通過pNext連接起來的就是複製鏈表。


代碼如下:

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if( pHead == NULL )
            return NULL;
        RandomListNode* p = pHead;
        while( p ) //複製每個節點
        {
            RandomListNode* temp = new RandomListNode(p->label);
            temp->next = p->next;
            p->next = temp;
            p = temp->next;
        }
        p = pHead;
        while( p ) //設置random指針
        {
            if( p->random )
                p->next->random = p->random->next;
            p = p->next->next;
        }
        p = pHead;
        RandomListNode* res = pHead->next;
        while( p ) //拆分
        {
            RandomListNode* n = p->next;
            p->next = n->next;
            if( n->next )
                n->next = n->next->next;
            p = p->next;
        }
        return res;
    }
};
發佈了52 篇原創文章 · 獲贊 54 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章