题目:实现函数 ComplexListNode* Clone( ComplexListNode* pHead ), 复制一个复杂链表,在复杂链表中除了有一个 pNext 指针指向下一个结点外,还有一个 pSibling 指向链表中的任意结点或者NULL, 结点定义如下:
struct ComplexListNode{ int value; ComplexListNode* pNext; ComplexListNode* pSibling; };
对于这个问题,有三种思路:
思路1:第一步先复制原始链表的每一个结点,并用 pNext 链接起来。第二步设置每个结点的 pSibling 指针。假设原始链表中某个结点N的pSibling指向结点S,由于S的位置在链表中的遍历时间复杂度为 O(n),这个对于一个含有n个结点的链表,该方法总的时间复杂度为 O(n^2);
思路2:在上面的算法中,由于时间复杂度主要花费在定位结点 pSibling 上,因此可以试着在这方面去做优化。我们还是分为两步,第一步复制原始链表上的每个结点N创建N‘, 然后把这些创建出来的结点用 pNext 连接起来,同时把 <N, N'> 的配对信息存在一个哈希表中。 第二步还是设置复制链表上每个结点的 pSibling。如果在原始链表中结点N的pSibling指向某个结点S, 那么在复制链表中对应的N’应该指向S。而有了哈希表,我们就可以在O(1)时间根据S找到S’了。此方法是利用了空间换取时间。通过一个大小为O(n)的哈希表,使得该算法的时间复杂度从O(n^2)变到 O(n);
★思路3:在不利用辅助空间的情况下,我们依旧复制原始链表的每个结点N来创建对应的N‘, 只是这次把N’ 链接在结点N的后面。完成这步的代码如下:
void CloneNodes( ComplexListNode * pHead ){ ComplexListNode *pNode = pHead; while( pNode != NULL){ ComplexListNode *pClone = new ConplexListNode(); pClone->value = pNode->value; pClone->pNext = pNode->pNext; pNode->pNext = pClone; pNode = pClone->pNext; } }
复制完结点后,接下来需要设置每个新结点的 pSibling。假设原始链表中结点N指向的pSibling为S, 那么对应的结点N‘ 指向的pSibling也为S’。故完成这步的代码如下所示:
void ConnectSiblingNodes( ComplexListNode *pHead ){ ComplexListNode *pNode = pHead; while( pNode != NULL ){ ComplextListNode *pClone = pNode->pNext; if( pNode->pSibling != NULL ){ pClone->pSibling = pNode->pSibling->mNext; } pNode = pClone->pNext; } }
完成上面两步后,现在的链表是有原始链表和复制链表组合而成的,因此现在可以通过奇偶位来得到复制的链表,实现代码如下:
ComplexListNode* ReconnectListNode( ComplexListNode* pHead ){ ComplexListNode *pNode = pHead; ComplexListNode *pCloneHead = NULL; ComplexListNode *pCloneNode = NULL; if( pNode != NULL ){ pCloneHead = pCloneNode = pNode->pNext; pNode = pCloneNode->pNext; while( pNode != NULL ){ pCloneNode->pNext = pNode->pNext; pCloneNode = pCloneNode->pNext; pNode = pCloneNode->pNext; } } return pCloneHead; }