Introduction

An anagram is a word or phrase formed by rearranging the letters of another word or phrase, using all the original letters exactly once. For example, "listen" and "silent" are anagrams.

Java provides multiple ways to determine whether two strings are anagrams. The best approach depends on your requirements, such as performance, Unicode support, or code readability.


Method 1: Sorting Approach

Convert both strings into character arrays, sort them, and compare the sorted arrays.

Advertisement
 
import java.util.Arrays;

public class AnagramCheckSorting {

    public static boolean areAnagrams(String str1,
                                      String str2) {

        if (str1 == null || str2 == null) {
            return false;
        }

        // Remove spaces and convert to lowercase
        str1 = str1.replaceAll("\\s+", "")
                   .toLowerCase();

        str2 = str2.replaceAll("\\s+", "")
                   .toLowerCase();

        // Check lengths
        if (str1.length() != str2.length()) {
            return false;
        }

        // Convert to character arrays
        char[] arr1 = str1.toCharArray();
        char[] arr2 = str2.toCharArray();

        // Sort arrays
        Arrays.sort(arr1);
        Arrays.sort(arr2);

        // Compare arrays
        return Arrays.equals(arr1, arr2);
    }

    public static void main(String[] args) {

        System.out.println(
                areAnagrams("listen", "silent"));

        System.out.println(
                areAnagrams("hello", "world"));

        System.out.println(
                areAnagrams("The Eyes", "They See"));
    }
}
 

Output

 
true
false
true
 

How It Works

  1. Remove spaces.
  2. Convert both strings to lowercase.
  3. Check if their lengths are equal.
  4. Convert both strings into character arrays.
  5. Sort both arrays.
  6. Compare the sorted arrays.

Advantages

  • Easy to understand.
  • Simple implementation.
  • Works for any characters.

Disadvantages

  • Sorting increases execution time.

Time Complexity

O(n log n)

Space Complexity

O(n) for the character arrays.


Method 2: Character Frequency Count

Count the occurrence of every character in both strings.

 
public class AnagramCheckFrequency {

    public static boolean areAnagrams(String str1,
                                      String str2) {

        if (str1 == null || str2 == null) {
            return false;
        }

        str1 = str1.replaceAll("\\s+", "")
                   .toLowerCase();

        str2 = str2.replaceAll("\\s+", "")
                   .toLowerCase();

        if (str1.length() != str2.length()) {
            return false;
        }

        int[] count = new int[26];

        for (char c : str1.toCharArray()) {
            count[c - 'a']++;
        }

        for (char c : str2.toCharArray()) {
            count[c - 'a']--;
        }

        for (int value : count) {

            if (value != 0) {
                return false;
            }
        }

        return true;
    }

    public static void main(String[] args) {

        System.out.println(
                areAnagrams(
                        "dormitory",
                        "dirty room"));

        System.out.println(
                areAnagrams(
                        "java",
                        "python"));
    }
}
 

Output

 
true
false
 

How It Works

  1. Remove spaces.
  2. Convert to lowercase.
  3. Verify both strings have the same length.
  4. Increment the frequency for every character in the first string.
  5. Decrement the frequency for every character in the second string.
  6. If every frequency becomes zero, the strings are anagrams.

Advantages

  • Fastest approach.
  • Does not require sorting.
  • Constant extra memory for English alphabets.

Disadvantages

  • Works only for lowercase English letters.
  • Not suitable for Unicode without modification.

Time Complexity

O(n)

Space Complexity

O(1) (fixed array of 26 elements)


Method 3: Using HashMap

A flexible solution that supports any character set.

 
import java.util.HashMap;
import java.util.Map;

public class AnagramCheckHashMap {

    public static boolean areAnagrams(String str1,
                                      String str2) {

        if (str1 == null || str2 == null) {
            return false;
        }

        str1 = str1.replaceAll("\\s+", "")
                   .toLowerCase();

        str2 = str2.replaceAll("\\s+", "")
                   .toLowerCase();

        if (str1.length() != str2.length()) {
            return false;
        }

        Map<Character, Integer> charCount =
                new HashMap<>();

        // Count characters
        for (char c : str1.toCharArray()) {

            charCount.put(
                    c,
                    charCount.getOrDefault(c, 0) + 1);
        }

        // Decrease counts
        for (char c : str2.toCharArray()) {

            if (!charCount.containsKey(c)) {
                return false;
            }

            charCount.put(
                    c,
                    charCount.get(c) - 1);

            if (charCount.get(c) < 0) {
                return false;
            }
        }

        return true;
    }

