环状链表的例题讲解

141. 环形链表 - 力扣(LeetCode)

141. 环形链表 - 力扣(LeetCode)

如图所示环状链表中的pos可以指向链表中任意位置。并且

因此我们想到一个思路是:快慢指针。

slow走一步,fast走两步:

fast先进入圈中开始循环,当slow进入到圈中时开始fast开始追击。

​ 

bool hasCycle(struct ListNode *head) {
    if(head == NULL || head->next == NULL)//head的next成员,可能导致程序崩溃或产生未定义的行为,应该先判断head是否为NULL,再判断head->next是否为NULL
    {
        return false;
    }
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(slow == fast)
        {
            return true;
        }
    }
    return false;
}

这个时候链表只有两个节点,即使第一个节点指向第二个节点,但是由于没有形成闭环,所以也应该返回false ,所以我们应该先迭代再判断。

代码的实现是非常简单的,我们再来看看以下常见问题:

1、为什么一定要相遇,有没有可能错过,或者追不上?

2、slow一次走一步,fast一次走3步,或走4步....

证明:1、为什么一定要相遇,有没有可能错过,或者追不上?

假设slow进环时,fast跟slow的距离为N

fast追击slow过程中的距离变化如下:

证明:2、slow一次走一步,fast一次走3步,或走4步....

fast追击slow的距离N变化有两种情况分别为偶数和奇数情况:

如果N是奇数C是偶数那么就追不上。

我们再来考虑一下是否永远不存在追不上的问题:

142. 环形链表 II - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/linked-list-cycle-ii/description/

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(slow == fast)
        {
            struct ListNode *meet = slow;
            while(meet != head)
            {
                head = head->next;
                meet = meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

这里运用的是数学思想: 

思路2: 

设置一个新的结点newhead让他存储meet->next,再让meet指向null,此时我们只需要让head从头往后走,当与newhead相遇时则返回此时的值,跟思路1一样,思路1是用meet进行,而我们的思路二只需要使head与newhead相交。

//相交代码
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode *curA = headA;
    struct ListNode *curB = headB;
    int lenA = 0;
    int lenB = 0;
    while(curA)
    {
        ++lenA;
        curA = curA->next;
    }
    while(curB)
    {
        ++lenB;
        curB = curB->next;
    }
    curA = headA;
    curB = headB;
    int gap = abs(lenA - lenB);
    if(lenA > lenB)
    {
        while(gap--)
        {
            curA = curA->next;
        }
    }
    else
    {
        while(gap--)
        {
            curB = curB->next;
        }
    }
    while(curA && curB)
    {
        if(curA == curB)
        {
            return curA;
        }
        curA = curA->next;
        curB = curB->next;
    }
    return NULL;
}
//查找代码
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(slow == fast)
        {
            struct ListNode *meet = slow;
            struct ListNode *newhead = meet->next;
            meet->next = NULL;
            return getIntersectionNode(head,newhead);
        }
    }
    return NULL;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值