Check if Two Strings Are Anagrams
Problem and examples
Given two strings s1 and s2, determine whether they are anagrams of each other.
- Two strings are considered anagrams if they contain the same characters with the same frequency, but possibly in a different order.
- The comparison should be case-insensitive, and spacing or punctuation is not ignored unless explicitly stated.
If either string is empty or null, handle appropriately.
| s1 | s2 | Are Anagrams? | Description |
|---|---|---|---|
| "listen" | "silent" | true | Characters match in count and type |
| "Listen" | "Silent" | true | Case-insensitive comparison |
| "triangle" | "integral" | true | Same characters in different order |
| "abc" | "def" | false | Completely different characters |
| "aabbcc" | "abccba" | true | Same letters and same frequency |
| "aabbcc" | "abc" | false | Frequencies do not match |
| "hello" | "helloo" | false | Different lengths |
| "" | "" | true | Both strings are empty |
| "" | "abc" | false | One string is empty |
| "" | "" | true | Empty strings are technically anagrams of each other |
Explore Check if Two Strings are Anagrams
Load an example or enter your own input. Use the player controls to follow each change.
Understanding the Problem
We are given two strings and asked to determine if they are anagrams. That means we need to check whether the two strings contain the same characters with the same frequency, but possibly in a different order. Think of it like this: Can we rearrange the letters of the first string to form the second one?
We also need to ignore the case of letters (uppercase vs lowercase), and carefully handle cases like different lengths or empty strings.
Step-by-Step Solution with Example
Step 1: Convert both strings to lowercase
This ensures that 'A' and 'a' are treated as the same character. For example, if we are comparing "Listen" and "Silent", we first convert both to "listen" and "silent".
Step 2: Check the lengths
If the strings have different lengths, they cannot be anagrams. For example, "hello" and "helloo" are not anagrams because one has an extra character.
Step 3: Count the frequency of each character
We use a dictionary (also called a map) to count how many times each character appears in each string.
Example: Compare "listen" and "silent".
- 'l': appears once in both
- 'i': once in both
- 's': once in both
- 't': once in both
- 'e': once in both
- 'n': once in both
Since every character and its count matches, they are anagrams.
Step 4: Compare both frequency maps
If the dictionaries for both strings are equal, the strings are anagrams. If even one character count is different, they are not.
Example: "aabbcc" vs "abc" → Not anagrams, because "aabbcc" has two of each letter, while "abc" has only one.
Edge Cases
- Empty strings: Two empty strings are considered anagrams because they contain the same (no) characters.
- One empty, one non-empty: Not anagrams.
- Case sensitivity: Convert to lowercase before comparison to ensure fair evaluation.
- Completely different letters: For example, "abc" and "xyz" → Not anagrams.
Finally
This problem tests your understanding of strings, maps, and case handling. By walking through the example step-by-step and handling edge cases carefully, you ensure a solid and beginner-friendly solution.
The overall time complexity of the solution is O(n), where n is the length of the strings, because we loop through each string a limited number of times.
- If the lengths of
s1ands2are different, return false immediately. - Convert both strings to lowercase to handle case-insensitivity.
- Initialize two hash maps:
map1andmap2. - Loop through each character in
s1and count frequency inmap1. - Loop through each character in
s2and count frequency inmap2. - If the number of unique keys in
map1andmap2differ, return false. - Check each key in
map1and compare its count withmap2. If any mismatch, return false. - If all checks pass, return true.
Implementation and efficiency
C implementation
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
bool isAnagram(const char* s1, const char* s2) {
if (strlen(s1) != strlen(s2)) return false;
int freq1[26] = {0};
int freq2[26] = {0};
for (int i = 0; s1[i]; i++) {
freq1[tolower(s1[i]) - 'a']++;
freq2[tolower(s2[i]) - 'a']++;
}
for (int i = 0; i < 26; i++) {
if (freq1[i] != freq2[i]) return false;
}
return true;
}
int main() {
printf("%d\n", isAnagram("listen", "silent")); // 1
printf("%d\n", isAnagram("Hello", "Olelh")); // 1
printf("%d\n", isAnagram("Hi", "Bye")); // 0
return 0;
}C++ implementation
#include <iostream>
#include <unordered_map>
#include <algorithm>
using namespace std;
bool isAnagram(string s1, string s2) {
if (s1.length() != s2.length()) return false;
transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
unordered_map<char, int> map1, map2;
for (char ch : s1) map1[ch]++;
for (char ch : s2) map2[ch]++;
return map1 == map2;
}
int main() {
cout << isAnagram("listen", "silent") << endl;
cout << isAnagram("Hello", "Olelh") << endl;
cout << isAnagram("Hi", "Bye") << endl;
return 0;
}Python implementation
def is_anagram(s1, s2):
if len(s1) != len(s2):
return False
s1, s2 = s1.lower(), s2.lower()
map1, map2 = {}, {}
for ch in s1:
map1[ch] = map1.get(ch, 0) + 1
for ch in s2:
map2[ch] = map2.get(ch, 0) + 1
return map1 == map2
print(is_anagram("listen", "silent")) # True
print(is_anagram("Hello", "Olelh")) # True
print(is_anagram("Hi", "Bye")) # FalseJava implementation
import java.util.*;
public class AnagramChecker {
public static boolean isAnagram(String s1, String s2) {
if (s1.length() != s2.length()) return false;
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
Map<Character, Integer> map1 = new HashMap<>();
Map<Character, Integer> map2 = new HashMap<>();
for (char ch : s1.toCharArray())
map1.put(ch, map1.getOrDefault(ch, 0) + 1);
for (char ch : s2.toCharArray())
map2.put(ch, map2.getOrDefault(ch, 0) + 1);
return map1.equals(map2);
}
public static void main(String[] args) {
System.out.println(isAnagram("listen", "silent"));
System.out.println(isAnagram("Hello", "Olelh"));
System.out.println(isAnagram("Hi", "Bye"));
}
}JavaScript implementation
function isAnagram(s1, s2) {
if (s1.length !== s2.length) return false;
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
const map1 = new Map();
const map2 = new Map();
for (let ch of s1) map1.set(ch, (map1.get(ch) || 0) + 1);
for (let ch of s2) map2.set(ch, (map2.get(ch) || 0) + 1);
if (map1.size !== map2.size) return false;
for (let [key, val] of map1) {
if (map2.get(key) !== val) return false;
}
return true;
}
console.log(isAnagram("listen", "silent"));
console.log(isAnagram("Hello", "Olelh"));
console.log(isAnagram("Hi", "Bye"));Go implementation
package main
import (
"fmt"
"strings"
)
func isAnagram(s1, s2 string) bool {
if len(s1) != len(s2) {
return false
}
s1 = strings.ToLower(s1)
s2 = strings.ToLower(s2)
freq1 := make(map[rune]int)
freq2 := make(map[rune]int)
for _, ch := range s1 {
freq1[ch]++
}
for _, ch := range s2 {
freq2[ch]++
}
if len(freq1) != len(freq2) {
return false
}
for k, v := range freq1 {
if freq2[k] != v {
return false
}
}
return true
}
func main() {
fmt.Println(isAnagram("listen", "silent"))
fmt.Println(isAnagram("Hello", "Olelh"))
fmt.Println(isAnagram("Hi", "Bye"))
}Rust implementation
use std::collections::HashMap;
fn is_anagram(s1: &str, s2: &str) -> bool {
if s1.len() != s2.len() {
return false;
}
let mut map1 = HashMap::new();
let mut map2 = HashMap::new();
for ch in s1.to_lowercase().chars() {
*map1.entry(ch).or_insert(0) += 1;
}
for ch in s2.to_lowercase().chars() {
*map2.entry(ch).or_insert(0) += 1;
}
map1 == map2
}
fn main() {
println!("{}", is_anagram("listen", "silent"));
println!("{}", is_anagram("Hello", "Olelh"));
println!("{}", is_anagram("Hi", "Bye"));
}Kotlin implementation
fun isAnagram(s1: String, s2: String): Boolean {
if (s1.length != s2.length) return false
val map1 = mutableMapOf<Char, Int>()
val map2 = mutableMapOf<Char, Int>()
for (ch in s1.lowercase()) {
map1[ch] = map1.getOrDefault(ch, 0) + 1
}
for (ch in s2.lowercase()) {
map2[ch] = map2.getOrDefault(ch, 0) + 1
}
return map1 == map2
}
fun main() {
println(isAnagram("listen", "silent"))
println(isAnagram("Hello", "Olelh"))
println(isAnagram("Hi", "Bye"))
}Swift implementation
func isAnagram(_ s1: String, _ s2: String) -> Bool {
if s1.count != s2.count { return false }
var map1: [Character: Int] = [:]
var map2: [Character: Int] = [:]
for ch in s1.lowercased() {
map1[ch, default: 0] += 1
}
for ch in s2.lowercased() {
map2[ch, default: 0] += 1
}
return map1 == map2
}
print(isAnagram("listen", "silent"))
print(isAnagram("Hello", "Olelh"))
print(isAnagram("Hi", "Bye"))TypeScript implementation
function isAnagram(s1: string, s2: string): boolean {
if (s1.length !== s2.length) return false;
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
const map1 = new Map<string, number>();
const map2 = new Map<string, number>();
for (const ch of s1) map1.set(ch, (map1.get(ch) || 0) + 1);
for (const ch of s2) map2.set(ch, (map2.get(ch) || 0) + 1);
if (map1.size !== map2.size) return false;
for (const [key, val] of map1) {
if (map2.get(key) !== val) return false;
}
return true;
}
console.log(isAnagram("listen", "silent"));
console.log(isAnagram("Hello", "Olelh"));
console.log(isAnagram("Hi", "Bye"));Time complexity
| Case | Time | Explanation |
|---|---|---|
| best case | O(n) | We scan both strings once to populate the maps and compare them. |
| average case | O(n) | Each character is processed once in both strings and looked up in hash maps. |
| worst case | O(n) | All characters are processed and map comparisons done linearly. |
Space complexity
O(1)
At most 26 characters are stored in the maps (for alphabetic strings), making space constant for English letters.