劍指offer_面試題26_複雜連結串列的複製
阿新 • • 發佈:2019-02-14
題目:請實現函式ComplexListNode * Clone(ComplexListNode * pHead),複製一個複雜連結串列。在複雜連結串列中,每個結點除了有一個 m_pNext 指標指向下一個結點外,還有一個 m_pSibling 指向連結串列中的任意結點或者NULL。
複雜連結串列結構定義如下:
typedef struct Node{
int m_nValue;
struct Node *m_pNext;
struct Node *m_pSibling;
}ComplexListNode;
方法一:
過程分析:
1、第一步複製原始連結串列上的每一個結點,並用 m_pNext 連結起來;
2、第二步設定每個結點的 m_pSibling 指標。
規律總結:
1、由於 m_pSibling 指標可能指向任意位置,因此需要有一個臨時指標遍歷,當遍歷到的結點的資料 等於 m_pSibling 指標 指向的結點的資料,說明臨時指標指向的位置就是 新連結串列 m_pSibling 指標 的值。不過前提是 連結串列中沒有重複結點。
2、如有重複結點,則需要 記錄 臨時指標 走了多少步 才到原 m_pSibling 指向的結點。然後複製連結串列也走這麼多步。
時間複雜度:O(n^2)
演算法如下:
/* 複製新的連結串列,使用了遞迴 */ ComplexListNode* CloneNode_own(ComplexListNode *pHead) { if(NULL == pHead) return pHead; ComplexListNode *pCloned = new ComplexListNode; pCloned->m_nValue = pHead->m_nValue; pCloned->m_pSibling = NULL; pCloned->m_pNext = CloneNode_own(pHead->m_pNext); return pCloned; } /* 指定 m_pSibling,使用的是總結的規律1 */ ComplexListNode* ConnectSiblingNodes_own(ComplexListNode *pHead,ComplexListNode *pClonedHead) { if(NULL == pHead || NULL == pClonedHead) return pClonedHead; ComplexListNode *pNode = pHead; ComplexListNode *pClonedNode = pClonedHead; while(pClonedNode != NULL) { if(pNode->m_pSibling != NULL) { ComplexListNode *temp = pClonedHead; /**ComplexListNode *temp = pClonedNode; 不要這樣寫,因為m_pSibling可能指向前面*/ while(temp->m_nValue != pNode->m_pSibling->m_nValue) { temp = temp->m_pNext; } pClonedNode->m_pSibling = temp; } pClonedNode = pClonedNode->m_pNext; pNode = pNode->m_pNext; /**這一步不要忘*/ } return pClonedHead; }
方法二:
第一步:根據原始連結串列的每個結點 N 建立對應的 N' ,並且將 N' 接在 N 的後面。
第二步:設定複製出來的結點的 m_pSibling 。假設原始連結串列上的 N 的 m_pSibling 指向結點 S,那麼其對應賦值出來的 N' 是 N 的 m_pNext 指向的結點,同樣 S' 也是 S 的 m_pNext 指向的結點。
第三步:將兩個連結串列拆分成兩個連結串列。
時間複雜度:O(n)
演算法如下:
/**第一步:複製原始連結串列的結點N並建立新結點N‘,再把N‘連結到N的後面*/ void CloneNodes(ComplexListNode* pHead) { ComplexListNode* pNode = pHead; while(pNode != NULL) { ComplexListNode* pCloned = new ComplexListNode(); pCloned->m_nValue = pNode->m_nValue; pCloned->m_pNext = pNode->m_pNext; pCloned->m_pSibling = NULL; pNode->m_pNext = pCloned; pNode = pCloned->m_pNext; } } /**第二步:設定賦值出來的結點的 m_pSibling */ void ConnectSiblingNodes(ComplexListNode* pHead) { ComplexListNode* pNode = pHead; while(pNode != NULL) { ComplexListNode* pCloned = pNode->m_pNext; if(pNode->m_pSibling != NULL) { pCloned->m_pSibling = pNode->m_pSibling->m_pNext; } pNode = pCloned->m_pNext; } } /**第三步:將長連結串列分割成兩個連結串列*/ ComplexListNode* ReconnectNodes(ComplexListNode* pHead) { ComplexListNode* pNode = pHead; ComplexListNode* pClonedHead = NULL; ComplexListNode* pClonedNode = NULL; if(pNode != NULL) { pClonedHead = pClonedNode = pNode->m_pNext; pNode->m_pNext = pClonedNode->m_pNext; pNode = pNode->m_pNext; } while(pNode != NULL) { pClonedNode->m_pNext = pNode->m_pNext; pClonedNode = pClonedNode->m_pNext; pNode->m_pNext = pClonedNode->m_pNext; pNode = pNode->m_pNext; } return pClonedHead; } ComplexListNode* Clone(ComplexListNode* pHead) { CloneNodes(pHead); ConnectSiblingNodes(pHead); return ReconnectNodes(pHead); }
總結:
這道題比較難理解,需要一步步分析,就比如方法二的第三步,需要有想象,一個拆線,連線的過程
/* 點滴積累,我的一小步 */