Here’s a Python implementation of the has_cycle function using the fast and slow pointers approach:

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def has_cycle(head: ListNode) -> bool:
    # Initialize fast and slow pointers to the head of the linked list
    slow = head
    fast = head

    # Iterate until fast reaches the end of the list or encounters a cycle
    while fast and fast.next:
        slow = slow.next  # Move slow pointer one step
        fast = fast.next.next  # Move fast pointer two steps

        # If there is a cycle, fast will eventually catch up with slow
        if slow == fast:
            return True

    # If fast reaches the end of the list, there is no cycle
    return False

# Example usage:
# Create a linked list with a cycle
head = ListNode(3)
head.next = ListNode(2)
head.next.next = ListNode(0)
head.next.next.next = ListNode(-4)
head.next.next.next.next = head.next  # Create a cycle

result1 = has_cycle(head)
print(result1)  # Output: True

# Create a linked list without a cycle
head_no_cycle = ListNode(1)
head_no_cycle.next = ListNode(2)
head_no_cycle.next.next = ListNode(3)

result2 = has_cycle(head_no_cycle)
print(result2)  # Output: False

This solution uses two pointers, a slow pointer that moves one step at a time and a fast pointer that moves two steps at a time. If there is a cycle, the fast pointer will eventually catch up with the slow pointer.

Time Complexity:

The time complexity is O(n), where n is the number of nodes in the linked list

Space Complexity:

The space complexity is O(1).