2
\$\begingroup\$

For this problem, I came up with this ugly solution of appending the characters to the output and in case there is adjacent duplicate deleting from the output. Considering StringBuilder.deleteCharAt(i) is O(N), performance is O(N) + O(N) = O(N).

Please critique this, if this is a right way.

public static String removeDuplicate(String s) {
StringBuilder builder = new StringBuilder();
char lastchar = '\0';
for (int i = 0; i < s.length(); i++) {
  String str = builder.toString();
  if (!str.equals("")
      && (str.charAt(str.length() - 1) == s.charAt(i))) {
    builder.deleteCharAt(str.length() - 1);
  } else if (s.charAt(i) != lastchar)
    builder.append(s.charAt(i));
  lastchar = s.charAt(i);
}
return builder.toString();
}

Sample input outputs:

Input: azxxzy
Output: ay

Input: caaabbbaacdddd
Output: Empty String

Input: acaaabbbacdddd
Output: acac

\$\endgroup\$
3
  • 7
    \$\begingroup\$ Why does it have to be recursive? ... and if it has to be recursive, why is your code not recursive? \$\endgroup\$
    – rolfl
    Commented Mar 6, 2014 at 0:31
  • 1
    \$\begingroup\$ Additionally, what does it mean to remove duplicates? If I give your code the word messy it returns mey... I was expecting mesy... which one is right? Why? \$\endgroup\$
    – rolfl
    Commented Mar 6, 2014 at 0:34
  • \$\begingroup\$ @rolfl The examples added in Rev 2 clarify both issues. "messy""mey". "Recursively remove" refers to the problem statement, not the implementation. \$\endgroup\$ Commented Mar 6, 2014 at 5:58

3 Answers 3

4
\$\begingroup\$

The problem is not that StringBuilder.deleteCharAt()is O(n) — you only ever use it to strip the last character. Rather, it's your builder.toString() that is problematic. It's an O(n) operation that is invoked in a loop up to n times.

Rather than using a StringBuilder, I recommend manipulating a char[] array directly. The problem, as you pointed out, is that StringBuilder.deleteCharAt(i) is O(n) because it shifts the rest of the string over. By doing your own accounting, you can just build the string correctly the first time.

public static String removeDuplicates(String s) {
    if (s.isEmpty()) {
        return s;
    }
    char[] buf = s.toCharArray();
    char lastchar = buf[0];

    // i: index of input char
    // o: index of output char
    int o = 1;
    for (int i = 1; i < buf.length; i++) {
        if (o > 0 && buf[i] == buf[o - 1]) {
            lastchar = buf[o - 1];
            while (o > 0 && buf[o - 1] == lastchar) {
                o--;
            }
        } else if (buf[i] == lastchar) {
            // Don't copy to output
        } else {
            buf[o++] = buf[i];
        }
    }
    return new String(buf, 0, o);
}
\$\endgroup\$
5
\$\begingroup\$

General

Your code formatting is all over the place. You should use consistent and structured indentation. See the Java Code-Style guide for, well, guidance.

if I take your code, and re-format it (Eclipse, CtrlA and CtrlshiftF), it looks like:

public static String removeDuplicate(String s) {
    StringBuilder builder = new StringBuilder();
    char lastchar = '\0';
    for (int i = 0; i < s.length(); i++) {
        String str = builder.toString();
        if (!str.equals("") && (str.charAt(str.length() - 1) == s.charAt(i))) {
            builder.deleteCharAt(str.length() - 1);
        } else if (s.charAt(i) != lastchar)
            builder.append(s.charAt(i));
        lastchar = s.charAt(i);
    }
    return builder.toString();
}

At least this allows us to see what you are doing.

Algorithm

A nice algorithm will take data from the input string, and add it to the output if it should be added. A system where you do multiple conversions, add things, and remove things, is complicated, and hard to follow.

Additionally, the null character \0 is actually a valid character in Java, so you may have (an extremely rare) bug.

I do not like that your code is removing all the duplicate values, it seems more practical to remove all but one of the duplicates, but you do not explain why it is supposed to be this way.

More Information required

The above, in itself, is a review, but, if you update your question with the requested details:

  • recursion yes/no/why?
  • dedup all, or all-but-one?

then I can add suggestions as to how to solve this in a more efficient way.

\$\endgroup\$
2
  • \$\begingroup\$ Actually I had issue while posting the code here, thats why formatting is all over the place. Anyways I follow Google style sheet in my eclipse, so it will be all right. \$\endgroup\$ Commented Mar 6, 2014 at 1:10
  • \$\begingroup\$ The question was : to remove adjacent duplicates from the code. I will post the valid inputs outputs in the question \$\endgroup\$ Commented Mar 6, 2014 at 1:11
0
\$\begingroup\$

Ultimately you have to remove the duplicates from the String without using HashSet. One technique is to sort the char array first. The complete code is:

public class Test3 {
    public static void main(String[] args) {
        String str = "ABBCDAABBBBBBBBOR";
        char[] ca = str.toCharArray();

        Arrays.sort(ca);

        String a = new String(ca);
        System.out.println("original => " + a);
        int i = 0 ;
        StringBuffer sbr = new StringBuffer();
         while(i < a.length()) {
             if(sbr.length() == 0 ) {sbr.append(a.charAt(i));}
             if(a.charAt(i) == sbr.charAt(sbr.length() -1)) {i++ ;}
             else {sbr.append(a.charAt(i));}
         }//while

         System.out.println("After removing the duplicates => " + sbr);
    }//main
}// end1
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.