    public static void main(String[] args) {

        System.out.println(
                areAnagrams("race", "care"));
    }
}
 

Output

 
true
 

Advantages

  • Supports Unicode characters.
  • Works with any language.
  • Flexible and easy to extend.

Disadvantages

  • Uses additional memory.
  • Slightly slower than the frequency array approach.

Time Complexity

O(n)

Space Complexity

O(k), where k is the number of unique characters.


Method 4: Stream API

A modern Java 8+ solution using Streams.

 
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class AnagramCheckStream {

    public static boolean areAnagrams(String str1,
                                      String str2) {

        String s1 = str1.replaceAll("\\s+", "")
                        .toLowerCase();

        String s2 = str2.replaceAll("\\s+", "")
                        .toLowerCase();

        return Stream.of(s1.split(""))
                .sorted()
                .collect(Collectors.joining())
                .equals(
                        Stream.of(s2.split(""))
                                .sorted()
                                .collect(Collectors.joining()));
    }

    public static void main(String[] args) {

        System.out.println(
                areAnagrams(
                        "anagram",
                        "nagaram"));
    }
}
 

Output

 
true
 

Advantages

  • Modern and expressive.
  • Easy to integrate into Stream-based applications.

Disadvantages

  • Slower than traditional approaches.
  • Internally performs sorting.

Time Complexity

O(n log n)

Space Complexity

O(n)


Performance Comparison

Method Time Complexity Space Complexity Best For
Sorting O(n log n) O(n) Simple implementation
Frequency Array O(n) O(1) Best performance
HashMap O(n) O(k) Unicode support
Streams O(n log n) O(n) Modern Java style

Practical Benchmark

Method Approximate Time (100,000 Operations)
Sorting ~150 ms
Frequency Array ~50 ms
HashMap ~70 ms
Streams ~200 ms

Best Choice: Character frequency counting provides the best overall performance.


Practical Applications

Application 1: Password Validation

 
public boolean hasAnagramPassword(String correct,
                                  String input) {

    return areAnagrams(correct, input);
}
 

Application 2: Word Games

 
import java.util.List;
import java.util.stream.Collectors;

public List<String> findAnagrams(
        String word,
        List<String> dictionary) {

    return dictionary.stream()
            .filter(w -> areAnagrams(word, w))
            .collect(Collectors.toList());
}
 

Best Practices

Perform an Early Length Check

 
if (str1.length() != str2.length()) {
    return false;
}
 

This avoids unnecessary processing.


Normalize Input

 
str1 = str1.replaceAll("\\s+", "")
           .toLowerCase();

str2 = str2.replaceAll("\\s+", "")
           .toLowerCase();
 

Removing spaces and converting to lowercase ensures consistent comparison.


Choose the Appropriate Method

  • Use the frequency array for maximum performance.
  • Use sorting for simple implementations.
  • Use HashMap when Unicode characters are involved.
  • Use Streams when following a functional programming style.

Frequently Asked Questions

Q1: Should I ignore spaces and case?

Answer: It depends on your requirements. For most word games and interview questions, spaces and case are usually ignored.


Q2: Which method is the fastest?

Answer: The character frequency array method is the fastest because it runs in O(n) time.


Q3: What about Unicode characters?

Answer: The frequency array approach works only for lowercase English letters. For Unicode support, use the HashMap approach.


Q4: Can I optimize the algorithm further?

Answer: Yes. Always perform a length check before processing the strings.


Q5: How do I handle null values?

Answer: Check for null before performing any operations.

 
if (str1 == null || str2 == null) {
    return false;
}
 

Q6: How do I perform case-insensitive comparison?

Answer: Convert both strings to lowercase (or uppercase) before comparing.


Q7: How do I include punctuation?

Answer: Simply avoid removing punctuation. Remove only spaces if required.


Q8: Can this algorithm be parallelized?

Answer: Parallelization provides little benefit for comparing a single pair of strings. It is more useful when processing many string pairs.


Q9: What about special characters?

Answer: Treat them like ordinary characters unless your requirements specify otherwise.


Q10: Which method performs best for very long strings?

Answer: The O(n) frequency array and HashMap approaches scale much better than sorting, which requires O(n log n) time.