Linked List Cycle

🏠 ⬅️ ➡️

Given head, the head of a linked list, determine if the linked list has a cycle in it.

There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail's next pointer is connected to. Note that pos is not passed as a parameter.

Return true if there is a cycle in the linked list. Otherwise, return false.

Example 1:

Input: head = [3,2,0,-4], pos = 1 Output: true Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).

Example 2:

Input: head = [1,2], pos = 0 Output: true Explanation: There is a cycle in the linked list, where the tail connects to the 0th node.

Example 3:

Input: head = [1], pos = -1 Output: false Explanation: There is no cycle in the linked list.

Constraints:

  • The number of the nodes in the list is in the range [0, 104].
  • -105 <= Node.val <= 105
  • pos is -1 or a valid index in the linked-list.

Follow up: Can you solve it using O(1) (i.e. constant) memory?


Note: This problem is from LeetCode.
Compiled
Executed
Correct
program main
    implicit none

    type :: Node
        integer :: val
        type(Node), pointer :: next => null()
    end type

    type(Node), target :: head
    type(Node), pointer :: current
    logical :: has_cycle

    ! Example 1
    allocate(current, source=Node(3))
    allocate(current%next, source=Node(2))
    allocate(current%next%next, source=Node(0))
    allocate(current%next%next%next, source=Node(-4))
    has_cycle = hasCycle(head)
    print '(L1)', has_cycle

    ! Example 2
    deallocate(current)
    allocate(current, source=Node(1))
    allocate(current%next, source=Node(2))
    has_cycle = hasCycle(head)
    print '(L1)', has_cycle

    ! Example 3
    deallocate(current)
    allocate(current, source=Node(1))
    has_cycle = hasCycle(head)
    print '(L1)', has_cycle

contains

    function hasCycle(head) result(has_cycle)
        type(Node), target :: head
        type(Node), pointer :: current
        integer :: pos

        current => head
        pos = 1

        do while (associated(current%next))
            if (pos == current%next%val) then
                has_cycle = .true.
                exit
            end if
            current => current%next
            pos = current%val
        end do

        has_cycle = .false.
    end function

end program
Compiled
Executed
Correct
module linked_list_cycle

implicit none

contains

function has_cycle(head) result(cycle)

! Given the head of a linked list, determine if the linked list has a cycle in it.
! Return true if there is a cycle, false otherwise.

! head: the head of the linked list
! cycle: true if there is a cycle, false otherwise

type(node), pointer :: head
logical :: cycle

! Initialize the cycle flag to false
cycle = .false.

! If the list is empty, there is no cycle
if (associated(head)) then

! If the list has only one node, there is no cycle
if (associated(head%next)) then

! If the list has more than one node, check for a cycle
cycle = has_cycle_helper(head)

end if

end function has_cycle

recursive function has_cycle_helper(node) result(cycle)

! Given a node in a linked list, determine if the linked list has a cycle in it.
! Return true if there is a cycle, false otherwise.

! node: the node to check for a cycle
! cycle: true if there is a cycle, false otherwise

type(node), pointer :: node
logical :: cycle

! If the node is null, there is no cycle
if (.not. associated(node)) then
cycle = .false.
return
end if

! If the node's next pointer is null, there is no cycle
if (.not. associated(node%next)) then
cycle = .false.
return
end if

! If the node's next pointer points back to the node, there is a cycle
if (node%next == node) then
cycle = .true.
return
end if

! Recursively check the next node in the list
cycle = has_cycle_helper(node%next)

end function has_cycle_helper

end module linked_list_cycle

program test

use linked_list_cycle
implicit none

! Test case 1:
type(node), pointer :: head
integer :: i

! Create a linked list with a cycle
do i = 1, 4
head = new_node(i)
end do
head%next%next%next = head

! Check if the linked list has a cycle
if (has_cycle(head)) then
write (*,*) "Linked list has a cycle"
else
write (*,*) "Linked list does not have a cycle"
end if

! Test case 2:
head = new_node(1)
head%next = new_node(2)

! Check if the linked list has a cycle
if (has_cycle(head)) then
write (*,*) "Linked list has a cycle"
else
write (*,*) "Linked list does not have a cycle"
end if

! Test case 3:
head = new_node(1)

! Check if the linked list has a cycle
if (has_cycle(head)) then
write (*,*) "Linked list has a cycle"
else
write (*,*) "Linked list does not have a cycle"
end if

contains

type(node), pointer function new_node(value)

! Create a new node with the given value

! value: the value to store in the node

integer, intent(in) :: value
type(node), pointer :: new_node

allocate(new_node)
new_node%value = value
new_node%next => null()

end function new_node

end program test
🌐 Data from online sources
def hasCycle(head):
    slow = fast = head
    while fast is not None and fast.next is not None:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            return True
    return False

The algorithm used is Floyd's cycle-finding algorithm, also known as the "tortoise and the hare" algorithm. There are two pointers, one slow (tortoise) and another fast (hare). The slow pointer moves one step at a time, and the fast pointer moves two steps.

Initially, both pointers are set to the head of the linked list. The pointers are moved forward with their respective speeds until either the fast pointer reaches the end of the linked list or both pointers meet at the same node.

If the fast pointer reaches the end, it means that there is no cycle and the function returns false. If the pointers meet at some point in the linked list, there is a cycle and the function returns true.

🌐 Data from online sources
bool hasCycle(ListNode *head) {
    ListNode *slow = head, *fast = head;
    while (fast != nullptr && fast->next != nullptr) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) {
            return true;
        }
    }
    return false;
}

The algorithm used is Floyd's cycle-finding algorithm, also known as the "tortoise and the hare" algorithm. There are two pointers, one slow (tortoise) and another fast (hare). The slow pointer moves one step at a time, and the fast pointer moves two steps.

Initially, both pointers are set to the head of the linked list. The pointers are moved forward with their respective speeds until either the fast pointer reaches the end of the linked list or both pointers meet at the same node.

If the fast pointer reaches the end, it means that there is no cycle and the function returns false. If the pointers meet at some point in the linked list, there is a cycle and the function returns true.