Repository: TheAlgorithms/Java
Pull request #4231 (2023-07-06 12:37:47)

Added new implementations for CheckAnagrams class
Changes:
- added 2 new algorithm implementations
- added unit tests for CheckAnagrams class

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.


yanglbme: Please move the test code to `src/test/java/com/thealgorithms/strings/` package @albina-astr 
albina-astr: @yanglbme Hi, thank you for the review. 
Sorry, I didn't notice that the test class already exists. I've just added new test cases to the test class.

Patch:
diff --git a/src/main/java/com/thealgorithms/strings/CheckAnagrams.java b/src/main/java/com/thealgorithms/strings/CheckAnagrams.java
index 87ec3fae..a20e8b4a 100644
--- a/src/main/java/com/thealgorithms/strings/CheckAnagrams.java
+++ b/src/main/java/com/thealgorithms/strings/CheckAnagrams.java
@@ -8,13 +8,6 @@ import java.util.Map;
  * differently (ignoring the case).
  */
 public class CheckAnagrams {
-
-    public static void main(String[] args) {
-        assert isAnagrams("Silent", "Listen");
-        assert isAnagrams("This is a string", "Is this a string");
-        assert !isAnagrams("There", "Their");
-    }
-
     /**
      * Check if two strings are anagrams or not
      *
@@ -50,4 +43,66 @@ public class CheckAnagrams {
         }
         return true;
     }
+
+    /**
+     * If given strings contain Unicode symbols.
+     * The first 128 ASCII codes are identical to Unicode.
+     * This algorithm is case-sensitive.
+     *
+     * @param s1 the first string
+     * @param s2 the second string
+     * @return true if two string are anagrams, otherwise false
+     */
+    public static boolean isAnagramsUnicode(String s1, String s2) {
+        int[] dict = new int[128];
+        for (char ch : s1.toCharArray()) {
+            dict[ch]++;
+        }
+        for (char ch : s2.toCharArray()) {
+            dict[ch]--;
+        }
+        for (int e : dict) {
+            if (e != 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * If given strings contain only lowercase English letters.
+     * <p>
+     * The main "trick":
+     * To map each character from the first string 's1' we need to subtract an integer value of 'a' character
+     * as 'dict' array starts with 'a' character.
+     *
+     * @param s1 the first string
+     * @param s2 the second string
+     * @return true if two string are anagrams, otherwise false
+     */
+    public static boolean isAnagramsOptimised(String s1, String s2) {
+        // 26 - English alphabet length
+        int[] dict = new int[26];
+        for (char ch : s1.toCharArray()) {
+            checkLetter(ch);
+            dict[ch - 'a']++;
+        }
+        for (char ch : s2.toCharArray()) {
+            checkLetter(ch);
+            dict[ch - 'a']--;
+        }
+        for (int e : dict) {
+            if (e != 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static void checkLetter(char ch) {
+        int index = ch - 'a';
+        if (index < 0 || index >= 26) {
+            throw new IllegalArgumentException("Strings must contain only lowercase English letters!");
+        }
+    }
 }


Test patch:
diff --git a/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java b/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java
index 4e285433..82a75a13 100644
--- a/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java
+++ b/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java
@@ -1,35 +1,69 @@
 package com.thealgorithms.strings;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 public class CheckAnagramsTest {
+    private static final String MESSAGE = "Strings must contain only lowercase English letters!";
 
+    // CHECK METHOD isAnagrams()
     @Test
-    public void CheckAnagrams() {
+    public void testCheckAnagrams() {
         String testString1 = "STUDY";
         String testString2 = "DUSTY";
-        assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
+        Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
     }
 
     @Test
-    public void CheckFalseAnagrams() {
+    public void testCheckFalseAnagrams() {
         String testString1 = "STUDY";
         String testString2 = "random";
-        assertFalse(CheckAnagrams.isAnagrams(testString1, testString2));
+        Assertions.assertFalse(CheckAnagrams.isAnagrams(testString1, testString2));
     }
 
     @Test
-    public void CheckSameWordAnagrams() {
+    public void testCheckSameWordAnagrams() {
         String testString1 = "STUDY";
-        assertTrue(CheckAnagrams.isAnagrams(testString1, testString1));
+        Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString1));
     }
 
     @Test
-    public void CheckDifferentCasesAnagram() {
+    public void testCheckDifferentCasesAnagram() {
         String testString1 = "STUDY";
         String testString2 = "dusty";
-        assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
+        Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString2));
+    }
+
+    // CHECK METHOD isAnagramsUnicode()
+    // Below tests work with strings which consist of Unicode symbols & the algorithm is case-sensitive.
+    @Test
+    public void testStringAreValidAnagramsCaseSensitive() {
+        Assertions.assertTrue(CheckAnagrams.isAnagramsUnicode("Silent", "liSten"));
+        Assertions.assertTrue(CheckAnagrams.isAnagramsUnicode("This is a string", "is This a string"));
+    }
+
+    @Test
+    public void testStringAreNotAnagramsCaseSensitive() {
+        Assertions.assertFalse(CheckAnagrams.isAnagramsUnicode("Silent", "Listen"));
+        Assertions.assertFalse(CheckAnagrams.isAnagramsUnicode("This is a string", "Is this a string"));
+    }
+
+    // CHECK METHOD isAnagramsOptimised()
+    // Below tests work with strings which consist of only lowercase English letters
+    @Test
+    public void testOptimisedAlgorithmStringsAreValidAnagrams() {
+        Assertions.assertTrue(CheckAnagrams.isAnagramsOptimised("silent", "listen"));
+        Assertions.assertTrue(CheckAnagrams.isAnagramsOptimised("mam", "amm"));
+    }
+
+    @Test
+    public void testOptimisedAlgorithmShouldThrowExceptionWhenStringsContainUppercaseLetters() {
+        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> CheckAnagrams.isAnagramsOptimised("Silent", "Listen"));
+        Assertions.assertEquals(exception.getMessage(), MESSAGE);
+
+        exception = assertThrows(IllegalArgumentException.class, () -> Assertions.assertFalse(CheckAnagrams.isAnagramsOptimised("This is a string", "Is this a string")));
+        Assertions.assertEquals(exception.getMessage(), MESSAGE);
     }
 }