Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll learn various techniques to check if all the characters present in a string, including non-ASCII characters, are unique. Additionally, all the methods discussed here are case-insensitive.

2. Brute-Force

This is one of the most obvious techniques, but it’s slightly crude and may not be the most efficient. We compare the characters in the string with each other:

public class UniqueCharChecker {
    public static boolean bruteForceCheck(String str) {
        char[] chars = str.toUpperCase().toCharArray();
        for (int i = 0; i < chars.length; i++) {
            for (int j = i + 1; j < chars.length; j++) {
                if(chars[i] == chars[j]) {
                    return false;
                }
            }
        }
        return true;
    }
}

Let’s write some test cases for the above method:

public class UniqueCharCheckerUnitTest {
    @Test
    public void givenUnique_whenBruteForceCheck_thenReturnTrue() {
        String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"};
        final String MSG = "Duplicate found";
        Arrays.stream(sampleStrings)
          .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.checkV1(sampleStr)));
    }

    @Test
    public void givenNotUnique_whenBruteForceCheck_thenReturnFalse() {
        String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"};
        final String MSG = "Duplicate not found";
        Arrays.stream(sampleStrings)
          .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.checkV1(sampleStr)));
    }
}

2. Sorting

So this is similar to the brute-force technique, but here we first sort the characters in the string and then compare them with just their neighbor, and not with everyone. Let’s check out the implementation:

public static boolean sortAndThenCheck(String str) {
    char[] chars = str.toUpperCase().toCharArray();
    Arrays.sort(chars);
    for (int i = 0; i < chars.length - 1; i++) {
        if(chars[i] == chars[i+1]) {
            return false;
        }
    }
    return true;
}

Let’s test it:

@Test
public void givenUnique_whenSortAndThenCheck_thenReturnTrue() {
    String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"};
    final String MSG = "Duplicate found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.checkV2(sampleStr)));
}
@Test
public void givenNotUnique_whenSortAndThenCheck_thenReturnFalse() {
    String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"};
    final String MSG = "Duplicate not found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.checkV2(sampleStr)));
}

3. HashSet

Here, we leverage the power of java.util.Set to remove duplicate characters:

public static boolean useSetCheck(String str) {
    char[] chars = str.toUpperCase().toCharArray();
    Set <Character> set = new HashSet <>();
    for (char c: chars) {
        if (!set.add(c)) {
            return false;
        }
    }
    return true;
}

Now, let’s have a look at the test cases:

@Test
public void givenUnique_whenUseSetCheck_thenReturnTrue() {
    String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ" };
    final String MSG = "Duplicate found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.checkV3(sampleStr)));
}
@Test
public void givenNotUnique_whenUseSetCheck_thenReturnFalse() {
    String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"};
    final String MSG = "Duplicate not found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.checkV3(sampleStr)));
}

4. Java Streams

This technique is similar to the method used in the previous section. However, we’re using the Streams API to create the Set. Let’s have a look at the implementation:

public static boolean useStreamCheck(String str) {
    boolean isUnique = str.toUpperCase().chars()
      .mapToObj(c -> (char) c)
      .collect(Collectors.toSet())
      .size() == str.length();
    return isUnique;
}

And let’s check the unit tests:

@Test
public void givenUnique_whenUseStreamCheck_thenReturnTrue() {
    String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ" };
    final String MSG = "Duplicate found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.checkV1(sampleStr)));
}
@Test
public void givenNotUnique_whenUseStreamCheck_thenReturnFalse() {
    String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"};
    final String MSG = "Duplicate not found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.checkV4(sampleStr)));
}

5. StringUtils

Basically, here, we’ll use the method containsIgnoreCase() in the commons-lang StringUtils class:

public static boolean useStringUtilscheck(String str) {
    for (int i = 0; i < str.length(); i++) {
        String curChar = String.valueOf(str.charAt(i));
        String remainingStr = str.substring(i+1);
        if(StringUtils.containsIgnoreCase(remainingStr, curChar)) {
            return false;
        }
    }
    return true;
}

Let’s test this method:

@Test
public void givenUnique_whenUseStringUtilscheck_thenReturnTrue() {
    String[] sampleStrings = new String[]{"Justfewdi123", "$%&Hibusc", "Hibusc%$#", "მშვნიერ"};
    final String MSG = "Duplicate found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertTrue(MSG + " in " + sampleStr, UniqueCharChecker.checkV5(sampleStr)));
}
@Test
public void givenNotUnique_whenUseStringUtilscheck_thenReturnFalse() {
    String[] sampleStrings = new String[]{"Justfewdif123", "$%&Hibushc", "Hibusuc%$#", "Hi%busc%$#", "მშვენიერი"};
    final String MSG = "Duplicate not found";
    Arrays.stream(sampleStrings)
      .forEach(sampleStr -> assertFalse(MSG + " in " + sampleStr, UniqueCharChecker.checkV5(sampleStr)));
}

6. Conclusion

In this tutorial, we saw five different ways to check if a string has unique characters. We also conclude that there are no out-of-the-box libraries available for solving this problem.

The code snippets used here, along with associated JUnit test cases, are available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.