两道题目带你入门环形链表(Leecode题目141, 142)

Leecode141. 环形链表

题目介绍

在这里插入图片描述

给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。

题目分析

这就是典型的快慢指针追击问题,就定义两个快慢指针,在有环的情况下,快指针走两步,慢指针走一步,结果快指针一定会追上慢指针。

那么为什么慢指针要走一步,快指针要走两步才能追上慢指针呢?为什么三步,走四步,甚至N步就不行呢?
假设是一个有环的链表,fast一定会先进环,slow就后进环,等slow进环的时候,可能fast就已经要追上slow了。
在这里插入图片描述
就算是最坏的情况,slow刚好进环的时候,fast就在slow的前面,之间的距离差了将近一个环
就像这样
在这里插入图片描述
就算这样,两个指针每移动一次的话,它们之间的距离拉近一步,最后slow走了R - 1 步(假设环长R),fast也追上了slow。

但是fast一次走三步,slow一次走一步的话
如果环是这样,那么阁下如何应对?
在这里插入图片描述

这样就永远不会相遇,因为fast把slow套圈了。

所以说,fast走两步,slow走一步就一定可以相遇滴

代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;

    while(fast != NULL && fast -> next != NULL)
    {
        fast = fast -> next ->next;
        slow = slow -> next;
        if(fast == slow)
        {
            return true;
        }
    }
    return false;
}

Leecode142. 环形链表II

题目介绍

在这里插入图片描述

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改链表。

题目分析

先根据题目,得到能够计算出来的点
在这里插入图片描述

解释点:
H = 链表头
pos = 进环的点(也就是题目要求的点)
M = fast 和 slow相遇的点
设:H ~ pos : 距离为L
pos ~ M : 距离为X
环长:R

由上面就能得到:
M ~ pos:距离为R - X
fast走的路程:L + X + nR(n为圈数)
slow走的路程:L + X
根据fast一次走两步,slow一次走一步则有能得到的表达式:

2 fast= slow
2(L + X + nR)= L + X
—>L = nR - X
在极端条件下,假设n为1(无论如何,n最小为1,因为等slow进环后,fast一定在slow的前面,就要跑了一圈才能追上)
故:L = R - X

**L = R - X的含义就是:**两个指针分别从H点和M点同时出发,每次移动一步的话,那么就会在进环点相遇
在这里插入图片描述

代码实现

  1. 找到M点(fast 和 slow相遇的点)
  2. 让两个指针分别从H点和M点同时出发,每次移动一步
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;

    // 找到相遇点M
    while(fast != NULL)
    {
        if(fast -> next == NULL)
        {
            return NULL;
        }
        fast = fast -> next -> next;
        slow = slow -> next;

        // 让让两个指针分别从H点和M点同时出发,每次移动一步
        if(fast == slow)
        {

            struct ListNode *q = slow;
            struct ListNode *p = head;

            while(p != q)
            {
                p = p -> next;
                q = q -> next;
            }
            return p;
        }
    }
    return NULL;
}

小结

总之环形链表入门还是很简单的,就是用双指针来解决就好了,难一点就寻找变量关系来得到表达式,最后得出题目的数学关系

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值