1. 给定一个链表,判断链表中是否有有环
  2. 求环的入口
  3. 求环的大小
  4. 链表倒数第k个节点
  5. 链表的中间节点

1. 如何判断链表有环?

快慢指针,慢指针速度为1(步长为1遍历节点),快指针速度为2。
如果链表没有环,那么快指针为None,就结束了。
如果链表有环,快指针不会为None,会一直环中循环下去;那么慢指针总会进入环。当快慢指针都在环中,二者相对速度(慢指针相当于不动,快指针相对速度为1)为1,那么快指针就会不断逼近慢指针,直至相遇。
https://leetcode-cn.com/problems/linked-list-cycle/

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def hasCycle(self, head: ListNode) -> bool:
  8. if not head or not head.next:
  9. return False
  10. slow, fast = head, head
  11. while fast and fast.next:
  12. slow = slow.next
  13. fast = fast.next.next
  14. if slow is fast:
  15. break
  16. return slow is fast

2. 如何判断环的入口?

https://leetcode-cn.com/problems/linked-list-cycle-lcci/

image.png
快慢两指针相遇,那么快指针所走的路程S1 是 慢指针所走路程S2 的 2倍。
链表环的问题 - 图2

进一步化简,得
链表环的问题 - 图3
从链表头到环入口的距离是:L
从相遇点P到环入口的距离是:H - x
因此,两个指针以同样的速度1,分别从链表头和相遇点出发,第一次相交的位置就是环入口。

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def detectCycle(self, head: ListNode) -> ListNode:
  8. if not head or not head.next:
  9. return
  10. slow, fast = head, head
  11. while fast and fast.next:
  12. slow = slow.next
  13. fast = fast.next.next
  14. if slow == fast:
  15. break
  16. if fast != slow: # 这个判断必须加 因为上面循环跳出也可能是循环体结束了导致的
  17. return
  18. slow = head
  19. while slow != fast:
  20. slow = slow.next
  21. fast = fast.next
  22. return slow

3. 求环的大小

找到入口后,入口处设定一指针,另外一指针在环中跑一圈同时计数,直到两指针相交。

4. 链表倒数第k个节点

https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/submissions/
注意边界条件,k如果大于链表的长度或者等于0。

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
  8. # 快慢指针
  9. # fast_ptr = head
  10. if head.next is None or k == 0:
  11. return head
  12. slow_ptr = head
  13. i = 0
  14. while head is not None:
  15. if i < k:
  16. # fast_ptr = fast_ptr.next
  17. i += 1
  18. else:
  19. # fast_ptr = fast_ptr.next
  20. slow_ptr = slow_ptr.next
  21. head = head.next
  22. return slow_ptr if i == k else None

5. 链表的中间节点

https://leetcode-cn.com/problems/middle-of-the-linked-list/submissions/

  1. # Definition for singly-linked list.
  2. # class ListNode:
  3. # def __init__(self, x):
  4. # self.val = x
  5. # self.next = None
  6. class Solution:
  7. def middleNode(self, head: ListNode) -> ListNode:
  8. if head is None:
  9. return None
  10. slow = head
  11. fast = head
  12. while fast and fast.next:
  13. slow = slow.next
  14. fast = fast.next.next
  15. return slow