图片.png
图片.png

使用 Set 使用

思路:使用 Set 记录访问过的节点

  1. /**
  2. * Definition for singly-linked list.
  3. * class ListNode {
  4. * val: number
  5. * next: ListNode | null
  6. * constructor(val?: number, next?: ListNode | null) {
  7. * this.val = (val===undefined ? 0 : val)
  8. * this.next = (next===undefined ? null : next)
  9. * }
  10. * }
  11. */
  12. function hasCycle(head: ListNode | null): boolean {
  13. const set = new Set<ListNode>()
  14. let current: ListNode | null = head
  15. while(current !== null) {
  16. if (set.has(current)) {
  17. return true
  18. }
  19. set.add(current)
  20. current = current.next
  21. }
  22. return false
  23. };

复杂度分析:

  • 时间复杂度:141. 环形链表 - 图3
  • 空间复杂度:141. 环形链表 - 图4

快慢指针

这里有一篇解释为什么快慢指针会在环内相遇,写得挺不错的:相爱相杀好基友——数组与链表。了解了为什么在环内相遇,就大致能理解如何使用快慢指针来进行求解:

  1. /**
  2. * Definition for singly-linked list.
  3. * class ListNode {
  4. * val: number
  5. * next: ListNode | null
  6. * constructor(val?: number, next?: ListNode | null) {
  7. * this.val = (val===undefined ? 0 : val)
  8. * this.next = (next===undefined ? null : next)
  9. * }
  10. * }
  11. */
  12. function hasCycle(head: ListNode | null): boolean {
  13. // 如果 head 则表示链表中没有元素,如何 head.next 则表示当链表只有一个元素的时候,next 并没有指向自己
  14. if (head === null || head.next === null) {
  15. return false
  16. }
  17. // 定义快慢指针,慢指针步长为1,而快指针步长为2
  18. let slow = head
  19. let fast = head.next
  20. while(slow !== fast) {
  21. // 当快指针为 null 的时候,或者快指针的 next 指向 null 的时候,表明链表没有环
  22. if (fast === null || fast.next === null) {
  23. return false
  24. }
  25. // 慢指针的步长为 1
  26. slow = slow.next
  27. // 快指针的步长为 2
  28. fast = fast.next.next
  29. }
  30. return true
  31. };