leetcode 环形链表II 解法

这篇博客探讨了LeetCode中的环形链表II问题,提供了两种解法。解法一利用哈希表记录节点,通过双指针判断环的存在并找到入环节点。解法二同样使用双指针,通过数学公式辅助找到环的入口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环形链表II

题目描述

给定一个可能包含一个环的链表。请验证这个链表是否有环,如果有请返回入环的第一个节点。如果无环返回null。

实例:

3-->2-->0-->-4--.
	^			|
	|___________|

返回:节点2

节点:

public class ListNode {
    int val;
    ListNode next;
    public ListNode(int x){
        this.val = x;
        next = null;
    }
}

解法一:哈希表记录

思路:

检验是否有环:首先用两个遍历速度分别为1和2的指针去遍历链表,如果两个指针能相遇即有环,如果速度快的指针遍历到尾了,则无环。

寻找入环的点:用一个HashSeti记录慢指针走过的节点,如果遇到重复的则返回该节点

public class Solution {
    public ListNode detectCycle(ListNode head) {
      if(head == null || head.next == null){
            return null;
        }
        ListNode front = head;
        ListNode pre = head;
        Set<ListNode> set = new HashSet<>();
        set.add(pre);
       	//检查是否存在环
        while (true){
            if(pre.next !=null){
                pre = pre.next;
                if(set.contains(pre)){
                    return pre;
                }
                //检查中顺便记录节点
                set.add(pre);
            }
            if(front.next!=null && front.next.next !=null){
                front = front.next.next;
            }else {
                return null; //到头了,无环,直接返回
            }
            if(pre == front){
                break;
            }
        }
        //能跳出上面的循环说明链表有环
        while (true){
            //记录节点
            pre = pre.next;
            //判断是否节点是否已经存在
            if(set.contains(pre)){
                return pre;
            }
            set.add(pre);
        }
    }
}

解法二:

检验是否有环:首先用两个遍历速度分别为1和2的指针去遍历链表,如果两个指针能相遇即有环,如果速度快的指针遍历到尾了,则无环。

**寻找入环节点:**用数学公式稍加推导

3-->2-->0-->-4--.
	^			|
	|___________|

假设3-->2这段入环的路程长度为y
已知两个指针相遇的节点为-4,则设2-->-4的长度为s1 , -4-->2的长度为s2
慢指针速度为x ,快指针速度为2x
则:	
1. y+s1+n(s1+s2) = xt (n为圈数,t为时间)
2. y+s1+k(s1+s2) = 2xt  (k为圈数,t为时间)

合并
y = (k-2n-1)(s1+s2)+s2

结论:y = s2+g(s1+s2)  (g为圈数),即y的长度是环长的整数倍加s2,所以检测出碰撞点之后,
就可以通过一个头节点和一个碰撞节点向中间逼近就可以算出入点

public class Solution {
    public ListNode detectCycle(ListNode head) {
     if(head == null || head.next == null){
            return null;
        }
        ListNode front = head;
        ListNode pre = head;
        while (true){
            if(pre.next !=null){
                pre = pre.next;
            }
            if(front.next!=null && front.next.next !=null){
                front = front.next.next;
            }else {
                return null;
            }
            if(pre == front){
                break;
            }
        }
        pre = head; //将慢节点复位 
        while (pre != front){
            pre = pre.next;
            front=front.next; //两个节点速度调为1
        }
        return pre;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值