Recursively remove all adjacent duplicates

Given a string, recursively remove adjacent duplicate characters from string. The output string should not have any adjacent duplicates. See following 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

A simple approach would be to run the input string through multiple passes. In every pass remove all adjacent duplicates from left to right. Stop running passes when there are no duplicates. The worst time complexity of this method would be O(n^2).

filter_none

edit
close

play_arrow

link
brightness_4
code

// C/C++ program to remove all adjacent duplicates 
// from a string 
#include <iostream> 
#include <string.h> 
using namespace std; 
  
// This function recursively removes duplicates 
// and returns modified string 
char* removeDup(char * str, int n) 
    int len = strlen(str); 
    int k = 0, i=0; // To store index of result 
  
    // Start from second character and add 
    // unique ones 
    for (int i=1; i< len; i++) 
    
        // If different, increment k and add 
        // previous character 
        if (str[i-1] != str[i]) 
            str[k++] = str[i-1]; 
  
        else
            // Keep skipping (removing) characters 
            // while they are same. 
            while (str[i-1] == str[i]) 
                i++; 
    
  
    // Add last character and terminator 
    str[k++] = str[i-1]; 
    str[k] = '\0'
  
    // If all characters were unique 
     return str; 
  
int main() 
    char str1[] = "geeksforgeeg"
    cout << removeDup(str1, strlen(str1)) << endl; 
  
    char str2[] = "azxxxzy"
    cout << removeDup(str2, strlen(str2)) << endl; 
  
    char str3[] = "caaabbbaac"
    cout << removeDup(str3, strlen(str3)) << endl; 
  
    char str4[] = "gghhg"
    cout << removeDup(str4, strlen(str4)) << endl; 
  
    char str5[] = "aaaacddddcappp"
    cout << removeDup(str5, strlen(str5)) << endl; 
  
    char str6[] = "aaaaaaaaaa"
    cout << removeDup(str6, strlen(str6)) << endl; 
  
    char str7[] = "qpaaaaadaaaaadprq"
    cout << removeDup(str7, strlen(str7)) << endl; 
  
    char str8[] = "acaaabbbacdddd"
    cout << removeDup(str8, strlen(str8)) << endl; 
  
    char str9[] = "acbbcddc"
    cout << removeDup(str9, strlen(str9)) << endl; 
// This code is contributed by Aditya Goel. 

chevron_right


Output:

gksforg
azz
c

cca

qpddpr
acac
acc

We can remove all duplicates in O(n) time.
1) Start from the leftmost character and remove duplicates at left corner if there are any.
2) The first character must be different from its adjacent now. Recur for string of length n-1 (string without first character).
3) Let the string obtained after reducing right substring of length n-1 be rem_str. There are three possible cases
……..a) If first character of rem_str matches with the first character of original string, remove the first character from rem_str.
……..b) If remaining string becomes empty and last removed character is same as first character of original string. Return empty string.
……..c) Else, append the first character of the original string at the beginning of rem_str.
4) Return rem_str.

Following are C++, Python and Java implementations of the above algorithm.



C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C/C++ program to remove all adjacent duplicates from a string
#include <iostream>
#include <string.h>
  
using namespace std;
  
// Recursively removes adjacent duplicates from str and returns
// new string. las_removed is a pointer to last_removed character
char* removeUtil(char *str, char *last_removed)
{
    // If length of string is 1 or 0
    if (str[0] == '\0' || str[1] == '\0')
        return str;
  
    // Remove leftmost same characters and recur for remaining 
    // string
    if (str[0] == str[1])
    {
        *last_removed = str[0];
        while (str[1] && str[0] == str[1])
            str++;
        str++;
        return removeUtil(str, last_removed);
    }
  
    // At this point, the first character is definiotely different 
    // from its adjacent. Ignore first character and recursively 
    // remove characters from remaining string
    char* rem_str = removeUtil(str+1, last_removed);
  
    // Check if the first character of the rem_string matches with 
    // the first character of the original string
    if (rem_str[0] && rem_str[0] == str[0])
    {
        *last_removed = str[0];
        return (rem_str+1); // Remove first character
    }
  
    // If remaining string becomes empty and last removed character
    // is same as first character of original string. This is needed
    // for a string like "acbbcddc"
    if (rem_str[0] == '\0' && *last_removed == str[0])
        return rem_str;
  
    // If the two first characters of str and rem_str don't match, 
    // append first character of str before the first character of
    // 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);
}
  
// Driver program to test above functions
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;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to remove all adjacent duplicates
// from a string
import java.io.*;
import java.util.*;
  
class GFG {
      // Recursively removes adjacent duplicates from str and returns 
      // new string. las_removed is a pointer to last_removed character
      static String removeUtil(String str, char last_removed)
      {
             // If length of string is 1 or 0 
             if (str.length() == 0 || str.length() == 1)
                 return str;
  
             // Remove leftmost same characters and recur for remaining  
             // string 
             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, last_removed); 
             }
  
             // At this point, the first character is definiotely different  
             // from its adjacent. Ignore first character and recursively  
             // remove characters from remaining string 
             String rem_str = removeUtil(str.substring(1,str.length()), last_removed);
  
             // Check if the first character of the rem_string matches with  
             // the first character of the original string
             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()); // Remove first character
             
  
  
             // If remaining string becomes empty and last removed character 
             // is same as first character of original string. This is needed 
             // for a string like "acbbcddc" 
             if (rem_str.length() == 0 && last_removed == str.charAt(0))
                 return rem_str;
  
             // If the two first characters of str and rem_str don't match,  
             // append first character of str before the first character of 
             // rem_str
             return (str.charAt(0) + rem_str);
      }
   
      static String remove(String str)  
      {
             char last_removed = '\0';
             return removeUtil(str, last_removed);       
      }
  
      // Driver code
      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));
         
      }
}
  
// This code is contibuted by rachana soma 

chevron_right


Python

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python program to remove all adjacent duplicates from a string
  
# Recursively removes adjacent duplicates from str and returns
# new string. las_removed is a pointer to last_removed character
def removeUtil(string, last_removed):
  
    # If length of string is 1 or 0
    if len(string) == 0 or len(string) == 1:
        return string
  
    # Remove leftmost same characters and recur for remaining 
    # 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)
  
    # At this point, the first character is definiotely different
    # from its adjacent. Ignore first character and recursively 
    # remove characters from remaining string
    rem_str = removeUtil(string[1:], last_removed)
  
    # Check if the first character of the rem_string matches 
    # with the first character of the original string
    if len(rem_str) != 0 and rem_str[0] == string[0]:
        last_removed = ord(string[0])
        return (rem_str[1:])
  
    # If remaining string becomes empty and last removed character
    # is same as first character of original string. This is needed
    # for a string like "acbbcddc"
    if len(rem_str) == 0 and last_removed == ord(string[0]):
        return rem_str
  
    # If the two first characters of str and rem_str don't match, 
    # append first character of str before the first character of 
    # rem_str.
    return ([string[0]] + rem_str)
  
def remove(string):
    last_removed = 0
    return toString(removeUtil(toList(string), last_removed))
  
# Utility functions
def toList(string):
    x = []
    for i in string:
        x.append(i)
    return x
  
def toString(x):
    return ''.join(x)
  
# Driver program
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)
  
# This code is contributed by BHAVYA JAIN

chevron_right



Output:

gksfor
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)

Thanks to Prachi Bodke for suggesting this problem and initial solution. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above



My Personal Notes arrow_drop_up

Improved By : pragya29, rachana soma