一、题目链接:. - 力扣(LeetCode)
二、思路
1.定义两个指针(快指针和慢指针)快指针一次走两步,慢指针一次走一步
2.找到快慢指针在环中相遇的结点,赋值为meet
3.让meet 和head 同时出发,直到二者相遇。
4.二者相遇的结点就是要找到的 链表入环的第一个结点
三、用数学方法分析思路的正确性
设环的结点数量为C,fast和slow指针相遇时的结点距离开始入环的结点距离为N,入环前的结点数为L
相遇时slow走过的总路程为 L+N
fast 走过的总路程为 L+ n*C+N (n为一个常数)
所以 :2 *(L+N)==L+n*C+N
化简得: L+N==n*C
L==n*C-N --> L==(n-1)*C + (C-N)
说明 不关 meet 指针绕了环多少圈,meet 指针总是 能和 head 指针在 开始入环的结点处相遇
四、代码
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode*fast=head;
struct ListNode*slow=head;
struct ListNode*meet=NULL;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)//找到相遇的结点
{
meet=slow;
while(meet!=head)//找到入环处的结点
{
meet=meet->next;
head=head->next;
}
return meet;
}
}
return NULL;
}
五、法二(相交链表法)
用两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
1.先找到fast 和 slow 在 环中的相交结点
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode*fast=head;
struct ListNode*slow=head;
struct ListNode*meet,*newhead=NULL;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)//找到相遇的结点
{
meet=slow;
newhead=meet->next;//将相遇的下一个结点作为一个链表的头结点
meet->next=NULL;//将相遇结点的next置为NULL
struct ListNode*nhead=getIntersectionNode(newhead,head);
return nhead;
}
}
return NULL;
}
步骤:
1.找到相遇的结点
2.将相遇的下一个结点 newhead 作为一个链表的头结点
3.将相遇结点的next置为NULL
将相交结点的下个结点newhead作为一条链表的头结点 ,而另一条链表的头结点就是head
这时问题就成了求两个单链表相交的起始节点的问题
2.求两个单链表相交的起始节点函数
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* cur1 = headA;
struct ListNode* cur2 = headB;
int countA = 0;
int countB = 0;
while (cur1->next)//计算A链一共有几个结点
{
countA++;
cur1 = cur1->next;
}
while (cur2->next)//计算B链一共有几个结点
{
countB++;
cur2 = cur2->next;
}
if (cur1 != cur2) //如果两条链的末尾的结点不相同,说明两条链并没有相交
return NULL;
int val = abs(countA - countB);//计算两条链的结点之差的绝对值
struct ListNode* longlist = headA;
struct ListNode* shortlist = headB;
if (countA - countB < 0) //如果B链更长,将B链赋给长链,A链赋给短链
{
longlist = headB;
shortlist = headA;
}
cur1 = longlist;
cur2 = shortlist;
while (val--) //让长链先走二者的差数步,这样可以保证两条链同时到达相交的结点
{
cur1 = cur1->next;
}
while (cur1->next && cur2->next)
{
if (cur1 == cur2)//如果相等,就跳出循环
break;
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1; //返回两条链的相交的结点
}
1.计算A链一共有几个结点,计算B链一共有几个结点
2.判断两条链的尾结点。如果两条链的末尾的结点不相同,说明两条链并没有相交,反之,相交了
3.计算两条链的结点之差的绝对值,定义长链和短链,防止代码冗余复杂。
4.先将A链设为长链,B设为短链。如果B链更长,将B链赋给长链,A链赋给短链
5.再让长链先走二者的差数步,这样可以保证两条链同时到达相交的结点
6.如果相等,就跳出循环。最后:返回两条链的相交的结点