链表带环判断,以及求入环节点,链表OJ分析

发布于:2022-12-26 ⋅ 阅读:(293) ⋅ 点赞:(0)

目录

1. 判断链表是否带环

1.1 快指针一次走几步,慢指针一次走几步

2. 求入环节点

3.OJ链接


我们先来观察一个带环链表

 我们可以换个更简单的方式来观察它

 我们可以看到带环链表的循环方式。

1. 判断链表是否带环

我们可以尝试,使用快慢指针来判断,链表是否带环。

如果有环,快指针先一步进环,在环内循环。等到慢指针进环后,快指针与慢指针相遇,判断若相等,则链表带环。

 如果不带环,快指针走到尾就结束了。

 大致的思路就是这样。

大致的思路有了,接下来我们需要考虑一些细节问题,

1.1 快指针一次走几步,慢指针一次走几步

我们怎么确定,快慢指针一定在环中相遇?

先说结论:

快指针一次走俩步,慢指针一次走一步。

假设慢指针进环时 ,它们的差距为 N, 快指针走两步,慢指针走一步,它们的差距减少 1,

即 N- 1   ,   N -2 ,  N-3 ,    N-4   , ……  0     它们在0处相遇。

如果不按上面的 ,快指针一次走三步,四步,…… 可以吗

接下来我们以 快指针一次走三步,慢指针一次走一步为例

假设慢指针进环时,它们的差距为 N, 它们的差距一次减少2 

N - 2

N -4

N- 6

N- 8

如果N为奇数

1

-1

(跳过了 0,它们没有相遇 ,fast 直接超过了 slow )

假设环的长度为 C ,那么此时它们的差距为 C-1 ,如果 ,C-1 为奇数 ,那么接着循环的后果就是,它们的距离最小任然为  -1 ,fast 用于也遇不到slow 。

总结一下 ,如果进环时,它们的差距N为奇数 ,且环长度C -1,也为奇数时,它们永远不会相遇。

所以我们在设置快慢指针时,为了避免这种情况,通常设置快指针一次走两步。

2. 求入环节点

 在快慢指针相遇时,fast 可能已经在环内循环了很多圈,假设从起点到入口点距离为 x,入口点到相遇点为  Y ,环长度为 C,fast 循环了 n 次。

 

慢指针走的路程是  X + Y 

快指针走的路程是  X + n*C +Y 

由于快指针走的路程是慢指针走的二倍

2(X+Y) =  X+ n*C +Y

  X = n*C -Y

此时,一个指针从 head 处出发,一个指针从 meet 处出发,它们会在 入口处相遇。

代码实例:

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*slow = head,*fast = head;

    while(fast && fast->next)
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)    // 相遇
        {
            struct ListNode* meet = fast;
            while(head != meet)
            {
                head = head->next;
                meet = meet->next;
            }
            return meet;

        }
    }
    return NULL;
}

3.OJ链接

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

142. 环形链表 II - 力扣(LeetCode)


网站公告

今日签到

点亮在社区的每一天
去签到