Back to DSA & Algorithms
DSA & Algorithms
easy
mid

How would you compare two linked lists for equality?

Walk both lists in lockstep with two pointers; at each step compare values; return false on first mismatch or unequal length. O(min(m,n)) time, O(1) space. Variants: compare for value-equality regardless of node identity; deep-compare lists of lists (recursion); compare cyclic lists (detect cycle with Floyd's, then compare lengths + values).

3 min read·~15 min to think through

Comparing two singly-linked lists is the linked-list version of array equality — a clean two-pointer walk.

Basic implementation

js
function equal(a, b) {
  while (a && b) {
    if (a.value !== b.value) return false;
    a = a.next;
    b = b.next;
  }
  return a === null && b === null;     // both ended together
}

Time O(min(m, n) + 1), Space O(1).

The a === null && b === null check matters — if one list is shorter, the loop ends but they're not equal.

Deep equality

If values can be objects or nested structures:

js
function deepEqual(a, b) {
  while (a && b) {
    if (!deepEq(a.value, b.value)) return false;
    a = a.next; b = b.next;
  }
  return a === null && b === null;
}

function deepEq(x, y) {
  if (x === y) return true;
  if (typeof x !== "object" || x === null || typeof y !== "object" || y === null) return false;
  const ka = Object.keys(x), kb = Object.keys(y);
  if (ka.length !== kb.length) return false;
  return ka.every((k) => deepEq(x[k], y[k]));
}

Cyclic lists

If the lists may have cycles, the walk-to-null approach is an infinite loop. Detect cycles with Floyd's for each list first, then compare lengths (cycle + tail) and walk with bounded steps:

js
function detectCycle(head) {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow.next; fast = fast.next.next;
    if (slow === fast) return slow;     // meeting point
  }
  return null;
}

For cyclic comparison, compute (tail length, cycle length, cycle structure) for both and compare structurally.

By-reference vs by-value

js
function sameList(a, b) { return a === b; }    // reference equality only

Common interview clarification: "compare the lists" almost always means value equality. Ask.

Compare two reversed lists (palindrome variant)

A related problem: "is this list a palindrome?" — find midpoint with fast/slow, reverse second half, compare halves, restore.

Edge cases

  • Both empty → equal.
  • One empty, one non-empty → not equal.
  • Same length, different values → not equal.
  • Same values, different lengths → not equal.
  • Cycle on one only → not equal (the non-cyclic ends; cyclic doesn't).

Linked list vs Array

If the problem allows, copying both lists to arrays makes comparison trivial — but uses O(n) space. The pointer walk is the canonical answer.

Interview framing

"Two-pointer walk: advance both lists in lockstep; on the first value mismatch, return false; when the loop exits, equal iff both pointers are null (same length). O(min(m, n)) time, O(1) space. Watch for the length-mismatch edge case — that's the bug interviewers look for. If values can be objects, swap !== for a deep-equal. If lists can be cyclic, detect cycles first (Floyd's) and compare structurally — naive walk-to-null would loop forever."

Follow-up questions

  • What's the bug in `while (a && b) { ... } return true;` (without the final null check)?
  • How would you handle deep value equality (object values)?
  • How do you compare two cyclic linked lists?
  • Could you do it recursively, and what's the cost?

Common mistakes

  • Returning true at the end of the while loop without checking both are null.
  • Crashing on null values inside the list when using shallow `!==`.
  • Infinite loop on cyclic lists.
  • Confusing reference equality with value equality.

Performance considerations

  • O(min(m,n)) time, O(1) space iteratively. Recursive version is O(n) space (stack). Deep equality multiplies cost by value size.

Edge cases

  • Both empty.
  • Different lengths with shared prefix.
  • Cycles in one or both.
  • Object values requiring deep equality.

Real-world examples

  • Equality checks in immutable list libraries (Immutable.js, Mori).
  • Test framework deep equals on list-shaped data.

Senior engineer discussion

Seniors get the final length-check right, clarify whether equality is reference or value, handle cycles defensively, and pick the iterative form by default to avoid stack overflow on long lists.

Related questions