mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-06 09:28:26 +08:00
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:
@ -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 }
|
||||
|
Reference in New Issue
Block a user