leetcode 141.环形链表 I - 142.环形链表 II 代码及指针相遇证明问题

⭐️ 环形链表 I 题目描述

给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
如果链表中存在环 ,则返回 true 。 否则,返回 false
在这里插入图片描述
思路:快慢指针问题。我们可以声明一个 fast 指针(一次走两步),声明一个 slow 指针(一次走一步)。如果链表中存在环,那么 fast 指针和 slow 指针就会相遇,如果相遇则代表有环,否则 fast 指针会结束代表没环。

🌠 为什么快指针走两步,慢指针走一步可以相遇?

图:
在这里插入图片描述
在这里插入图片描述

假设 slow 进环后,fastslow 距离是 N N N。这时候 fast 开始追击 slowfast 一次走两步,slow一次走一步,他们之间的距离每次缩小 1 1 1NN-1N-2...210最终他们相遇了,所以结论是肯定会相遇,因为他们的距离每次缩小 1 1 1

🌠 那快指针一次走三步,慢指针走一步可以相遇吗?

在这里插入图片描述
还是假设 slow 进环后,fastslow 距离是 N N N。这时候 fast 一次走三步,slow 一次走一步,他们之间的距离每次缩小 2 2 2

  1. N N N 是偶数的情况:NN-2N-4...420 相遇追上了。
  2. N N N 是奇数的情况:NN-2N-4...31-1。这里 -1 意味着刚好错过了,但是此时 fast 是要超出 slow 一步,再假设环的大小是 C C C。那么现在 fastslow 的距离刚好是 C − 1 C - 1 C1步。又分为两种情况:
    • 如果 C − 1 C - 1 C1 是偶数的话,那么 fastslow 就可以相遇。
    • 如果 C − 1 C - 1 C1 是奇数的话,那么 fast 就会重复上面是奇数的情况,永远不会相遇。

结论:当 fast 一次走三步,slow 一次走一步,不一定可以相遇。
在这里插入图片描述


leetcode链接:141.环形链表 I

⭕️ 代码:

bool hasCycle(struct ListNode *head) {
    struct ListNode * slow = head;
    struct ListNode * fast = head;
    
    // 考虑没有环的情况下,奇数和偶数个链表 fast 结束条件不同
    while (fast && fast->next) {
        fast = fast->next->next;
        slow = slow->next;

        if (fast == slow) {
            return true;
        }
    }

    return false;
}

⭐️ 环形链表 II 题目描述

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL。不允许修改链表。
结论是当一个指针从 fastslow 的相遇点 meet 开始走,一个指针从 head 位置开始走,最终 meethead 会在入环点相遇。
在这里插入图片描述

🌠 为什么一个指针从相遇点走,一个指针从头走,他俩会在入环点相遇呢?

假设 head 到入环点的距离是 L L L ,入环点到相遇点的距离是 X X X,而环的大小是 C C C
首先 slow 进环之后,fast 在一圈之内,一定可以追上 slow!因为追击的过程他们距离每次缩小1,首先排除错过,而 slow 进环 fast 与其最大长度也只是 C − 1 C - 1 C1,所以 slow 最多走不到半圈,fast 就会追上。
slow 走的路程: L + X L + X L+X
fast 走的路程: L + N ∗ C + X L + N * C + X L+NC+X    ( N > = 1 ) (N>=1) (N>=1) 假设 slow 在进环前,fast 在环里转了 N N N 圈。

所以 fast 走了 slow 2倍。

  • 2 ∗ ( L + X ) = L + N ∗ C + X 2 * (L + X) = L + N * C + X 2(L+X)=L+NC+X
  • L + X = N ∗ C L + X = N * C L+X=NC
  • L = N ∗ C − X L = N * C - X L=NCX

所以 L L L 的距离就是绕了 N N N 圈之后到达 meet 的距离在减去 X X X 的距离,就是入环点。
结论:一个指针从 meet 开始走,一个指针从 head 开始走,他们会在入环点相遇。
在这里插入图片描述


leetcode链接:142.环形链表 II

⭕️ 代码:

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode * slow = head;
    struct ListNode * fast = head;
    
    // 考虑没有环的情况下,奇数和偶数个链表 fast 结束条件不同
    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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值