环形链表——快慢指针

367 阅读1分钟

image.png

方法1:哈希表

使用map判断当前节点是否存在于map中,直到找到重复结点或者链表遍历完

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
    slice := map[*ListNode]int{}
    for {
        if head == nil{
            return nil
        }
        if _,ok := slice[head]; ok {
            return head
        }
        slice[head] = 1
        head = head.Next
    }
}

方法二:快慢指针

{024F397E-BA3D-D061-41AE-DD9827446BB2}.jpg

我们设置两个指针,slow,fast,都位于起始地点,slow指针每次移动一个结点,fast每次两个,如果存在环,则两个指针会在环里相遇,并且是在slow指针循环第一遍环的时候相遇。

此时设fast在环中转了n圈

fast走的距离: a + (b+c)*n +b
slow走到距离: a + b
其中fast走到距离等于二倍的slow的距离
即:(a + b)*2 == a + (b+c)*n + b
推导等式得: a == (b+c)*n - b
也就是 a的长度等于 n圈之后减一个b,所以当fast与slow相遇的时候我们在链表的头结点再设置一个指针item,一次移动一个结点,最终会和slow指针在环的入口处相遇 。
当然我们也可以将等式写为 a == (b+c)x(n-1)+c
即slow在走(n-1)圈之后再走c的距离与item指针在入口处相遇。

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
    var ans,slow,fast *ListNode
    slow,fast = head,head
    for fast != nil{
        if fast.Next == nil {
            break
        }
        fast = fast.Next.Next
        slow = slow.Next
        if fast == slow {
            ans = head
            for ans != slow{
                ans = ans.Next
                slow = slow.Next
            }
            break
        }
    }
    return ans
}