Topicsβ€ΊStackβ€ΊRemove All Adjacent Duplicates
πŸ“–

Remove All Adjacent Duplicates

Stack
~20 min read
5 practice problems

Overview

Remove adjacent duplicates: repeatedly remove two adjacent duplicate characters until no more can be removed (e.g. "abbaca" β†’ "ca"). Use a stack: for each character, if it equals the top of the stack, pop; otherwise push. The stack is the current string without adjacent duplicates; join at the end.


When to Use

  • Remove pairs of adjacent same chars β€” stack: match with top, pop; else push.
  • Remove k adjacent same chars β€” stack of (char, count); when count reaches k, pop.
  • Candy crush / match-3 style β€” same "collapse when run length β‰₯ k" idea.

How It Works

One pass. Stack = "result so far" with no adjacent duplicates. New char: if same as top, pop (cancel pair); else push. Final string = stack joined.


Example 1: Standard (Remove 2 Adjacent)

function removeDuplicates(s: string): string {
  const stack: string[] = [];
  for (const c of s) {
    if (stack.length > 0 && stack[stack.length - 1] === c) stack.pop();
    else stack.push(c);
  }
  return stack.join('');
}

Time: O(n). Space: O(n).


Example 2: Remove K Adjacent Duplicates

Remove k or more adjacent same characters. Store (char, count). Push: if same as top, increment count; if count === k, pop; else push (c, 1). New char different from top: push (c, 1).

function removeDuplicatesK(s: string, k: number): string {
  const stack: [string, number][] = [];
  for (const c of s) {
    if (stack.length > 0 && stack[stack.length - 1][0] === c) {
      stack[stack.length - 1][1]++;
      if (stack[stack.length - 1][1] === k) stack.pop();
    } else stack.push([c, 1]);
  }
  return stack.map(([ch, cnt]) => ch.repeat(cnt)).join('');
}

Example 3: Step-by-Step Trace

s = "abbaca". a: push β†’ [a]. b: push β†’ [a,b]. b: same as top, pop β†’ [a]. a: push β†’ [a,a]. a: same as top, pop β†’ [a]. c: push β†’ [a,c]. Result "ac".


Example 4: Edge Cases

  • Empty string: stack stays empty β†’ "".
  • All duplicates: "aaaa" β†’ push, pop, push, pop β†’ "".
  • No duplicates: "abc" β†’ [a,b,c] β†’ "abc".
  • Alternating: "abab" β†’ no adjacent same β†’ "abab".

Example 5: In-Place with Two Pointers (Optional)

Use a slow index as "stack top": result[0..slow] is the current string. For each char, if slow β‰₯ 0 and result[slow] === c, slow--; else result[++slow] = c. Return result.slice(0, slow + 1). Same logic, O(1) extra space if we can overwrite input.


Summary

  • Remove 2 adjacent: stack; if top === c pop else push; join stack.
  • Remove k adjacent: stack of (char, count); increment or push; pop when count === k. See Stack Basics.