Leetcode141&142.环形链表

文章讲述了如何使用快慢指针方法检测给定链表中是否存在环以及环的入口节点。通过分析快慢指针的速度差异,确定环的存在并找到环的起始位置。
摘要由CSDN通过智能技术生成

141.环形链表

题目

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

思路(快慢指针法)

  1. 假设链表长度为 m m m,其中环的长度为 n n n.其中 0 ≤ n ≤ m {0}{\le}{n}{\le}{m} 0nm,当 n = 0 n=0 n=0时,此时链表中没有环.
  2. 快慢指针都从头节点head出发,其中快指针fast每次向前移动2个结点,慢指针slow每次向前运动1个结点.
  3. 当快慢指针在第 x x x步相遇时,说明链表中存在环.

原理:快慢指针在离环的第一个结点共有 c c c结点时相遇.慢指针已经走了 x x x步,快指针已经走了 2 x 2x 2x步,此时应当满足方程:
{ x = c + ( m − n ) + k 1 n k 1 ∈ N 2 x + 1 = c + ( m − n ) + k 2 n k 2 ∈ N \begin{cases} x=c+(m-n)+k_1n &k_1\in \mathbb{N}\\ 2x+1=c+(m-n)+k_2n &k_2\in \mathbb{N} \end{cases} {x=c+(mn)+k1n2x+1=c+(mn)+k2nk1Nk2N
其中 0 ≤ c ≤ n ≤ m 0\le{c}{\le}{n}{\le}{m} 0cnm.
在这里插入图片描述

由上述式子可以得到,只需找到关于未知数 x , c , k 1 , k 2 x,c,k_1,k_2 x,c,k1,k2满足方程
{ x = ( k 2 − k 1 ) n − 1 ( k 2 − 2 k 1 + 1 ) n = m + c + 1 \begin{cases} x=(k_2-k_1)n-1\\ (k_2-2k_1+1)n=m+c+1 \end{cases} {x=(k2k1)n1(k22k1+1)n=m+c+1
的解,就可以说明快慢指针一定能够相遇.特别地,当 n = 0 n=0 n=0时,此时第二个方程不成立,链表没有环.
n ≠ 0 n\ne0 n=0,方程 x = ( k 2 − k 1 ) n x=(k_2-k_1)n x=(k2k1)n显然能够成立,此时只需 ( k 2 − 2 k 1 + 1 ) n = m + c + 1 (k_2-2k_1+1)n=m+c+1 (k22k1+1)n=m+c+1也成立即可.又因为 m ≤ c + m ≤ n + m {m}{\le}{c+m}{\le}{n+m} mc+mn+m,此时区间 [ m + 1 , n + m + 1 ] [m+1,n+m+1] [m+1,n+m+1]的长度为 n n n,说明一定有一个整数满足是 n n n的倍数,即上述方程 ( k 2 − 2 k 1 + 1 ) n = m + c + 1 (k_2-2k_1+1)n=m+c+1 (k22k1+1)n=m+c+1也成立.说明链表中存在环.

代码

public class Solution {
    public boolean hasCycle(ListNode head) {
        // 若链表为空或只有一个结点,则不存在环,返回false
        if (head == null || head.next == null){
            return false;
        }
        ListNode slow = head, fast = head.next;
        // 快慢指针相遇时,说明链表中存在环
        while (slow != fast){
            if (fast == null || fast.next == null){
                return false;
            }
            slow = slow.next;//慢指针每次向前移动1个结点
            fast = fast.next.next;//快指针每次向前移动2个结点                   
        }
        return true;
    }
}

142.环形链表II

题目

给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

示例1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

快慢指针法

  1. 仿照上题,当快慢指针进行相遇时。此时慢指针已经走了 x = ( k 2 − k 1 ) n − 1 x=(k_2-k_1)n-1 x=(k2k1)n1,如果让慢指针再走 m − n + 1 m-n+1 mn+1步时,此时慢指针走了 x = m + ( k 2 − k 1 ) n x=m+(k_2-k_1)n x=m+(k2k1)n。长度刚好为整个队长加上环长度的整数倍,此时指针指向指向入环的第一个结点。
  2. 当快慢指针进行相遇时,慢指针移动一个结点后。此时让一个新指针从头节点出发,经过 m − n m-n mn步时,此时新指针刚好指向入环的第一个结点。说明此时新指针和慢指针在入环的第一个结点相遇。

代码

public class Solution {
    public ListNode detectCycle(ListNode head) {
        // 若链表为空或只有一个结点,则不存在环,返回false
        if (head == null || head.next == null){
            return null;
        }
        ListNode slow = head, fast = head.next;
        // 快慢指针相遇时,说明链表中存在环
        while (slow != fast){
            if (fast == null || fast.next == null){
                return null;
            }
            slow = slow.next;//慢指针每次向前移动1个结点
            fast = fast.next.next;//快指针每次向前移动2个结点                   
        }
        //快慢结点相遇后,令一个指针指向头节点,另一个指向慢指针下一个结点
        ListNode a = head;
        ListNode b = slow.next;
        while (a != b){
            a=a.next;
            b=b.next;
        }
        return a;
    }
}
  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值