πŸ”§ JavaScript Linked List Operations

Pattern 1 β€” Reverse a Linked List

🧠 How to Approach This

Step 1 β€” Recognize the pattern: In-place pointer reversal with 3 variables.

Step 2 β€” Brute force (what NOT to do): Push to array, rebuild β€” O(n) space.

Step 3 β€” Optimal insight: prev/curr/next swap loop.

Step 4 β€” Algorithm:

1. prev = null, curr = head

2. Each step: save next, flip curr.next = prev, advance both

3. Return prev

Step 5 β€” Edge cases: Empty or single node.

function reverseList(head) {
  let prev = null, curr = head;
  while (curr) {
    const next = curr.next;
    curr.next  = prev;
    prev       = curr;
    curr       = next;
  }
  return prev;
}

Time: O(n) | Space: O(1)


Pattern 2 β€” Find Middle (Slow/Fast)

🧠 How to Approach This

Step 1 β€” Recognize the pattern: Fast pointer moves 2x, slow moves 1x.

Step 2 β€” Brute force (what NOT to do): Count, walk n/2 β€” two passes.

Step 3 β€” Optimal insight: One pass β€” when fast hits end, slow is at middle.

Step 4 β€” Algorithm:

1. slow = fast = head

2. While fast && fast.next: slow++, fast += 2

3. Return slow

Step 5 β€” Edge cases: Even length returns second middle.

function findMiddle(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }
  return slow;
}

Time: O(n) | Space: O(1)


Pattern 3 β€” Detect Cycle

🧠 How to Approach This

Step 1 β€” Recognize the pattern: If cycle exists, fast pointer laps slow pointer.

Step 2 β€” Brute force (what NOT to do): Store visited nodes in a Set β€” O(n) space.

Step 3 β€” Optimal insight: Floyd's: slow+1, fast+2. They meet inside cycle.

Step 4 β€” Algorithm:

1. slow = fast = head

2. Advance; if they meet === β†’ cycle

3. Loop exits β†’ no cycle

Step 5 β€” Edge cases: null or 1 node without self-loop β†’ false.

function hasCycle(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
    if (slow === fast) return true;
  }
  return false;
}

Time: O(n) | Space: O(1)


Pattern 4 β€” Merge Two Sorted Lists

🧠 How to Approach This

Step 1 β€” Recognize the pattern: Two-pointer merge step from merge sort.

Step 2 β€” Brute force (what NOT to do): Collect, sort, rebuild β€” O(n log n).

Step 3 β€” Optimal insight: Compare heads, attach smaller, advance that pointer.

Step 4 β€” Algorithm:

1. Dummy head

2. While both exist: attach smaller, advance

3. Attach remainder

Step 5 β€” Edge cases: Either list empty.

function mergeTwoLists(l1, l2) {
  const dummy = new ListNode(0);
  let tail = dummy;
  while (l1 && l2) {
    if (l1.val <= l2.val) { tail.next = l1; l1 = l1.next; }
    else                  { tail.next = l2; l2 = l2.next; }
    tail = tail.next;
  }
  tail.next = l1 ?? l2;
  return dummy.next;
}

Time: O(n + m) | Space: O(1)


Pattern 5 β€” Remove Nth From End

🧠 How to Approach This

Step 1 β€” Recognize the pattern: Two pointers with gap of N+1 β€” one pass.

Step 2 β€” Brute force (what NOT to do): Count length, walk to position β€” two passes.

Step 3 β€” Optimal insight: Advance fast N+1 steps first, then move both until fast = null.

Step 4 β€” Algorithm:

1. Dummy, fast advances N+1 steps

2. Move both until fast = null

3. slow.next = slow.next.next

Step 5 β€” Edge cases: Remove head node β€” dummy handles.

function removeNthFromEnd(head, n) {
  const dummy = new ListNode(0, head);
  let slow = dummy, fast = dummy;
  for (let i = 0; i <= n; i++) fast = fast.next;
  while (fast) { slow = slow.next; fast = fast.next; }
  slow.next = slow.next.next;
  return dummy.next;
}

Time: O(n) | Space: O(1)


Pattern 6 β€” Intersection of Two Lists

🧠 How to Approach This

Step 1 β€” Recognize the pattern: Path equalisation β€” traverse A+B and B+A.

Step 2 β€” Brute force (what NOT to do): Store all A nodes in a Set, traverse B.

Step 3 — Optimal insight: a walks A→B, b walks B→A. Equal total distance → meet at intersection.

Step 4 β€” Algorithm:

1. a = headA, b = headB

2. Advance; switch heads on null

3. Return when a === b

Step 5 β€” Edge cases: No intersection β†’ both null together.

function getIntersectionNode(headA, headB) {
  let a = headA, b = headB;
  while (a !== b) {
    a = a !== null ? a.next : headB;
    b = b !== null ? b.next : headA;
  }
  return a;
}

Time: O(n + m) | Space: O(1)