📑 题目:142. 环形链表 II

🚀 本题 LeetCode 传送门

题目大意

判断链表是否有环,不能使用额外的空间。如果有环,输出环的起点指针,如果没有环,则输出空。

解题思路

这道题是第 141 题的加强版。在判断是否有环的基础上,还需要输出环的第一个点。

分析一下判断环的原理。fast 指针一次都 2 步,slow 指针一次走 1 步。令链表 head 到环的一个点需要 x1 步,从环的第一个点到相遇点需要 x2 步,从环中相遇点回到环的第一个点需要 x3 步。那么环的总长度是 x2 + x3 步。

fast 和 slow 会相遇,说明他们走的时间是相同的,可以知道他们走的路程有以下的关系:

  1. fast t = (x1 + x2 + x3 + x2) / 2
  2. slow t = (x1 + x2) / 1
  3. x1 + x2 + x3 + x2 = 2 * (x1 + x2)
  4. 所以 x1 = x3

所以 2 个指针相遇以后,如果 slow 继续往前走,fast 指针回到起点 head,两者都每次走一步,那么必定会在环的起点相遇,相遇以后输出这个点即是结果。

代码

  1. package leetcode
  2. /**
  3. * Definition for singly-linked list.
  4. * type ListNode struct {
  5. * Val int
  6. * Next *ListNode
  7. * }
  8. */
  9. func detectCycle(head *ListNode) *ListNode {
  10. if head == nil || head.Next == nil {
  11. return nil
  12. }
  13. isCycle, slow := hasCycle142(head)
  14. if !isCycle {
  15. return nil
  16. }
  17. fast := head
  18. for fast != slow {
  19. fast = fast.Next
  20. slow = slow.Next
  21. }
  22. return fast
  23. }
  24. func hasCycle142(head *ListNode) (bool, *ListNode) {
  25. fast := head
  26. slow := head
  27. for slow != nil && fast != nil && fast.Next != nil {
  28. fast = fast.Next.Next
  29. slow = slow.Next
  30. if fast == slow {
  31. return true, slow
  32. }
  33. }
  34. return false, nil
  35. }