merge: Upgrade checkAnagram function & Fixes (#902)

* pref: optimize the algo via reduce & replace method

* feat: add TypeError for invalid types

* test: upgrade test case for invalid types

* docs: add js doc

* test: modify the case-sensitive test case

* pref: Optimize algo & add case-insensitive mode

* style: format with standard style

* docs: fix the js doc

* docs: rename function name & add comments

* feat: add chackAnagramViaMap function

* test: add test case for checkAnagramViaMap func

* fix: remove **Via** from functions name

* style: fix alignment of js doc

* chore: grammar fix

Co-authored-by: Rak Laptudirm <raklaptudirm@gmail.com>
This commit is contained in:
Fahim Faisaal
2022-02-25 22:26:30 +06:00
committed by GitHub
parent 0178efd8df
commit d466be977e
2 changed files with 173 additions and 51 deletions

View File

@ -1,10 +1,17 @@
// An [Anagram](https://en.wikipedia.org/wiki/Anagram) is a string that is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
// Anagram check is case sensitive; i.e. Aba and aba is not a anagram.
// inputs are strings i.e. str1 and str2
const checkAnagram = (str1, str2) => {
// An [Anagram](https://en.wikipedia.org/wiki/Anagram) is a string that is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. Anagram check is not case-sensitive;
/**
* @function checkAnagramRegex
* @param {string} str1
* @param {string} str2
* @returns {boolean}
* @description - check anagram with the help of Regex
* @example - checkAnagramRegex('node', 'deno') => true
* @example - checkAnagramRegex('Eleven plus two', 'Twelve plus one') => true
*/
const checkAnagramRegex = (str1, str2) => {
// check that inputs are strings.
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
return 'Not string(s)'
throw new TypeError('Both arguments should be strings.')
}
// If both strings have not same lengths then they can not be anagram.
@ -12,36 +19,58 @@ const checkAnagram = (str1, str2) => {
return false
}
// Use hashmap to keep count of characters in str1
/**
* str1 converted to an array and traverse each letter of str1 by reduce method
* reduce method return string which is empty or not.
* if it returns empty string '' -> falsy, with Logical !(NOT) Operator, it's will be converted to boolean and return true else false
*/
return ![...str1].reduce(
(str2Acc, cur) => str2Acc.replace(new RegExp(cur, 'i'), ''), // remove the similar letter from str2Acc in case-insensitive
str2
)
}
const str1CharCount = new Map()
/**
* @function checkAnagramMap
* @description - check anagram via using HashMap
* @param {string} str1
* @param {string} str2
* @returns {boolean}
* @example - checkAnagramMap('node', 'deno') => true
* @example - checkAnagramMap('Eleven plus two', 'Twelve plus one') => true
*/
const checkAnagramMap = (str1, str2) => {
// check that inputs are strings.
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
throw new TypeError('Both arguments should be strings.')
}
for (let i = 0; i < str1.length; i++) {
let previousCount = 0
if (str1CharCount.has(str1[i])) {
previousCount = str1CharCount.get(str1[i])
// If both strings have not same lengths then they can not be anagram.
if (str1.length !== str2.length) {
return false
}
const str1List = Array.from(str1.toUpperCase()) // str1 to array
// get the occurrences of str1 characters by using HashMap
const str1Occurs = str1List.reduce(
(map, char) => map.set(char, map.get(char) + 1 || 1),
new Map()
)
for (const char of str2.toUpperCase()) {
// if char has not exist to the map it's return false
if (!str1Occurs.has(char)) {
return false
}
str1CharCount.set(str1[i], previousCount + 1)
}
// Now check if second string has same characters?
let getCharCount = str1Occurs.get(char)
str1Occurs.set(char, --getCharCount)
for (let i = 0; i < str2.length; i++) {
let previousCount = 0
// if str1CharCount has no key for str2[i] then not anagram.
if (!str1CharCount.has(str2[i])) return false
previousCount = str1CharCount.get(str2[i])
str1CharCount.set(str2[i], previousCount - 1)
}
// Now check if all entries in hashmap has zeros.
for (const key in str1CharCount) {
if (str1CharCount[key] !== 0) return false
getCharCount === 0 && str1Occurs.delete(char)
}
return true
}
export { checkAnagram }
export { checkAnagramRegex, checkAnagramMap }