环形列表II 题目分析

一、题目链接:. - 力扣(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.如果相等,就跳出循环。最后:返回两条链的相交的结点

3.在函数detectCycle中 调用 getIntersectionNode 即可

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值