題目:請實現函數ComplexListNode複製一個複雜鏈表。在複雜鏈表中,每個結點除了有一個m_pNext指針指向下一個結點外,還有一個m_pSibling指向鏈表中的任意結點或者NULL;
下圖是一個含有5個結點的該類型複雜鏈表。圖中實線箭頭表示m_pNext指針,虛線箭頭表示m_pSibling指針。爲簡單起見,指向NULL的指針沒有畫出。
看到這個問題,我的第一反應是分成兩步:第一步是複製原始鏈表上的每個鏈表,並用m_pNext鏈接起來。第二步,假設原始鏈表中的某節點N的m_pSibling指向結點S。由於S的位置在鏈表上有可能在N的前面也可能在N的後面,所以要定位N的位置我們需要從原始鏈表的頭結點開始找。假設從原始鏈表的頭結點開始經過s步找到結點S。那麼在複製鏈表上結點N的m_pSibling的S’,離複製鏈表的頭結點的距離也是s。用這種辦法我們就能爲複製鏈表上的每個結點設置m_pSibling了。
對一個含有n個結點的鏈表,由於定位每個結點的m_pSibling,都需要從鏈表頭結點開始經過O(n)步才能找到,因此這種方法的總時間複雜度是O(n2)。
由於上述方法的時間主要花費在定位結點的m_pSibling上面,我們試着在這方面去做優化。我們還是分爲兩步:第一步仍然是複製原始鏈表上的每個結點N,並創建N’,然後把這些創建出來的結點鏈接起來。這裏我們對<N,N’>的配對信息放到一個哈希表中。第二步還是設置複製鏈表上每個結點的m_pSibling。如果在原始鏈表中結點N的m_pSibling指向結點S,那麼在複製鏈表中,對應的N’應該指向S’。由於有了哈希表,我們可以用O(1)的時間根據S找到S’。
第二種方法相當於用空間換時間,以O(n)的空間消耗實現了O(n)的時間效率。
接下來我們再換一種思路,在不用輔助空間的情況下實現O(n)的時間效率。第三種方法的第一步仍然是根據原始鏈表的每個結點N創建對應N’。這一次,我們把N’鏈接到N的後面。
第二步設置複製出來的結點的m_pSibling。假設原始鏈表上的N的m_pSibling指向結點S,那麼其對應複製出來的N'是m_pnext指向的結點,同樣S’也是S的m_pNext指向的結點。
第三步把這個長鏈表拆分成兩個鏈表:把奇數位置的結點用m_pnext鏈接起來就是初始鏈表,把偶數位置的結點用m_pnext鏈接起來就是複製出來的鏈表。
public class Solution {
public ComplexListNode Clone(ComplexListNode pHead)
{
if(pHead == null){
return null;
}
//複製接結點
CloneNodes(pHead);
//連接隨機指針
ConnectSiblingNodes(pHead);
//拆分鏈表
return ReconnectNodes(pHead);
}
public static void CloneNodes(ComplexListNode pHead){
ComplexListNode pNode = pHead;
while(pNode != null){
ComplexListNode pCloned = new ComplexListNode(pNode.label);
pCloned.m_pnext = pNode.m_pnext;
pCloned.m_pSibling = null;
pNode.m_pnext = pCloned;
pNode = pCloned.m_pnext;
}
}
public static void ConnectSiblingNodes(ComplexListNode pHead){
RandomListNode pNode = pHead;
while(pNode != null){
ComplexListNode pCloned = pNode.m_pnext;
if(pNode.m_pSibling != null){
pCloned.m_pSibling = pNode.m_Sibling.m_pnext;
}
pNode = pCloned.m_pnext;
}
}
public static 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_next = pNode.m_next;
pClonedNode = pClonedNode.m_pnext;
pNode.m_pnext = pClonedNode.m_pnext;
pNode = pNode.m_pnext;
}
return pClonedHead;
}
}