Last Updated: March 29, 2026
We have two strings where the # character acts like a backspace key. When you encounter a #, it deletes the character immediately before it (if one exists). If the text is already empty, the backspace does nothing.
Our job is to figure out whether both strings produce the same final result after processing all the backspaces.
The simplest way to think about this: simulate what a text editor does. Process each string character by character, applying backspaces as you go, then compare the two results. But the follow-up asks us to do this without building the final strings at all, which pushes us toward a clever two-pointer approach that works backwards through both strings.
1 <= s.length, t.length <= 200 → With lengths at most 200, even an O(n^2) approach would be fast. But the follow-up challenges us to achieve O(n) time and O(1) space.s and t only contain lowercase letters and '#' characters → No uppercase, no special characters beyond #. Simple character handling.The most natural way to think about this: simulate exactly what a text editor does. You read characters from left to right. If you see a regular letter, type it. If you see a #, press backspace (delete the last character you typed).
This is textbook stack behavior. Push letters onto the stack, and pop when you hit a #. After processing both strings, whatever remains in each stack is the final text. If they match, return true.
# and the stack isn't empty, pop the top element.s and t.This approach works correctly but uses O(n + m) extra space to store the built strings. What if we could compare the strings character by character without ever constructing them?
Here's the key insight: backspaces only affect characters to their left. So if we process the strings from right to left, we can handle backspaces as we encounter them. When we see a #, we know some number of upcoming characters (moving leftward) need to be skipped. We keep a counter of how many characters to skip.
The approach works like this: start two pointers at the end of each string. For each string, walk left while skipping characters that have been "backspaced." Once both pointers land on a character that actually survives, compare them. If they differ, the strings aren't equal. If both pointers exhaust their strings at the same time, the strings are equal.
The reason we can process backwards is that a # only ever affects characters to its left. When we walk from right to left, we encounter the # before the characters it would delete. So we simply count how many characters to skip and skip them as we continue leftward.
This is different from processing forward, where you don't know if the current character will be deleted by a future #. By going backwards, every # we see immediately tells us to skip one future (leftward) character. There's no ambiguity.
i at the end of s and pointer j at the end of t.skipS = 0 and skipT = 0 to count pending backspaces.i >= 0 or j >= 0:i leftward, processing backspaces for s:s[i] is #, increment skipS and move left.skipS > 0, decrement skipS (skip this character) and move left.i is at a valid character. Stop.j with string t.i >= 0 and j >= 0: compare s[i] and t[j]. If they differ, return false.i and j to move to the next characters.