Check If Two Strings Are Anagrams: C, C++, Java, Python
Count array and sort-then-compare: two anagram check approaches in C, C++, Java and Python with O(n) and O(n log n) complexity analysis.
Two strings are anagrams when they contain the same characters in any order: “listen” and “silent” qualify, “hello” and “world” do not.
The problem appears in AMCAT Automata, service-tier technical rounds, and campus-drive coding tests. Two implementations cover every variant: one runs in linear time with constant space, one trades time for readability.
What Makes Two Strings Anagrams
A string S1 is an anagram of S2 when both strings have the same length and the same character frequencies. “Character frequency” means the count of each distinct character must be identical across both strings.
Three worked examples span the range of inputs:
| S1 | S2 | Anagram? | Reason |
|---|---|---|---|
| listen | silent | Yes | Same six characters (l, i, s, t, e, n) rearranged |
| hello | world | No | ”hello” has two l’s; “world” has none. Frequency mismatch. |
| act | cat | Yes | Same three characters (a, c, t) in different order |
The length check is always the first step. Two strings of different lengths cannot share identical character frequencies, so comparing lengths before scanning characters saves time on mismatched inputs.
Approach 1: Count Array
Increment a counter for each character in the first string, decrement for each character in the second. When all counters return to zero, the strings are anagrams.
The counter array has 26 slots, one per lowercase English letter. The expression c - 'a' maps each character to its slot: ‘a’ to index 0, ‘b’ to index 1, and so on up to ‘z’ at index 25. Both strings can be traversed in a single combined loop because the lengths are equal after the initial check.
C
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool areAnagrams(const char *s1, const char *s2) {
if (strlen(s1) != strlen(s2)) return false;
int count[26] = {0};
for (int i = 0; s1[i]; i++) {
count[s1[i] - 'a']++;
count[s2[i] - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (count[i] != 0) return false;
}
return true;
}
int main(void) {
printf("%s\n", areAnagrams("listen", "silent") ? "Anagram" : "Not an anagram");
printf("%s\n", areAnagrams("hello", "world") ? "Anagram" : "Not an anagram");
return 0;
}
Output:
Anagram
Not an anagram
C++
#include <iostream>
#include <string>
#include <array>
using namespace std;
bool areAnagrams(const string &s1, const string &s2) {
if (s1.size() != s2.size()) return false;
array<int, 26> count = {};
for (char c : s1) count[c - 'a']++;
for (char c : s2) count[c - 'a']--;
for (int n : count) {
if (n != 0) return false;
}
return true;
}
int main() {
cout << (areAnagrams("listen", "silent") ? "Anagram" : "Not an anagram") << "\n";
cout << (areAnagrams("hello", "world") ? "Anagram" : "Not an anagram") << "\n";
}
Java
public class AnagramCheck {
public static boolean areAnagrams(String s1, String s2) {
if (s1.length() != s2.length()) return false;
int[] count = new int[26];
for (char c : s1.toCharArray()) count[c - 'a']++;
for (char c : s2.toCharArray()) count[c - 'a']--;
for (int n : count) {
if (n != 0) return false;
}
return true;
}
public static void main(String[] args) {
System.out.println(areAnagrams("listen", "silent")); // true
System.out.println(areAnagrams("hello", "world")); // false
}
}
Python
Python’s collections.Counter builds the frequency map in one call:
from collections import Counter
def are_anagrams(s1: str, s2: str) -> bool:
return Counter(s1) == Counter(s2)
print(are_anagrams("listen", "silent")) # True
print(are_anagrams("hello", "world")) # False
Counter returns a dictionary of character-to-count mappings. Comparing two Counter objects checks that every character appears the same number of times in both strings. The length check is implicit: if s1 is longer than s2, at least one character count will differ.
Complexity
- Time: O(n) — two linear passes over the characters, plus one pass over the 26-element array (constant work).
- Space: O(1) — the count array is always 26 slots regardless of input length.
This is the fastest correct approach for ASCII lowercase inputs. The single-pass array pattern here is the same structure used in find smallest and largest element in an array, where one traversal tracks two running values simultaneously.
Approach 2: Sort Then Compare
Sort both strings into alphabetical order. If the sorted results are equal, the strings are anagrams. This approach is easier to explain in an interview and requires no index arithmetic.
C++ (with std::sort)
std::sort from <algorithm> sorts a string’s characters in-place in O(n log n) average time. Passing s1 and s2 by value means the originals are not modified.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
bool areAnagramsSort(string s1, string s2) {
if (s1.size() != s2.size()) return false;
sort(s1.begin(), s1.end());
sort(s2.begin(), s2.end());
return s1 == s2;
}
int main() {
cout << (areAnagramsSort("listen", "silent") ? "Anagram" : "Not an anagram") << "\n";
cout << (areAnagramsSort("hello", "world") ? "Anagram" : "Not an anagram") << "\n";
}
C (with qsort)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
static int cmpChar(const void *a, const void *b) {
return (*(const char *)a - *(const char *)b);
}
bool areAnagramsSort(const char *s1, const char *s2) {
size_t n = strlen(s1);
if (n != strlen(s2)) return false;
char *a = strdup(s1);
char *b = strdup(s2);
qsort(a, n, sizeof(char), cmpChar);
qsort(b, n, sizeof(char), cmpChar);
bool result = strcmp(a, b) == 0;
free(a);
free(b);
return result;
}
int main(void) {
printf("%s\n", areAnagramsSort("listen", "silent") ? "Anagram" : "Not an anagram");
printf("%s\n", areAnagramsSort("hello", "world") ? "Anagram" : "Not an anagram");
return 0;
}
strdup allocates copies of both strings before sorting so the originals remain unchanged. The copies are freed before returning to avoid a memory leak.
Java
import java.util.Arrays;
public class AnagramSort {
public static boolean areAnagrams(String s1, String s2) {
if (s1.length() != s2.length()) return false;
char[] a1 = s1.toCharArray();
char[] a2 = s2.toCharArray();
Arrays.sort(a1);
Arrays.sort(a2);
return Arrays.equals(a1, a2);
}
public static void main(String[] args) {
System.out.println(areAnagrams("listen", "silent")); // true
System.out.println(areAnagrams("hello", "world")); // false
}
}
Python
def are_anagrams_sort(s1: str, s2: str) -> bool:
return sorted(s1) == sorted(s2)
print(are_anagrams_sort("listen", "silent")) # True
print(are_anagrams_sort("hello", "world")) # False
Complexity
- Time: O(n log n) — dominated by the sort step.
- Space: O(n) — two sorted copies of the strings are held in memory simultaneously (in C++, the copies are implicit via pass-by-value; in Java and Python,
toCharArrayandsortedeach allocate new arrays).
Complexity Comparison
| Approach | Time | Space | Best for |
|---|---|---|---|
| Count array | O(n) | O(1) | ASCII lowercase inputs; performance-sensitive contexts |
| Sort then compare | O(n log n) | O(n) | Any character set; simpler to explain in interviews |
For placement coding rounds where time constraints are visible, the count-array approach is the default answer. When an interviewer asks for the simplest possible version, sort-then-compare is acceptable and is easier to derive from scratch under pressure.
Edge Cases
Three edge cases appear in extended interviews and online test variants.
Different Lengths
Check length first. “act” and “cater” are not anagrams because they have different lengths. The count-array and sort-based implementations above both return false immediately when lengths differ, without scanning characters.
Case-Insensitive Check
“Listen” and “Silent” should qualify as anagrams under a case-insensitive rule. Lowercase both strings before applying either approach:
from collections import Counter
def are_anagrams_ci(s1: str, s2: str) -> bool:
return Counter(s1.lower()) == Counter(s2.lower())
print(are_anagrams_ci("Listen", "Silent")) # True
In C and C++, call tolower() on each character inside the loop before updating the count array.
Empty Strings
Two empty strings are anagrams of each other. Both have length zero and their character frequencies are identically empty. Both implementations above return true for two empty inputs because the length check passes and no counter is incremented.
Strings with Spaces or Special Characters
The 26-slot count array assumes lowercase English letters (‘a’ to ‘z’). For inputs that include spaces, digits, or non-ASCII characters, replace the fixed array with a hash map. The Python Counter approach already handles this correctly for arbitrary inputs.
Where This Appears in Placement Tests
The anagram check turns up in three distinct placement contexts.
- AMCAT Automata: one of the standard easy-level string problems. The case-sensitive version is most common; a case-insensitive or space-stripping variant appears occasionally at medium difficulty.
- Service-tier technical rounds: TCS, Infosys, and Wipro use anagram checks as warm-up questions in the first coding round before more complex algorithmic problems. The interviewer may ask the candidate to explain why the count-array approach is faster, which tests complexity reasoning rather than just code recall.
- Campus-drive extensions: common follow-ups include: strip spaces before checking, make the check case-insensitive, or determine whether any permutation of string S1 is a contiguous substring of S2. Each extension is a single step on top of the core algorithm.
The palindrome check uses the same character-by-character comparison logic and appears at the same difficulty level. See check whether a string is a palindrome for the two-pointer and reverse-and-compare implementations in all four languages.
For the full set of string and data structure questions that appear across Indian IT placement rounds, 20 most asked data structures interview questions covers arrays, linked lists, trees, graphs, and hash tables with complexity analysis.
The count-array approach builds a 26-slot frequency table, which is the same counting logic that underlies unigram language models. TinkerLLM at ₹299 picks up from that 26-slot array and builds toward token-frequency distributions in actual language models, making the anagram check one of the earliest exercises in understanding how LLMs represent language.
Primary sources
Frequently asked questions
What is an anagram?
An anagram is a word formed by rearranging the letters of another word, using each original letter exactly once. 'listen' and 'silent' are a classic pair: same six characters, different order.
Which approach is faster for checking anagrams?
The count-array approach runs in O(n) time and O(1) space, making it faster than sort-then-compare at O(n log n) time and O(n) space. Use the count-array approach whenever performance matters.
Do the two strings need to be the same length to be anagrams?
Yes. Two strings of different lengths cannot be anagrams. Every correct implementation checks lengths first and returns false immediately when they differ.
How do I make the anagram check case-insensitive?
Lowercase both strings before applying either approach. In Python: s1.lower() and s2.lower(). In Java: s1.toLowerCase() and s2.toLowerCase(). In C or C++: call tolower() on each character before processing.
Does the count-array approach work for strings with spaces or special characters?
The basic 26-slot count array assumes lowercase English letters only. For strings with spaces, digits, or Unicode characters, replace the fixed array with a hash map. Python's Counter handles arbitrary character sets automatically.
Can I use Python's Counter for the anagram check?
Yes. Counter(s1) == Counter(s2) is idiomatic Python and handles any character set. It is functionally equivalent to the count-array approach but uses a hash map internally, with O(n) average time and O(k) space where k is the number of distinct characters.
A self-paced playground for building with LLMs.
TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.
Try TinkerLLM (₹299 launch)