链表——7.力扣题目:142. 环形链表 II

题目链接

解析:(快慢指针)

题目要求,判断一个链表是否存在环,并且返回进入环的第一个结点

问题①:如何判断是是否存在环?

使用快慢指针,快慢指针同时从head出发,快指针每次向后迭代两位,慢指针每次向后迭代一位。

如果链表不存在环,那么快指针最终会到null位置(链表结点总数为奇数时)或者null的前一个位置(链表结点总数为偶数时)。

&[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YC71kVpQ-1678782940336)(https://code-thinking.cdn.bcebos.com/gifs/141.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.gif)]

如果存在环,如下图,在快慢指针都进入环后,快指针以两倍于慢指针的速度,在环内追赶慢指针,最终一定能追上。

也就是当快指针连续向后位移两位,慢指针向后位移一位后,快指针和慢指针指向同一个结点,这样就是两个结点相遇。(快指针在迭代的途中遇到慢指针不算遇到),所以只要快指针和慢指针能够相遇,就证明有环。

问题②:如何找到环的入口?

&img

如上图,一圈环是y+z

相遇时,slowIndex走过的节点数是x+y+n(y+z),因为Index可能走了不止一圈。

fastIndex走过的结点数是x+y+m(y+z),fastIndex肯定走了不止一圈,由于fastIndex走的更快,所以m>n。

由于slowIndex和fastIndex同时从头结点向后迭代,并且fastInsex向后迭代的速度是slowIndex的两倍。所以可以推断出:fastIndex走过的结点数,始终是slowIndex的两倍。

可得等式:2*(x+y+n(y+z)) = x+y+m(y+z)

要求的是环的入口位置,也就是x,x是从头结点出发走到环入口位置需要经过的结点数量

分离出x可得:x = (m-n)(y+z)-y

由于m>n并且m,n均为非负整数,所以令k=m-n,(k>=1,k为正整数)

所以:x = k(y+z)-y

变换公式可得:x = (k-1)(y+z)+z

y+z的含义是走一圈环需要的位移数,(k-1)是一个非负整数,所以 (k-1)(y+z)+z表示一共走了k-1圈再加z个结点。如果从快慢指针相遇结点出发,经过k-1圈,还是在相遇结点,再经过z个结点,正好到了环的入口。

整个公式的意义就是:从头结点出发走到环入口位置需要经过的结点数量 等于 从快慢指针相遇结点出发走了k-1圈再加z个结点到达环入口位置所经过的结点数量。所以从头结点出发和从相遇位置出发的两个指针(一次向后迭代一个位置),必然会在同一时刻指向环形入口。

所以按照公式,创建两个指针,一个从头结点向后迭代,一个从相遇位置向后迭代,两个结点的速度都是一次迭代向后走一个位置,那么当两个指针指向同一个指针时,就是到了环形入口的位置。

注意点:慢指针进环后,第一次被快指针追上时,肯定还没走满一圈环

代码随想录提出上面的n一定是0,因为相对于slowIndex,fastIndex是以一次一个单位追赶的,所以进环时,slowIndex和fastIndex的距离相差肯定小于环的长度,那么快指针追上慢指针的迭代次数肯定小于以一次一个单位的速度走一圈环的迭代次数(因为相对于slowIndex,fastIndex是以一次一个单位追赶的),同样慢指针在这个迭代次数下肯定还没走满一圈,所以上面解析的n一定是0.

代码:
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slowIndex = head, fastIndex = head;
        while (fastIndex != null && fastIndex.next != null) {
            fastIndex = fastIndex.next.next;
            slowIndex = slowIndex.next;
            if (fastIndex == slowIndex) {
                ListNode cur1 = head;
                ListNode cur2 = slowIndex;
                while (cur1 != cur2) {
                    cur1 = cur1.next;
                    cur2 = cur2.next;
                }
                return cur1;
            }
        }
        return null;
    }
}

索引
图片来自于代码随想录,链接https://www.programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#%E6%80%9D%E8%B7%AF

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值