Given a string, recursively remove adjacent duplicate characters from the string. The output string should not have any adjacent duplicates. See the following examples.
Examples:
Input: azxxzy
Output: ay
- First “azxxzy” is reduced to “azzy”.
- The string “azzy” contains duplicates,
- so it is further reduced to “ay”.
Input: geeksforgeeg
Output: gksfor
- First “geeksforgeeg” is reduced to “gksforgg”.
- The string “gksforgg” contains duplicates,
- so it is further reduced to “gksfor”.
Input: caaabbbaacdddd
Output: Empty String
Input: acaaabbbacdddd
Output: acac
The following approach can be followed to remove duplicates in O(N) time:
- Start from the leftmost character and remove duplicates at left corner if there are any.
- The first character must be different from its adjacent now. Recur for string of length n-1 (string without first character).
- Let the string obtained after reducing right substring of length n-1 be rem_str. There are three possible cases
- If first character of rem_str matches with the first character of original string, remove the first character from rem_str.
- If remaining string becomes empty and last removed character is same as first character of original string. Return empty string.
- Else, append the first character of the original string at the beginning of rem_str.
- Return rem_str.
Below image is a dry run of the above approach:

Below is the implementation of the above approach:
C++14
#include <bits/stdc++.h>
using namespace std;
char * removeUtil( char * str, char * last_removed)
{
if (str[0] == '\0' || str[1] == '\0' )
return str;
if (str[0] == str[1]) {
*last_removed = str[0];
while (str[1] && str[0] == str[1])
str++;
str++;
return removeUtil(str, last_removed);
}
char * rem_str = removeUtil(str + 1, last_removed);
if (rem_str[0] && rem_str[0] == str[0]) {
*last_removed = str[0];
return (rem_str + 1);
}
if (rem_str[0] == '\0' && *last_removed == str[0])
return rem_str;
rem_str--;
rem_str[0] = str[0];
return rem_str;
}
char * remove ( char * str)
{
char last_removed = '\0' ;
return removeUtil(str, &last_removed);
}
int main()
{
char str1[] = "geeksforgeeg" ;
cout << remove (str1) << endl;
char str2[] = "azxxxzy" ;
cout << remove (str2) << endl;
char str3[] = "caaabbbaac" ;
cout << remove (str3) << endl;
char str4[] = "gghhg" ;
cout << remove (str4) << endl;
char str5[] = "aaaacddddcappp" ;
cout << remove (str5) << endl;
char str6[] = "aaaaaaaaaa" ;
cout << remove (str6) << endl;
char str7[] = "qpaaaaadaaaaadprq" ;
cout << remove (str7) << endl;
char str8[] = "acaaabbbacdddd" ;
cout << remove (str8) << endl;
char str9[] = "acbbcddc" ;
cout << remove (str9) << endl;
return 0;
}
|
C
#include <stdio.h>
#include <string.h>
char * removeUtil( char * str, char * last_removed)
{
if (str[0] == '\0' || str[1] == '\0' )
return str;
if (str[0] == str[1]) {
*last_removed = str[0];
while (str[1] && str[0] == str[1])
str++;
str++;
return removeUtil(str, last_removed);
}
char * rem_str = removeUtil(str + 1, last_removed);
if (rem_str[0] && rem_str[0] == str[0]) {
*last_removed = str[0];
return (rem_str + 1);
}
if (rem_str[0] == '\0' && *last_removed == str[0])
return rem_str;
rem_str--;
rem_str[0] = str[0];
return rem_str;
}
char * removes( char * str)
{
char last_removed = '\0' ;
return removeUtil(str, &last_removed);
}
int main()
{
char str1[] = "geeksforgeeg" ;
printf ( "%s\n" , removes(str1));
char str2[] = "azxxxzy" ;
printf ( "%s\n" , removes(str2));
char str3[] = "caaabbbaac" ;
printf ( "%s\n" , removes(str3));
char str4[] = "gghhg" ;
printf ( "%s\n" , removes(str4));
char str5[] = "aaaacddddcappp" ;
printf ( "%s\n" , removes(str5));
char str6[] = "aaaaaaaaaa" ;
printf ( "%s\n" , removes(str6));
char str7[] = "qpaaaaadaaaaadprq" ;
printf ( "%s\n" , removes(str7));
char str8[] = "acaaabbbacdddd" ;
printf ( "%s\n" , removes(str8));
char str9[] = "acbbcddc" ;
printf ( "%s\n" , removes(str9));
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static char last_removed;
static String removeUtil(String str)
{
if (str.length() == 0 || str.length() == 1 )
return str;
if (str.charAt( 0 ) == str.charAt( 1 )) {
last_removed = str.charAt( 0 );
while (str.length() > 1
&& str.charAt( 0 ) == str.charAt( 1 ))
str = str.substring( 1 , str.length());
str = str.substring( 1 , str.length());
return removeUtil(str);
}
String rem_str
= removeUtil(str.substring( 1 , str.length()));
if (rem_str.length() != 0
&& rem_str.charAt( 0 ) == str.charAt( 0 )) {
last_removed = str.charAt( 0 );
return rem_str.substring( 1 , rem_str.length());
}
if (rem_str.length() == 0
&& last_removed == str.charAt( 0 ))
return rem_str;
return (str.charAt( 0 ) + rem_str);
}
static String remove(String str)
{
last_removed = '\0' ;
return removeUtil(str);
}
public static void main(String args[])
{
String str1 = "geeksforgeeg" ;
System.out.println(remove(str1));
String str2 = "azxxxzy" ;
System.out.println(remove(str2));
String str3 = "caaabbbaac" ;
System.out.println(remove(str3));
String str4 = "gghhg" ;
System.out.println(remove(str4));
String str5 = "aaaacddddcappp" ;
System.out.println(remove(str5));
String str6 = "aaaaaaaaaa" ;
System.out.println(remove(str6));
String str7 = "qpaaaaadaaaaadprq" ;
System.out.println(remove(str7));
String str8 = "acaaabbbacdddd" ;
System.out.println(remove(str8));
}
}
|
Python
def removeUtil(string, last_removed):
if len (string) = = 0 or len (string) = = 1 :
return string
if string[ 0 ] = = string[ 1 ]:
last_removed = ord (string[ 0 ])
while len (string) > 1 and string[ 0 ] = = string[ 1 ]:
string = string[ 1 :]
string = string[ 1 :]
return removeUtil(string, last_removed)
rem_str = removeUtil(string[ 1 :], last_removed)
if len (rem_str) ! = 0 and rem_str[ 0 ] = = string[ 0 ]:
last_removed = ord (string[ 0 ])
return (rem_str[ 1 :])
if len (rem_str) = = 0 and last_removed = = ord (string[ 0 ]):
return rem_str
return ([string[ 0 ]] + rem_str)
def remove(string):
last_removed = 0
return toString(removeUtil(toList(string),
last_removed))
def toList(string):
x = []
for i in string:
x.append(i)
return x
def toString(x):
return ''.join(x)
string1 = "geeksforgeeg"
print remove(string1)
string2 = "azxxxzy"
print remove(string2)
string3 = "caaabbbaac"
print remove(string3)
string4 = "gghhg"
print remove(string4)
string5 = "aaaacddddcappp"
print remove(string5)
string6 = "aaaaaaaaaa"
print remove(string6)
string7 = "qpaaaaadaaaaadprq"
print remove(string7)
string8 = "acaaabbbacdddd"
print remove(string8)
string9 = "acbbcddc"
print remove(string9)
|
C#
using System;
class GFG {
static string removeUtil( string str, char last_removed)
{
if (str.Length == 0 || str.Length == 1)
return str;
if (str[0] == str[1]) {
last_removed = str[0];
while (str.Length > 1 && str[0] == str[1]) {
str = str.Substring(1, str.Length - 1);
}
str = str.Substring(1, str.Length - 1);
return removeUtil(str, last_removed);
}
string rem_str = removeUtil(
str.Substring(1, str.Length - 1), last_removed);
if (rem_str.Length != 0 && rem_str[0] == str[0]) {
last_removed = str[0];
return rem_str.Substring(1, rem_str.Length - 1);
}
if (rem_str.Length == 0 && last_removed == str[0])
return rem_str;
return (str[0] + rem_str);
}
static string remove( string str)
{
char last_removed = '\0' ;
return removeUtil(str, last_removed);
}
public static void Main()
{
string str1 = "geeksforgeeg" ;
Console.Write(remove(str1) + "\n" );
string str2 = "azxxxzy" ;
Console.Write(remove(str2) + "\n" );
string str3 = "caaabbbaac" ;
Console.Write(remove(str3) + "\n" );
string str4 = "gghhg" ;
Console.Write(remove(str4) + "\n" );
string str5 = "aaaacddddcappp" ;
Console.Write(remove(str5) + "\n" );
string str6 = "aaaaaaaaaa" ;
Console.Write(remove(str6) + "\n" );
string str7 = "qpaaaaadaaaaadprq" ;
Console.Write(remove(str7) + "\n" );
string str8 = "acaaabbbacdddd" ;
Console.Write(remove(str8) + "\n" );
string str9 = "acbbcdd" ;
Console.Write(remove(str9) + "\n" );
}
}
|
Javascript
<script>
function removeUtil(string, last_removed){
if (string.length == 0 || string.length == 1)
return string
if (string[0] == string[1]){
last_removed = string.charCodeAt(0)
while (string.length > 1 && string[0] == string[1])
string = string.substr(1,)
string = string.substr(1,)
return removeUtil(string, last_removed)
}
let rem_str = removeUtil(string.substr(1,), last_removed)
if (rem_str.length != 0 && rem_str[0] == string[0]){
last_removed = string.charCodeAt(0)
return rem_str.substr(1,)
}
if (rem_str.length == 0 && last_removed == string.charCodeAt(0))
return rem_str
let res = string[0] + rem_str
return res
}
function remove(string){
let last_removed = 0
return removeUtil(string,last_removed)
}
let string1 = "geeksforgeeg"
document.write(remove(string1), "</br>" )
let string2 = "azxxxzy"
document.write(remove(string2), "</br>" )
let string3 = "caaabbbaac"
document.write(remove(string3), "</br>" )
let string4 = "gghhg"
document.write(remove(string4), "</br>" )
let string5 = "aaaacddddcappp"
document.write(remove(string5), "</br>" )
let string6 = "aaaaaaaaaa"
document.write(remove(string6), "</br>" )
let string7 = "qpaaaaadaaaaadprq"
document.write(remove(string7), "</br>" )
let string8 = "acaaabbbacdddd"
document.write(remove(string8), "</br>" )
let string9 = "acbbcddc"
document.write(remove(string9), "</br>" )
</script>
|
Outputgksfor
ay
g
a
qrq
acac
a
Time Complexity: The time complexity of the solution can be written as T(n) = T(n-k) + O(k) where n is length of the input string and k is the number of first characters which are same. Solution of the recurrence is O(n)
Auxiliary Space: O(n)
Thanks to Prachi Bodke for suggesting this problem and initial solution.
Another Approach:
The idea here is to check whether the String remStr has the repeated character that matches the last char of the parent String. If that is happening then we have to keep removing that character before concatenating string s and string remStr.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
string removeDuplicates(string s, char ch)
{
if (s.length() <= 1) {
return s;
}
int i = 0;
while (i < s.length()) {
if (i + 1 < s.length() && s[i] == s[i + 1]) {
int j = i;
while (j + 1 < s.length() && s[j] == s[j + 1]) {
j++;
}
char lastChar = i > 0 ? s[i - 1] : ch;
string remStr = removeDuplicates(
s.substr(j + 1, s.length()), lastChar);
s = s.substr(0, i);
int k = s.length(), l = 0;
while (remStr.length() > 0 && s.length() > 0
&& remStr[0] == s[s.length() - 1]) {
while (remStr.length() > 0
&& remStr[0] != ch
&& remStr[0] == s[s.length() - 1]) {
remStr
= remStr.substr(1, remStr.length());
}
s = s.substr(0, s.length() - 1);
}
s = s + remStr;
i = j;
}
else {
i++;
}
}
return s;
}
int main()
{
string str1 = "mississipie" ;
cout << removeDuplicates(str1, ' ' ) << endl;
string str2 = "ocvvcolop" ;
cout << removeDuplicates(str2, ' ' ) << endl;
}
|
Java
import java.io.*;
import java.lang.*;
import java.util.*;
class GFG {
private static String removeDuplicates(String s,
char ch)
{
if (s == null || s.length() <= 1 ) {
return s;
}
int i = 0 ;
while (i < s.length()) {
if (i + 1 < s.length()
&& s.charAt(i) == s.charAt(i + 1 )) {
int j = i;
while (j + 1 < s.length()
&& s.charAt(j) == s.charAt(j + 1 )) {
j++;
}
char lastChar
= i > 0 ? s.charAt(i - 1 ) : ch;
String remStr = removeDuplicates(
s.substring(j + 1 , s.length()),
lastChar);
s = s.substring( 0 , i);
int k = s.length(), l = 0 ;
while (remStr.length() > 0 && s.length() > 0
&& remStr.charAt( 0 )
== s.charAt(s.length() - 1 )) {
while (remStr.length() > 0
&& remStr.charAt( 0 ) != ch
&& remStr.charAt( 0 )
== s.charAt(s.length()
- 1 )) {
remStr = remStr.substring(
1 , remStr.length());
}
s = s.substring( 0 , s.length() - 1 );
}
s = s + remStr;
i = j;
}
else {
i++;
}
}
return s;
}
public static void main(String[] args)
{
String str1 = "mississipie" ;
System.out.println(removeDuplicates(str1, ' ' ));
String str2 = "ocvvcolop" ;
System.out.println(removeDuplicates(str2, ' ' ));
}
}
|
Python3
def removeDuplicates(s, ch):
if ( len (s) < = 1 ):
return s
i = 0
while (i < len (s)):
if (i + 1 < len (s) and s[i] = = s[i + 1 ]):
j = i
while (j + 1 < len (s) and s[j] = = s[j + 1 ]):
j + = 1
lastChar = s[i - 1 ] if (i > 0 ) else ch
remStr = removeDuplicates(s[j + 1 : len (s)], lastChar)
s = s[ 0 : i]
k, l = len (s), 0
while ( len (remStr) > 0 and len (s) > 0
and remStr[ 0 ] = = s[ len (s) - 1 ]):
while ( len (remStr) > 0
and remStr[ 0 ] ! = ch
and remStr[ 0 ] = = s[ len (s) - 1 ]):
remStr = remStr[ 1 : len (remStr) + 1 ]
s = s[ 0 : len (s) - 1 ]
s = s + remStr
i = j
else :
i + = 1
return s
str1 = "mississipie"
print (removeDuplicates(str1, ' ' ))
str2 = "ocvvcolop"
print (removeDuplicates(str2, ' ' ))
|
C#
using System;
class HelloWorld {
static string removeDuplicates( string s, char ch)
{
if (s.Length <= 1) {
return s;
}
int i = 0;
while (i < s.Length) {
if (i + 1 < s.Length && s[i] == s[i + 1]) {
int j = i;
while (j + 1 < s.Length
&& s[j] == s[j + 1]) {
j++;
}
char lastChar = i > 0 ? s[i - 1] : ch;
string remStr = removeDuplicates(
s.Substring(j + 1, s.Length - j - 1),
lastChar);
s = s.Substring(0, i);
int k = s.Length;
while (remStr.Length > 0 && s.Length > 0
&& remStr[0] == s[s.Length - 1]) {
while (
remStr.Length > 0 && remStr[0] != ch
&& remStr[0] == s[s.Length - 1]) {
remStr = remStr.Substring(
1, remStr.Length - 1);
}
s = s.Substring(0, s.Length - 1);
}
s = s + remStr;
i = j;
}
else {
i++;
}
}
return s;
}
static void Main()
{
string str1 = "mississipie" ;
Console.WriteLine(removeDuplicates(str1, ' ' ));
string str2 = "ocvvcolop" ;
Console.WriteLine(removeDuplicates(str2, ' ' ));
}
}
|
Javascript
<script>
function removeDuplicates(s,ch)
{
if (s.length <= 1) {
return s;
}
let i = 0;
while (i < s.length) {
if (i + 1 < s.length && s[i] == s[i + 1]) {
let j = i;
while (j + 1 < s.length && s[j] == s[j + 1]) {
j++;
}
let lastChar = i > 0 ? s[i - 1] : ch;
let remStr = removeDuplicates(
s.substring(j + 1, s.length), lastChar);
s = s.substring(0, i);
let k = s.length, l = 0;
while (remStr.length > 0 && s.length > 0
&& remStr[0] == s[s.length - 1]) {
while (remStr.length > 0
&& remStr[0] != ch
&& remStr[0] == s[s.length - 1]) {
remStr
= remStr.substring(1, remStr.length+1);
}
s = s.substring(0, s.length - 1);
}
s = s + remStr;
i = j;
}
else {
i++;
}
}
return s;
}
let str1 = "mississipie" ;
console.log(removeDuplicates(str1, ' ' ));
let str2 = "ocvvcolop" ;
document.write(removeDuplicates(str2, ' ' ), "</br>" );
</script>
|
Time Complexity: O(n2), as substr method takes o(n) time, so the complexity will be O(n2).
Auxiliary Space: O(n2), as a substring copy of the original string is passed in the recursive function.
Another Approach:
The idea here is to find the duplicate characters using regular expression and run a loop to find the characters having length more than 1. If the resultant string still needs improvement then we will call the function again with the resultant string as a parameter. Here our ps would be having previous string and s would be having new string. If both are equal we will break the loop and return the answer.
C++
#include<bits/stdc++.h>
#include<string>
#include<regex>
using namespace std;
string remove (string s)
{
smatch match;
string str;
while (regex_search(s,match, regex(R "((.)\1*)" )))
{
if (match.str().size() > 1)
{
s=match.suffix().str();
}
else
{
str+=match.str();
s=match.suffix().str();
}
}
return str;
}
string rremove(string s)
{
string temp;
while (s.size() != temp.size())
{
temp = s;
s = remove (s);
}
return s;
}
int main()
{
string str1 = "geeksforgeek" ;
cout<<rremove(str1)<<endl;
string str2 = "abccbccba" ;
cout<<rremove(str2)<<endl;
return 0;
}
|
Java
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args)
{
String str1 = "geeksforgeek" ;
System.out.println(rremove(str1));
String str2 = "abccbccba" ;
System.out.println(rremove(str2));
}
public static String remove(String s)
{
Pattern pattern = Pattern.compile( "(.)\\1*" );
Matcher matcher = pattern.matcher(s);
String str = "" ;
while (matcher.find()) {
if (matcher.group().length() > 1 ) {
s = matcher.replaceFirst( "" );
matcher = pattern.matcher(s);
}
else {
str += matcher.group();
s = matcher.replaceFirst( "" );
matcher = pattern.matcher(s);
}
}
return str;
}
public static String rremove(String s)
{
String temp;
while (s.length() != (temp = remove(s)).length()) {
s = temp;
}
return s;
}
}
|
Python3
import re
def remove(s):
groups = [(match.group() for match in re.finditer(r '(.)\1*' ,s))]
s = ''
for i in groups:
if len (i)> 1 :
continue
s + = i
return s
def rremove(s):
ps = ''
while len (ps)! = len (s):
ps = s
s = remove(s)
return s
str1 = "geeksforgeek"
print (rremove(str1))
str2 = "abccbccba"
print (rremove(str2))
|
C#
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
class Program {
static void Main( string [] args)
{
string str1 = "geeksforgeek" ;
Console.WriteLine(rremove(str1));
string str2 = "abccbccba" ;
Console.WriteLine(rremove(str2));
Console.ReadKey();
}
static string remove( string s)
{
MatchCollection match;
string str = "" ;
while (Regex.IsMatch(s, @"(.)\1*" )) {
match = Regex.Matches(s, @"(.)\1*" );
if (match[0].Length > 1) {
s = s.Substring(match[0].Length);
}
else {
str += match[0].Value;
s = s.Substring(match[0].Length);
}
}
return str;
}
static string rremove( string s)
{
string temp;
while (s.Length != (temp = remove(s)).Length) {
s = temp;
}
return s;
}
}
|
Javascript
function remove(s)
{
const groups = s.match(/(.)\1*/g) || [];
let result = '' ;
for (const group of groups) {
if (group.length > 1) {
continue ;
}
result += group;
}
return result;
}
function rremove(s) {
let prevStr = '' ;
while (prevStr !== s) {
prevStr = s;
s = remove(s);
}
return s;
}
const str1 = "geeksforgeek" ;
console.log(rremove(str1));
const str2 = "abccbccba" ;
console.log(rremove(str2));
|
Time Complexity: O(n), as remove() is taking only O(n) time, so the complexity would be O(n).
Auxiliary Space: O(n2), as groups and ps is taking O(n) space and O(n) is used for function recursion stack (Auxiliary Space).
Another Approach:
To solve this problem, we can utilize a stack data structure and recursion. The idea is to traverse the string from left to right and maintain a stack to store the characters. Whenever we encounter a character that is the same as the top of the stack, we remove both the character from the stack and the character from the string. This process continues until there are no more adjacent duplicates.
Python3
class Solution:
def rremove( self , S):
new = [i for i in S]
st = []
i = 0
while i < len (S):
if st and st[ - 1 ] = = S[i]:
while i < len (S) and S[i] = = st[ - 1 ]:
i + = 1
st.pop()
if i < len (S):
st.append(S[i])
i + = 1
if new = = st:
return ''.join(new)
else :
return self .rremove(''.join(st))
s = Solution()
input_string = "geeksforgeekss"
output_string = s.rremove(input_string)
print ( "Output:" , output_string)
|
Javascript
class Solution {
rremove(S) {
let ne = Array.from(S);
let st = [];
let i = 0;
while (i < S.length) {
if (st.length && st[st.length - 1] === S[i]) {
while (i < S.length && S[i] === st[st.length - 1]) {
i += 1;
}
st.pop();
}
if (i < S.length) {
st.push(S[i]);
i += 1;
}
}
if (ne.join( '' ) === st.join( '' )) {
return ne.join( '' );
}
else {
return this .rremove(st.join( '' ));
}
}
}
let s = new Solution();
let input_string = "geeksforgeekss" ;
let output_string = s.rremove(input_string);
console.log( "Output:" , output_string);
|
Time Complexity Analysis:
The time complexity of this code is O(n), where n is the length of the input string S. This is because we traverse the string once using the while loop, and each character is processed only once.
Space Complexity Analysis:
The space complexity of this code is O(n), where n is the length of the input string S. The space is mainly used to store the characters in the stack and the resulting string.