LeetCode 1910 Remove All Occurrences of a Substring - Optimal Solution using stack (Med, Java, O(n))


Overall Strategy
The algorithm uses a stack simulation with a character array to efficiently remove all occurrences of a substring. It processes the string character by character and removes matching substrings as soon as they're detected.
Code Breakdown
Static Block (Warmup)
static {
for (int i = 0; i < 100; i++) {
removeOccurrences("daabcbaabcbc", "abc");
}
}
This runs the method 100 times during class loading to "warm up" the JVM - optimizing performance for online judges that run multiple test cases.
Main Algorithm
1. Setup:
char[] pt = part.toCharArray(); // Convert substring to char array
char[] stack = new char[s.length()]; // Stack simulation (max size = s.length)
int m = pt.length, size = 0; // m = substring length, size = stack size
char end = pt[m - 1]; // Last character of substring
2. Process each character:
for (char cur : s.toCharArray()) {
stack[size++] = cur; // Always add current character to stack
// Check if we might have a complete match
if (cur == end && size >= m) {
// Potential match found - verify backwards
}
}
3. Match verification (the tricky part):
if (cur == end && size >= m) {
int j = m - 1, k = size - j - 1; // j = pattern index, k = stack start position
while (j >= 0 && stack[k + j] == pt[j])
j--;
if (j < 0) size = j + k + 1; // Match found - "pop" the substring
}
How the Match Verification Works
Let's trace through an example: s = "daabcbaabcbc"
, part = "abc"
When we encounter 'c' (potential end of "abc"):
j = 2
(last index of "abc")k = size - j - 1 = size - 3
(start position to check in stack)- Compare backwards:
stack[k+2] == 'c'
,stack[k+1] == 'b'
,stack[k] == 'a'
- If all match,
j
becomes-1
, so we "pop" by settingsize = j + k + 1 = k
Visual Example
s = "daabcbaabcbc", part = "abc"
Step by step:
stack: [d] -> [d,a] -> [d,a,a] -> [d,a,a,b] -> [d,a,a,b,c]
↑
'c' matches end of "abc"
Check backwards: a,b,c ✓
Remove 3 chars: stack = [d,a]
Continue: [d,a,b] -> [d,a,b,a] -> [d,a,b,a,a] -> [d,a,b,a,a,b] -> [d,a,b,a,a,b,c]
↑
Check: a,b,c ✓
Remove: [d,a,b,a]
Continue: [d,a,b,a,b] -> [d,a,b,a,b,c]
↑
Check: a,b,c ✓
Remove: [d,a,b]
Final result: "dab"
Why It's Efficient
- Single Pass: O(n) time complexity - each character is processed once
- Space Efficient: Uses a character array instead of StringBuilder
- Early Detection: Only checks for matches when the last character matches
- No String Operations: Avoids expensive string creation during processing
This is much faster than the naive approach that repeatedly searches and replaces, especially for cases with many overlapping occurrences.
Subscribe to my newsletter
Read articles from Anni Huang directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Anni Huang
Anni Huang
I am Anni HUANG, a software engineer with 3 years of experience in IDE development and Chatbot.