diff --git a/.github/workflows/JavascriptAlgoCL.yml b/.github/workflows/JavascriptAlgoCL.yml new file mode 100644 index 0000000000..e67ff5bf56 --- /dev/null +++ b/.github/workflows/JavascriptAlgoCL.yml @@ -0,0 +1,36 @@ +# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Javascript Algorithm CI + +on: [push, pull_request] + +permissions: write-all + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js + uses: actions/setup-node@v2 + + - name: npm install, build, and test + run: | + npm install doctest + npm install standard --save-dev + npx doctest **/*.js || true # TODO: Add all doctests + npx standard + npm ci + npm run build --if-present + + env: + CI: true + + - name: Run the tests + run: npm test -- --coverage + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3.1.0 diff --git a/.github/workflows/codacy-analysis.yaml b/.github/workflows/codacy-analysis.yaml new file mode 100644 index 0000000000..9c7d5fe5a1 --- /dev/null +++ b/.github/workflows/codacy-analysis.yaml @@ -0,0 +1,14 @@ +name: Codacy Analysis CLI + +on: [push, pull_request] + +jobs: + codacy-analysis-cli: + name: Codacy Analysis CLI + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@main + + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@master diff --git a/DIRECTORY.md b/DIRECTORY.md index dccfbb7c9a..e2a0ed81d7 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -170,6 +170,7 @@ * [IsEven](Maths/IsEven.js) * [IsOdd](Maths/IsOdd.js) * [IsPronic](Maths/IsPronic.js) + * [JugglerSequence](Maths/JugglerSequence.js) * [LeapYear](Maths/LeapYear.js) * [LinearSieve](Maths/LinearSieve.js) * [LucasSeries](Maths/LucasSeries.js) @@ -186,9 +187,7 @@ * [PerfectNumber](Maths/PerfectNumber.js) * [PerfectSquare](Maths/PerfectSquare.js) * [PermutationAndCombination](Maths/PermutationAndCombination.js) - * [PiApproximationMonteCarlo](Maths/PiApproximationMonteCarlo.js) * [Polynomial](Maths/Polynomial.js) - * [Pow](Maths/Pow.js) * [PowLogarithmic](Maths/PowLogarithmic.js) * [PrimeCheck](Maths/PrimeCheck.js) * [PrimeFactors](Maths/PrimeFactors.js) @@ -281,10 +280,8 @@ * [TimSort](Sorts/TimSort.js) * [TopologicalSort](Sorts/TopologicalSort.js) * **String** - * [AlphaNumericPalindrome](String/AlphaNumericPalindrome.js) * [AlternativeStringArrange](String/AlternativeStringArrange.js) * [BoyerMoore](String/BoyerMoore.js) - * [CheckAnagram](String/CheckAnagram.js) * [CheckCamelCase](String/CheckCamelCase.js) * [CheckExceeding](String/CheckExceeding.js) * [CheckFlatCase](String/CheckFlatCase.js) diff --git a/Maths/PiApproximationMonteCarlo.js b/Maths/PiApproximationMonteCarlo.js deleted file mode 100644 index 08849b5475..0000000000 --- a/Maths/PiApproximationMonteCarlo.js +++ /dev/null @@ -1,21 +0,0 @@ -// Wikipedia: https://en.wikipedia.org/wiki/Monte_Carlo_method -// Video Explanation: https://www.youtube.com/watch?v=ELetCV_wX_c - -const piEstimation = (iterations = 100000) => { - let circleCounter = 0 - - for (let i = 0; i < iterations; i++) { - // generating random points and checking if it lies within a circle of radius 1 - const x = Math.random() - const y = Math.random() - const radius = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) - - if (radius < 1) circleCounter += 1 - } - - // fomula for pi = (ratio of number inside circle and total iteration) x 4 - const pi = (circleCounter / iterations) * 4 - return pi -} - -export { piEstimation } diff --git a/Maths/Pow.js b/Maths/Pow.js deleted file mode 100644 index 44ce31e8ac..0000000000 --- a/Maths/Pow.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @function powLinear - * @description - The powLinear function is a power function with Linear O(n) complexity - * @param {number} base - * @param {number} exponent - * @returns {number} - * @example - powLinear(2, 2) => 4 --> 2 * 2 - * @example - powLinear(3, 3) => 27 --> 3 * 3 * 3 - */ -const powLinear = (base, exponent) => { - if (exponent < 0) { - base = 1 / base - exponent = -exponent - } - - let result = 1 - - while (exponent--) { // Break the execution while the exponent will 0 - result *= base - } - - return result -} - -/** - * @function powFaster - * @description - The powFaster function is a power function with O(logN) complexity - * @param {number} base - * @param {number} exponent - * @returns {number} - * @example - powFaster(2, 2) => 4 --> 2 * 2 - * @example - powFaster(3, 3) => 27 --> 3 * 3 * 3 - */ -const powFaster = (base, exponent) => { - if (exponent < 2) { // explanation below - 1 - return base && ([1, base][exponent] || powFaster(1 / base, -exponent)) - } - - if (exponent & 1) { // if the existing exponent is odd - return base * powFaster(base * base, exponent >> 1) // explanation below - 2 - } - - return powFaster(base * base, exponent / 2) -} - -/** - * 1 - Magic of short circuit evaluation (&&, ||) - * if the base is 0 then it returns 0 cause 0 is falsy - * if the base is not 0 then it's must be truthy. after that, it will be executed the right portion of the && (AND) operator - * Now it checks the exponent by the help array index, is it 0 or 1. - * if the exponent is not 0 or 1 it's definitely less than 0, and a negative number is not a valid index number so it returns "undefined" - * if the expression is undefined mean -> falsy, the || (OR) operator evaluates the right portion that is a recursive function. - */ - -/** - * 2 - Play with right shift bitwise operator (>>) - * right shift with any odd numbers it returns the floor number instead of float. - * E.g. if the number is 5, after right shifting with 1 it's will give us 2, not 2.5 - * cause the right shift formula is --> x >> y = |x| / 2^y - */ - -export { powLinear, powFaster } diff --git a/Maths/test/PiApproximationMonteCarlo.test.js b/Maths/test/PiApproximationMonteCarlo.test.js deleted file mode 100644 index 9727aa5788..0000000000 --- a/Maths/test/PiApproximationMonteCarlo.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import { piEstimation } from '../PiApproximationMonteCarlo' - -describe('PiApproximationMonteCarlo', () => { - it('should be between the range of 2 to 4', () => { - const pi = piEstimation() - const piRange = pi >= 2 && pi <= 4 - expect(piRange).toBeTruthy() - }) -}) diff --git a/Maths/test/Pow.test.js b/Maths/test/Pow.test.js deleted file mode 100644 index 9ffb64e52d..0000000000 --- a/Maths/test/Pow.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import { powLinear, powFaster } from '../Pow' - -describe('Testing powLinear function', () => { - it('should return 1 for numbers with exponent 0', () => { - expect(powLinear(2, 0)).toBe(1) - }) - - it('should return 0.5 for numbers with exponent -1', () => { - expect(powLinear(2, -1)).toBe(0.5) - }) - - it('should return 0 for numbers with base 0', () => { - expect(powLinear(0, 23)).toBe(0) - }) - - it('should return the base to the exponent power', () => { - expect(powLinear(24, 4)).toBe(331776) - }) -}) - -describe('Testing powFaster function', () => { - it('should return 1 for numbers with exponent 0', () => { - expect(powFaster(2, 0)).toBe(1) - }) - - it('should return 0.5 for numbers with exponent -1', () => { - expect(powFaster(2, -1)).toBe(0.5) - }) - - it('should return 0 for numbers with base 0', () => { - expect(powFaster(0, 23)).toBe(0) - }) - - it('should return the base to the exponent power', () => { - expect(powFaster(24, 4)).toBe(331776) - }) - - it('should return the result in O(lonN) complexity', () => { - expect(powFaster(2, 64)).toBe(18446744073709552000) // execution time Math.log2(64) -> 6 - }) -}) diff --git a/String/AlphaNumericPalindrome.js b/String/AlphaNumericPalindrome.js deleted file mode 100644 index f3de94b642..0000000000 --- a/String/AlphaNumericPalindrome.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @function alphaNumericPalindrome - * @description alphaNumericPalindrome should return true if the string has alphanumeric characters that are palindrome irrespective of special characters and the letter case. - * @param {string} str the string to check - * @returns {boolean} - * @see [Palindrome](https://en.wikipedia.org/wiki/Palindrome) - * @example - * The function alphaNumericPalindrome() receives a string with varying formats - * like "racecar", "RaceCar", and "race CAR" - * The string can also have special characters - * like "2A3*3a2", "2A3 3a2", and "2_A3*3#A2" - * - * But the catch is, we have to check only if the alphanumeric characters - * are palindrome i.e remove spaces, symbols, punctuations etc - * and the case of the characters doesn't matter - */ -const alphaNumericPalindrome = (str) => { - if (typeof str !== 'string') { - throw new TypeError('Argument should be string') - } - - // removing all the special characters and turning everything to lowercase - const newStr = str.replace(/[^a-z0-9]+/ig, '').toLowerCase() - const midIndex = newStr.length >> 1 // x >> y = floor(x / 2^y) - - for (let i = 0; i < midIndex; i++) { - if (newStr.at(i) !== newStr.at(~i)) { // ~n = -(n + 1) - return false - } - } - - return true -} - -export default alphaNumericPalindrome diff --git a/String/CheckAnagram.js b/String/CheckAnagram.js deleted file mode 100644 index 1fc5854298..0000000000 --- a/String/CheckAnagram.js +++ /dev/null @@ -1,76 +0,0 @@ -// 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') { - throw new TypeError('Both arguments should be strings.') - } - - // If both strings have not same lengths then they can not be anagram. - if (str1.length !== str2.length) { - return false - } - - /** - * 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 - ) -} - -/** - * @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.') - } - - // 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 - } - - let getCharCount = str1Occurs.get(char) - str1Occurs.set(char, --getCharCount) - - getCharCount === 0 && str1Occurs.delete(char) - } - - return true -} - -export { checkAnagramRegex, checkAnagramMap } diff --git a/String/test/AlphaNumericPalindrome.test.js b/String/test/AlphaNumericPalindrome.test.js deleted file mode 100644 index ab7373b53b..0000000000 --- a/String/test/AlphaNumericPalindrome.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import alphaNumericPalindrome from '../AlphaNumericPalindrome' - -describe('Testing the alpha numeric palindrome', () => { - // should return true if the given string has alphanumeric characters that are palindrome irrespective of case and symbols - it('Testing with valid alphabetic palindrome', () => { - expect(alphaNumericPalindrome('eye')).toBe(true) - expect(alphaNumericPalindrome('Madam')).toBe(true) - expect(alphaNumericPalindrome('race CAR')).toBe(true) - expect(alphaNumericPalindrome('A man, a plan, a canal. Panama')).toBe(true) - }) - - it('Testing with number and symbol', () => { - expect(alphaNumericPalindrome('0_0 (: /-:) 0-0')).toBe(true) - expect(alphaNumericPalindrome('03_|53411435|_30')).toBe(true) - }) - - it('Testing with alphabets and symbols', () => { - expect(alphaNumericPalindrome('five|_/|evif')).toBe(true) - expect(alphaNumericPalindrome('five|_/|four')).toBe(false) - }) -}) diff --git a/String/test/CheckAnagram.test.js b/String/test/CheckAnagram.test.js deleted file mode 100644 index 44adc196bc..0000000000 --- a/String/test/CheckAnagram.test.js +++ /dev/null @@ -1,181 +0,0 @@ -import { checkAnagramMap, checkAnagramRegex } from '../CheckAnagram' - -describe('Testing checkAnagramRegex', () => { - it.each` - inputOne | inputTwo - ${123456} | ${'abcd'} - ${[1, 2, 3, 4, 5, 6]} | ${'abcd'} - ${{ test: 'test' }} | ${'abcd'} - ${'abcd'} | ${123456} - ${'abcd'} | ${[1, 2, 3, 4, 5, 6]} - ${'abcd'} | ${{ test: 'test' }} - `( - 'expects to throw the type Error given values $inputOne and $inputTwo', - ({ inputOne, inputTwo }) => { - expect( - () => checkAnagramRegex(inputOne, inputTwo) - ).toThrowError() - } - ) - - it('expects to return false if the arguments have different lengths', () => { - const SUT = checkAnagramRegex('abs', 'abds') - expect(SUT).toBe(false) - }) - - it('expects to return false if the arguments are not anagrams', () => { - const SUT = checkAnagramRegex('abcs', 'abds') - expect(SUT).toBe(false) - }) - - it('expects to return true if the arguments are anagrams', () => { - const SUT = checkAnagramRegex('abcd', 'bcad') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments of length 1 and are the same letter', () => { - const SUT = checkAnagramRegex('a', 'a') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments of are both empty strings', () => { - const SUT = checkAnagramRegex('', '') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams with an odd length', () => { - const SUT = checkAnagramRegex('abcde', 'edcab') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams with an even length', () => { - const SUT = checkAnagramRegex('abcdef', 'fedcab') - expect(SUT).toBe(true) - }) - - it('expects to return false if either argument is an empty string while the other is not', () => { - const SUT = checkAnagramRegex('', 'edcab') - expect(SUT).toBe(false) - const SUT2 = checkAnagramRegex('edcab', '') - expect(SUT2).toBe(false) - }) - - it('expects to return true if the arguments contain the same letters but have unequal case', () => { - const SUT = checkAnagramRegex('ABDCE', 'abcde') - expect(SUT).toBe(true) - const SUT2 = checkAnagramRegex('AbCdE', 'aBCdE') - expect(SUT2).toBe(true) - const SUT3 = checkAnagramRegex('Eleven plus two', 'Twelve plus one') - expect(SUT3).toBe(true) - }) - - it('expects to return true if the arguments are anagrams and contain number characters', () => { - const SUT = checkAnagramRegex('a1b2', '12ba') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams and contain space characters', () => { - const SUT = checkAnagramRegex('a1 b2', '1 2ba') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams and contain punctuation characters', () => { - const SUT = checkAnagramRegex('a!1b@2', '1@2ba!') - expect(SUT).toBe(true) - }) - - it('expects to return false if the arguments contain the same letters but contain a different amount of space characters', () => { - const SUT = checkAnagramRegex('ea cb', 'e cba') - expect(SUT).toBe(false) - }) -}) - -describe('Testing checkAnagramMap', () => { - it.each` - inputOne | inputTwo - ${123456} | ${'abcd'} - ${[1, 2, 3, 4, 5, 6]} | ${'abcd'} - ${{ test: 'test' }} | ${'abcd'} - ${'abcd'} | ${123456} - ${'abcd'} | ${[1, 2, 3, 4, 5, 6]} - ${'abcd'} | ${{ test: 'test' }} - `( - 'expects to throw the type Error given values $inputOne and $inputTwo', - ({ inputOne, inputTwo }) => { - expect( - () => checkAnagramMap(inputOne, inputTwo) - ).toThrowError() - } - ) - - it('expects to return false if the arguments have different lengths', () => { - const SUT = checkAnagramMap('abs', 'abds') - expect(SUT).toBe(false) - }) - - it('expects to return false if the arguments are not anagrams', () => { - const SUT = checkAnagramMap('abcs', 'abds') - expect(SUT).toBe(false) - }) - - it('expects to return true if the arguments are anagrams', () => { - const SUT = checkAnagramMap('abcd', 'bcad') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments of length 1 and are the same letter', () => { - const SUT = checkAnagramMap('a', 'a') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments of are both empty strings', () => { - const SUT = checkAnagramMap('', '') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams with an odd length', () => { - const SUT = checkAnagramMap('abcde', 'edcab') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams with an even length', () => { - const SUT = checkAnagramMap('abcdef', 'fedcab') - expect(SUT).toBe(true) - }) - - it('expects to return false if either argument is an empty string while the other is not', () => { - const SUT = checkAnagramMap('', 'edcab') - expect(SUT).toBe(false) - const SUT2 = checkAnagramMap('edcab', '') - expect(SUT2).toBe(false) - }) - - it('expects to return true if the arguments contain the same letters but have unequal case', () => { - const SUT = checkAnagramMap('ABDCE', 'abcde') - expect(SUT).toBe(true) - const SUT2 = checkAnagramMap('AbCdE', 'aBCdE') - expect(SUT2).toBe(true) - const SUT3 = checkAnagramMap('Eleven plus two', 'Twelve plus one') - expect(SUT3).toBe(true) - }) - - it('expects to return true if the arguments are anagrams and contain number characters', () => { - const SUT = checkAnagramMap('a1b2', '12ba') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams and contain space characters', () => { - const SUT = checkAnagramMap('a1 b2', '1 2ba') - expect(SUT).toBe(true) - }) - - it('expects to return true if the arguments are anagrams and contain punctuation characters', () => { - const SUT = checkAnagramMap('a!1b@2', '1@2ba!') - expect(SUT).toBe(true) - }) - - it('expects to return false if the arguments contain the same letters but contain a different amount of space characters', () => { - const SUT = checkAnagramMap('ea cb', 'e cba') - expect(SUT).toBe(false) - }) -})
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: