diff --git a/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js new file mode 100644 index 0000000..d42af05 --- /dev/null +++ b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js @@ -0,0 +1,43 @@ +/** + * Searches recursively number from the list + * @param {Array} list + * @param {number} item Search item + * @param {number} low Lower limit of search in the list + * @param {number} high Highest limit of search in the list + * @return {(number | null)} Number if the value is found or NULL otherwise + */ +const binarySearch = ( list, item, low, high ) => { + let arrLength = list.length; + while ( low <= high ) { + let mid = Math.floor((low + high) / 2); + let guess = list[mid]; + + if ( guess === item ) { + return mid; + } else if ( guess > item ) { + high = mid - 1; + list = list.slice( 0, mid ); + return binarySearch( list, item, low, high ); + } else { + low = mid + 1; + list = list.slice( low, arrLength ); + return binarySearch( list, item, low, high ); + } + } + + return null; +}; + +/** + * Creates the array that contains numbers 1...N + * @param {number} n - number N + * @return {Array} + */ +const createArr = ( n ) => Array.from({length: n}, (v, k) => k + 1); + +const myList = createArr( 100 ); +let low = 0; +let high = myList.length - 1; + +console.log( binarySearch( myList, 3, low, high ) ); // 2 +console.log( binarySearch( myList, -1, low, high ) ); // null diff --git a/02_selection_sort/javascript/02_recursive_selection_sort.js b/02_selection_sort/javascript/02_recursive_selection_sort.js new file mode 100644 index 0000000..70f4f06 --- /dev/null +++ b/02_selection_sort/javascript/02_recursive_selection_sort.js @@ -0,0 +1,33 @@ +/** + * Finds smallest element of an aray + * @param {Array} arr array for searching + * @return {number} index of the smallest element in array + */ +const findSmallest = ( arr ) => { + let smallest = arr[0]; + let smallestIndex = 0; + let arrLen = arr.length; + + for ( let i = 0; i < arrLen; i++ ) { + if ( arr[i] < smallest ) { + smallest = arr[i]; + smallestIndex = i; + } + } + return smallestIndex; +}; + +/** + * Sorts0 recursively an array of numbers + * @param {Array} arr An array of numbers + * @return {Array} New sorted array + */ +const selectionSort = ( arr ) => { + if ( !arr.length ) return []; + let smallest = arr.splice( findSmallest( arr ), 1 ); + return smallest.concat( selectionSort( arr ) ); +}; + +let arr = [5, 3, 6, 2, 10]; + +console.log( selectionSort(arr) ); diff --git a/04_quicksort/ES6/01_loop_sum.js b/04_quicksort/ES6/01_loop_sum.js index b3ffc63..b4affdc 100644 --- a/04_quicksort/ES6/01_loop_sum.js +++ b/04_quicksort/ES6/01_loop_sum.js @@ -1,9 +1,18 @@ -const sum = (arr) => { - let total = 0; - for (let x = 0; x < arr.length; x += 1) { - total += arr[x]; - } - return total; +/** + * Sums values in array by loop "for" + * @param {Array} arr Array of numbers + * @return {number} Sum of the numbers + */ +const sumLoop = ( arr ) => { + let result = 0; + + for ( let i = 0; i < newArr.length; i++ ) { + result += newArr[i]; + } + + return result; }; -console.log(sum([1, 2, 3, 4])); // 10 +let arr = [1, 2, 3, 4]; + +console.log( sumLoop( arr ) ); // 10 diff --git a/04_quicksort/ES6/01_loop_sum_reduce_version.js b/04_quicksort/ES6/01_loop_sum_reduce_version.js new file mode 100644 index 0000000..b280792 --- /dev/null +++ b/04_quicksort/ES6/01_loop_sum_reduce_version.js @@ -0,0 +1,16 @@ +/** + * Sums values in array by function "reduce" + * @param {Array} arr Array of numbers + * @return {number} Sum of the numbers + */ +const sumReduce = ( arr ) => { + let result = newArr.reduce( ( curr, prev ) => { + return curr + prev; + } ); + + return result; +}; + +let arr = [1, 2, 3, 4]; + +console.log( sumReduce( arr ) ); // 10 diff --git a/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js b/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js new file mode 100644 index 0000000..cd3f16d --- /dev/null +++ b/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js @@ -0,0 +1,36 @@ +/** + * Recursive function of Euclidean algorithm for two numbers + * + * @param {number} a first number + * @param {number} b second number (base case) + * + * @return {number} GCD (greatest common divisor) + */ +let gcdOfTwo = ( a, b ) => { + if ( !b ) { + return a; + } + return gcdOfTwo( b, a % b ); +}; + +/** + * Recursive function of Euclidean algorithm for set of the numbers + * + * @param {Array} set Set of the numbers + * + * @return {number} GCD (greatest common divisor) + */ +let gcdOfSet = ( set ) => { + let result = set[0]; + let newArr = Array.prototype.slice.call( set, 1 ); + + newArr.map( ( el ) => { + result = gcdOfTwo( result, el ); + } ); + + return result; +}; + +const set = [1680, 640, 3360, 160, 240, 168000]; + +console.log( gcdOfSet( set ) ); // 80 diff --git a/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js b/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js new file mode 100644 index 0000000..0748369 --- /dev/null +++ b/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js @@ -0,0 +1,19 @@ +/** + * Recursive function of Euclidean algorithm + * + * @param {number} a first number + * @param {number} b second number (base case) + * + * @return {number} GCD (greatest common divisor) + */ +let getGCD = ( a, b ) => { + if ( !b ) { + return a; + } + return getGCD( b, a % b ); +}; + +const a = 1680; +const b = 640; + +console.log( getGCD( a, b ) ); // 80 diff --git a/04_quicksort/javascript/01_loop_sum.js b/04_quicksort/javascript/01_loop_sum.js index d2f70fd..4f18b77 100644 --- a/04_quicksort/javascript/01_loop_sum.js +++ b/04_quicksort/javascript/01_loop_sum.js @@ -1,11 +1,18 @@ -'use strict'; +/** + * Sums values in array by loop "for" + * @param {Array} arr Array of numbers + * @return {number} Sum of the numbers + */ +function sumLoop( arr ) { + var result = 0; -function sum(arr) { - let total = 0; - for (let x = 0; x < arr.length; x++) { - total += arr[x]; - } - return total; + for ( var i = 0; i < newArr.length; i++ ) { + result += newArr[i]; + } + + return result; } -console.log(sum([1, 2, 3, 4])) // 10 +var arr = [1, 2, 3, 4]; + +console.log( sumLoop( arr ) ); // 10 diff --git a/04_quicksort/javascript/01_loop_sum_reduce_version.js b/04_quicksort/javascript/01_loop_sum_reduce_version.js new file mode 100644 index 0000000..cd42997 --- /dev/null +++ b/04_quicksort/javascript/01_loop_sum_reduce_version.js @@ -0,0 +1,16 @@ +/** + * Sums values in array by function "reduce" + * @param {Array} arr Array of numbers + * @return {number} Sum of the numbers + */ +function sumReduce( arr ) { + var result = newArr.reduce( ( curr, prev ) => { + return curr + prev; + } ); + + return result; +} + +var arr = [1, 2, 3, 4]; + +console.log( sumReduce( arr ) ); // 10 diff --git a/04_quicksort/javascript/02_recursive_sum.js b/04_quicksort/javascript/02_recursive_sum.js index b0712f2..1d458a2 100644 --- a/04_quicksort/javascript/02_recursive_sum.js +++ b/04_quicksort/javascript/02_recursive_sum.js @@ -1,10 +1,13 @@ -'use strict'; +const arr = [1, 2, 3, 4]; -function sum(list) { - if (list.length === 0) { - return 0; - } - return list[0] + sum(list.slice(1)); -} +/** + * Sums values in array recursively + * @param {Array} arr Array of numbers + * @return {number} Sum of the numbers + */ +const sumRecursive = ( arr ) => { + if ( arr.length == 1 ) return arr[0]; + return arr[0] + sumRecursive( arr.slice( 1 ) ); +}; -console.log(sum([1, 2, 3, 4])) // 10 +console.log( sumRecursive( arr ) ); // 10 diff --git a/05_hash_tables/javascript/03_hashtable.js b/05_hash_tables/javascript/03_hashtable.js new file mode 100644 index 0000000..7c02d9d --- /dev/null +++ b/05_hash_tables/javascript/03_hashtable.js @@ -0,0 +1,173 @@ +/** + * Class HashTable + * + * @param {object} obj + */ +let HashTable = function( obj ) { + let length = 0; + this._items = ( function( obj ) { + let items = {}; + for ( let p in obj ) { + items[p] = obj[p]; + length++; + } + return items; + }( obj ) ); + + /** + * Associates the specified value to the specified key + * + * @param {string} key The key to which associate the value + * @param {string} value The value to associate to the key + * + * @return {(undefined|object)} Undefined is object didn't exists before this call + */ + this.set = function( key, value ) { + let previous = undefined; + + if ( this.has( key ) ) { + previous = this._items[key]; + } else { + length++; + } + + this._items[key] = value; + + return previous; + }; + + /** + * Returns the value associated to the specified key + * + * @param {string} key The key from which retrieve the value + * + * @return {(undefined|string)} Undefined or associated value + */ + this.get = function( key ) { + return this._items.hasOwnProperty( key ) ? this._items[key] : undefined; + }; + + /** + * Returns whether the hashtable contains the specified key + * + * @param {string} key The key to check + * + * @return {boolean} + */ + this.has = function( key ) { + return this._items.hasOwnProperty( key ); + }; + + /** + * Removes the specified key with its value + * + * @param {string} key The key to remove + * + * @return {(undefined|string)} Undefined if key doesn't exist and + * string (previous value) - value of deleted item + */ + this.remove = function( key ) { + if ( this.has( key ) ) { + let previous = this._items[key]; + length--; + delete this._items[key]; + return previous; + } else { + return undefined; + } + }; + + /** + * Returns an array with all the registered keys + * + * @return {array} + */ + this.getKeys = function() { + let keys = []; + + for ( let i in this._items ) { + if ( this.has( i ) ) { + keys.push( i ); + } + } + + return keys; + }; + + /** + * Returns an array with all the registered values + * + * @return {array} + */ + this.getValues = function() { + let values = []; + + for ( let i in this._items ) { + if ( this.has( i ) ) { + values.push( this._items[i] ); + } + } + + return values; + }; + + /** + * Iterates all entries in the specified iterator callback + * @param {function} callback A method with 2 parameters: key, value + */ + this.each = function( callback ) { + for ( let i in this._items ) { + if ( this.has( i ) ) { + callback( i, this._items[i] ); + } + } + }; + + /** + * Deletes all the key-value pairs on the hashmap + */ + this.clear = function() { + this._items = {}; + length = 0; + }; + + /** + * Gets the count of the entries in the hashtable + */ + Object.defineProperty( this, 'length', { + get: function() { + return length; + }, + }); + + /** + * Gets an array of all keys in the hashtable + */ + Object.defineProperty(this, 'keys', { + get: function() { + return this.getKeys(); + }, + }); + + /** + * Gets an array of all values in the hashtable + */ + Object.defineProperty(this, 'values', { + get: function() { + return this.getValues(); + }, + }); +}; + +let hashtable = new HashTable({'one': 1, 'two': 2, 'three': 3, 'cuatro': 4}); + +console.log( 'Original length: ' + hashtable.length ); // Original length: 4 +console.log( 'Value of key "one": ' + hashtable.get( 'one' ) ); // Value of key "one": 1 +console.log( 'Has key "foo"? ' + hashtable.has( 'foo' )); // Has key "foo"? false +console.log( 'Previous value of key "foo": ' + hashtable.set( 'foo', 'bar' ) ); // Previous value of key "foo": undefined +console.log( 'Length after set: ' + hashtable.length ); // Length after set: 5 +console.log( 'Value of key "foo": ' + hashtable.get( 'foo' ) ); // Value of key "foo": bar +console.log( 'Value of key "cuatro": ' + hashtable.get( 'cuatro' )); // Value of key "cuatro": 4 +console.log( 'Get keys by using property: ' + hashtable.keys ); // Get keys by using property: one,two,three,cuatro,foo +hashtable.clear(); +console.log( 'Length after clear: ' + hashtable.length ); // Length after clear: 0 diff --git a/09_dynamic_programming/javascript/01_longest_common_subsequence.js b/09_dynamic_programming/javascript/01_longest_common_subsequence.js index f1054d0..42660ff 100644 --- a/09_dynamic_programming/javascript/01_longest_common_subsequence.js +++ b/09_dynamic_programming/javascript/01_longest_common_subsequence.js @@ -1,7 +1,78 @@ -if (word_a[i] === word_b[j]) { - // The letters match - cell[i][j] = cell[i-1][j-1] + 1; -} else { - // The letters don't match - cell[i][j] = Math.max(cell[i-1][j], cell[i][j-1]); +/** + * Search for LCS + * + * @param {string} string1 first string + * @param {string} string2 second string + * + * @return {object} with keys: lcs, offset, sequence + */ +function lcs(string1, string2) { + if (!string1 || !string2) { + return { + lcs: 0, + offset: 0, + sequence: "" + }; + } + + let lcs = 0; + + let lastSubIndex = 0; + + let table = []; + let len1 = string1.length; + let len2 = string2.length; + let row; + let col; + + /** + * Matrix + * - has an increased dimension to avoid extra checks for previous elements + * + * - the number of rows is equal to the length of the first string + 1 + * - the number of columns is equal to the length of the second string + 1 + */ + for (row = 0; row <= len1; row++) { + table[row] = []; + for (col = 0; col <= len2; col++) { + table[row][col] = 0; + } + } + + // Fill the matrix + let i; + let j; + + for (i = 0; i < len1; i++) { + for (j = 0; j < len2; j++) { + if (string1[i] === string2[j]) { + // The letters match + if (table[i][j] === 0) { + table[i + 1][j + 1] = 1; + } else { + table[i + 1][j + 1] = table[i][j] + 1; + } + + // increment lcs if it's needed + if (table[i + 1][j + 1] > lcs) { + lcs = table[i + 1][j + 1]; + lastSubIndex = i; + } + } else { + // The letters don't match + table[i + 1][j + 1] = 0; + } + } + } + + return { + lcs: lcs, + offset: lastSubIndex - lcs + 1, + sequence: string1.slice(lastSubIndex - lcs + 1, lastSubIndex + 1) + }; } + +console.log(lcs("hish", "fish")); // { lcs: 3, offset: 1, sequence: 'ish' } +console.log(lcs("vista", "hish")); // { lcs: 2, offset: 1, sequence: 'is' } +console.log(lcs("google", "abcdefgooglehijklm")); // { lcs: 6, offset: 0, sequence: 'google' } +console.log(lcs("0", 0)); // { lcs: 0, offset: 0, sequence: '' } diff --git a/09_dynamic_programming/javascript/02_levenstein.js b/09_dynamic_programming/javascript/02_levenstein.js new file mode 100644 index 0000000..2137ea7 --- /dev/null +++ b/09_dynamic_programming/javascript/02_levenstein.js @@ -0,0 +1,47 @@ +/** + * Compute the edit distance between the two given strings + * + * @param {*} source + * @param {*} target + * + * @return {number} + */ +function getEditDistance(source, target) { + if (source.length == 0) return target.length; + if (target.length == 0) return source.length; + + let i; + let j; + let matrix = []; + + // Fill the column + for (i = 0; i <= target.length; i++) { + matrix[i] = [i]; + } + + // Fill the column + for (j = 0; j <= source.length; j++) { + matrix[0][j] = j; + } + + // Fill in the rest of the matrix + for (i = 1; i <= target.length; i++) { + for (j = 1; j <= source.length; j++) { + if (target.charAt(i - 1) == source.charAt(j - 1)) { + matrix[i][j] = matrix[i - 1][j - 1]; + } else { + matrix[i][j] = Math.min( + matrix[i - 1][j - 1] + 1, // substitution + Math.min( + matrix[i][j - 1] + 1, // insertion + matrix[i - 1][j] + 1 + ) + ); // deletion + } + } + } + + return matrix[target.length][source.length]; +} + +console.log(getEditDistance("google", "notgoogl")); // 4