链表相关笔试题(二)
来源:互联网 发布:金融行业的网络销售 编辑:程序博客网 时间:2024/04/25 15:55
1.复杂链表的复制
题目:请实现函数,复制一个复杂链表。在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个pSibling指向链表中的任意结点或者NULL。
方法一:先复制原始链表上的每一个结点,并用next链接起来,然后设置每个节点的pSibling指针。假设原始链表中的某个结点N的pSibling指向结点S,由于S的位置在链表中可能在N的前面也可能在N的后面,所以要定位S的位置需要从原始链表的头结点开始找。因此这种方法的时间复杂度为O(n^2).
方法二:第一步先复制原始链表的每个结点N创建N',然后将创建出的结点用next链接起来,同时借助哈希表存储<N,N'>的配对信息,第二步还是设置复制链表上的每个结点的pSibling。如果在原始链表中结点N的pSibling指向结点S,那么在复制链表中,对应的N'指向S'。这种方法的时间复杂度为O(n)。
方法三:第一步,根据原始链表的每个结点N创建N',并把N'链在N的后面,第二步,设置复制出来的结点的pSibling。假设原始链表上的N的pSibling指向S,那么对应的N'是N的next结点,S'是S的next指向的结点,第三步,将这个长链表拆分成两个链表,奇数位置上的结点用next链接起来就是原始链表,偶数位置的结点用next链接起来就是复制出来的链表。
实现代码:
void CloneNodes(ListNode* pHead){ListNode* cur = pHead;while (cur != NULL){ListNode* pCloned = new ListNode();pCloned->data = cur->data;pCloned->next = cur->next;pCloned->pSibling = NULL;cur->next = pCloned;cur = pCloned->next;}}void ConnectSiblingNodes(ListNode* pHead){ListNode* cur = pHead;while (cur != NULL){ListNode* pCloned = cur->next;if (cur->pSibling != NULL){pCloned->pSibling = cur->pSibling->next;}cur = pCloned->next;}}ListNode* ReconnectNodes(ListNode* pHead){ListNode* cur = pHead;ListNode* CloneHead = NULL;ListNode* CloneNode = NULL;if (cur != NULL){CloneHead = CloneNode = cur->next;cur->next = CloneNode->next;cur = cur->next;}while (cur != NULL){CloneNode->next = cur->next;CloneNode = CloneNode->next;cur->next = CloneNode->next;cur = cur->next;}return CloneHead;}ListNode* Clone(ListNode* pHead){CloneNodes(pHead);ConnectSiblingNodes(pHead);return ReconnectNodes(pHead);}
2.两个链表的第一个公共结点
方法一:在第一个链表上顺序遍历每个结点,每遍历到一个结点时,在第二个链表上顺序遍历每个结点,判断是否相同。
方法二:首先遍历两个链表得到它们的长度,就知道那个链表长以及长的链表比短的链表多几个结点。在第二次遍历时,在长链表上先走n步,接着同时遍历两个链表,找到的第一个相同的结点就是它们的第一个公共结点。
实现代码:
size_t GetListLength(ListNode* pHead){ size_t len = 0; ListNode* cur = pHead; while (cur != NULL) { ++len; cur = cur->next; } return len;}ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2){ if(pHead1 == NULL || pHead2 == NULL){ return NULL; } size_t len1 = GetListLength(pHead1); size_t len2 = GetListLength(pHead2); int diflen = len1 - len2; ListNode* longlist = pHead1; ListNode* shortlist = pHead2; if (len2 > len1) { longlist = pHead2; shortlist = pHead1; diflen = len2 - len1; } for (int i = 0; i < diflen; ++i) { longlist = longlist->next; } while (longlist != NULL && shortlist != NULL) { if(longlist == shortlist) { return longlist; } longlist = longlist->next; shortlist = shortlist->next; } return NULL;}
3.删除排序链表中重复的节点
分析:从头遍历结点,如果当前结点的值与下一个节点的值相同,则删除它们,要确保删除后的链表仍然是相连的,要把当前结点的前一个结点和后面值比当前值大的结点相连。
实现代码:
void deleteDuplication(ListNode*& pHead){if (pHead == NULL){return;}ListNode *PreNode = NULL;ListNode *cur = pHead;while (cur != NULL){ListNode *pNext = cur->next;if (pNext != NULL && pNext->data == cur->data){int val = cur->data;ListNode* Del = cur;while (Del != NULL && Del->data == val){pNext = Del->next;delete Del;Del = NULL;Del = pNext;}if (PreNode == NULL){pHead = pNext;}else{PreNode->next = pNext;}cur = pNext;}else{PreNode = cur;cur = cur->next;}}}
4.求链表中环的入口结点
方法一:定义两个指针都指向链表的头结点,如果链表中的环有n个结点,先让一个指针在链表上向前移动n步,然后两个指针同时向前移动,当第二个指针指向环的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。
实现代码:
ListNode* HasCycle(ListNode *pHead){ListNode *fast = pHead;ListNode *slow = pHead;while (fast && fast->next){fast = fast->next->next;slow = slow->next;if (slow == fast){return slow;}}return NULL;}int GetLength(ListNode *MeetNode){ListNode *cur = MeetNode;int count = 1;while (cur->next != MeetNode){cur = cur->next;count++;} return count;}ListNode* EntryNodeOfLoop(ListNode* pHead){ListNode *ret = HasCycle(pHead); if(ret == NULL){ return NULL; }int len = GetLength(ret); ListNode *fast = pHead; ListNode *slow = pHead; while(len--) { fast = fast->next; } while (fast != NULL && slow != NULL){ if(fast == slow){ return fast; }fast = fast->next;slow = slow->next;}return NULL;}
方法二:如果可以改变链表结构,定义两个指针,一个指向pHead的下一个结点,另一个紧跟着这个指针,两个指针同时向前移动,每移动一次,让后面的指针指向NULL,也就是说,断开访问过的结点,最后到达的结点一定是尾结点的下一个结点,也就是环的入口结点,因为这是第二次访问该结点,它的next指向NULL,因此这时循环结束。
实现代码:
ListNode* EntryNodeOfLoop(ListNode* pHead) { if (!pHead->next) return NULL; ListNode* previous = pHead; ListNode* front = pHead ->next; while (front) { previous->next = NULL; previous = front; front = front->next; } return previous; }
方法三:第一步,找环中相汇点。分别用两个指向链表头部,一个每次走一步,另一个每次走二步,直到找到在环中的相汇点;第二步,找环的入口。接上步,用一个指针指向链表头部,另一个指向上一步求出的相汇点,当两个指针相遇时,即为环的入口点。
ListNode* HasCycle(ListNode *pHead){ListNode *fast = pHead;ListNode *slow = pHead;while (fast && fast->next){fast = fast->next->next;slow = slow->next;if (slow == fast){return slow;}}return NULL;}ListNode* GetEnterNode(ListNode *pHead, ListNode *MeetNode){ListNode *cur = pHead;ListNode *tmp = MeetNode;while (cur && tmp){if (cur == tmp){return cur;}cur = cur->next;tmp = tmp->next;}return NULL;}ListNode* EntryNodeOfLoop(ListNode* pHead){ListNode *ret = HasCycle(pHead);return GetEnterNode(pHead, ret);}
- 链表相关笔试题(二)
- 面试笔试系列之二 链表相关
- 二叉树相关笔试题(二)
- 一道链表相关的笔试题
- 链表相关笔试题(一)
- 链表笔试题汇编(二)
- 【笔试面试】链表相关操作
- 笔试算法学习--链表相关
- 笔试题相关
- 哈希表 相关笔试题
- 堆 相关笔试题
- .net笔试题(二)
- 中兴笔试题 (二)
- Java笔试题(二)
- Java 笔试题 二
- 腾讯笔试题(二)
- 笔试题二
- 笔试题二【解答】
- 第十周项目五 教师兼干部类
- 获得数据的post,get
- c# 字典
- 表单元素编码formenctype属性
- TextView实现自动滚动显示
- 链表相关笔试题(二)
- linux基础之shell编程(1)
- [设计模式]简单工厂模式
- hihoCoder 挑战赛20 打折机票(线段树/RMQ)
- 最小生成树总结
- 网页适配传输方法和相关装置及通信系统
- 20160507note
- Android 关于缓存的一些类
- WebClient 没有销毁 导致 Unity 卡死