链表带环问题

今天我们来看一下链表的经典问题,带环问题

这个问题可以算是比较经典的面试题了,接下来咱们看看题目内容

看到这个题目,首先我们应该想到的思路,就是“快慢指针”;

  • 让快慢指针slow 和 fast 都为head,随后将让fast以slow的两倍速度进行移动,具体如下图

  • 然后注意判断,如果是不带环的链表,那么fast或者fast->next中肯定会有一个为空指针,如下图所示

此时代码可以写为:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow=head,*fast = head;

    while(fast&&fast->next)//判断是否带环,以fast为判断条件
    {
       slow = slow->next;
       fast = fast->next->next; 
    }
   return false;
}

之后我们需要解决while循环中的代码,此时我们需要找到规律

  • 当fast和slow走到环内,一共有两种情况,一种是走着相交,一种是永不相交,此时我们需要判断是哪种情况 

1.当fast指针的速度是slow的两倍,那么fast追赶slow,(设fast和slow之间的距离为N),N(偶数)的距离就是N -> N-1 -> N-2 .....  N-(N-1) -> 0,所以在这种情况下,N的值肯定为0。所以肯定相交。

2.当fast的指针速度是slow的三倍,那么fast追赶slow,N的距离N-2 -> N-4 ->N-6 ..... N-(N-1) -> -1

在这种情况下,就要进入第二次追赶(设环的长度为C)如果C为奇数,那么就需要走N+1的距离

又因为N+1是偶数,所以在C为奇数时,fast和slow会相交。

如果C为偶数,那么fast和slow就不可能相交。

  • 其实我们需要一个公式就可以知道,C不可能在是N为偶数的情况下为奇数

 

设head到环入口节点位置的距离为L,fast到slow的距离为N,环的长度为C

3*L = L+x*C+C-N 

2*L = (x+1)C-N

从此得出,在两边都为偶数的情况下,C不可能为奇数

即永远相交

 那么我们补完代码即可解答这个问题。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow=head,*fast = head;

    while(fast&&fast->next)//判断是否带环,以fast为判断条件
    {
       slow = slow->next;
       fast = fast->next->next; 
        if(fast == slow)
        return true;
    }
   return false;
}

  附加问题(变题)

 这次我们重新设,并且用表达式解决

假设fast和slow已经相遇,N,L和C不变(fast为slow速度的两倍)。得出:

2*L=L+x*C+N

L=x*C+N

不管x为何数,以head和slow或fast节点为头开始走都会同时走到环头节点,此时可以写出代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow=head,*fast = head;

    while(fast&&fast->next)//判断是否带环,以fast为判断条件
    {
        slow = slow->next;
        fast = fast->next->next; 
       
        if(slow == fast){
            struct ListNode* meet = slow
            while(meet!=head)
            {
                head = head->next;
                meet = meet->next;
            }
          }return head;
   return NULL;
     }

那么这题就全部解答完成啦。

咱们下次再见哦 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值