Removing Stars From a String
Problem
s mixes lowercase letters and '*' characters.
Each star acts like a backspace: it erases itself together with the closest
not-yet-erased letter on its left. Apply this for every star and return what remains.
The input guarantees every star has a letter available to erase, and the result is unique.s = "leet**cod*e"Output"lecoe"s = "erase*****"Output""s = "ab*c"Output"ac"1 ≤ s.length ≤ 105 · s has lowercase letters and '*' · the operation is always possible
Try it yourself
class Solution {
public String removeStars(String s) {
}
}
Instinct Things resolve in reverse order of arrival (brackets, adjacent pairs, nested expressions) - push now, pop when its partner shows up.
Memory hack Last in, first out - like a pile of plates, you only ever touch the one on top; every closer pops its opener.
Open the Stack guide →Approaches
Brute ForceSimulate Each Star with Deletions
O(n2)Space O(n)Find the leftmost star; the character just before it is the nearest kept letter (anything earlier is a letter, since earlier stars are already gone). Delete both and repeat. Every deletion shifts the tail of the buffer, so many stars make it quadratic.
public String removeStars(String s) { StringBuilder sb = new StringBuilder(s); int i = 0; while (i < sb.length()) { if (sb.charAt(i) == '*') { sb.delete(i - 1, i + 1); // the star and its left letter, O(n) shift i--; // continue right where the letter was } else { i++; } } return sb.toString(); }
Direct translation of the rules, but O(n²) for star-heavy inputs.
BetterExplicit Stack
O(n)Space O(n)Scan once. Push each letter; on a star pop the top, which is exactly the nearest surviving letter to the left. The stack, read from bottom to top, is the answer.
public String removeStars(String s) { Deque<Character> stack = new ArrayDeque<>(); for (char c : s.toCharArray()) { if (c == '*') stack.pop(); // guaranteed non-empty else stack.push(c); } StringBuilder sb = new StringBuilder(); while (!stack.isEmpty()) sb.append(stack.pollLast()); // bottom first return sb.toString(); }
Linear, but uses a boxed Deque plus a rebuild step.
OptimalWrite Pointer (char[] as Stack)
O(n)Space O(n)Let the array prefix a[0..w-1] be the stack. A letter is written at
w and w grows; a star just decrements w.
w never exceeds the read index, so overwriting is safe. Return the first
w characters.
public String removeStars(String s) { char[] a = s.toCharArray(); int w = 0; // size of the kept prefix for (int r = 0; r < a.length; r++) { if (a[r] == '*') w--; // erase the last kept letter else a[w++] = a[r]; } return new String(a, 0, w); }
Dry run"ab*c*d"
- r=1abr*wc*dkept "ab"
- r=2abw*rc*dstar → w=1
- r=3ac*wcr*dwrite c, w=2
- r=4acw*c*rdstar → w=1
- r=5ad*wc*drreturn "ad" ✔
Single pass with the smallest constant factor — only the output buffer.
At a glance
| Level | Approach | Time | Space |
|---|---|---|---|
| Brute Force | Simulate Each Star with Deletions | O(n2) | O(n) |
| Better | Explicit Stack | O(n) | O(n) |
| Optimal | Write Pointer (char[] as Stack) | O(n) | O(n) |
- Erasing the nearest letter to the right of the star instead of the left.
- Building the result with
s.substring/string concatenation in a loop — O(n²). - Reading the Deque top-first — produces the answer reversed.
- Spot the backspace analogy right away — it screams “stack”.
- Note the guarantee means no empty-stack check is required (mention it anyway).
- Finish with the in-place write pointer to show constant-factor awareness.