LeetCode破解之环形链表

187 阅读2分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

题意描述

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

image-20211129204355688

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

解法1:双指针

思路:主要分两步

  • 第一次循环使用快慢指针确认是否为循环链表

  • 第二次循环找到循环链表的起始节点,首先假定链表起点到入环的第一个节点A的长度为x,到快慢指针相遇的节点B的长度为(x+y)

    分析:假设慢指针走了x + y步,其中x表示从头节点到环入口节点的长度,y 表示从环的入口到相遇节点的位置。快指针走了x + n*z + y步,其中,n表示快指针已经绕着环走了n次,z表示环的长度。已知,快指针每次走2步,慢指针每次走1步=>2(x + y) = x + nz + y => x = n*z -y

    public class Solution {
        public ListNode detectCycle(ListNode head) {
            ListNode slow = head, fast = head;
            // 是否需要重置
            boolean resetFlag = true;
            while (null != fast && null != fast.next) {
                slow = slow.next;
                if (resetFlag) {
                    fast = fast.next.next;
                } else {
                    fast = fast.next;
                }
    
                if (slow == fast) {
                    if (resetFlag) {
                        slow = head;
                        resetFlag = false;
                        if (slow == fast) {
                            return slow;
                        }
                    } else {
                        return slow;
                    }
                }
            }
            return null;
        }
    }
    
解法2:Set

思路:在解法一的思路上,利用数据结构Set做一些优化

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