【面试题】链表成环?求入环点?证明+代码?必须安排~

在这里插入图片描述

个人主页:@Weraphael
✍作者简介:目前学习C++和算法
✈️专栏:Leetcode + 面试/笔试
希望大家多多支持,咱一起进步!
如果文章对你有帮助的话
欢迎 评论 点赞 收藏 加关注✨


标题

  • 一、环形链表I
      • 1.1 题目描述
      • 1.2 思路 + 代码实现
      • 1.3 证明
  • 二、环形链表II
      • 2.1 题目描述
      • 2.2 思路 + 代码
      • 2.3 证明
  • 5、总结

一、环形链表I

1.1 题目描述

LeetCode链接:环形链表I
【面试题】链表成环?求入环点?证明+代码?必须安排~_第1张图片

1.2 思路 + 代码实现

【思路】
可以使用快慢指针,然后转化成追击问题。快指针一次走2步,慢指针一次走1步,如果链表成环,快指针就一定能追上慢指针。
此篇博客详细讲述了快慢指针 —> 点我跳转

【代码实现】

bool hasCycle(struct ListNode *head) 
{
    struct ListNode* fast = head,*slow = head;
    while (fast && fast->next)
    {
        //快指针一次走2步,慢指针一次走1步
        fast = fast->next->next;
        slow = slow->next;
        
        if (fast == slow)
            return true;
    }
    return false;
}

【面试题】链表成环?求入环点?证明+代码?必须安排~_第2张图片

1.3 证明

写出以上代码并不难,关键在于证明。

  • 为什么慢指针slow走1步,快指针fast走2步,它们一定就能相遇?有没有可能会错过?请证明。

【证明】
假设慢指针slow进环时,设快指针fast和慢指针slow之间的距离是Nslow进环后,fast就开始追加slowslow每走一步,fast就会走2步,它们之间的距离就会逐渐缩小1。
fastslow之间的距离变化:
N — 起始距离
N-1
N-2

3
2
1
0 – 相遇
直到N的距离逐渐缩小到0,它们就一定能相遇。

  • 假设慢指针slow走1步,快指针fast走x步(x ≥ 3),它们会相遇还是会错过?请证明。

【证明】
假设x = 3,与上面同样的道理,设slow进环时,fastslow之间的距离为Nslow进环后,fast就开始追击slowslow走1步,fast走3步,它们之间的距离就会逐渐缩小2。但这次的证明与上一个不同,因为上一个之间的距离逐渐缩小1,所以无论N的值是多少,N最后一定会被减到0。而这次证明需要对N进行分类讨论,N是偶数或奇数。
fastslow之间的距离变化:
①当N是偶数时,再加上fastslow的距离逐渐缩小2,最后的它们之间的距离一定为0
N — 起始距离
N - 2
N - 4

4
2
0 – 相遇
②当N是奇数时
N
N - 2
N - 4

3
1
-1
当走到最后,fastslow之间的距离为-1,这说明fast在追加slow的时候超过slow了,此时fastslow之间的距离就是周长 - 1(往后假设周长为C),相当于进入新一轮追击。这里就要再判断C - 1是奇数还是偶数,如果C - 1是偶数代表一定能追的上,否则就追不上。

二、环形链表II

2.1 题目描述

LeetCode链接:环形链表II

【面试题】链表成环?求入环点?证明+代码?必须安排~_第3张图片

2.2 思路 + 代码

【思路】
先给出结论:一个指针从相遇点开始走,另一个指针从起始点开始走。它们最终会在入环点相遇。 后面会给出i详细的证明过程

【代码实现】

struct ListNode *detectCycle(struct ListNode *head) 
{
    //快慢指针找相遇点
    struct ListNode* fast = head,*slow = head;
    while (fast && fast->next )
    {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast)
        {
            //相遇点(slow改成fast也行)
            struct ListNode* meet = slow;
            //记录起始点
            struct ListNode* start = head;
            while (start != meet)
            {
                meet = meet->next;
                start = start->next;
            }
            //最终他们会在入环点相遇
            return meet;
        }
    }    
    return NULL;
}

【面试题】链表成环?求入环点?证明+代码?必须安排~_第4张图片

2.3 证明

面试官:你怎么知道一个指针从相遇点开始走,另一个指针从起始点开始走,它们最终会在入环点相遇。请证明

【面试题】链表成环?求入环点?证明+代码?必须安排~_第5张图片
【证明过程】

  1. 设起始点->入环点的距离为L
    入环点->相遇点的距离为X
    环的长度为C
  2. 所以,慢指针移动的距离:L + X
    快指针移动的距离:L + nC + X
  • 为什么快慢指针相遇时,慢指针的移动距离小于环长,换句话说,为什么慢指针的移动距离不是L + X + n
    答:考虑最坏的情况下,当慢指针入环时,快指针敲好在慢指针前面,快指针则需要走C - 1步才能与慢指针相遇,所以无论对于任何情况,快指针到慢指针的距离都不会超过C - 1步,所以,慢指针的移动距离更不会大于环长
    【面试题】链表成环?求入环点?证明+代码?必须安排~_第6张图片

  • 快指针的移动距离不能写成L + C + X
    答:因为起始点到入环点和相遇点到入环点有可能不相等。
    【面试题】链表成环?求入环点?证明+代码?必须安排~_第7张图片

  1. 规定快指针走2步,慢指针走1步。所以,快指针的移动距离是慢指针的2倍。
    所以,不难可以列出等式:2(L + X) = L + nc + X
  2. 化简等式得:L = nC - X --> 意味着:一个指针从相遇点走,另一个指针从起始点走,它们最后会在入口点相遇。

5、总结

若证明过程有啥问题的,欢迎大佬指出,虚心接受orz

你可能感兴趣的:(面试/笔试题,LeetCode,链表,数据结构,算法,学习,leetcode)