LeetCode142之环形链表 II(相关话题:快慢指针,绘图分析)

题目描述

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

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

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

进阶:

你是否可以使用 O(1) 空间解决此题?
 

示例 1:

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


示例 2:

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


示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

思路分析

刚开始想到用快慢指针,但是没想明白怎么样才能定位到环形链表的入口点呢?看了下题解的图之后自己思考下终于整明白了。这里将运用思维逻辑分析

fig1

fast指针每次走2步,slow指针每次走1步。相遇时fast的路程一定是slow的两倍。假设在紫色点处相遇fast比slow多走了一个环的路程。这就说明

a+b+(若干个环的路程)= 2*(a+b)
即 
a+b+n*(b+c)= 2*(a+b)
可以看出a = (n-1)(b+c) +c
这个公式可以理解为a的距离等于c加上若干个环的距离
n=1时a=c 

slow指针一定是在未跑满一圈时被fast指针追上的(这个可以用反证法来证明,slow如果跑了1圈还没被追上,那么fast跑了2圈,这2圈内一定会追过slow的产生矛盾)

fast和slow相遇时,如果此时有一个指针ptr 从链表头出发,一定可以和low指针在环形链表入口点相遇。

方法一

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode slow = head, fast = head;
        while (fast != null) {
            slow = slow.next;
            if (fast.next != null) {
                fast = fast.next.next;
            } else {
                return null;
            }
            if (fast == slow) {
                ListNode ptr = head;
                while (ptr != slow) {
                    ptr = ptr.next;
                    slow = slow.next;
                }
                return ptr;
            }
        }
        return null;
    }
}

方法二

方法二是常规实思路先用HashMap记录每个节点,如果遇到重复的节点就是环形链表入口点

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode pos = head;
        Set<ListNode> visited = new HashSet<ListNode>();
        while (pos != null) {
            if (visited.contains(pos)) {
                return pos;
            } else {
                visited.add(pos);
            }
            pos = pos.next;
        }
        return null;
    }
}

 解题总结

方法一的技巧性太强,没刷过题的情况下几乎不可能想到,方法二的思路比较常规。看来技巧性的题目还需要题海战术。

类型题目

LeetCode160相交链表

LeetCode876链表的中间结点

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据与算法架构提升之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值