【牛客-剑指offer-数据结构篇】JZ23 链表中环的入口结点 两种实现 Java实现


1 题目链接

https://www.nowcoder.com/exam/oj/ta?page=1&tpId=13&type=13

2 题目

在这里插入图片描述
在这里插入图片描述

3 思路 & 代码

方案一 HashSet

遍历链表,把遇到的节点全都放入hashset中,每次在向set中添加元素之前,先检查一下set中是否已经包含此节点:

  • 如果包含,则表示该节点就是链表的环的入口,直接返回该节点即可

  • 如果链表遍历结束,还没有出现重复的节点,则说明该链表中没有环,返回null

import java.util.*;
/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {

        if (pHead == null) {
            return null;
        }

        HashSet<ListNode> set = new HashSet<>();
        ListNode tmp = pHead;
        while (tmp != null) {
            if (set.contains(tmp)) {
                return tmp;
            }
            set.add(tmp);
            tmp = tmp.next;
        }
        return null;
    }
}

方案二 快慢指针

指定两个指针slow和fast,fast每次后移两个,slow每次后移一个。fast指针的速度是slow指针的两倍,相遇时所经历的时间是一样的,所以fast指针所走的距离时slow指针所走距离的了两倍。

假设:

  • 从头节点到链表的环的入口的距离为x
  • 从环的入口到相遇地点的距离是y
  • 从相遇地点再走到环的入口的距离是z
  • 在相遇之前,fast指针走了n个完整的环,slow指针走了m个完整的环,0<=m<n

由前面得出的fast和slow所走的距离的关系,可得出:

x + n(y + z) + y ------ fast指针走的距离

x + m(y + z) + y ------ slow指针走的距离

x + n(y + z) + y = 2[x + m(y + z) + y]

两边移项

x + y = (n - 2m)(y + z)

其中,

y + z刚好是环的大小;x + y是从头节点,经过环的入口到达相遇节点的距离;

也就是说,从头节点,经过环的入口到达相遇节点的距离环的大小的整数倍

在fast和slow相遇以后,将其中一个指针移到头节点,然后两个指针以每次移动一个的速度前进

最终,两个指针会再次同时到达相遇地点,当两个节点再次到达相遇地点之前,肯定已经先进入环了,在环中共同走过一段,所以,两个指针第一次相等的节点,就是环的入口。

import java.util.*;
/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {

        //空链表
        if (pHead == null) {
            return null;
        }

        ListNode fast = pHead;
        ListNode slow = pHead;

        while (fast != null && fast.next != null) {
            //fast移动两次
            fast = fast.next.next;
            //slow移动一次
            slow = slow.next;
            
            //fast和slow相遇,说明链表中有环
            if (fast == slow) {
                //将fast指针移向头节点
                fast = pHead;
                while (fast != slow) {
                    //fast和slow移动一次
                    //再次相遇的地点就是环的入口
                    fast = fast.next;
                    slow = slow.next;
                }
                return slow;
            }
        }
        //如果while循环结束,说明fast指针先到达链表的结尾,链表中没有环,返回null
        return null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值