C语言单链表面试题2
2017-06-14 22:20
281 查看
题目
判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度。判断两个链表是否相交,若相交,求交点。(假设链表不带环)
判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】
求带环链表环长
(无环返回 -1)思路:
快慢指针法,快指针一次走两步,慢指针一次走一步,如果链表带环,则从慢指针到达入口点开始,由于快慢指针都在环上移动,每次移动快指针都追慢指针一步,慢指针走一圈之内,快指针一定追上慢指针。
相遇之后,一次追一步,再次相遇刚好追一圈——环的长度。
int SizeOfRing(ListNode* pList)
{
ListNode* fast = pList; ListNode* slow = pList;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
break;
}
if (fast != slow || fast->next == NULL)
return -1;
else {
int count =
0;
do{
fast = fast->next->next;
slow = slow->next; count++;
}
while (fast != slow);
return count; }
}
求环入口点
(无环返回 NULL)思路:
同求环长,快慢指针相遇停止。
此时,将路程分为三段,一是 T——尾长(非环长度),二是 S——慢指针入环到被追上,三是 C——快指针追慢指针多跑的圈。那么,慢指针走的路程为 T+S,快指针走的路程为 T+S+C,可得 2(T+S)=T+S+C,T=C-S,此时,一个指针从起点出发走 T步,一个指针从快慢指针相遇点出发走 C-S 步,此时两指针刚好都在入口点。
两指针一个从头结点出发,一个从快慢指针相遇点出发,一步一步走,相遇的节点即为入口点(走的步数即为尾长 T(C-S))。
ListNode* IntranceOfRing(ListNode* pList)
{
ListNode* fast = pList;
ListNode* slow = pList;
while
(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if
(fast == slow)
break;
}
if
(fast != slow || fast->next
== NULL)
return
NULL;
while
(pList != slow)
{
pList = pList->next;
slow = slow->next;
}
return
pList;
}
相交链表求交点(无环)intersect1()
(无交点返回 NULL)ListNode* intersect1(ListNode* pList1, ListNode* pList2)
{
int count1 =
0,
count2 = 0;
ListNode* p1 = pList1, *p2 = pList2;
while
(p1->next)
{
count1++;
p1 = p1->next;
}
while
(p2->next)
{
count2++;
p2 = p2->next;
}
if
(p1 != p2)return
NULL;
if
(count1 >= count2)
{
count1 -= count2;
while
(count1--)
pList1 = pList1->next;
while
(pList1 != pList2)
{
pList1 = pList1->next;
pList2 = pList2->next;
}
return
pList1;
}
else
{
count2 -= count1;
while
(count2--)
pList2 = pList2->next;
while
(pList1 != pList2)
{
pList1 = pList1->next;
pList2 = pList2->next;
}
return
pList1;
}
}
相交链表求交点(可能带环)intersect2
(无交点返回 NULL, 环上相交返回第一个链表的环入口点)思路:
先列举情况
求交点之前,需要先判断是否带环,用环入口点函数判断,并保存入口点。
两个入口点都为空,是 1、2 两种情况,直接使用无环链表求交点函数。
如果只有一个为空,一定是第三种情况,不相交,返回 NULL。
剩下便是两入口点都不为空,且入口点相同,则是 3、4 两种情况,不必做区分,统计从两头结点到入口点的长度,然后(同无环链表求交点3、4) 比较两链表到入口点长度,快指针从长链表头结点开始,走比短链表长的节点数。慢指针从另一链表头结点开始,与快指针一起一步一步走,指针相同时停止。返回任意一个指针。
区分最后两种情况通过一个指针从其中一个入口点出发,走一圈之内,如果与另一入口点相遇,是第 7 种情况,返回第一个链表的入口点(也可以是第二个),否则是第 6 种情况,返回 NULL。
ListNode* intersect2(ListNode* pList1, ListNode* pList2){
ListNode* intr1 = IntranceOfRing(pList1);
ListNode* intr2 = IntranceOfRing(pList2);
if (intr1 == NULL && intr2 == NULL) return intersect1(pList1, pList2); else if (intr1 == NULL || intr2 == NULL) return NULL; else if (intr1 == intr2) { int count1 = 0, count2 = 0; ListNode* p1 = pList1, *p2 = pList2; while (p1->next != intr1) { count1++; p1 = p1->next; } while (p2->next != intr1) { count2++; p2 = p2->next; } if (count1 >= count2) { count1 -= count2; while (count1--) pList1 = pList1->next; while (pList1 != pList2) { pList1 = pList1->next; pList2 = pList2->next; } return pList1; } else { count2 -= count1; while (count2--) pList2 = pList2->next; while (pList1 != pList2) { pList1 = pList1->next; pList2 = pList2->next; } return pList1; } } else { ListNode* pList = intr2->next; while (pList != intr2 && pList != intr1) { pList = pList->next; } return pList == intr1 ? intr1 : NULL; } }
相关文章推荐
- C语言—链表面试题之带环问题的总结
- 【数据结构】C语言单链表面试题
- C语言 — 链表面试题复杂链表问题
- 单链表的实现和相关面试题及其详解(C语言)
- 【c语言】链表的实现、链表部分面试题的解答
- 【C语言】单链表的相关热点面试题(包括:从尾到头打印,逆置,冒泡,寻找中间节点,倒数k节点)
- C语言链表面试题(增强版)
- C语言单链表面试题1
- 【C语言】单链表相关面试题(一)
- c语言实现链表面试题
- C语言实现单链表,单链表面试题面试
- C语言实现单链表-面试题(基础篇)
- C语言实现无头单链表及链表相关面试题(重点!)
- C语言常见单链表面试题(2)
- c语言链表面试题
- C语言中的单链表面试题----基础
- 经典面试题---单链表的基本操作(C语言实现)
- C语言单链表面试题(进阶)
- C语言常见单链表面试题(1)
- C语言的单链表面试题----进阶