【LeetCode】142. 环形链表 II(Java)

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

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

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

进阶:
你是否可以不用额外空间解决此题?

解法一

常规解法,不考虑空间复杂度,解法二用快慢指针,解决空间复杂度问题。

/**
 * 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) {
        //set
        Set<ListNode> set = new HashSet<>();

        ListNode temp = head;
        while (temp != null) {
            //添加失败,说明回到了环的第一个节点
            if (!set.add(temp)) {
                return temp;
            }
            temp = temp.next;
        }
        return null;
	}
}

在这里插入图片描述
虽然用set在入环点就返回结果了,不过中途存入set消耗了一定的时间,所以用了4ms。

解法二

快慢指针

public class Solution {
    public ListNode detectCycle(ListNode head) {
        //下面是做`287. 寻找重复数`时,理解的快慢指针,这道题也类似,就直接复制之前的理解笔记

        //入环前的距离:a
        //把环从碰撞点分割成两段,第一段是入环点到碰撞点s1,第二段碰撞点到入环点s2

        //因为找到相等值值后,快指针走的是 入环前的距离 + n圈 + n+1圈的入环点到碰撞的位置(即a+n(s1+s2)+s1),
        //快指针至少比慢指针多走一圈才能碰撞,这里我们可以假设快指针只走了一圈,在第二圈的某个点和慢指针碰撞了,
        //那么快指针走过的距离为f=a+s1+s2+s1,而慢指针假设它一圈都没走就和快指针碰撞了,那么它走过的距离为s=a+s1,
        //而快指针每次走都比多一步,是慢指针的两倍,即f=2s,替换后变为f=2a+2s1,和f的原公式相减后得出:a=s2
        //其实a应该等于n(s1+s2)+s2的,不过我们并不关心走了几圈,所以可以忽略
        //那么再让一个指针从头出发一次循环走一步走到入环点为a,而环中的指针每次走一步,走到入环点为s2,
        //又根据上面得出的a=s2,那么它们就会在入环点再次碰撞。


        ListNode fast = head, slow = head;
        do {
            //如果为空,说明没有环,直接返回空
            if (fast == null || fast.next == null) {
                return null;
            }
            //快指针走两步,慢指针走一步
            fast = fast.next.next;
            slow = slow.next;
        //相等即是相遇,跳出循环
        } while (fast != slow);

        //快指针不动,慢指针从头重新出发
        slow = head;
        while (fast != slow) {
            fast = fast.next;
            slow = slow.next;
        }
        //跳出循环说明相遇了,相遇的点就是入环点,直接返回
        return fast;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值