带环单链表的追击问题(快慢指针的运用)

目录

一.题目介绍

二.证明为何相等

三.题目练习

题目一.判断是否为环形链表

题目二.返回环形链表的初始结点


一.题目介绍

如何判断一个链表是否带环

像如下这样

解决办法就是用快慢指针来解决 定义一个慢指针每次走一步,一个快指针每次走两步,如果他们相等(快慢指针的值相等既为带环链表),如果不相等fast最后就会为NULL跳出循环,即不为带环链表。参考代码如下

// 函数定义
bool hasCycle(ListNode *head) {
    if (head == NULL || head->next == NULL) {
        return false;
    }

    ListNode *slow = head;       // 慢指针
    ListNode *fast = head->next; // 快指针

    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;       // 慢指针每次移动一步
        fast = fast->next->next; // 快指针每次移动两步

        if (slow == fast) {      // 如果快慢指针相遇,则存在环
            return true;
        }
    }

    return false; // 如果快指针到达链表末尾,说明没有环
}

二.证明为何相等

但是可能有些朋友就会问了,为什么带环就一定会让fast与slow指针相等呢,有没有可能错过呢,不相等呢接下来我们来证明一下下。

(1)追击问题

当慢指针刚刚进入环内的时候是这个样子的(假设逆时针旋转)

也就是说当慢指针刚进入环内他们的距离之差为N,这时候由于快指针移动次数多(或者说速度更快)它将会缩短他们之间的距离 如果我们假设slow指针每次一步 fast指针每次两步 

N-1

N-2

N-3

N-4

....

N=0

到最后N一定会等于0

当N等于0的时候就是相遇的时候

当然上面是假设了他们的速度,且差值为奇数,那如果把这个N或者速度的差值给奇特一点会不会不相遇造成死循环呢,比如说它们错过了呢

这里我先给出答案,我们要看速度的差值,这里我们假设一下当速度差值为一个偶数的时候(因为第一次错过的情况就在这)当N为偶数与奇数时

当N偶数        当N奇数

N-2                N-2

N-4                N-4

...                   ...

0                    -1

 可以很明显的看到当N为奇数 速度差为偶数的时候确实会错过一次但是这种错过只是将他们之间的距离改变成了C-1 假设圆环的周长为C这时候的距离N就是圆环的周长-1

这时候又有两种情况,C为奇数与C为偶数的情况,C为奇数就说明C-1(就是距离N)为偶数 C为偶数就说明C-1(N)为奇数,我们再看看上的距离N,如果C为偶数的话变成死循环不可能相遇!!

哦哦哦 我们来总结一下下

总结一下:
1、N是偶数,第一轮就追上了
2、N就是,第一轮追击会错过,距离变成C-1
a、如果C-1是偶数,下一轮就追上了
b、如果C-1是偶数,那么永远追不上

当速度差为偶数,N是奇数,C-1为奇数只有这种情况就会死循环永远也追不上!!!

三.题目练习

题目一.判断是否为环形链表

. - 力扣(LeetCode)

套用模板想当简单

题目二.返回环形链表的初始结点

. - 力扣(LeetCode)

 

注意中里不仅要判断是否为带环链表还必须返回开始结点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) 
{
    if(head==NULL||head->next==NULL)
    {
        return NULL;
    }
    struct ListNode *fast=head;
    struct ListNode *slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            fast=head;
            while(1)
            {
                if(fast==slow)
                {
                    return fast;
                }
                fast=fast->next;
                slow=slow->next;
            }
        }
    }
    return NULL;
    
}

由于个人精力,能力有限 ,如有错误欢迎指出!!!!

小bit!!!

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值