diff --git a/src/_Classics_/caeser_cipher/index.js b/src/_Classics_/caeser_cipher/index.js new file mode 100644 index 00000000..8851bf03 --- /dev/null +++ b/src/_Classics_/caeser_cipher/index.js @@ -0,0 +1,61 @@ +/** + * Most simplest encryption scheme. Read more: [http://practicalcryptography.com/ciphers/caesar-cipher/] + * @param {String} str + * @param {Number} num + */ + +function caesarCipher(str, num) { + if (!num) throw new Error('Missing argument: num'); + + const lowerCaseString = str.toLowerCase(); + const alphabets = 'abcdefghijklmnopqrstuvwxyz'.split(''); + const totalAlphabets = alphabets.length; + let result = ''; + + // handle large number, like 300 or -300 + num %= totalAlphabets; + + const alphabetsMap = new Map(); + + for (const index in alphabets) { + alphabetsMap[alphabets[index]] = index; + } + + for (let index in lowerCaseString) { + // get the current character + const currentCharacter = lowerCaseString[index]; + + // if character is space, add it to the result and continue to next + if (currentCharacter === ' ') { + result += currentCharacter; + continue; + } + + // determine the new index + /** + * const currentIndex = alphabets.indexOf(currentCharacter); + * + * With indexOf complexity will be O(n*26) + * With Map complexity will be O(n). + */ + const currentIndex = Number(alphabetsMap[currentCharacter]); + let newIndex = currentIndex + num; + + // if the index passes 25, restart from 0 + if (newIndex> totalAlphabets - 1) { + newIndex -= totalAlphabets; + } + + if (newIndex < 0) { + newIndex = totalAlphabets + newIndex; + } + + // check if the character in original string was upper case + if (str[index] === str[index].toUpperCase()) { + result += alphabets[newIndex].toUpperCase(); + } else { + result += alphabets[newIndex]; + } + } + return result; +} diff --git a/src/_Classics_/fibonacci/index.js b/src/_Classics_/fibonacci/index.js new file mode 100644 index 00000000..936f01ae --- /dev/null +++ b/src/_Classics_/fibonacci/index.js @@ -0,0 +1,36 @@ +// the algorithm has time complexity of O(n^2), very bad! +function fibonacci(position) { + // if position is 1 or 2, the number in fibonacci sequence will be 1 + if (position < 3) { + return 1; + } + // else the element in fibonacci sequence will be the sum of + // element at position(p) (p -1) and (p - 2) + return fibonacci(position - 2) + fibonacci(position - 1); +} + +/** + * Memoization. In computing, memoization or memoisation is an + * optimization technique used primarily to speed up computer + * programs by storing the results of expensive function + * calls and returning the cached result when the + * same inputs occur again + */ + +// Linear time, test with index as 510 for both the functions +function fibonacciMemoized(index, cache) { + cache = cache || []; + + if (cache[index]) { + return cache[index]; + } else { + if (index < 3) { + return 1; + } else { + cache[index] = + fibonacciMemoized(index - 1, cache) + + fibonacciMemoized(index - 2, cache); + } + } + return cache[index]; +} diff --git a/src/_Problems_/reverse-number/index.js b/src/_Problems_/reverse-number/index.js index a2d6c822..bec47765 100644 --- a/src/_Problems_/reverse-number/index.js +++ b/src/_Problems_/reverse-number/index.js @@ -15,6 +15,47 @@ function reverseNumber(num) { return reverse * Math.sign(num); } +/** + * + * Given a 32-bit signed integer, reverse digits of an integer. + + Example 1: + + Input: 123 + Output: 321 + Example 2: + + Input: -123 + Output: -321 + Example 3: + + Input: 1534236469 + Output: 0 // overflows + Note: + Assume we are dealing with an environment which could only + store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. + For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows. + */ + +function reverse32BitInt(x) { + let isNegetive = 0; + if (x < 0) { + x *= -1; + isNegetive = 1; + } + let reverse = 0; + while (x>= 1) { + const r = Math.floor(x % 10); + reverse = reverse * 10 + r; + x = Math.floor(x / 10); + } + if (reverse> 0x7fffffff) { + return 0; + } + return isNegetive ? reverse * -1 : reverse; +} + module.exports = { reverseNumber, + reverse32BitInt }; diff --git a/src/_Problems_/reverse-number/reverse-number.test.js b/src/_Problems_/reverse-number/reverse-number.test.js index 947a4780..b4dff2f5 100644 --- a/src/_Problems_/reverse-number/reverse-number.test.js +++ b/src/_Problems_/reverse-number/reverse-number.test.js @@ -1,23 +1,43 @@ -const { reverseNumber } = require('.'); +const { reverseNumber, reverse32BitInt } = require('.'); describe('Reverse Numbers', () => { - it('Should return a number', () => { - expect(typeof reverseNumber(1) === 'number'); - }); + describe('Normal Reverse', () => { + it('Should return a number', () => { + expect(typeof reverseNumber(1) === 'number'); + }); - it('Should reverse 45 to 54', () => { - expect(reverseNumber(45)).toEqual(54); - }); + it('Should reverse 45 to 54', () => { + expect(reverseNumber(45)).toEqual(54); + }); - it('Should reverse -2 to -2', () => { - expect(reverseNumber(-2)).toEqual(-2); - }); + it('Should reverse -2 to -2', () => { + expect(reverseNumber(-2)).toEqual(-2); + }); + + it('Should reverse -1234567 to -7654321', () => { + expect(reverseNumber(-1234567)).toEqual(-7654321); + }); - it('Should reverse -1234567 to -7654321', () => { - expect(reverseNumber(-1234567)).toEqual(-7654321); + it('Should throw error for invalid argument', () => { + expect(() => reverseNumber('hello')).toThrow('Invalid Argument'); + }); }); - it('Should throw error for invalid argument', () => { - expect(() => reverseNumber('hello')).toThrow('Invalid Argument'); + describe('32-bit signed integer reversal', () => { + it('Should return a number', () => { + expect(typeof reverse32BitInt(1) === 'number'); + }); + + it('Should reverse 123 to 321', () => { + expect(reverse32BitInt(123)).toEqual(321); + }); + + it('Should reverse -871 to -178', () => { + expect(reverse32BitInt(-871)).toEqual(-178); + }); + + it('Should return 0 for 1534236469 because of overflow when reversed', () => { + expect(reverse32BitInt(1534236469)).toEqual(0); + }); }); });