Problem
Given two strings s
and part
, perform the following operation on s
until all occurrences of the substring part
are removed:
- Find the leftmost occurrence of the substring
part
and remove it froms
.
Return s
after removing all occurrences of part
.
A substring is a contiguous sequence of characters in a string.
Examples
Example 1:
Input: s = "daabcbaabcbc", part = "abc"
Output: "dab"
**Explanation** : The following operations are done:
- s = "da** _abc_** baabcbc", remove "abc" starting at index 2, so s = "dabaabcbc".
- s = "daba** _abc_** bc", remove "abc" starting at index 4, so s = "dababc".
- s = "dab** _abc_** ", remove "abc" starting at index 3, so s = "dab".
Now s has no occurrences of "abc".
Example 2:
Input: s = "axxxxyyyyb", part = "xy"
Output: "ab"
**Explanation** : The following operations are done:
- s = "axxx** _xy_** yyyb", remove "xy" starting at index 4 so s = "axxxyyyb".
- s = "axx** _xy_** yyb", remove "xy" starting at index 3 so s = "axxyyb".
- s = "ax** _xy_** yb", remove "xy" starting at index 2 so s = "axyb".
- s = "a** _xy_** b", remove "xy" starting at index 1 so s = "ab".
Now s has no occurrences of "xy".
Constraints:
1 <= s.length <= 1000
1 <= part.length <= 1000
s
andpart
consists of lowercase English letters.
Solution
Video explanation
Here is the video explaining below methods in detail. Please check it out:
Method 1 - Naive
This approach continues to remove the substring part
from the string s
until no more occurrences are found. It uses the contains
method to check for the presence of part
and the indexOf
method to find its position. The substring
method is used to rebuild the string without the part
.
Code
Java
class Solution {
public String removeOccurrences(String s, String part) {
int idx;
while ((idx = s.indexOf(part)) != -1) {
s = s.substring(0, idx) + s.substring(idx + part.length());
}
return s;
}
}
Python
class Solution:
def removeOccurrences(self, s: str, part: str) -> str:
while part in s:
idx = s.find(part)
s = s[:idx] + s[idx + len(part):]
return s
Complexity
- ⏰ Time complexity:
O((n/m) * n)
, wheren
is the length of the strings
andm
is the length of the substringpart
. In the worst case, each removal might take up toO(n)
time, and we might have to do thisn/m
times. - 🧺 Space complexity:
O(n)
due to the creation of new strings during each iteration.
Method 2 - Naive - Delete chars in mutable string
To solve this problem, we can use a simple iterative approach:
- We will keep looking for the
part
in strings
. - As long as the
part
is found, we will remove it by reconstructing the string. - Once no more occurrences of
part
are found, we return the modified string.
This approach leverages the built-in string functions efficiently to find and modify the string iteratively.
Code
Java
We use a StringBuilder
to facilitate efficient modifications. The indexOf
method helps find the leftmost occurrence of part
, and the delete
method removes it.
class Solution {
public String removeOccurrences(String s, String part) {
StringBuilder ans = new StringBuilder(s);
int idx;
while ((idx = ans.indexOf(part)) != -1) {
ans.delete(idx, idx + part.length());
}
return ans.toString();
}
}
Python
class Solution:
def removeOccurrences(self, s: str, part: str) -> str:
ans = list(s)
m = len(part)
i = 0
while i <= len(ans) - m:
if "".join(ans[i:i + m]) == part:
ans = ans[:i] + s_list[i + part_len:]
i = max(0, i - m) # Reset index to check for overlapping parts
else:
i += 1
return "".join(ans)
Complexity
- ⏰ Time complexity:
O(n ^ 2 / m)
. In the worst case, this might need to iterate through the length of the strings
multiple times. - 🧺 Space complexity:
O(1)
additional space, butO(n)
if we consider the space for the result string.
Method 3 - Using Stack
Here is the approach:
- Traverse the string from the beginning, pushing each character onto a stack until its size matches that of
part
. - When the stack’s size equals
part
, check characters from the end ofpart
against the top of the stack. If they match, pop the stack for each matching character. - If a character in
part
does not match the top of the stack, refill the stack with the previously checked characters and continue. - After processing, build the final string using the remaining characters in the stack by converting them with
StringBuilder
or equivalent.
Code
Java
class Solution {
public String removeOccurrences(String s, String part) {
Stack<Character> stack = new Stack<>();
int m = part.length();
for (char ch : s.toCharArray()) {
stack.push(ch);
if (stack.size() >= m) {
StringBuilder temp = new StringBuilder();
boolean isMatch = true;
for (int i = m - 1; i >= 0; i--) {
if (stack.isEmpty() || stack.peek() != part.charAt(i)) {
isMatch = false;
break;
}
temp.append(stack.pop());
}
if (!isMatch) {
for (int i = temp.length() - 1; i >= 0; i--) {
stack.push(temp.charAt(i));
}
}
}
}
StringBuilder ans = new StringBuilder();
while (!stack.isEmpty()) {
ans.append(stack.pop());
}
return ans.reverse().toString();
}
}
Python
class Solution:
def removeOccurrences(self, s: str, part: str) -> str:
stack: list[str] = []
m: int = len(part)
for ch in s:
stack.append(ch)
if len(stack) >= m:
temp = []
is_match = True
for j in range(m - 1, -1, -1):
if not stack or stack[-1] != part[j]:
is_match = False
break
temp.append(stack.pop())
if not is_match:
stack.extend(reversed(temp))
return ''.join(stack)
Complexity
- ⏰ Time complexity:
O(n.m)
, because for each character ins
, checking the topm
characters of the stack for a match takes O(m) time. - 🧺 Space complexity:
O(n + m)
, because the stack usesO(n)
space, and temporary matching substring useO(m)
space.
Method 4 - Using Stack String
The idea is to use a stack to build the resulting string while checking for the part
substring on the fly.
- Initialise an empty list to use as a stack.
- Iterate through the string
s
, pushing each character onto the stack. - Each time you push a character, check if the top of the stack forms the
part
string. - If it does, pop
part.length
characters from the stack to remove thepart
substring. - After processing all characters, join the stack to form the resulting string.
Code
Java
class Solution {
public String removeOccurrences(String s, String part) {
StringBuilder stack = new StringBuilder();
int m = part.length();
for (char c : s.toCharArray()) {
stack.append(c);
int len = stack.length();
if (len >= m &&
stack.substring(len - m).equals(part)) {
stack.delete(len - m, len);
}
}
return stack.toString();
}
}
Python
class Solution:
def removeOccurrences(self, s: str, part: str) -> str:
stack: list[str] = []
m: int = len(part)
for ch in s:
stack.append(ch)
if len(stack) >= m and ''.join(stack[-m:]) == part:
del stack[-m:]
return ''.join(stack)
Complexity
- ⏰ Time complexity:
O(n.m)
, wheren
is the length of the strings
. Each character is processed once. - 🧺 Space complexity:
O(n)
, as we might need to store all characters in the stack.