Advanced Linked List Manipulation: Pair Swapping, Nth Node Removal, Intersection Detection, and Cycle Analysis
Swapping Adjacent Nodes in Pairs
Iterative reconfiguration requires a sentinel node to manage boundary conditions and a systematic pointer update sequence. To avoid breaking the chain during link redirection, temporary references must capture the nodes immediately preceding the swap boundaries and the remainder of the list. The iteration proceeds as long as two subsequent nodes are available for exchange.
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
sentinel = ListNode(0, head)
current = sentinel
while current.next and current.next.next:
first_node = current.next
second_node = current.next.next
remainder = second_node.next
current.next = second_node
second_node.next = first_node
first_node.next = remainder
current = first_node
return sentinel.next
Removing the N-th Node from the List End
The optimal strategy employs a dual-pointer sliding window to achieve single-pass complexity. A virtual head node standardizes edge-case handling. By advancing a leading pointer n + 1 steps ahead of a trailing pointer, the trailing pointer naturally positions itself at the direct predecessor of the target node once the leader reaches the terminus. This eliminates the need for explicit length calculations or list reversals.
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
anchor = ListNode(0, head)
fast, slow = anchor, anchor
# Create the required offset
for _ in range(n + 1):
fast = fast.next
# Move in tandem until the fast pointer reaches the boundary
while fast:
fast = fast.next
slow = slow.next
# Unlink the target node
slow.next = slow.next.next
return anchor.next
Identifying Intersection Nodes Across Two Lists
Intersection detection relies on verifying object identity (memory addresses) rather than value equality. The synchronization technique exploits path length commutativity. Two pointers traverse their respective lists; upon reaching a None terminus, each pointer seamlessly continues into the opposing list. Both pointers will have traveled exactly len(A) + len(B) nodes when they align. If a shared segment exists, they converge at the initial intersection. Otherwise, both simultaneously resolve to None.
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
pointer_a = headA
pointer_b = headB
while pointer_a != pointer_b:
pointer_a = pointer_a.next if pointer_a else headB
pointer_b = pointer_b.next if pointer_b else headA
return pointer_a
Detecting and Locating Linked List Cycles
Floyd’s algorithm bifurcates the problem into cycle verification and entry point calculation. Initially, a slow pointer advances at one step while a fast pointer advances at two steps per iteration. Within a loop, the fast pointer inevitably laps the slow pointer. The mathematical relationship dictates that the distance from the head to the cycle entrance equals the distance from the meeting node back to the entrance, modulo loop iterations. Resetting the slow pointer to the head and advancing both pointers at a uniform single-step pace ensures they intersect precisely at the cycle's starting node.
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return None
slow, fast = head, head
# Phase 1: Verify loop existence
has_cycle = False
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
has_cycle = True
break
if not has_cycle:
return None
# Phase 2: Calculate entry coordinates
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow