Remove a Character from a String: In-Place, Two-Pointer, Stream

Remove a Character from a String: In-Place, Two-Pointer, and Stream Variants

Removing characters from a string is a foundational interview problem that tests in-place manipulation, two-pointer technique, and the realization that strings are immutable in many languages. The base problem — remove all occurrences of a target character — is simple enough to solve in 30 seconds. Interviewers use it as a warm-up, then push into harder variants: remove duplicates, remove characters matching a set, remove the kth occurrence, or stream-based filtering. This guide covers all the standard variants with working code.

Problem Statement

Given a string s and a character c, return a new string with all occurrences of c removed.

Examples:

  • s = "hello world", c = 'l'"heo word"
  • s = "abc", c = 'd'"abc"
  • s = "", any c → ""

Approach 1: List Comprehension / String Builder

Idiomatic in Python: filter and join.

def remove_char(s: str, c: str) -> str:
    """O(n) time, O(n) space — idiomatic Python."""
    return "".join(ch for ch in s if ch != c)


# Equivalent
def remove_char_alt(s: str, c: str) -> str:
    return s.replace(c, "")

str.replace is the practical answer in Python. Complexity: O(n) time, O(n) space (new string).

For interview purposes, write the comprehension version to demonstrate you can solve it manually, then mention replace.

Approach 2: In-Place with Two Pointers (For Mutable Arrays)

If the string is given as a mutable character array (Java, C++, or a list-of-characters in Python), use two pointers to remove in place. Read pointer scans the array; write pointer fills positions to keep.

def remove_char_inplace(chars: list[str], c: str) -> int:
    """Modify chars in place; return new length.
    O(n) time, O(1) extra space."""
    write = 0
    for read in range(len(chars)):
        if chars[read] != c:
            chars[write] = chars[read]
            write += 1
    return write


# Test
chars = list("hello world")
new_len = remove_char_inplace(chars, "l")
print("".join(chars[:new_len]))  # "heo word"

Complexity: O(n) time, O(1) space. The standard answer when interviewers specify “in place” or “no extra string allocation.”

Approach 3: Filter Multiple Characters

Generalize: remove all characters matching a set. Useful follow-up.

def remove_chars(s: str, to_remove: set) -> str:
    """O(n) time, O(n) space."""
    return "".join(ch for ch in s if ch not in to_remove)


# Test
print(remove_chars("hello world", {"l", "o"}))  # "he wrd"

Use set for O(1) lookups. str.translate in Python is the optimized stdlib alternative:

def remove_chars_translate(s: str, to_remove: str) -> str:
    """O(n) time using str.translate."""
    return s.translate(str.maketrans("", "", to_remove))

Approach 4: Remove Duplicates

(LeetCode #316, #1047 — Remove Adjacent Duplicates) Remove consecutive duplicate characters using a stack.

def remove_adjacent_duplicates(s: str) -> str:
    """O(n) time, O(n) space — stack-based."""
    stack = []
    for ch in s:
        if stack and stack[-1] == ch:
            stack.pop()
        else:
            stack.append(ch)
    return "".join(stack)


# Tests
print(remove_adjacent_duplicates("abbaca"))  # "ca"
print(remove_adjacent_duplicates("aaaa"))    # ""

The stack pattern repeatedly cancels adjacent equal characters, naturally handling the “after removal, new adjacencies appear” case.

Approach 5: Stream Filtering

For very large strings or true streaming use cases, generators avoid loading the full string in memory.

def filter_stream(stream, c):
    """Generator that yields characters from stream, skipping c."""
    for ch in stream:
        if ch != c:
            yield ch


# Usage with file streaming
# with open("large.txt") as f:
#     filtered = "".join(filter_stream(f.read(), "l"))

The interview rarely demands streaming, but mentioning the generator approach signals memory awareness.

Common Variations

Remove all whitespace

s.replace(" ", "") for spaces, or "".join(s.split()) to also collapse tabs/newlines. Or use str.translate with a whitespace set.

Remove kth occurrence

Track a counter; remove only when counter matches k. O(n) time.

def remove_kth_occurrence(s: str, c: str, k: int) -> str:
    result = []
    count = 0
    for ch in s:
        if ch == c:
            count += 1
            if count == k:
                continue
        result.append(ch)
    return "".join(result)

Remove all but k occurrences

Variant: keep the first k occurrences, remove the rest. Useful for deduplication-style problems.

Remove according to a predicate

Generalize to any predicate function. Most languages have stdlib filter equivalents (Python’s filter(), JavaScript’s Array.filter(), C++’s std::remove_if).

Sliding window with character removal

(LeetCode #3 — Longest Substring Without Repeating Characters) Different problem family. Sliding window pattern; remove characters from a window, not the string itself.

Common Mistakes

  • Treating Python strings as mutable. Strings are immutable; s[i] = "x" raises TypeError. Convert to list, modify, join. Or use the comprehension approach to build a new string.
  • Using += in a loop to build the result. In Python, result += ch in a loop is technically O(n²) due to string immutability and reallocation. Use a list with append and join at the end. CPython has internal optimizations that sometimes hide the cost, but the pattern is fragile.
  • Off-by-one in the two-pointer in-place version. The write pointer must advance only when the current character is kept; the read pointer always advances. Mixing up these conditions corrupts the output.
  • Returning new length but leaving stale data. If the caller uses the array after in-place removal, they should read only up to the returned length. Some implementations zero out the trailing positions; usually unnecessary.
  • Confusing “remove all occurrences” with “remove first occurrence.” Read the prompt carefully. str.replace removes all by default; s.replace(c, "", 1) removes only the first.

Frequently Asked Questions

What’s the expected interview answer?

List comprehension or two-pointer in-place, depending on whether the string is mutable in the interview’s language. Walk through both. Mention str.replace as the production-equivalent. The interviewer is checking whether you understand string immutability and two-pointer mechanics; clean code in either approach is sufficient.

Why is in-place removal preferred when applicable?

O(1) extra space versus O(n) for the new-string approach. For huge inputs (gigabyte-scale buffers, embedded systems with tight memory), in-place matters. For interview-sized inputs, the difference is negligible; the question is about technique, not performance.

How do I handle Unicode correctly?

Python strings are sequences of Unicode code points by default; iteration yields code points, not bytes. str.replace handles Unicode correctly. The two-pointer approach also works on lists of code points. Issues arise only at the byte level (e.g., when the string is encoded as UTF-8 bytes); avoid byte-level operations on Unicode strings.

What’s the most common follow-up?

Remove adjacent duplicates (LeetCode #1047) using a stack. The pattern teaches a different technique while sharing the “manipulate a string” theme. Other follow-ups: remove characters from a set; remove kth occurrence; sliding window for longest substring without repeats.

How does this generalize to other languages?

Java: convert to char[] for in-place; use StringBuilder for new-string approach; or String.replace. C++: use std::remove + erase idiom (the “remove-erase” pattern). JavaScript: String.replace with global flag, or Array.filter + Array.join. Go: strings.ReplaceAll. The two-pointer pattern is universal; the language-idiomatic stdlib varies.

See also: Longest Palindromic SubstringPrint String PermutationsTwo Sum: Find a Pair in an Array

💡Strategies for Solving This Problem

String Manipulation Basics

Simple problem that tests your understanding of strings and efficiency. Got this at Apple in 2023 as a warmup question.

The Problem

Remove all occurrences of a character from a string. For example, remove all 'a' from "banana" → "bnn".

Naive Approach: String Concatenation

Loop through string, build new string by concatenating characters that aren't the target.

Works but in languages where strings are immutable (like Java), each concatenation creates a new string object. O(n²) time.

Better: StringBuilder / Array

Use a mutable data structure. In Java, StringBuilder. In Python, list then join. In JavaScript, array then join.

O(n) time, O(n) space.

In-Place (For Mutable Strings)

If string is mutable (like char array in C), use two pointers:

  • Read pointer scans forward
  • Write pointer tracks where to write next keeper character
  • Overwrite array in place

O(n) time, O(1) space.

Built-In Methods

Most languages have built-ins: str.replace() in JavaScript, str.replace() in Python.

Know these exist, but interviewer usually wants you to implement it yourself.

At Apple

Started with naive approach. Interviewer asked "What if the string is a million characters long?" That's when I switched to array-based solution.

Then asked: "Remove multiple characters?" Pass a set of chars to remove instead of single char.

Scroll to Top