I have written a code to recursively remove the adjacent duplicates from a string
class Solution{
String rremove(String s) {
// code here
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < s.length()) {
char currentChar = s.charAt(i);
int j = i + 1;
// Find the index of the next different character
while (j < s.length() && s.charAt(j) == currentChar) {
j++;
}
// If adjacent duplicates found, skip them
if (j - i > 1) {
i = j;
} else {
sb.append(currentChar);
i++;
}
}
String result = sb.toString();
// If result string is different from original, recursively call the function
if (!result.equals(s)) {
return rremove(result);
}
return result;
}
Now, I want to understand the time complexity of this code as the number of recursive calls is not fixed here, hence got quite confused looking at the code. Although, each method call is O(n), but with the depth of recursion, it gets uncertain. Hence, please help me understand the best case and worst case scenarion for this code.
The code is from GFG with this title "Recursively remove all adjacent duplicates "
If we exclude the recursive call from the analysis, the complexity is indeed O(𝑛). This is also the best case time complexity, i.e. when no recursive call is made because there are no adjacent duplicates in the input.
When we incorporate the recursive call, then the worst case occurs when you have a palindrome where the only duplicate character occurs at the center. For instance abababababbababababa
. Now we have calls of rremove
that get strings of length 𝑛, then 𝑛−2, 𝑛−4, ... 2, 0.
And so the worst-case time complexity is O(𝑛²).
The worst-case time complexity can be improved by popping characters from the end of the StringBuilder instance when they are found equal to the current character.
Here is an implementation:
static String rremove(String s) {
StringBuilder sb = new StringBuilder();
boolean skip = false;
char currentChar = ' ';
for (int i = 0; i < s.length(); i++) {
if (!skip || s.charAt(i) != currentChar) {
currentChar = s.charAt(i);
skip = sb.length() > 0 && currentChar == sb.charAt(sb.length() - 1);
if (skip) {
sb.setLength(sb.length() - 1);
} else {
sb.append(currentChar);
}
}
}
return sb.toString();
}
This has linear time complexity.