# Algorithm to determine if two strings are an anagram
> The anagram test is commonly used to demonstrate how an naive implementation can perform significant order of magnitudes slower than an efficient one.
> A word is an anagram of another if you can rearrange its characters to produce the second word. Here we write a function that given two strings determines if they are anagrams of each other.


```js
/**
 * A word is an anagram of another if you can rearrange its characters to produce the second word.
 * Given two strings determine if they are anagrams of each other.
 * - 'earth' and 'heart' are anagrams
 * - 'silent' and 'listen' are anagrams
 * - 'foo' and 'bar' are not anagrams
 */
```

* We will start by creating our areAnagrams function

```js
export function areAnagrams(s1: string, s2: string): boolean {
}
```
A plain implementation that derives from the definition would be to
* check all the permutations of s1
* and then see if it is equal to s2
* If they are then the strings are anagrams
* If no permutation matched then they are not anagrams

```js
export function areAnagrams(s1: string, s2: string): boolean {
  for (const permutation of permutations(s1)) {
    if (permutation === s2) return true;
  }
  return false;
}
```
***Select the for line***
* Although such an implementation would work, in this case the complexity of the algorithm will be equal to possible permutations of s1, so order of n! (where n is the number of characters in the string).

***Select the first line of the requirements***
* If you read into the requirements you can realize that instead of doing actual re-arrangments you simply need to check if they have *exactly* the same characters.

***Delete the function body***
One quick way of checking the equality between two sets of characters in strings is simply to
* break the strings into their characters, sort them, and join them again.
* we do the same for the second strings.
* finally we check if the strings are equal.
* if these sorted character strings are equal then the original strings were anagrams.

```js
  s1 = s1.split('').sort().join('');
  s2 = s2.split('').sort().join('');
  return s1 === s2;
```

***Select the sort function***
* The complexity in this case will be driven by the sort function which is of the order `nLogn`. We can do better.

***Delete the function body***
* A better way to make sure that the strings have the same characters is to simply use a HashMap that counts the characters between the two strings and makes sure this count per character is the same between the strings

```js
export function areAnagrams(s1: string, s2: string): boolean {
  const charCount = new Map<string, number>();
  for (const char of s1.split('')) {
    charCount.set(char, (charCount.get(char) || 0) + 1);
  }
  for (const char of s2.split('')) {
    if (!charCount.has(char)) return false;
    charCount.set(char, charCount.get(char) - 1);
  }
  return Array.from(charCount.values()).every(val => val === 0);
}
```
* We start by creating a map to track this character count. We initialize it to a map with string keys and number values.
* We go ahead and iterate through all the characters in string 1.
  * For each character in string 1
  * We set the character count for this character.
  * We get the previous value, If there was no previous value we initializing it to 0
  * Finally we increment the previous count by 1.
* We repeat the process for the second string. Iterating through all the characters in the second string.
  * if there is no key for it from string 1. Then we know we don't have an anagram.
  * Otherwise simply decrement the count
* Finally we go through all the values in the characterCount map
  * and simply make sure that every value is 0.
  * This ensures that we saw an equal number of character counts in string 1 (during incrementing) and string 2 (during decrementing).

***Select the implementation***
* Since we are simply looping through the characters in the two strings and doing constant amount of work in each iteration the time complexity of this version is of order n (O(n)) where n is the number of characters in the strings.
import { areAnagrams } from './anagram';

test('anagrams', () => {
  expect(areAnagrams('life', 'file')).toBeTruthy();
  expect(areAnagrams('life', 'lifl')).toBeFalsy();
  expect(areAnagrams('life', 'lifel')).toBeFalsy();
});
/**
 * A word is an anagram of another if you can rearrange its characters to produce the second word.
 * Given two strings determines if they are anagrams of each other.
 * - 'earth' and 'heart' are anagrams
 * - 'silent' and 'listen' are anagrams
 * - 'foo' and 'bar' are not anagrams
 */
function areAnagrams(s1: string, s2: string): boolean {
  const charCount = new Map<string, number>();
  for (const char of s1.split('')) {
    charCount.set(char, (charCount.get(char) || 0) + 1);
  }
  for (const char of s2.split('')) {
    if (!charCount.has(char)) return false;
    charCount.set(char, charCount.get(char) - 1);
  }
  return Array.from(charCount.values()).every(val => val === 0);
}


console.log("listen and silent:")
console.log(areAnagrams("listen", "silent"))

console.log("foo and bar:")
console.log(areAnagrams("foo", "bar"))

<!DOCTYPE html>
<html>
  <body>
    <!-- // make console.log will write to the page for better in-browser experience -->
    <script>
      (function () {
    var body = document.querySelector('body');
    body.style['fontFamily'] = 'monospace';
    body.style['fontSize'] = '2em';
    console.log = function (x) { body.innerText += x + '\n'; };
    }());
  </script>
  <script src="./anagram.js"></script>
  </body>
</html>