Linear Patterns (1D)
To catch someone on a circular track, you don't run at the same speed. You run faster. Eventually, you're guaranteed to meet.
How can you detect a cycle in a sequence? Try this problem before reading on.
Problem: Linked List Cycle: (LeetCode Link) : Given a linked list, determine if it has a cycle in it. 💡 HintUse two pointers moving at different speeds.
One approach to solve the above problem is to store every node you visit in a hash set, but do we really need to use extra space? The most optimal solution here is to use the tortoise and hare algorithm (fast and slow pointers).
The general algorithm is as follows:
slow and fast pointers at the beginning of the list.slow by one step (slow = slow.next) and fast by two steps (fast = fast.next.next).def hasCycle(head):
if not head or not head.next:
return False
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;
}
}
return false;
}
bool hasCycle(ListNode *head) {
if (head == nullptr || head->next == nullptr) return false;
ListNode *slow = head;
ListNode *fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
return true;
}
}
return false;
}
Another variation of this pattern is the Read-Write Pointer. This is often used to modify an array in-place.
read) iterates through the array to examine every element. A second pointer (write) lags behind, only moving when it needs to place a valid element. This ensures that you don't overwrite data before you've had a chance to read it.