Skip to content

Commit 9ecc3aa

Browse files
authored
Add a new implementation for CheckAnagrams (TheAlgorithms#4231)
1 parent 2456d86 commit 9ecc3aa

File tree

2 files changed

+105
-16
lines changed

2 files changed

+105
-16
lines changed

src/main/java/com/thealgorithms/strings/CheckAnagrams.java

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@
88
* differently (ignoring the case).
99
*/
1010
public class CheckAnagrams {
11-
12-
public static void main(String[] args) {
13-
assert isAnagrams("Silent", "Listen");
14-
assert isAnagrams("This is a string", "Is this a string");
15-
assert !isAnagrams("There", "Their");
16-
}
17-
1811
/**
1912
* Check if two strings are anagrams or not
2013
*
@@ -50,4 +43,66 @@ public static boolean isAnagrams(String s1, String s2) {
5043
}
5144
return true;
5245
}
46+
47+
/**
48+
* If given strings contain Unicode symbols.
49+
* The first 128 ASCII codes are identical to Unicode.
50+
* This algorithm is case-sensitive.
51+
*
52+
* @param s1 the first string
53+
* @param s2 the second string
54+
* @return true if two string are anagrams, otherwise false
55+
*/
56+
public static boolean isAnagramsUnicode(String s1, String s2) {
57+
int[] dict = new int[128];
58+
for (char ch : s1.toCharArray()) {
59+
dict[ch]++;
60+
}
61+
for (char ch : s2.toCharArray()) {
62+
dict[ch]--;
63+
}
64+
for (int e : dict) {
65+
if (e != 0) {
66+
return false;
67+
}
68+
}
69+
return true;
70+
}
71+
72+
/**
73+
* If given strings contain only lowercase English letters.
74+
* <p>
75+
* The main "trick":
76+
* To map each character from the first string 's1' we need to subtract an integer value of 'a' character
77+
* as 'dict' array starts with 'a' character.
78+
*
79+
* @param s1 the first string
80+
* @param s2 the second string
81+
* @return true if two string are anagrams, otherwise false
82+
*/
83+
public static boolean isAnagramsOptimised(String s1, String s2) {
84+
// 26 - English alphabet length
85+
int[] dict = new int[26];
86+
for (char ch : s1.toCharArray()) {
87+
checkLetter(ch);
88+
dict[ch - 'a']++;
89+
}
90+
for (char ch : s2.toCharArray()) {
91+
checkLetter(ch);
92+
dict[ch - 'a']--;
93+
}
94+
for (int e : dict) {
95+
if (e != 0) {
96+
return false;
97+
}
98+
}
99+
return true;
100+
}
101+
102+
private static void checkLetter(char ch) {
103+
int index = ch - 'a';
104+
if (index < 0 || index >= 26) {
105+
throw new IllegalArgumentException("Strings must contain only lowercase English letters!");
106+
}
107+
}
53108
}
Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,69 @@
11
package com.thealgorithms.strings;
22

3-
import static org.junit.jupiter.api.Assertions.*;
3+
import static org.junit.jupiter.api.Assertions.assertThrows;
44

5+
import org.junit.jupiter.api.Assertions;
56
import org.junit.jupiter.api.Test;
67

78
public class CheckAnagramsTest {
9+
private static final String MESSAGE = "Strings must contain only lowercase English letters!";
810

11+
// CHECK METHOD isAnagrams()
912
@Test
10-
public void CheckAnagrams() {
13+
public void testCheckAnagrams() {
1114
String testString1 = "STUDY";
1215
String testString2 = "DUSTY";
13-
assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
16+
Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
1417
}
1518

1619
@Test
17-
public void CheckFalseAnagrams() {
20+
public void testCheckFalseAnagrams() {
1821
String testString1 = "STUDY";
1922
String testString2 = "random";
20-
assertFalse(CheckAnagrams.isAnagrams(testString1, testString2));
23+
Assertions.assertFalse(CheckAnagrams.isAnagrams(testString1, testString2));
2124
}
2225

2326
@Test
24-
public void CheckSameWordAnagrams() {
27+
public void testCheckSameWordAnagrams() {
2528
String testString1 = "STUDY";
26-
assertTrue(CheckAnagrams.isAnagrams(testString1, testString1));
29+
Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString1));
2730
}
2831

2932
@Test
30-
public void CheckDifferentCasesAnagram() {
33+
public void testCheckDifferentCasesAnagram() {
3134
String testString1 = "STUDY";
3235
String testString2 = "dusty";
33-
assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
36+
Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
37+
}
38+
39+
// CHECK METHOD isAnagramsUnicode()
40+
// Below tests work with strings which consist of Unicode symbols & the algorithm is case-sensitive.
41+
@Test
42+
public void testStringAreValidAnagramsCaseSensitive() {
43+
Assertions.assertTrue(CheckAnagrams.isAnagramsUnicode("Silent", "liSten"));
44+
Assertions.assertTrue(CheckAnagrams.isAnagramsUnicode("This is a string", "is This a string"));
45+
}
46+
47+
@Test
48+
public void testStringAreNotAnagramsCaseSensitive() {
49+
Assertions.assertFalse(CheckAnagrams.isAnagramsUnicode("Silent", "Listen"));
50+
Assertions.assertFalse(CheckAnagrams.isAnagramsUnicode("This is a string", "Is this a string"));
51+
}
52+
53+
// CHECK METHOD isAnagramsOptimised()
54+
// Below tests work with strings which consist of only lowercase English letters
55+
@Test
56+
public void testOptimisedAlgorithmStringsAreValidAnagrams() {
57+
Assertions.assertTrue(CheckAnagrams.isAnagramsOptimised("silent", "listen"));
58+
Assertions.assertTrue(CheckAnagrams.isAnagramsOptimised("mam", "amm"));
59+
}
60+
61+
@Test
62+
public void testOptimisedAlgorithmShouldThrowExceptionWhenStringsContainUppercaseLetters() {
63+
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> CheckAnagrams.isAnagramsOptimised("Silent", "Listen"));
64+
Assertions.assertEquals(exception.getMessage(), MESSAGE);
65+
66+
exception = assertThrows(IllegalArgumentException.class, () -> Assertions.assertFalse(CheckAnagrams.isAnagramsOptimised("This is a string", "Is this a string")));
67+
Assertions.assertEquals(exception.getMessage(), MESSAGE);
3468
}
3569
}

0 commit comments

Comments
 (0)