面试题26:复杂链表的赋值
2015-07-08 21:04
609 查看
题目:请实现ComplexListNode*clone(ComplexListNode*pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个m_pNext指针指向下一个结点外,还有一个m_pSibling指向链表中任意一个节点。结点定义如下:
下图为一个含有5个结点的复杂链表:
解法一:时间复杂度为O(N2)的算法
将整个复制过程分为两步:第一步复制原始链表上的每一个节点,并用m_pNext链接起来。第二步是设置m_pSibling指针。假设原始链表中的某个结点N的m_pSibling指向结点S,由于S的位置可能在N的前面也可能在N的后面,所以需要从原始链表的头结点开始查找。如果从原始链表的头结点开始沿着m_pNext经过s步到达S结点,那么在赋值链表中结点N'的m_pSibling离赋值链表的头结点的距离也是沿着m_pSibling指针S步。
解法二:空间换时间的解法
解法一的时间主要花费在定位结点的m_pSibling上,可以从这方面做优化。还是分为两步求解:
第一步仍然是复制原始链表上的每一个节点,并用m_pNext链接起来。同时,我们把<N,N'>的配对信息放到一个哈希表中。第二步还是设置m_pSibling指针。如果在原始链表中结点N的m_pSibling指针指向结点S,那么对应的N’应该指向S'。由于有了hash表,我们可以在O(1)的时间内根据S找到S'。
解法三:无需辅助空间,时间复杂度为O(N)的解法。
第一步仍然根据原始链表中的每个结点N创建对应的节点N'。这一次,我们把N'链接在N的后面。
第二步设置复制出来的结点的m_pSibling指针。假设原始链表上N的m_pSibling指针指向S,那么其对应复制出来的N'是N的下一个结点,同样S'也是S的下一个结点。
第三步把这个长链表拆分成两个链表:将奇数位置的结点链接起来就是原始链表,将偶数位置的结点链接起来就是复制的链表。
最后将三步合起来:
struct ComplexListNode { int m_val; ComplexListNode* m_pNext; ComplexListNode* m_pSibling; };
下图为一个含有5个结点的复杂链表:
解法一:时间复杂度为O(N2)的算法
将整个复制过程分为两步:第一步复制原始链表上的每一个节点,并用m_pNext链接起来。第二步是设置m_pSibling指针。假设原始链表中的某个结点N的m_pSibling指向结点S,由于S的位置可能在N的前面也可能在N的后面,所以需要从原始链表的头结点开始查找。如果从原始链表的头结点开始沿着m_pNext经过s步到达S结点,那么在赋值链表中结点N'的m_pSibling离赋值链表的头结点的距离也是沿着m_pSibling指针S步。
解法二:空间换时间的解法
解法一的时间主要花费在定位结点的m_pSibling上,可以从这方面做优化。还是分为两步求解:
第一步仍然是复制原始链表上的每一个节点,并用m_pNext链接起来。同时,我们把<N,N'>的配对信息放到一个哈希表中。第二步还是设置m_pSibling指针。如果在原始链表中结点N的m_pSibling指针指向结点S,那么对应的N’应该指向S'。由于有了hash表,我们可以在O(1)的时间内根据S找到S'。
解法三:无需辅助空间,时间复杂度为O(N)的解法。
第一步仍然根据原始链表中的每个结点N创建对应的节点N'。这一次,我们把N'链接在N的后面。
void cloneNodes(CommplexNode* pHead) { ComplexListNode* pNode = pHead; while (pNode != NULL) { ComplexListNode* pCloned = new ComplexListNode(); pCloned->m_val = pNode->m_val; pCloned->m_pNext = pNode->next; pCloned->m_pSibling = NULL; pNode->next = pCloned; pNode = pCloned->m_pNext; } }
第二步设置复制出来的结点的m_pSibling指针。假设原始链表上N的m_pSibling指针指向S,那么其对应复制出来的N'是N的下一个结点,同样S'也是S的下一个结点。
void connectSibingNodes(ComplexListNode* pHead) { ComplexListNode* pNode = pHead; while (pNode != NULL) { ComplexListNode* pCloned = pNode->m_pNext; if (pNode->m_pSibling != NULL) pCloned->m_pSibing = pNode->m_pSibling->m_pNext; pNode = pCloned->m_pNext; } }
第三步把这个长链表拆分成两个链表:将奇数位置的结点链接起来就是原始链表,将偶数位置的结点链接起来就是复制的链表。
ComplexListNode* reconnectNodes(ComplexListNode* pHead) { ComplexListNode* pNode = pHead; ComplexListNode* pCloneHead = NULL; ComplexListNode* pCloneNode = NULL; if (pNode!=NULL) { pCloneHead = pCloneNode = pNode->m_pNext; pNode->m_pNext = pCloneNode->m_pNext; pNode = pNode->m_pNext; } while (pNode != NULL) { pCloneNode->m_pNext = pNode->m_pNext; pCloneNode = 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); }
相关文章推荐
- 爱奇艺算法工程师面试题(2015年)
- 《程序员的自我修养》读书笔记6
- 黑马程序员---反射
- 黑马程序员--小结
- block面试题
- 史上最全的程序员求职渠道总结
- 细说高级程序员的几个成长阶段
- 对程序员非常重要的24个软技能
- 【面试题】-反转句子
- (剑指Offer)面试题11:数值的整数次方
- 黑马程序员——JAVA String类
- 黑马程序员——JAVA异常
- 黑马程序员——JAVA类和对象
- 黑马程序员—Java反射
- Java7K面试题—银行业务调度系统
- 黑马程序员—交通灯管理系统
- (剑指Offer)面试题10:二进制中1的个数
- 记一次糟糕的面试
- 黑马程序员---正则表达式
- 程序猿职业规划,未来该何去何从