From 61b2925a2d1b64b2a527f948a6927e949d0004de Mon Sep 17 00:00:00 2001 From: Alexandrshy Date: Sun, 21 Jul 2019 09:05:39 +0400 Subject: [PATCH 001/140] Fixed formatting problems, example and JSDoc --- 04_quicksort/ES6/01_loop_sum.js | 12 +++---- .../ES6/01_loop_sum_reduce_version.js | 8 ++--- 04_quicksort/ES6/02_recursive_sum.js | 12 +++---- 04_quicksort/ES6/03_recursive_count.js | 12 +++---- 04_quicksort/ES6/04_recursive-max.js | 29 +++++++++++++---- 04_quicksort/ES6/05_quicksort.js | 17 +++++++--- .../ES6/06_euclidean_algorithm_set_numbers.js | 31 +++++++----------- .../ES6/07_euclidean_algorithm_two_numbers.js | 16 ++-------- 04_quicksort/javascript/01_loop_sum.js | 21 ++++++------ .../javascript/01_loop_sum_reduce_version.js | 12 ++++--- 04_quicksort/javascript/02_recursive_sum.js | 16 +++++----- 04_quicksort/javascript/03_recursive_count.js | 15 +++++---- 04_quicksort/javascript/04_recursive_max.js | 32 +++++++++++++++---- 04_quicksort/javascript/05_quicksort.js | 13 +++++--- 14 files changed, 140 insertions(+), 106 deletions(-) diff --git a/04_quicksort/ES6/01_loop_sum.js b/04_quicksort/ES6/01_loop_sum.js index e02fa914..102c1dea 100644 --- a/04_quicksort/ES6/01_loop_sum.js +++ b/04_quicksort/ES6/01_loop_sum.js @@ -1,12 +1,12 @@ /** - * Sums values in array by loop "for" - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by loop "for" + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -const sumLoop = arr => { +const sumLoop = array => { let result = 0; - for (let i = 0; i < arr.length; i++) { - result += arr[i]; + for (let i = 0; i < array.length; i++) { + result += array[i]; } return result; }; diff --git a/04_quicksort/ES6/01_loop_sum_reduce_version.js b/04_quicksort/ES6/01_loop_sum_reduce_version.js index 22de0b36..7dc84dd0 100644 --- a/04_quicksort/ES6/01_loop_sum_reduce_version.js +++ b/04_quicksort/ES6/01_loop_sum_reduce_version.js @@ -1,8 +1,8 @@ /** - * Sums values in array by function "reduce" - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by function "reduce" + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -const sumReduce = arr => arr.reduce((curr, prev) => curr + prev); +const sumReduce = array => array.reduce((curr, prev) => curr + prev); console.log(sumReduce([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/ES6/02_recursive_sum.js b/04_quicksort/ES6/02_recursive_sum.js index f8e55d55..abe904b0 100644 --- a/04_quicksort/ES6/02_recursive_sum.js +++ b/04_quicksort/ES6/02_recursive_sum.js @@ -1,8 +1,8 @@ -const sum = (list) => { - if (list.length === 0) { - return 0; - } - return list[0] + sum(list.slice(1)); -}; +/** + * Sums values in the array by recursive + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers + */ +const sum = array => (array.length === 0 ? 0 : array[0] + sum(array.slice(1))); console.log(sum([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/ES6/03_recursive_count.js b/04_quicksort/ES6/03_recursive_count.js index 417340d5..19ce7235 100644 --- a/04_quicksort/ES6/03_recursive_count.js +++ b/04_quicksort/ES6/03_recursive_count.js @@ -1,8 +1,8 @@ -const count = (list) => { - if (list.length === 0) { - return 0; - } - return 1 + count(list.slice(1)); -}; +/** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ +const count = array => (array.length === 0 ? 0 : 1 + count(array.slice(1))); console.log(count([0, 1, 2, 3, 4, 5])); // 6 diff --git a/04_quicksort/ES6/04_recursive-max.js b/04_quicksort/ES6/04_recursive-max.js index 5e237b2a..e967c78b 100644 --- a/04_quicksort/ES6/04_recursive-max.js +++ b/04_quicksort/ES6/04_recursive-max.js @@ -1,9 +1,26 @@ -const max = (list) => { - if (list.length === 2) { - return list[0] > list[1] ? list[0] : list[1]; - } - const subMax = max(list.slice(1)); - return list[0] > subMax ? list[0] : subMax; +/** + * Calculate the largest number + * This solution only works for arrays longer than one + * @param {Array} array Array of numbers + * @returns {number} The argest number + */ +const max = array => { + if (array.length === 2) return array[0] > array[1] ? array[0] : array[1]; + const subMax = max(array.slice(1)); + return array[0] > subMax ? array[0] : subMax; }; +/** + * Calculate the largest number + * This solution works for arrays of any length + * @param {Array} array Array of numbers + * @param {number} max Maximum value + * @returns {number} The argest number + */ +const alternativeSolutionMax = (array, max = 0) => + array.length === 0 + ? max + : alternativeSolutionMax(array.slice(1), array[0] > max ? array[0] : max); + console.log(max([1, 5, 10, 25, 16, 1])); // 25 +console.log(alternativeSolutionMax([1, 5, 10, 25, 16, 1])); // 25 diff --git a/04_quicksort/ES6/05_quicksort.js b/04_quicksort/ES6/05_quicksort.js index 7014216a..c3c7d479 100644 --- a/04_quicksort/ES6/05_quicksort.js +++ b/04_quicksort/ES6/05_quicksort.js @@ -1,11 +1,18 @@ -const quickSort = (array) => { - if (array.length < 2) { - return array; - } +/** + * Quick array sorting + * @param {Array} array Source array + * @returns {Array} Sorted array + */ +const quickSort = array => { + if (array.length < 2) return array; const pivot = array[0]; const keysAreLessPivot = array.slice(1).filter(key => key <= pivot); const keysAreMorePivot = array.slice(1).filter(key => key > pivot); - return [...quickSort(keysAreLessPivot), pivot, ...quickSort(keysAreMorePivot)]; + return [ + ...quickSort(keysAreLessPivot), + pivot, + ...quickSort(keysAreMorePivot) + ]; }; console.log(quickSort([10, 5, 2, 3])); // [2, 3, 5, 10] diff --git a/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js b/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js index cd3f16d7..9e106b4e 100644 --- a/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js +++ b/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js @@ -1,36 +1,27 @@ /** * 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) + * @returns {number} GCD (greatest common divisor) */ -let gcdOfTwo = ( a, b ) => { - if ( !b ) { - return a; - } - return gcdOfTwo( b, a % b ); -}; +const gcdOfTwo = (a, b) => (!b ? a : 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) + * @returns {number} GCD (greatest common divisor) */ -let gcdOfSet = ( set ) => { - let result = set[0]; - let newArr = Array.prototype.slice.call( set, 1 ); +const gcdOfSet = set => { + let result = set[0]; + let newArr = set.slice(1); - newArr.map( ( el ) => { - result = gcdOfTwo( result, el ); - } ); + newArr.map(el => { + result = gcdOfTwo(result, el); + }); - return result; + return result; }; const set = [1680, 640, 3360, 160, 240, 168000]; -console.log( gcdOfSet( set ) ); // 80 +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 index 07483698..27873354 100644 --- a/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js +++ b/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js @@ -1,19 +1,9 @@ /** * Recursive function of Euclidean algorithm - * * @param {number} a first number * @param {number} b second number (base case) - * - * @return {number} GCD (greatest common divisor) + * @returns {number} GCD (greatest common divisor) */ -let getGCD = ( a, b ) => { - if ( !b ) { - return a; - } - return getGCD( b, a % b ); -}; +const getGCD = (a, b) => (!b ? a : getGCD(b, a % b)); -const a = 1680; -const b = 640; - -console.log( getGCD( a, b ) ); // 80 +console.log(getGCD(1680, 640)); // 80 diff --git a/04_quicksort/javascript/01_loop_sum.js b/04_quicksort/javascript/01_loop_sum.js index 2037a78d..755ace30 100644 --- a/04_quicksort/javascript/01_loop_sum.js +++ b/04_quicksort/javascript/01_loop_sum.js @@ -1,15 +1,16 @@ +"use strict"; + /** - * Sums values in array by loop "for" - * @param {Array} arr Array of numbers - * @return {total} Sum of the numbers + * Sums values in the array by loop "for" + * @param {Array} array Array of numbers + * @returns {total} Sum of the numbers */ - -function sum(arr) { - let total = 0; - for (let i = 0; i < arr.length; i++) { - total += arr[i]; - } - return total; +function sum(array) { + let total = 0; + for (let i = 0; i < array.length; i++) { + total += array[i]; + } + return total; } console.log(sum([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/javascript/01_loop_sum_reduce_version.js b/04_quicksort/javascript/01_loop_sum_reduce_version.js index 101871da..c12aaa1d 100644 --- a/04_quicksort/javascript/01_loop_sum_reduce_version.js +++ b/04_quicksort/javascript/01_loop_sum_reduce_version.js @@ -1,10 +1,12 @@ +"use strict"; + /** - * Sums values in array by function "reduce" - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by function "reduce" + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -function sumReduce(arr) { - return arr.reduce(function(curr, prev) { +function sumReduce(array) { + return array.reduce(function(curr, prev) { return curr + prev; }); } diff --git a/04_quicksort/javascript/02_recursive_sum.js b/04_quicksort/javascript/02_recursive_sum.js index 06c9dc33..c74e1e5f 100644 --- a/04_quicksort/javascript/02_recursive_sum.js +++ b/04_quicksort/javascript/02_recursive_sum.js @@ -1,13 +1,13 @@ +"use strict"; + /** - * Sums values in array recursively - * @param {Array} arr Array of numbers - * @return {number} Sum of the numbers + * Sums values in the array by recursive + * @param {Array} array Array of numbers + * @returns {number} Sum of the numbers */ -function sumRecursive(arr) { - if (arr.length == 1) { - return arr[0]; - } - return arr[0] + sumRecursive(arr.slice(1)); +function sumRecursive(array) { + if (array.length == 1) return array[0]; + return array[0] + sumRecursive(array.slice(1)); } console.log(sumRecursive([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/javascript/03_recursive_count.js b/04_quicksort/javascript/03_recursive_count.js index 139acfcd..882650cf 100644 --- a/04_quicksort/javascript/03_recursive_count.js +++ b/04_quicksort/javascript/03_recursive_count.js @@ -1,10 +1,13 @@ -'use strict'; +"use strict"; -function count(list) { - if (list.length === 0) { - return 0; - } - return 1 + count(list.slice(1)); +/** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ +function count(array) { + if (array.length === 0) return 0; + return 1 + count(array.slice(1)); } console.log(count([0, 1, 2, 3, 4, 5])); // 6 diff --git a/04_quicksort/javascript/04_recursive_max.js b/04_quicksort/javascript/04_recursive_max.js index fe457e9c..f3c15f9b 100644 --- a/04_quicksort/javascript/04_recursive_max.js +++ b/04_quicksort/javascript/04_recursive_max.js @@ -1,11 +1,29 @@ -'use strict'; +"use strict"; -function max(list) { - if (list.length === 2) { - return list[0] > list[1] ? list[0] : list[1]; - } - let sub_max = max(list.slice(1)); - return list[0] > sub_max ? list[0] : sub_max; +/** + * Calculate the largest number + * This solution only works for arrays longer than one + * @param {Array} array Array of numbers + * @returns {number} The argest number + */ +function max(array) { + if (array.length === 2) return array[0] > array[1] ? array[0] : array[1]; + let sub_max = max(array.slice(1)); + return array[0] > sub_max ? array[0] : sub_max; +} + +/** + * Calculate the largest number + * This solution works for arrays of any length + * @param {Array} array Array of numbers + * @param {number} max Maximum value + * @returns {number} The argest number + */ +function alternativeSolutionMax(array, max = 0) { + return array.length === 0 + ? max + : alternativeSolutionMax(array.slice(1), array[0] > max ? array[0] : max); } console.log(max([1, 5, 10, 25, 16, 1])); // 25 +console.log(alternativeSolutionMax([1, 5, 10, 25, 16, 1])); // 25 diff --git a/04_quicksort/javascript/05_quicksort.js b/04_quicksort/javascript/05_quicksort.js index e31a9490..5c45388b 100644 --- a/04_quicksort/javascript/05_quicksort.js +++ b/04_quicksort/javascript/05_quicksort.js @@ -1,8 +1,13 @@ +"use strict"; + +/** + * Quick array sorting + * @param {Array} array Source array + * @returns {Array} Sorted array + */ function quicksort(array) { - if (array.length < 2) { - // base case, arrays with 0 or 1 element are already "sorted" - return array; - } + // base case, arrays with 0 or 1 element are already "sorted" + if (array.length < 2) return array; // recursive case let pivot = array[0]; // sub-array of all the elements less than the pivot From 84b6d19416d27549d92a1f0a09002bc2444b9935 Mon Sep 17 00:00:00 2001 From: Alexandrshy Date: Tue, 23 Jul 2019 08:37:29 +0400 Subject: [PATCH 002/140] Fixed formatting problems --- 05_hash_tables/ES6/02_check_voter.js | 18 +- 05_hash_tables/javascript/02_check_voter.js | 12 +- 05_hash_tables/javascript/03_hashtable.js | 321 ++++++++++---------- 3 files changed, 174 insertions(+), 177 deletions(-) diff --git a/05_hash_tables/ES6/02_check_voter.js b/05_hash_tables/ES6/02_check_voter.js index d2aeeb1c..1bf5d706 100644 --- a/05_hash_tables/ES6/02_check_voter.js +++ b/05_hash_tables/ES6/02_check_voter.js @@ -1,14 +1,18 @@ const voted = {}; -const checkVoter = (name) => { + +/** + * Vote check + * @param {string} name Voter name + */ +const checkVoter = name => { if (voted[name]) { - console.log('kick them out!'); + console.log("kick them out!"); } else { voted[name] = true; - console.log('let them vote!'); + console.log("let them vote!"); } }; - -checkVoter('tom'); // let them vote! -checkVoter('mike'); // let them vote! -checkVoter('mike'); // kick them out! +checkVoter("tom"); // let them vote! +checkVoter("mike"); // let them vote! +checkVoter("mike"); // kick them out! diff --git a/05_hash_tables/javascript/02_check_voter.js b/05_hash_tables/javascript/02_check_voter.js index 288eba63..4f1c2c50 100644 --- a/05_hash_tables/javascript/02_check_voter.js +++ b/05_hash_tables/javascript/02_check_voter.js @@ -1,16 +1,20 @@ -'use strict'; +"use strict"; const voted = {}; + +/** + * Vote check + * @param {string} name Voter name + */ function check_voter(name) { if (voted[name]) { - console.log('kick them out!'); + console.log("kick them out!"); } else { voted[name] = true; - console.log('let them vote!'); + console.log("let them vote!"); } } - check_voter("tom"); // let them vote! check_voter("mike"); // let them vote! check_voter("mike"); // kick them out! diff --git a/05_hash_tables/javascript/03_hashtable.js b/05_hash_tables/javascript/03_hashtable.js index 7c02d9dd..ceaeebe5 100644 --- a/05_hash_tables/javascript/03_hashtable.js +++ b/05_hash_tables/javascript/03_hashtable.js @@ -1,173 +1,162 @@ /** * Class HashTable - * - * @param {object} obj + * @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(); - }, - }); +const 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 + * @returns {(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 + * @returns {(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 + * @returns {boolean} + */ + this.has = function(key) { + return this._items.hasOwnProperty(key); + }; + + /** + * Removes the specified key with its value + * @param {string} key The key to remove + * @returns {(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 + * @returns {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 + * @returns {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}); +const 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 +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 +console.log("Length after clear: " + hashtable.length); // Length after clear: 0 From a1dbe470cc79937a2d05ec4954f1773bb68318e6 Mon Sep 17 00:00:00 2001 From: Alexandrshy Date: Wed, 24 Jul 2019 09:25:02 +0400 Subject: [PATCH 003/140] Fixed formatting problems, added JSDoc, added example for JS, fixed example for JS --- .../ES6/01_breadth-first_search.js | 29 +++++++---- ...breadth-first_search_by_Rytikov_Dmitrii.js | 40 ++++++++++------ .../javascript/01_breadth-first_search.js | 20 ++++++-- .../02_breadth-first_search_recursion.js | 48 +++++++++++++++++++ 4 files changed, 108 insertions(+), 29 deletions(-) create mode 100644 06_breadth-first_search/javascript/02_breadth-first_search_recursion.js diff --git a/06_breadth-first_search/ES6/01_breadth-first_search.js b/06_breadth-first_search/ES6/01_breadth-first_search.js index f140373f..1767cbeb 100644 --- a/06_breadth-first_search/ES6/01_breadth-first_search.js +++ b/06_breadth-first_search/ES6/01_breadth-first_search.js @@ -1,18 +1,27 @@ -const personIsSeller = name => name[name.length - 1] === 'm'; - const graph = {}; -graph.you = ['alice', 'bob', 'claire']; -graph.bob = ['anuj', 'peggy']; -graph.alice = ['peggy']; -graph.claire = ['thom', 'jonny']; +graph.you = ["alice", "bob", "claire"]; +graph.bob = ["anuj", "peggy"]; +graph.alice = ["peggy"]; +graph.claire = ["thom", "jonny"]; graph.anuj = []; graph.peggy = []; graph.thom = []; graph.jonny = []; -const search = (name) => { - let searchQueue = []; - searchQueue = searchQueue.concat(graph[name]); +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +const personIsSeller = name => name[name.length - 1] === "m"; + +/** + * Find a mango seller + * @param {string} name Friend's name + * @returns {boolean} Search results + */ +const search = name => { + let searchQueue = [...graph[name]]; // This array is how you keep track of which people you've searched before. const searched = []; while (searchQueue.length) { @@ -31,4 +40,4 @@ const search = (name) => { return false; }; -search('you'); // thom is a mango seller! +search("you"); // thom is a mango seller! diff --git a/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js b/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js index 5f3836c5..75f5405f 100644 --- a/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js +++ b/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js @@ -1,23 +1,35 @@ const graph = {}; -graph.you = ['alice', 'bob', 'claire']; -graph.bob = ['anuj', 'peggy']; -graph.alice = ['peggy']; -graph.claire = ['thom', 'jonny']; +graph.you = ["alice", "bob", "claire"]; +graph.bob = ["anuj", "peggy"]; +graph.alice = ["peggy"]; +graph.claire = ["thom", "jonny"]; graph.anuj = []; graph.peggy = []; graph.thom = []; -const isSeller = name => name[name.length - 1] === 'm'; +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +const isSeller = name => name[name.length - 1] === "m"; -const search = (name, graph) => { - const iter = (waited, visited) => { - if (waited.length === 0) { - return false; - } +/** + * Find a mango seller + * @param {string} name Friend's name + * @param {Object} graph Hash table + * @returns {boolean} Search results + */ +const search = (name, graph = {}) => { + /** + * Recursive function to test people + * @param {Array} waited List of people you need to check + * @param {Set} visited List of checked people + */ + const iter = (waited = [], visited) => { + if (waited.length === 0) return false; const [current, ...rest] = waited; - if (visited.has(current)) { - return iter(rest, visited); - } + if (visited.has(current)) return iter(rest, visited); if (isSeller(current)) { console.log(`${current} is a mango seller!`); return true; @@ -29,4 +41,4 @@ const search = (name, graph) => { return iter(graph[name], new Set()); }; -search('you'); +search("you", graph); diff --git a/06_breadth-first_search/javascript/01_breadth-first_search.js b/06_breadth-first_search/javascript/01_breadth-first_search.js index c3f478f0..a4700654 100644 --- a/06_breadth-first_search/javascript/01_breadth-first_search.js +++ b/06_breadth-first_search/javascript/01_breadth-first_search.js @@ -1,7 +1,3 @@ -function person_is_seller(name) { - return name[name.length - 1] === "m"; -} - const graph = {}; graph["you"] = ["alice", "bob", "claire"]; graph["bob"] = ["anuj", "peggy"]; @@ -12,6 +8,20 @@ graph["peggy"] = []; graph["thom"] = []; graph["jonny"] = []; +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +function personIsSeller(name) { + return name[name.length - 1] === "m"; +} + +/** + * Find a mango seller + * @param {string} name Friend's name + * @returns {boolean} Search results + */ function search(name) { let search_queue = []; search_queue = search_queue.concat(graph[name]); @@ -21,7 +31,7 @@ function search(name) { let person = search_queue.shift(); // Only search this person if you haven't already searched them if (searched.indexOf(person) === -1) { - if (person_is_seller(person)) { + if (personIsSeller(person)) { console.log(person + " is a mango seller!"); return true; } diff --git a/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js b/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js new file mode 100644 index 00000000..c08be6c3 --- /dev/null +++ b/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js @@ -0,0 +1,48 @@ +const graph = {}; +graph["you"] = ["alice", "bob", "claire"]; +graph["bob"] = ["anuj", "peggy"]; +graph["alice"] = ["peggy"]; +graph["claire"] = ["thom", "jonny"]; +graph["anuj"] = []; +graph["peggy"] = []; +graph["thom"] = []; +graph["jonny"] = []; + +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +function personIsSeller(name) { + return name[name.length - 1] === "m"; +} + +/** + * Find a mango seller + * @param {string} name Friend's name + * @param {Object} graph Hash table + * @returns {boolean} Search results + */ +function search(name, graph) { + graph = graph || {}; + /** + * Recursive function to check people + * @param {Array} waited List of people you need to check + * @param {Array} visited List of checked people + */ + function inner(waited, visited) { + waited = waited || []; + if (waited.length === 0) return false; + const person = waited[0]; + const waitedCloned = waited.slice(1); + if (visited.indexOf(person) !== -1) return inner(waitedCloned, visited); + if (personIsSeller(person)) { + console.log(person + " is a mango seller!"); + return true; + } + return inner(waitedCloned.concat(graph[person]), visited.concat(person)); + } + return inner(graph[name], []); +} + +search("you", graph); From b4b5161ff99e8c072bd8787f8f8317b6342bb6ad Mon Sep 17 00:00:00 2001 From: Alexandrshy Date: Wed, 24 Jul 2019 22:38:14 +0400 Subject: [PATCH 004/140] Fixed formatting problems, added JSDoc, added example for JS, fixed example for JS --- .../ES6/01_breadth-first_search.js | 29 +++++++---- ...breadth-first_search_by_Rytikov_Dmitrii.js | 40 ++++++++++------ .../javascript/01_breadth-first_search.js | 20 ++++++-- .../02_breadth-first_search_recursion.js | 48 +++++++++++++++++++ 4 files changed, 108 insertions(+), 29 deletions(-) create mode 100644 06_breadth-first_search/javascript/02_breadth-first_search_recursion.js diff --git a/06_breadth-first_search/ES6/01_breadth-first_search.js b/06_breadth-first_search/ES6/01_breadth-first_search.js index f140373f..1767cbeb 100644 --- a/06_breadth-first_search/ES6/01_breadth-first_search.js +++ b/06_breadth-first_search/ES6/01_breadth-first_search.js @@ -1,18 +1,27 @@ -const personIsSeller = name => name[name.length - 1] === 'm'; - const graph = {}; -graph.you = ['alice', 'bob', 'claire']; -graph.bob = ['anuj', 'peggy']; -graph.alice = ['peggy']; -graph.claire = ['thom', 'jonny']; +graph.you = ["alice", "bob", "claire"]; +graph.bob = ["anuj", "peggy"]; +graph.alice = ["peggy"]; +graph.claire = ["thom", "jonny"]; graph.anuj = []; graph.peggy = []; graph.thom = []; graph.jonny = []; -const search = (name) => { - let searchQueue = []; - searchQueue = searchQueue.concat(graph[name]); +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +const personIsSeller = name => name[name.length - 1] === "m"; + +/** + * Find a mango seller + * @param {string} name Friend's name + * @returns {boolean} Search results + */ +const search = name => { + let searchQueue = [...graph[name]]; // This array is how you keep track of which people you've searched before. const searched = []; while (searchQueue.length) { @@ -31,4 +40,4 @@ const search = (name) => { return false; }; -search('you'); // thom is a mango seller! +search("you"); // thom is a mango seller! diff --git a/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js b/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js index 5f3836c5..75f5405f 100644 --- a/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js +++ b/06_breadth-first_search/ES6/02_breadth-first_search_by_Rytikov_Dmitrii.js @@ -1,23 +1,35 @@ const graph = {}; -graph.you = ['alice', 'bob', 'claire']; -graph.bob = ['anuj', 'peggy']; -graph.alice = ['peggy']; -graph.claire = ['thom', 'jonny']; +graph.you = ["alice", "bob", "claire"]; +graph.bob = ["anuj", "peggy"]; +graph.alice = ["peggy"]; +graph.claire = ["thom", "jonny"]; graph.anuj = []; graph.peggy = []; graph.thom = []; -const isSeller = name => name[name.length - 1] === 'm'; +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +const isSeller = name => name[name.length - 1] === "m"; -const search = (name, graph) => { - const iter = (waited, visited) => { - if (waited.length === 0) { - return false; - } +/** + * Find a mango seller + * @param {string} name Friend's name + * @param {Object} graph Hash table + * @returns {boolean} Search results + */ +const search = (name, graph = {}) => { + /** + * Recursive function to test people + * @param {Array} waited List of people you need to check + * @param {Set} visited List of checked people + */ + const iter = (waited = [], visited) => { + if (waited.length === 0) return false; const [current, ...rest] = waited; - if (visited.has(current)) { - return iter(rest, visited); - } + if (visited.has(current)) return iter(rest, visited); if (isSeller(current)) { console.log(`${current} is a mango seller!`); return true; @@ -29,4 +41,4 @@ const search = (name, graph) => { return iter(graph[name], new Set()); }; -search('you'); +search("you", graph); diff --git a/06_breadth-first_search/javascript/01_breadth-first_search.js b/06_breadth-first_search/javascript/01_breadth-first_search.js index c3f478f0..a4700654 100644 --- a/06_breadth-first_search/javascript/01_breadth-first_search.js +++ b/06_breadth-first_search/javascript/01_breadth-first_search.js @@ -1,7 +1,3 @@ -function person_is_seller(name) { - return name[name.length - 1] === "m"; -} - const graph = {}; graph["you"] = ["alice", "bob", "claire"]; graph["bob"] = ["anuj", "peggy"]; @@ -12,6 +8,20 @@ graph["peggy"] = []; graph["thom"] = []; graph["jonny"] = []; +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +function personIsSeller(name) { + return name[name.length - 1] === "m"; +} + +/** + * Find a mango seller + * @param {string} name Friend's name + * @returns {boolean} Search results + */ function search(name) { let search_queue = []; search_queue = search_queue.concat(graph[name]); @@ -21,7 +31,7 @@ function search(name) { let person = search_queue.shift(); // Only search this person if you haven't already searched them if (searched.indexOf(person) === -1) { - if (person_is_seller(person)) { + if (personIsSeller(person)) { console.log(person + " is a mango seller!"); return true; } diff --git a/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js b/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js new file mode 100644 index 00000000..c08be6c3 --- /dev/null +++ b/06_breadth-first_search/javascript/02_breadth-first_search_recursion.js @@ -0,0 +1,48 @@ +const graph = {}; +graph["you"] = ["alice", "bob", "claire"]; +graph["bob"] = ["anuj", "peggy"]; +graph["alice"] = ["peggy"]; +graph["claire"] = ["thom", "jonny"]; +graph["anuj"] = []; +graph["peggy"] = []; +graph["thom"] = []; +graph["jonny"] = []; + +/** + * Determine whether a person is a seller + * @param {string} name Friend's name + * @returns {boolean} Result of checking + */ +function personIsSeller(name) { + return name[name.length - 1] === "m"; +} + +/** + * Find a mango seller + * @param {string} name Friend's name + * @param {Object} graph Hash table + * @returns {boolean} Search results + */ +function search(name, graph) { + graph = graph || {}; + /** + * Recursive function to check people + * @param {Array} waited List of people you need to check + * @param {Array} visited List of checked people + */ + function inner(waited, visited) { + waited = waited || []; + if (waited.length === 0) return false; + const person = waited[0]; + const waitedCloned = waited.slice(1); + if (visited.indexOf(person) !== -1) return inner(waitedCloned, visited); + if (personIsSeller(person)) { + console.log(person + " is a mango seller!"); + return true; + } + return inner(waitedCloned.concat(graph[person]), visited.concat(person)); + } + return inner(graph[name], []); +} + +search("you", graph); From 2216e23b6b2c4d584dcffb7c7fa77ec01c8f34c7 Mon Sep 17 00:00:00 2001 From: Alexandrshy Date: Thu, 25 Jul 2019 08:53:03 +0400 Subject: [PATCH 005/140] Fixed formatting problems, added JSDoc --- .../ES6/01_dijkstras_algorithm.js | 20 ++++---- .../javascript/01_dijkstras_algorithm.js | 48 ++++++++++--------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js b/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js index 1516bb16..5dc16e9c 100644 --- a/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js +++ b/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js @@ -21,21 +21,25 @@ costs.fin = Infinity; // the parents table const parents = {}; -parents.a = 'start'; -parents.b = 'start'; +parents.a = "start"; +parents.b = "start"; parents.fin = null; let processed = []; - -const findLowestCostNode = (itCosts) => { +/** + * Find the lowest node + * @param {Object} itCosts Hash table + * @returns {(string|null)} The lowest node + */ +const findLowestCostNode = itCosts => { let lowestCost = Infinity; let lowestCostNode = null; - Object.keys(itCosts).forEach((node) => { + Object.keys(itCosts).forEach(node => { const cost = itCosts[node]; // If it's the lowest cost so far and hasn't been processed yet... - if (cost < lowestCost && (processed.indexOf(node) === -1)) { + if (cost < lowestCost && processed.indexOf(node) === -1) { // ... set it as the new lowest-cost node. lowestCost = cost; lowestCostNode = node; @@ -50,7 +54,7 @@ while (node !== null) { const cost = costs[node]; // Go through all the neighbors of this node const neighbors = graph[node]; - Object.keys(neighbors).forEach((n) => { + Object.keys(neighbors).forEach(n => { const newCost = cost + neighbors[n]; // If it's cheaper to get to this neighbor by going through this node if (costs[n] > newCost) { @@ -68,5 +72,5 @@ while (node !== null) { node = findLowestCostNode(costs); } -console.log('Cost from the start to each node:'); +console.log("Cost from the start to each node:"); console.log(costs); // { a: 5, b: 2, fin: 6 } diff --git a/07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js b/07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js index 97cc23a1..946ef447 100644 --- a/07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js +++ b/07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; // the graph const graph = {}; @@ -17,44 +17,48 @@ graph["fin"] = {}; // The costs table const costs = {}; -costs['a'] = 6; -costs['b'] = 2; -costs['fin'] = Infinity; +costs["a"] = 6; +costs["b"] = 2; +costs["fin"] = Infinity; // the parents table const parents = {}; -parents['a'] = 'start'; -parents['b'] = 'start'; -parents['fin'] = null; +parents["a"] = "start"; +parents["b"] = "start"; +parents["fin"] = null; let processed = []; - -function find_lowest_cost_node(costs) { - let lowest_cost = Infinity; - let lowest_cost_node = null; +/** + * Find the lowest node + * @param {Object} itCosts Hash table + * @returns {(string|null)} The lowest node + */ +function findLowestCostNode(costs) { + let lowestCost = Infinity; + let lowestCostNode = null; // Go through each node for (let node in costs) { - let cost = costs[node]; + const cost = costs[node]; // If it's the lowest cost so far and hasn't been processed yet... - if (cost < lowest_cost && (processed.indexOf(node) === -1)) { + if (cost < lowestCost && processed.indexOf(node) === -1) { // ... set it as the new lowest-cost node. - lowest_cost = cost; - lowest_cost_node = node; + lowestCost = cost; + lowestCostNode = node; } } - return lowest_cost_node; + return lowestCostNode; } -let node = find_lowest_cost_node(costs); +let node = findLowestCostNode(costs); while (node !== null) { - let cost = costs[node]; + const cost = costs[node]; // Go through all the neighbors of this node - let neighbors = graph[node]; + const neighbors = graph[node]; Object.keys(neighbors).forEach(function(n) { - let new_cost = cost + neighbors[n]; + const new_cost = cost + neighbors[n]; // If it's cheaper to get to this neighbor by going through this node if (costs[n] > new_cost) { // ... update the cost for this node @@ -66,9 +70,9 @@ while (node !== null) { // Mark the node as processed processed = processed.concat(node); - + // Find the next node to process, and loop - node = find_lowest_cost_node(costs); + node = findLowestCostNode(costs); } console.log("Cost from the start to each node:"); From 5a1d2c04d4491a2a193ac15280bc2f2c2f97d23b Mon Sep 17 00:00:00 2001 From: Alexandrshy Date: Fri, 26 Jul 2019 00:29:41 +0400 Subject: [PATCH 006/140] Fixed formatting problems --- 08_greedy_algorithms/ES6/01_set_covering.js | 15 +++++----- .../javascript/01_set_covering.js | 29 +++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/08_greedy_algorithms/ES6/01_set_covering.js b/08_greedy_algorithms/ES6/01_set_covering.js index 2e075ccf..8f934155 100644 --- a/08_greedy_algorithms/ES6/01_set_covering.js +++ b/08_greedy_algorithms/ES6/01_set_covering.js @@ -1,20 +1,19 @@ // You pass an array in, and it gets converted to a set. -let statesNeeded = new Set(['mt', 'wa', 'or', 'id', 'nv', 'ut', 'ca', 'az']); +let statesNeeded = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); const stations = {}; -stations.kone = new Set(['id', 'nv', 'ut']); -stations.ktwo = new Set(['wa', 'id', 'mt']); -stations.kthree = new Set(['or', 'nv', 'ca']); -stations.kfour = new Set(['nv', 'ut']); -stations.kfive = new Set(['ca', 'az']); +stations.kone = new Set(["id", "nv", "ut"]); +stations.ktwo = new Set(["wa", "id", "mt"]); +stations.kthree = new Set(["or", "nv", "ca"]); +stations.kfour = new Set(["nv", "ut"]); +stations.kfive = new Set(["ca", "az"]); const finalStations = new Set(); - while (statesNeeded.size) { let bestStation = null; let statesCovered = new Set(); - Object.keys(stations).forEach((station) => { + Object.keys(stations).forEach(station => { const states = stations[station]; const covered = new Set([...statesNeeded].filter(x => states.has(x))); if (covered.size > statesCovered.size) { diff --git a/08_greedy_algorithms/javascript/01_set_covering.js b/08_greedy_algorithms/javascript/01_set_covering.js index a2bb41ef..5b49f955 100644 --- a/08_greedy_algorithms/javascript/01_set_covering.js +++ b/08_greedy_algorithms/javascript/01_set_covering.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; // You pass an array in, and it gets converted to a set. -let states_needed = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); +let statesNeeded = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); const stations = {}; stations["kone"] = new Set(["id", "nv", "ut"]); @@ -10,22 +10,21 @@ stations["kthree"] = new Set(["or", "nv", "ca"]); stations["kfour"] = new Set(["nv", "ut"]); stations["kfive"] = new Set(["ca", "az"]); -const final_stations = new Set(); +const finalStations = new Set(); - -while (states_needed.size) { - let best_station = null; - let states_covered = new Set(); +while (statesNeeded.size) { + let bestStation = null; + let statesCovered = new Set(); for (let station in stations) { - let states = stations[station]; - let covered = new Set([...states_needed].filter((x) => states.has(x))); - if (covered.size > states_covered.size) { - best_station = station; - states_covered = covered; + const states = stations[station]; + const covered = new Set([...statesNeeded].filter(x => states.has(x))); + if (covered.size > statesCovered.size) { + bestStation = station; + statesCovered = covered; } } - states_needed = new Set([...states_needed].filter((x) => !states_covered.has(x))); - final_stations.add(best_station); + statesNeeded = new Set([...statesNeeded].filter(x => !statesCovered.has(x))); + finalStations.add(bestStation); } -console.log(final_stations); // Set { 'kone', 'ktwo', 'kthree', 'kfive' } +console.log(finalStations); // Set { 'kone', 'ktwo', 'kthree', 'kfive' } From a76c5e5d7d51ffc938f155f17744f6f916e74feb Mon Sep 17 00:00:00 2001 From: Alexandrshy Date: Sat, 27 Jul 2019 02:00:06 +0400 Subject: [PATCH 007/140] Fixed formatting problems, added JSDoc, deleted duplicate example --- .../ES6/01_longest_common_subsequence.js | 92 ++++++++++++------- 09_dynamic_programming/ES6/examples/base.js | 7 -- .../ES6/examples/diff_two_words.js | 27 ------ 3 files changed, 58 insertions(+), 68 deletions(-) delete mode 100644 09_dynamic_programming/ES6/examples/base.js delete mode 100644 09_dynamic_programming/ES6/examples/diff_two_words.js diff --git a/09_dynamic_programming/ES6/01_longest_common_subsequence.js b/09_dynamic_programming/ES6/01_longest_common_subsequence.js index 366d23e9..f23a7cf2 100644 --- a/09_dynamic_programming/ES6/01_longest_common_subsequence.js +++ b/09_dynamic_programming/ES6/01_longest_common_subsequence.js @@ -1,54 +1,78 @@ -function createMatrix(rows, cols) { - const matrix = new Array(rows); +/** + * Create a matrix + * @param {number} rows Number of rows + * @param {number} columns ANumber of columns + * @returns {Array} Matrix + */ +const createMatrix = (rows = 0, columns = 0) => { + const matrix = []; - for (let i = 0; i < matrix.length; i++) { - matrix[i] = new Array(cols).fill(0); + for (let i = 0; i < rows; i++) { + matrix[i] = Array(columns).fill(0); } return matrix; -} +}; -function substring(a, b) { - const cell = createMatrix(a.length + 1, b.length + 1); - let lcs = 0; - let lastSubIndex = 0; +/** + * Find the longest substring + * @param {string} firstWord First word + * @param {string} secondWord Second word + * @returns {string} The longest substring + */ +const longestSubstring = (firstWord = "", secondWord = "") => { + const matrix = JSON.parse( + JSON.stringify(createMatrix(firstWord.length, secondWord.length)) + ); + let sizeSequence = 0; + let indexSequence = 0; - for (let i = 1; i <= a.length; i++) { - for (let j = 1; j <= b.length; j++) { - if (a[i - 1] === b[j - 1]) { - cell[i][j] = cell[i - 1][j - 1] + 1; + for (let i = 0; i < firstWord.length; i++) { + for (let j = 0; j < secondWord.length; j++) { + if (firstWord[i] === secondWord[j]) { + matrix[i][j] = (i && j) > 0 ? matrix[i - 1][j - 1] + 1 : 1; - if (cell[i][j] > lcs) { - lcs = cell[i][j]; - lastSubIndex = i; + if (matrix[i][j] >= sizeSequence) { + sizeSequence = matrix[i][j]; + indexSequence = i + 1; } } else { - cell[i][j] = 0; + matrix[i][j] = 0; } } } - return a.slice(lastSubIndex - lcs, lastSubIndex); -} + return firstWord.slice(indexSequence - sizeSequence, indexSequence); +}; -substring("vista", "hish"); // "is" -substring("fish", "hish"); // "ish" +longestSubstring("vista", "hish"); // "is" +longestSubstring("fish", "hish"); // "ish" -function subsequence(a, b) { - const cell = createMatrix(a.length + 1, b.length + 1); - - for (let i = 1; i <= a.length; i++) { - for (let j = 1; j <= b.length; j++) { - if (a[i] === b[j]) { - cell[i][j] = cell[i - 1][j - 1] + 1; +/** + * Find the longest common subsequence + * @param {string} firstWord First word + * @param {string} secondWord Second word + * @returns {number} The longest common subsequence + */ +const longestCommonSubsequence = (firstWord = "", secondWord = "") => { + const matrix = JSON.parse( + JSON.stringify(createMatrix(firstWord.length, secondWord.length)) + ); + if (matrix.length === 0 || matrix[0].length === 0) return 0; + for (let i = 0; i < firstWord.length; i++) { + for (let j = 0; j < secondWord.length; j++) { + if (firstWord[i] === secondWord[j]) { + matrix[i][j] = (i && j) > 0 ? matrix[i - 1][j - 1] + 1 : 1; } else { - cell[i][j] = Math.max(cell[i - 1][j], cell[i][j - 1]); + matrix[i][j] = Math.max( + i > 0 ? matrix[i - 1][j] : 0, + j > 0 ? matrix[i][j - 1] : 0 + ); } } } + return matrix[firstWord.length - 1][secondWord.length - 1]; +}; - return cell[a.length][b.length]; -} - -subsequence("fish", "fosh"); // 3 -subsequence("fort", "fosh"); // 2 +longestCommonSubsequence("fish", "fosh"); // 3 +longestCommonSubsequence("fort", "fosh"); // 2 diff --git a/09_dynamic_programming/ES6/examples/base.js b/09_dynamic_programming/ES6/examples/base.js deleted file mode 100644 index d50dda8e..00000000 --- a/09_dynamic_programming/ES6/examples/base.js +++ /dev/null @@ -1,7 +0,0 @@ -export const initializeMatrix = (rows, cols) => { - const matrix = []; - for (let i = 0; i < rows.length; i += 1) { - matrix.push(Array(cols.length).fill(0)); - } - return matrix; -}; diff --git a/09_dynamic_programming/ES6/examples/diff_two_words.js b/09_dynamic_programming/ES6/examples/diff_two_words.js deleted file mode 100644 index 1ac7d02c..00000000 --- a/09_dynamic_programming/ES6/examples/diff_two_words.js +++ /dev/null @@ -1,27 +0,0 @@ -import { initializeMatrix } from "./base"; - -const diff = (firstWord, secondWord) => { - const arr1 = firstWord.split(""); - const arr2 = secondWord.split(""); - const matrix = initializeMatrix(arr1, arr2); - for (let i = 0; i < arr1.length; i += 1) { - for (let j = 0; j < arr2.length; j += 1) { - if (arr1[i] === arr2[j]) { - if (i > 0 && j > 0) { - matrix[i][j] = matrix[i - 1][j - 1] + 1; - } else { - matrix[i][j] = 1; - } - } else { - if (i > 0 && j > 0) { - matrix[i][j] = Math.max(matrix[i - 1][j], matrix[i][j - 1]); - } else { - matrix[i][j] = 0; - } - } - } - } - return matrix[arr1.length - 1][arr2.length - 1]; -}; - -export default diff; From 591111e596e705de5bc085911bc7c72ee4a51bde Mon Sep 17 00:00:00 2001 From: Candido Sales Gomes Date: Wed, 30 Oct 2019 15:29:20 -0600 Subject: [PATCH 008/140] add dijkstra to golang (#149) --- .../golang/01_dijkstras_algorithm.go | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go diff --git a/07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go b/07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go new file mode 100644 index 00000000..73b22743 --- /dev/null +++ b/07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go @@ -0,0 +1,94 @@ +package main + +import ( + "fmt" + "math" +) + +var graph map[string]map[string]float64 +var costs map[string]float64 +var parents map[string]string +var processed []string + +func main() { + // the graph + graph = make(map[string]map[string]float64) + graph["start"] = make(map[string]float64) + graph["start"]["a"] = 6 + graph["start"]["b"] = 2 + + graph["a"] = make(map[string]float64) + graph["a"]["fin"] = 1 + + graph["b"] = make(map[string]float64) + graph["b"]["a"] = 3 + graph["b"]["fin"] = 5 + + graph["fin"] = make(map[string]float64) + + // the costs table + costs = make(map[string]float64) + costs["a"] = 6 + costs["b"] = 2 + costs["fin"] = math.Inf(1) + + // the parents table + parents = make(map[string]string) + parents["a"] = "start" + parents["b"] = "start" + parents["fin"] = "" + + // Find the lowest-cost node that you haven't processed yet. + node := find_lowest_cost_node(costs) + // If you've processed all the nodes, this while loop is done. + + for node != "" { + cost := costs[node] + // Go through all the neighbors of this node. + neighbors := graph[node] + + for node, _ := range neighbors { + new_cost := cost + neighbors[node] + // If it's cheaper to get to this neighbor by going through this node... + if costs[node] > new_cost { + // ... update the cost for this node. + costs[node] = new_cost + // This node becomes the new parent for this neighbor. + parents[node] = node + } + } + // Mark the node as processed. + processed = append(processed, node) + // Find the next node to process, and loop. + node = find_lowest_cost_node(costs) + } + + fmt.Println(costs) + +} + +func find_lowest_cost_node(costs map[string]float64) string { + lowest_cost := math.Inf(1) + lowest_cost_node := "" + + for node, _ := range costs { + // fmt.Println("Node:", node, "Value:", value) + cost := costs[node] + // If it's the lowest cost so far and hasn't been processed yet... + if cost < lowest_cost && !contains(processed, node) { + // ... set it as the new lowest-cost node. + lowest_cost = cost + lowest_cost_node = node + } + } + return lowest_cost_node +} + +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} From 009689b294116311bbed8824b32352a7a8f986f4 Mon Sep 17 00:00:00 2001 From: Ivan Novikov Date: Thu, 31 Oct 2019 00:30:20 +0300 Subject: [PATCH 009/140] Kotlin examples for 08 chapter (#147) --- .../kotlin/01_set_covering.kt | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 08_greedy_algorithms/kotlin/01_set_covering.kt diff --git a/08_greedy_algorithms/kotlin/01_set_covering.kt b/08_greedy_algorithms/kotlin/01_set_covering.kt new file mode 100644 index 00000000..5049fee5 --- /dev/null +++ b/08_greedy_algorithms/kotlin/01_set_covering.kt @@ -0,0 +1,26 @@ +var statesNeeded = setOf("mt", "wa", "or", "id", "nv", "ut", "ca", "az") +val stations = mapOf( + "kone" to setOf("id", "nv", "ut"), + "ktwo" to setOf("wa", "id", "mt"), + "kthree" to setOf("or", "nv", "ca"), + "kfour" to setOf("nv", "ut"), + "kfive" to setOf("ca", "az") +) + +fun main() { + val finalStations = mutableSetOf() + while (statesNeeded.isNotEmpty()) { + var bestStation: String? = null + var statesCovered = setOf() + stations.forEach { (station, states) -> + val covered = statesNeeded.intersect(states) + if (covered.size > statesCovered.size) { + bestStation = station + statesCovered = covered + } + } + statesNeeded = statesNeeded - statesCovered + bestStation?.let { finalStations.add(it) } + } + println(finalStations) +} \ No newline at end of file From d889159744f25be3c7e4d6ec74b42e7fa4e4f500 Mon Sep 17 00:00:00 2001 From: Alexander Danilchenko <39950413+OlexanderD@users.noreply.github.com> Date: Wed, 30 Oct 2019 23:30:31 +0200 Subject: [PATCH 010/140] Added C++ Solution for 9th chapter (#146) * Added C++ Solution for 9th chapter * Fixed extra space * Fixed another extra space * Output style correction --- .../\321\201++/01_longest_common_subsequence" | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 "09_dynamic_programming/\321\201++/01_longest_common_subsequence" diff --git "a/09_dynamic_programming/\321\201++/01_longest_common_subsequence" "b/09_dynamic_programming/\321\201++/01_longest_common_subsequence" new file mode 100644 index 00000000..a0837120 --- /dev/null +++ "b/09_dynamic_programming/\321\201++/01_longest_common_subsequence" @@ -0,0 +1,43 @@ +#include +#include + +int main() { + std::string wordA = "Fish", wordB = "Fosh"; + const size_t& aSize = wordA.size(), &bSize = wordB.size(); + + size_t** table = new size_t* [aSize]; + for (size_t l = 0; l < aSize; ++l) + table[l] = new size_t[bSize]{}; // all values in table will be initialized as zero + + for (size_t i = 0; i < aSize; ++i) + for (size_t j = 0; j < bSize; ++j) + if (wordA[i] == wordB[j]) + if (i > 0 && j > 0) + table[i][j] = table[i - 1][j - 1] + 1; + else + table[i][j] = 1; + else + if (i > 0 && j > 0) + table[i][j] = std::max(table[i - 1][j], table[i][j - 1]); + else if (i == 0 && j > 0) + table[i][j] = table[i][j - 1]; + else if (i > 0 && j == 0) + table[i][j] = table[i - 1][j]; + else + table[i][j] = 0; + + for (size_t i = 0; i < aSize; ++i) { + std::cout << "[ "; + for (size_t j = 0; j < bSize; ++j) + std::cout << table[i][j] << ' '; + std::cout << ']' << std::endl; + } + + // [1 1 1 1] + // [1 1 1 1] + // [1 1 2 2] + // [1 1 2 3] + + system("pause"); + return 0; +} From fb81c11ca940d7763d88ae956f6967f1a241fef9 Mon Sep 17 00:00:00 2001 From: Alexander Danilchenko <39950413+OlexanderD@users.noreply.github.com> Date: Wed, 30 Oct 2019 23:30:40 +0200 Subject: [PATCH 011/140] C++11 solution to the 8th chapter problem. (#145) * C++11 solution to 8th chapter problem. * Update 01_set_covering.cpp * Extra space correction --- .../c++11/01_set_covering.cpp | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 08_greedy_algorithms/c++11/01_set_covering.cpp diff --git a/08_greedy_algorithms/c++11/01_set_covering.cpp b/08_greedy_algorithms/c++11/01_set_covering.cpp new file mode 100644 index 00000000..b5b6125b --- /dev/null +++ b/08_greedy_algorithms/c++11/01_set_covering.cpp @@ -0,0 +1,59 @@ +#include +#include +#include + +std::unordered_set operator & (const std::unordered_set&, + const std::unordered_set&); +void operator -= (std::unordered_set&, + const std::unordered_set&); + +int main() { + std::unordered_set statesNeeded({ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }); + + std::unordered_map> stations; + stations.insert({ "kone", {"id", "nv", "ut"} }); + stations.insert({ "ktwo", {"wa", "id", "mt" } }); + stations.insert({ "kthree", {"or", "nv", "ca" } }); + stations.insert({ "kfour", {"nv", "ut" } }); + stations.insert({ "kfive", {"ca", "az" } }); + + std::unordered_set finalStations; + + while (!statesNeeded.empty()) { + std::string bestStation; + std::unordered_set statesCovered; + for (const auto& i : stations) { + std::unordered_set coverage = i.second & statesNeeded; + if (coverage.size() > statesCovered.size()) { + bestStation = i.first; + statesCovered = coverage; + } + } + statesNeeded -= statesCovered; + finalStations.insert(bestStation); + } + + for (const auto& i : finalStations) + std::cout << i << std::endl; + + system("pause"); + return 0; +} + + std::unordered_set operator & (const std::unordered_set& a, + const std::unordered_set& b) { + std::unordered_set result; + for (const auto& i : a) + for (const auto& j : b) + if (i == j) + result.insert(i); + return result; + } + +void operator -= (std::unordered_set& a, + const std::unordered_set& b) { + for (auto j = b.begin(); j != b.end(); ++j) + for (auto i = a.begin(); i != a.end(); ) + if (*i == *j) i = a.erase(i); + else ++i; + } From 03db2855d6099cc11e64178b42e87dbe25601882 Mon Sep 17 00:00:00 2001 From: Alexander Danilchenko <39950413+OlexanderD@users.noreply.github.com> Date: Wed, 30 Oct 2019 23:31:21 +0200 Subject: [PATCH 012/140] According to the book changes (#144) Changed the name of the variable according to the book --- 08_greedy_algorithms/python/01_set_covering.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/08_greedy_algorithms/python/01_set_covering.py b/08_greedy_algorithms/python/01_set_covering.py index bbd1b5ff..1c77d41f 100644 --- a/08_greedy_algorithms/python/01_set_covering.py +++ b/08_greedy_algorithms/python/01_set_covering.py @@ -13,8 +13,8 @@ while states_needed: best_station = None states_covered = set() - for station, states in stations.items(): - covered = states_needed & states + for station, states_for_station in stations.items(): + covered = states_needed & states_for_station if len(covered) > len(states_covered): best_station = station states_covered = covered From ee7dcd3b3d02129e30fcff4b678d10ab5060efb2 Mon Sep 17 00:00:00 2001 From: Evgeniy <38191914+hero1292@users.noreply.github.com> Date: Thu, 31 Oct 2019 00:31:50 +0300 Subject: [PATCH 013/140] Update 02_recursive_binary_search.js (#125) --- .../ES6/02_recursive_binary_search.js | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js index 9fb9e96b..d203777d 100644 --- a/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js +++ b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js @@ -7,25 +7,20 @@ * @return {(number | null)} Number if the value is found or NULL otherwise */ const binarySearch = ( list, item, low = 0, high = list.length - 1 ) => { - let arrLength = list.length; - while ( low <= high ) { - let mid = Math.floor((low + high) / 2); - let guess = list[mid]; + 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 ); - } - } + if ( low > high ) return null; - return null; + if ( guess === item ) { + return mid; + } else if ( guess > item ) { + high = mid - 1; + return binarySearch( list, item, low, high ); + } else { + low = mid + 1; + return binarySearch( list, item, low, high ); + } }; /** From 4bc813264710113db4f622ce301880a3bd41d76a Mon Sep 17 00:00:00 2001 From: Alexander Danilchenko <39950413+OlexanderD@users.noreply.github.com> Date: Wed, 30 Oct 2019 23:32:05 +0200 Subject: [PATCH 014/140] Update 01_breadth-first_search.cpp (#124) Improved code stylistic integrity. --- .../c++11/01_breadth-first_search.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/06_breadth-first_search/c++11/01_breadth-first_search.cpp b/06_breadth-first_search/c++11/01_breadth-first_search.cpp index 2053590e..81cf7d01 100644 --- a/06_breadth-first_search/c++11/01_breadth-first_search.cpp +++ b/06_breadth-first_search/c++11/01_breadth-first_search.cpp @@ -18,9 +18,8 @@ bool search(const T& name, const std::unordered_map>& graph) { std::unordered_set searched; // add all friends to search queue - for (auto friend_name : graph.find(name) -> second) { + for (auto&& friend_name : graph.find(name) -> second) search_queue.push(friend_name); - } while (!search_queue.empty()) { T& person = search_queue.front(); @@ -32,12 +31,10 @@ bool search(const T& name, const std::unordered_map>& graph) { cout << person << " is a mango seller!" << endl; return true; } - std::vector friend_list = graph.find(person) -> second; // add all friends of a person to search queue - for (T friend_name : friend_list) { + for (auto&& friend_name : graph.find(person) -> second) search_queue.push(friend_name); - } // mark this person as searched searched.insert(person); @@ -61,4 +58,4 @@ int main() { std::string name = "you"; bool result = search(name, graph); cout << "Found mango seller: " << result << endl; -} \ No newline at end of file +} From 59ee067417c8cbc8e0cb512906ccad7f4d5ecbcc Mon Sep 17 00:00:00 2001 From: Alexander Danilchenko <39950413+OlexanderD@users.noreply.github.com> Date: Wed, 30 Oct 2019 23:32:21 +0200 Subject: [PATCH 015/140] Update 01_selection_sort.js (#122) --- 02_selection_sort/ES6/01_selection_sort.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02_selection_sort/ES6/01_selection_sort.js b/02_selection_sort/ES6/01_selection_sort.js index 31b6a8cb..fcb6919f 100644 --- a/02_selection_sort/ES6/01_selection_sort.js +++ b/02_selection_sort/ES6/01_selection_sort.js @@ -1,4 +1,4 @@ -// Selection Sort - O(log n^2) +// Selection Sort - O(n^2) // Parameter: // 1. random array From 878e26217dca2b7de7f36030217b117c891ce758 Mon Sep 17 00:00:00 2001 From: Lu Zhang Date: Wed, 30 Oct 2019 14:32:32 -0700 Subject: [PATCH 016/140] Update SetCovering.java (#120) The statesNeeded and finalStations set should be updated after the for loop which finds the bestStation. --- .../java/01_set_covering/src/SetCovering.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java b/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java index 86f07910..9afd2c82 100644 --- a/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java +++ b/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java @@ -25,13 +25,13 @@ public static void main(String[] args) { bestStation = station.getKey(); statesCovered = covered; } - statesNeeded.removeIf(statesCovered::contains); + } + statesNeeded.removeIf(statesCovered::contains); - if (bestStation != null) { - finalStations.add(bestStation); - } + if (bestStation != null) { + finalStations.add(bestStation); } } System.out.println(finalStations); // [ktwo, kone, kthree, kfive] } -} \ No newline at end of file +} From 9b0288d791954702bb6c9b98f6a3d6cf0566a37f Mon Sep 17 00:00:00 2001 From: Yury Date: Tue, 12 Nov 2019 22:17:35 +0700 Subject: [PATCH 017/140] Update 02_recursive_selection_sort.js (#119) --- 02_selection_sort/javascript/02_recursive_selection_sort.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02_selection_sort/javascript/02_recursive_selection_sort.js b/02_selection_sort/javascript/02_recursive_selection_sort.js index 70f4f06b..69e2abc5 100644 --- a/02_selection_sort/javascript/02_recursive_selection_sort.js +++ b/02_selection_sort/javascript/02_recursive_selection_sort.js @@ -18,7 +18,7 @@ const findSmallest = ( arr ) => { }; /** - * Sorts0 recursively an array of numbers + * Sorts recursively an array of numbers * @param {Array} arr An array of numbers * @return {Array} New sorted array */ From 3a50470e3d7ed011b924b27566c908753dd7800d Mon Sep 17 00:00:00 2001 From: Evgeny Samsonov Date: Tue, 12 Nov 2019 18:18:00 +0300 Subject: [PATCH 018/140] Add dijkstras algorithm in golang (#118) * Golang dijkstra algorithm * New line in end of file --- .../Golang/01_dijkstras_algorithm.go | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go diff --git a/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go b/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go new file mode 100644 index 00000000..b25fb001 --- /dev/null +++ b/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go @@ -0,0 +1,73 @@ +package main + +import ( + "fmt" + "math" +) + +func main() { + graph := make(map[string]map[string]int) + graph["start"] = map[string]int{} + graph["start"]["a"] = 6 + graph["start"]["b"] = 2 + + graph["a"] = map[string]int{} + graph["a"]["finish"] = 1 + + graph["b"] = map[string]int{} + graph["b"]["a"] = 3 + graph["b"]["finish"] = 5 + + graph["finish"] = map[string]int{} + + costs, parents := findShortestPath(graph, "start", "finish") + fmt.Println(costs, parents) +} + +// Finds shortest path using dijkstra algorithm +func findShortestPath(graph map[string]map[string]int, startNode string, finishNode string) (map[string]int, map[string]string) { + costs := make(map[string]int) + costs[finishNode] = math.MaxInt32 + + parents := make(map[string]string) + parents[finishNode] = "" + + processed := make(map[string]bool) + + // Initialization of costs and parents + for node, cost := range graph[startNode] { + costs[node] = cost + parents[node] = startNode + } + + lowestCostNode := findLowestCostNode(costs, processed) + for ; lowestCostNode != "" ; { + // Calculation costs for neighbours + for node, cost := range graph[lowestCostNode] { + newCost := costs[lowestCostNode] + cost + if newCost < costs[node] { + // Set new cost for this node + costs[node] = newCost + parents[node] = lowestCostNode + } + } + + processed[lowestCostNode] = true + lowestCostNode = findLowestCostNode(costs, processed) + } + + return costs, parents +} + +func findLowestCostNode(costs map[string]int, processed map[string]bool) string { + lowestCost := math.MaxInt32 + lowestCostNode := "" + for node, cost := range costs { + if _, inProcessed := processed[node]; cost < lowestCost && !inProcessed { + lowestCost = cost + lowestCostNode = node + } + } + + return lowestCostNode +} From 6b9faa9cab921b93b086cd5623a4e206a014ba19 Mon Sep 17 00:00:00 2001 From: bigpas Date: Tue, 12 Nov 2019 15:18:17 +0000 Subject: [PATCH 019/140] fix: naming convention. Min. refactor (#116) * fix: naming convention. Min. refactor * add: 05 for Kotlin --- .../kotlin/01_price_of_groceries.kt | 10 ++++ 05_hash_tables/kotlin/02_check_voter.kt | 19 ++++++++ 05_hash_tables/kotlin/readme.md | 14 ++++++ 06_breadth-first_search/golang/bfs.go | 47 ++++++++++--------- 4 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 05_hash_tables/kotlin/01_price_of_groceries.kt create mode 100644 05_hash_tables/kotlin/02_check_voter.kt create mode 100644 05_hash_tables/kotlin/readme.md diff --git a/05_hash_tables/kotlin/01_price_of_groceries.kt b/05_hash_tables/kotlin/01_price_of_groceries.kt new file mode 100644 index 00000000..3de68db6 --- /dev/null +++ b/05_hash_tables/kotlin/01_price_of_groceries.kt @@ -0,0 +1,10 @@ +fun main(args: Array) { + + val book = hashMapOf( + "apple" to 0.67, + "milk" to 1.49, + "avocado" to 1.49 + ) + + println(book) +} diff --git a/05_hash_tables/kotlin/02_check_voter.kt b/05_hash_tables/kotlin/02_check_voter.kt new file mode 100644 index 00000000..97acaee6 --- /dev/null +++ b/05_hash_tables/kotlin/02_check_voter.kt @@ -0,0 +1,19 @@ +val voted:HashMap = HashMap() + +fun checkVoter(name: String) { + + if(!voted.containsKey(name)){ + voted.put(name, true) + println("let them vote!") + } else { + println("kick them out!") + } + +} + +fun main(args: Array) { + + checkVoter("tom") + checkVoter("mike") + checkVoter("mike") +} diff --git a/05_hash_tables/kotlin/readme.md b/05_hash_tables/kotlin/readme.md new file mode 100644 index 00000000..bc2c9515 --- /dev/null +++ b/05_hash_tables/kotlin/readme.md @@ -0,0 +1,14 @@ +# HOW TO: + +## Example 01: + +### Compile +`kotlinc 01_price_of_groceries.kt -include-runtime -d price_of_groceries.jar` +### Execute +`java -jar price_of_groceries.jar` + +## Example 02: +### Compile +`kotlinc 02_check_voter.kt -include-runtime -d check_voter.jar` +### Execute +`java -jar check_voter.jar` diff --git a/06_breadth-first_search/golang/bfs.go b/06_breadth-first_search/golang/bfs.go index a3624313..274c7275 100644 --- a/06_breadth-first_search/golang/bfs.go +++ b/06_breadth-first_search/golang/bfs.go @@ -5,43 +5,36 @@ import ( ) func PersonIsSeller(name string) bool { - /* Assuming the person whose name ends with m as the mango seller as per the book */ return string(name[len(name)-1]) == "m" } -func search(name string) bool { - graph := make(map[string][]string) - graph["you"] = []string{"alice", "bob", "claire"} - graph["bob"] = []string{"anuj", "peggy"} - graph["alice"] = []string{"peggy"} - graph["claire"] = []string{"thom", "jonny"} - graph["anuj"] = []string{} - graph["peggy"] = []string{} - graph["thom"] = []string{} - graph["jonny"] = []string{} +func search(aGraph map[string][]string, name string) bool { //search queue - var search_queue []string - search_queue = append(search_queue, graph[name]...) + var searchQueue []string + searchQueue = append(searchQueue, aGraph[name]...) var searched []string - for len(search_queue) > 0 { - var person = search_queue[0] - search_queue = search_queue[1:] - var person_already_searched = false + + for len(searchQueue) > 0 { + var person = searchQueue[0] + searchQueue = searchQueue[1:] + personAlreadySearched := false + /* Checking to see if this person has already been searched */ for i := 0; i < len(searched); i++ { if searched[i] == person { - person_already_searched = true + personAlreadySearched = true } } - if person_already_searched == false { + + if personAlreadySearched == false { if PersonIsSeller(person) { - fmt.Println(person + " is the mango seller!") + fmt.Println(person, "is a mango seller!") return true } - search_queue = append(search_queue, graph[person]...) + searchQueue = append(searchQueue, aGraph[person]...) searched = append(searched, person) } @@ -51,5 +44,15 @@ func search(name string) bool { } func main() { - search("you") + graph := make(map[string][]string) + graph["you"] = []string{"alice", "bob", "claire"} + graph["bob"] = []string{"anuj", "peggy"} + graph["alice"] = []string{"peggy"} + graph["claire"] = []string{"thom", "jonny"} + graph["anuj"] = []string{} + graph["peggy"] = []string{} + graph["thom"] = []string{} + graph["jonny"] = []string{} + + search(graph, "you") } From 4c3bc702f4dc0fc2fb3a5da2bdccdd72b435656a Mon Sep 17 00:00:00 2001 From: Felice Forby Date: Wed, 13 Nov 2019 00:18:34 +0900 Subject: [PATCH 020/140] Add recursive binary search for ruby (ch. 1) and improve recursive max for ruby (ch. 4) (#113) * add recursive binary search for ruby * account for cases with empty lists and lists with only one item * use p instead of print to show nil value * add newline at end of file --- .../ruby/02_recursive_binary_search.rb | 26 +++++++++++++++++++ 04_quicksort/ruby/04_recursive_max.rb | 7 ++--- 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 01_introduction_to_algorithms/ruby/02_recursive_binary_search.rb diff --git a/01_introduction_to_algorithms/ruby/02_recursive_binary_search.rb b/01_introduction_to_algorithms/ruby/02_recursive_binary_search.rb new file mode 100644 index 00000000..f2fff1bc --- /dev/null +++ b/01_introduction_to_algorithms/ruby/02_recursive_binary_search.rb @@ -0,0 +1,26 @@ +def binary_search(list, item, low = 0, high = list.length - 1) + while low <= high + mid = (low + high) / 2 + guess = list[mid] + + if guess == item + return mid + elsif guess > item + high = mid - 1 + binary_search(list, item, low, high) + else + low = mid + 1 + binary_search(list, item, low, high) + end + end + + # If item is not found + return nil +end + +# Create array with numbers 1 through 100 +my_list = (1..100).to_a + +puts binary_search(my_list, 2) # => 1 +puts binary_search(my_list, 50) # => 49 +p binary_search(my_list, 101) # => nil diff --git a/04_quicksort/ruby/04_recursive_max.rb b/04_quicksort/ruby/04_recursive_max.rb index 59e7d948..fd4f90c8 100644 --- a/04_quicksort/ruby/04_recursive_max.rb +++ b/04_quicksort/ruby/04_recursive_max.rb @@ -1,7 +1,8 @@ def max(list) - if list.length == 2 - # condition ? then : else - list[0] > list[1] ? list[0] : list[1] + if list.empty? + nil + elsif list.length == 1 + numbers[0] else sub_max = max(list[1..-1]) list[0] > sub_max ? list[0] : sub_max From 184f80127c868d31883b968aecaa11746e1fc695 Mon Sep 17 00:00:00 2001 From: Michael Mkwelele Date: Tue, 12 Nov 2019 07:18:52 -0800 Subject: [PATCH 021/140] Add tests for factorial example. (#112) --- .../java/03_factorial/src/Factorial2.java | 21 +++++++++++++++++++ .../java/03_factorial/src/Factorial2Test.java | 20 ++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 03_recursion/java/03_factorial/src/Factorial2.java create mode 100644 03_recursion/java/03_factorial/src/Factorial2Test.java diff --git a/03_recursion/java/03_factorial/src/Factorial2.java b/03_recursion/java/03_factorial/src/Factorial2.java new file mode 100644 index 00000000..c9bafcb2 --- /dev/null +++ b/03_recursion/java/03_factorial/src/Factorial2.java @@ -0,0 +1,21 @@ +public class Factorial2 { + public static void main(String[] args) { + Factorial2 factorial2 = new Factorial2(); + System.out.println("The factorial of 5 is " + factorial2.getFactorial(5)); + } + + public int getFactorial(int number) { + if (isZeroOrOne(number)) { + return 1; + } + + return number * getFactorial(number - 1); + } + + public boolean isZeroOrOne(int number) { + if (number > 1) { + return false; + } + return true; + } +} diff --git a/03_recursion/java/03_factorial/src/Factorial2Test.java b/03_recursion/java/03_factorial/src/Factorial2Test.java new file mode 100644 index 00000000..a5fdd4e6 --- /dev/null +++ b/03_recursion/java/03_factorial/src/Factorial2Test.java @@ -0,0 +1,20 @@ +import org.junit.Assert; +import org.junit.Test; + +public class Factorial2Test { + @Test + public void testIsZeroOrOne() { + Factorial2 factorial2 = new Factorial2(); + + Assert.assertEquals(true, factorial2.isZeroOrOne(0)); + Assert.assertEquals(true, factorial2.isZeroOrOne(1)); + Assert.assertEquals(false, factorial2.isZeroOrOne(5)); + } + + @Test + public void testFactorial() { + Factorial2 factorial2 = new Factorial2(); + + Assert.assertEquals(120, factorial2.getFactorial(5)); + } +} From 0377eab73c1634c00b37dd19b1c22cf09e1b27d4 Mon Sep 17 00:00:00 2001 From: Michael Mkwelele Date: Tue, 12 Nov 2019 07:19:00 -0800 Subject: [PATCH 022/140] Add tests for the binary search implementation. (#110) --- .../src/main/BinarySearch.java | 63 +++++++++++++++++++ .../src/test/BinarySearchTest.java | 50 +++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 01_introduction_to_algorithms/java/01_binary_search/src/main/BinarySearch.java create mode 100644 01_introduction_to_algorithms/java/01_binary_search/src/test/BinarySearchTest.java diff --git a/01_introduction_to_algorithms/java/01_binary_search/src/main/BinarySearch.java b/01_introduction_to_algorithms/java/01_binary_search/src/main/BinarySearch.java new file mode 100644 index 00000000..bc3086d3 --- /dev/null +++ b/01_introduction_to_algorithms/java/01_binary_search/src/main/BinarySearch.java @@ -0,0 +1,63 @@ +package main; + +public class BinarySearch { + public static void main(String[] args) { + int[] myList = {87, 21, 45, 93}; + + System.out.println(binarySearch(myList, 93)); + System.out.println(binarySearch(myList, 16)); + } + + public static int binarySearch(int[] list, int item) { + if (isListEmpty(list)) { + return -1; + } + + int low = 0; + int high = list.length - 1; + + while (low <= high) { + int mid = (low + high) / 2; + int guess = list[mid]; + + if (guessEqualsItem(guess, item)) { + return mid; + } else if (guessGreaterThanItem(guess, item)) { + high = mid - 1; + } else if(guessLessThanItem(guess, item)) { + low = mid + 1; + } + } + + return -1; + } + + public static boolean isListEmpty(int[] myList) { + int listSize = myList.length; + if (listSize == 0) { + return true; + } + return false; + } + + public static boolean guessEqualsItem(int guess, int item) { + if (guess != item) { + return false; + } + return true; + } + + public static boolean guessGreaterThanItem(int guess, int item) { + if (guess < item) { + return false; + } + return true; + } + + public static boolean guessLessThanItem(int guess, int item) { + if (guess > item) { + return false; + } + return true; + } +} diff --git a/01_introduction_to_algorithms/java/01_binary_search/src/test/BinarySearchTest.java b/01_introduction_to_algorithms/java/01_binary_search/src/test/BinarySearchTest.java new file mode 100644 index 00000000..5ebc5e38 --- /dev/null +++ b/01_introduction_to_algorithms/java/01_binary_search/src/test/BinarySearchTest.java @@ -0,0 +1,50 @@ +package test; + +import main.BinarySearch; +import org.junit.Assert; +import org.junit.Test; + +public class BinarySearchTest { + @Test + public void testListIsEmpty() { + BinarySearch binarySearch = new BinarySearch(); + int[] myList = {6, 9}; + int[] emptyList = {}; + + Assert.assertEquals(false, binarySearch.isListEmpty(myList)); + Assert.assertEquals(true, binarySearch.isListEmpty(emptyList)); + } + + @Test + public void testGuessEqualsItem() { + BinarySearch binarySearch = new BinarySearch(); + + Assert.assertEquals(true, binarySearch.guessEqualsItem(3, 3)); + Assert.assertEquals(false, binarySearch.guessEqualsItem(0, 4)); + } + + @Test + public void testGuessIsLessThanItem() { + BinarySearch binarySearch = new BinarySearch(); + + Assert.assertEquals(true, binarySearch.guessLessThanItem(2, 7)); + Assert.assertEquals(false, binarySearch.guessLessThanItem(6, 1)); + } + + @Test + public void testGuessGreaterThanItem() { + BinarySearch binarySearch = new BinarySearch(); + + Assert.assertEquals(true, binarySearch.guessGreaterThanItem(17, 12)); + Assert.assertEquals(false, binarySearch.guessGreaterThanItem(13, 28)); + } + + @Test + public void testGivenListAndItemReturnIndexOfItem() { + BinarySearch binarySearch = new BinarySearch(); + int[] testList = {1, 3, 5, 7, 9}; + + Assert.assertEquals(1, binarySearch.binarySearch(testList, 3)); + Assert.assertEquals(-1, binarySearch.binarySearch(testList, 77)); + } +} From 30bbe9cf0114b4b776d3367e8d6dc1dfb4029fd8 Mon Sep 17 00:00:00 2001 From: fdrvrtm <49094977+fdrvrtm@users.noreply.github.com> Date: Tue, 12 Nov 2019 17:19:09 +0200 Subject: [PATCH 023/140] Fix the variable typo and add the function call (#109) --- 03_recursion/c++11/02_greet.cpp | 1 + 04_quicksort/c++11/02_recursive_sum.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/03_recursion/c++11/02_greet.cpp b/03_recursion/c++11/02_greet.cpp index c743a898..9af462f4 100644 --- a/03_recursion/c++11/02_greet.cpp +++ b/03_recursion/c++11/02_greet.cpp @@ -17,6 +17,7 @@ void greet(std::string name) { cout << "Hello, " + name + "!" << endl; greet2(name); cout << "Getting ready to say bye..." << endl; + bye(); } diff --git a/04_quicksort/c++11/02_recursive_sum.cpp b/04_quicksort/c++11/02_recursive_sum.cpp index b75a8201..652fe0cb 100644 --- a/04_quicksort/c++11/02_recursive_sum.cpp +++ b/04_quicksort/c++11/02_recursive_sum.cpp @@ -10,7 +10,7 @@ T sum(std::vector arr) { T last_num = arr.back(); // save last number value arr.pop_back(); // and remove it from array for next recursive call - return first_num + sum(arr); + return last_num + sum(arr); } int main() { From 9dc7611411dc23eabeb922a9a09c52b957850ce5 Mon Sep 17 00:00:00 2001 From: Massoud Afrashteh Date: Tue, 12 Nov 2019 18:49:21 +0330 Subject: [PATCH 024/140] Julia samples (#108) * Add julialang binary search sample * Add unit test * Add julialang selection sort sample * Change julia suffix to jl * Add recursion and quick sort with tests * add quick sort * Add hash table samples * Add BFS * Changed file names * Add dijkstras * Add Dijkstras test --- ...{binary_search.jil => 01_binary_search.jl} | 0 02_selection_sort/julia/01_selection_sort.jl | 26 ++++++++ 03_recursion/julia/01_countdown.jl | 24 +++++++ 03_recursion/julia/02_greet.jl | 24 +++++++ 03_recursion/julia/03_factorial.jl | 10 +++ 04_quicksort/julia/01_loop_sum.jl | 11 ++++ 04_quicksort/julia/02_recursive_sum.jl | 10 +++ 04_quicksort/julia/03_recursive_cout.jl | 10 +++ 04_quicksort/julia/04_recursive_max.jl | 11 ++++ 04_quicksort/julia/05_quick_sort.jl | 11 ++++ 05_hash_tables/julia/01_price_of_groceries.jl | 2 + 05_hash_tables/julia/02_check_voter.jl | 13 ++++ .../julia/01_breadth-first_search.jl | 39 +++++++++++ .../julia/01_dijkstras_algorithm.jl | 64 +++++++++++++++++++ 14 files changed, 255 insertions(+) rename 01_introduction_to_algorithms/julia/{binary_search.jil => 01_binary_search.jl} (100%) create mode 100644 02_selection_sort/julia/01_selection_sort.jl create mode 100644 03_recursion/julia/01_countdown.jl create mode 100644 03_recursion/julia/02_greet.jl create mode 100644 03_recursion/julia/03_factorial.jl create mode 100644 04_quicksort/julia/01_loop_sum.jl create mode 100644 04_quicksort/julia/02_recursive_sum.jl create mode 100644 04_quicksort/julia/03_recursive_cout.jl create mode 100644 04_quicksort/julia/04_recursive_max.jl create mode 100644 04_quicksort/julia/05_quick_sort.jl create mode 100644 05_hash_tables/julia/01_price_of_groceries.jl create mode 100644 05_hash_tables/julia/02_check_voter.jl create mode 100644 06_breadth-first_search/julia/01_breadth-first_search.jl create mode 100644 07_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl diff --git a/01_introduction_to_algorithms/julia/binary_search.jil b/01_introduction_to_algorithms/julia/01_binary_search.jl similarity index 100% rename from 01_introduction_to_algorithms/julia/binary_search.jil rename to 01_introduction_to_algorithms/julia/01_binary_search.jl diff --git a/02_selection_sort/julia/01_selection_sort.jl b/02_selection_sort/julia/01_selection_sort.jl new file mode 100644 index 00000000..2aeb51f6 --- /dev/null +++ b/02_selection_sort/julia/01_selection_sort.jl @@ -0,0 +1,26 @@ +using Test + +function find_smallest(arr) + smallest = arr[1] + smallest_index = 1 + for i = 1:length(arr) + if arr[i] < smallest + smallest = arr[i] + smallest_index = i + end + end + return smallest_index +end + +function selection_sort(arr) + new_arr = Array{Int64}(undef,0) + for i = 1:length(arr) + smallest = find_smallest(arr) + append!(new_arr,arr[smallest]) + deleteat!(arr,smallest) + end + return new_arr +end + +arr = [5,3,6,2,10] +@test selection_sort(arr) == [2,3,5,6,10] diff --git a/03_recursion/julia/01_countdown.jl b/03_recursion/julia/01_countdown.jl new file mode 100644 index 00000000..2d47ceb2 --- /dev/null +++ b/03_recursion/julia/01_countdown.jl @@ -0,0 +1,24 @@ +using Test +using Suppressor + +function countdown(i) + println(i) + if i <= 0 + return + end + countdown(i-1) +end + +result = @capture_out(countdown(10)) # return stdout result +@test result == "10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 +" diff --git a/03_recursion/julia/02_greet.jl b/03_recursion/julia/02_greet.jl new file mode 100644 index 00000000..3d607da7 --- /dev/null +++ b/03_recursion/julia/02_greet.jl @@ -0,0 +1,24 @@ +using Test +using Suppressor + +function greet2(name) + println("how are you, ",name,"?") +end + +function bye() + println("ok bye!") +end + +function greet(name) + println("hello, ",name,"!") + greet2(name) + println("getting ready to say bye...") + bye() +end + +result = @capture_out greet("adit") +@test result == "hello, adit! +how are you, adit? +getting ready to say bye... +ok bye! +" diff --git a/03_recursion/julia/03_factorial.jl b/03_recursion/julia/03_factorial.jl new file mode 100644 index 00000000..96675b03 --- /dev/null +++ b/03_recursion/julia/03_factorial.jl @@ -0,0 +1,10 @@ +using Test + +function factorial(x) + if x == 1 + return 1 + end + return x * factorial(x-1) +end + +@test factorial(5) == 120 diff --git a/04_quicksort/julia/01_loop_sum.jl b/04_quicksort/julia/01_loop_sum.jl new file mode 100644 index 00000000..e15e502a --- /dev/null +++ b/04_quicksort/julia/01_loop_sum.jl @@ -0,0 +1,11 @@ +using Test + +function sum(arr) + total = 0 + for x in arr + total += x + end + return total +end + +@test sum([1,2,3,4]) == 10 diff --git a/04_quicksort/julia/02_recursive_sum.jl b/04_quicksort/julia/02_recursive_sum.jl new file mode 100644 index 00000000..7933a3a8 --- /dev/null +++ b/04_quicksort/julia/02_recursive_sum.jl @@ -0,0 +1,10 @@ +using Test + +function sum(arr) + if isempty(arr) + return 0 + end + return arr[1] + sum(arr[2:end]) +end + +@test sum([1,2,3,4]) == 10 diff --git a/04_quicksort/julia/03_recursive_cout.jl b/04_quicksort/julia/03_recursive_cout.jl new file mode 100644 index 00000000..3e73ebf4 --- /dev/null +++ b/04_quicksort/julia/03_recursive_cout.jl @@ -0,0 +1,10 @@ +using Test + +function count(arr) + if isempty(arr) + return 0 + end + return 1 + count(arr[2:end]) +end + +@test count([1,2,3,4]) == 4 diff --git a/04_quicksort/julia/04_recursive_max.jl b/04_quicksort/julia/04_recursive_max.jl new file mode 100644 index 00000000..1eee2a43 --- /dev/null +++ b/04_quicksort/julia/04_recursive_max.jl @@ -0,0 +1,11 @@ +using Test + +function max_(arr) + if length(arr) == 1 + return arr[1] + end + sub_max = max_(arr[2:end]) + return arr[1] > sub_max ? arr[1] : sub_max +end + +@test max_([1,5,8,20,9,10]) == 20 diff --git a/04_quicksort/julia/05_quick_sort.jl b/04_quicksort/julia/05_quick_sort.jl new file mode 100644 index 00000000..34b2ef24 --- /dev/null +++ b/04_quicksort/julia/05_quick_sort.jl @@ -0,0 +1,11 @@ +using Test + +function quick_sort(arr) + if length(arr) < 2 return arr end + pivot = arr[1] + less = [i for i in arr[2:end] if i <= pivot] + greater = [i for i in arr[2:end] if i > pivot] + return vcat(quick_sort(less), [pivot], quick_sort(greater)) +end + +@test quick_sort([3,5,2,1,4]) == [1,2,3,4,5] diff --git a/05_hash_tables/julia/01_price_of_groceries.jl b/05_hash_tables/julia/01_price_of_groceries.jl new file mode 100644 index 00000000..3ddb89b7 --- /dev/null +++ b/05_hash_tables/julia/01_price_of_groceries.jl @@ -0,0 +1,2 @@ +book = Dict("apple"=> 0.67, "milk"=> 1.49, "avocado"=> 1.49) +println(book) diff --git a/05_hash_tables/julia/02_check_voter.jl b/05_hash_tables/julia/02_check_voter.jl new file mode 100644 index 00000000..700a52d6 --- /dev/null +++ b/05_hash_tables/julia/02_check_voter.jl @@ -0,0 +1,13 @@ +function check_vote(name) + if voted.get(name) + println("kick them out!") + else + voted[name] = true + println("let them vote!") + end +end + +voted = Dict() +check_vote("tom") +check_vote("mike") +check_vote("mike") diff --git a/06_breadth-first_search/julia/01_breadth-first_search.jl b/06_breadth-first_search/julia/01_breadth-first_search.jl new file mode 100644 index 00000000..4fa3c1bc --- /dev/null +++ b/06_breadth-first_search/julia/01_breadth-first_search.jl @@ -0,0 +1,39 @@ +using DataStructures, Test, Suppressor + +graph = Dict() +graph["you"] = ["alice","bob","claire"] +graph["bob"] = ["anuj","peggy"] +graph["claire"] = ["thom","jonny"] +graph["alice"] = ["peggy"] +graph["anuj"] = [] +graph["peggy"] = [] +graph["thom"] = [] +graph["jonny"] = [] + +function person_is_seller(name) + return name[end] == 'm' +end + +function search(name) + search_queue = Deque{String}() + map(n -> push!(search_queue,n),graph[name]) + searched = [] + while isempty(search_queue) == false + person = popfirst!(search_queue) + if (person in searched) == false + if person_is_seller(person) + println(person , " is a mango seller") + return true + else + map(n -> push!(search_queue,n),graph[person]) + push!(searched,person) + end + end + end + return false +end + + +result = @capture_out search("you") +@test result == "thom is a mango seller +" diff --git a/07_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl b/07_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl new file mode 100644 index 00000000..3949267d --- /dev/null +++ b/07_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl @@ -0,0 +1,64 @@ +# Julia version: LTS (v1.0.3) +using Test + +graph = Dict() +graph["start"] = Dict() +graph["start"]["a"] = 6 +graph["start"]["b"] = 2 + +graph["a"] = Dict() +graph["a"]["fin"] = 1 + +graph["b"] = Dict() +graph["b"]["a"] = 3 +graph["b"]["fin"] = 5 + +graph["fin"] = Dict() + +# the costs table +infinity = Inf +costs = Dict() +costs["a"] = 6 +costs["b"] = 2 +costs["fin"] = infinity + +# the parents table +parents = Dict() +parents["a"] = "start" +parents["b"] = "start" +parents["fin"] = nothing + +processed = [] + +function find_lowest_cost_node(costs) + lowest_cost = Inf + lowest_cost_node = nothing + for node in keys(costs) + cost = costs[node] + if cost < lowest_cost && node ∉ processed + lowest_cost = cost + lowest_cost_node = node + end + end + return lowest_cost_node +end + +node = find_lowest_cost_node(costs) +while node != nothing + global node + cost = costs[node] + neighbors = graph[node] + for n in keys(neighbors) + new_cost = cost + neighbors[n] + if costs[n] > new_cost + costs[n] = new_cost + parents[n] = node + end + end + push!(processed,node) + node = find_lowest_cost_node(costs) +end + +println("Cost from the start to each node:") +println(costs) +@test costs == Dict("fin"=>6,"b"=>2,"a"=>5) From d8da439590649335707419430267d3f1385e8dda Mon Sep 17 00:00:00 2001 From: Giorgio Date: Tue, 12 Nov 2019 10:19:36 -0500 Subject: [PATCH 025/140] implement recursive binary serach in rust (#93) --- .../rust/01_binary_search/cargo.lock | 4 + .../rust/01_binary_search/cargo.toml | 6 + .../rust/01_binary_search/src/main.rs | 103 ++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 01_introduction_to_algorithms/rust/01_binary_search/cargo.lock create mode 100644 01_introduction_to_algorithms/rust/01_binary_search/cargo.toml create mode 100644 01_introduction_to_algorithms/rust/01_binary_search/src/main.rs diff --git a/01_introduction_to_algorithms/rust/01_binary_search/cargo.lock b/01_introduction_to_algorithms/rust/01_binary_search/cargo.lock new file mode 100644 index 00000000..8a9c7c6c --- /dev/null +++ b/01_introduction_to_algorithms/rust/01_binary_search/cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "binary-search" +version = "0.1.0" + diff --git a/01_introduction_to_algorithms/rust/01_binary_search/cargo.toml b/01_introduction_to_algorithms/rust/01_binary_search/cargo.toml new file mode 100644 index 00000000..0404e767 --- /dev/null +++ b/01_introduction_to_algorithms/rust/01_binary_search/cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "binary-search" +version = "0.1.0" +authors = ["giorgiodelgado "] + +[dependencies] diff --git a/01_introduction_to_algorithms/rust/01_binary_search/src/main.rs b/01_introduction_to_algorithms/rust/01_binary_search/src/main.rs new file mode 100644 index 00000000..8ed4d15b --- /dev/null +++ b/01_introduction_to_algorithms/rust/01_binary_search/src/main.rs @@ -0,0 +1,103 @@ +// to run tests, you must have rust and cargo installed +// then run `cargo test` + +use std::cmp; + +// assumes that the slice is already sorted +fn binary_search(lst: &[T], item: T) -> Option { + let mid = ((lst.len() / 2) as f32).ceil() as usize; + + match lst.get(mid) { + None => None, + Some(val) => { + if *val == item { + Some(mid) + } else if *val > item { + let sublist = &lst[..mid]; + binary_search(sublist, item) + } else { + let sublist = &lst[(mid + 1)..]; + // mapping is necessary when the item is + // to the right of the middle since indices on the + // sublist are erased and being at 0, 1, 2, 3, ... etc + binary_search(sublist, item).map(|pos| pos + mid + 1) + } + }, + } +} + +fn main() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + let result = binary_search(num_slice, 70); + + println!("Result: {:?}", result); +} + + +#[cfg(test)] +mod test { + use super::binary_search; + + #[test] + fn finds_number_near_end_of_list() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + assert_eq!(binary_search(num_slice, 70), Some(16)); + } + + #[test] + fn finds_number_near_start_of_list() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + assert_eq!(binary_search(num_slice, 5), Some(2)); + } + + #[test] + fn returns_none_for_numbers() { + let num_slice = &[2, 4, 5, 12, 15, 30, 32, 33, 34, 40, 45, 51, 55, 57, 60, 66, 70, 71, 90, 99, 100]; + + assert_eq!(binary_search(num_slice, 1), None); + } + + #[test] + fn finds_char() { + let char_slice = &[ + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + ]; + + assert_eq!(binary_search(char_slice, 'l'), Some(11)); + } + + #[test] + fn returns_none_for_chars() { + let char_slice = &['a', 'b', 'c']; + + assert_eq!(binary_search(char_slice, 'l'), None); + } +} From b4c440089fb2592b391f64d280a07f8ce07fc383 Mon Sep 17 00:00:00 2001 From: Dmitry Neverovski Date: Wed, 20 Nov 2019 20:15:19 +0300 Subject: [PATCH 026/140] Update zero factorial The Definition of a Zero Factorial Because zero has no lower numbers but is still in and of itself a number, there is still but one possible combination of how that data set can be arranged: it cannot. This still counts as one way of arranging it, so by definition, a zero factorial is equal to one, just as 1! is equal to one because there is only a single possible arrangement of this data set. --- 03_recursion/Golang/03_factorial/Factorial.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_recursion/Golang/03_factorial/Factorial.go b/03_recursion/Golang/03_factorial/Factorial.go index 5a0a6e1c..24214021 100644 --- a/03_recursion/Golang/03_factorial/Factorial.go +++ b/03_recursion/Golang/03_factorial/Factorial.go @@ -3,7 +3,7 @@ package main import "fmt" func fact(x int) int { - if x == 1 { + if x == 0 { return 1 } From 7971852b0ee8baa50c3e0c265928100e6b99ff5e Mon Sep 17 00:00:00 2001 From: BryanChan777 <43082778+BryanChan777@users.noreply.github.com> Date: Sat, 23 Nov 2019 16:46:38 -0800 Subject: [PATCH 027/140] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9246b147..73508514 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is the code in my book [Grokking Algorithms](https://www.manning.com/bhargava). -Also check out [Python Tutor](http://pythontutor.com/), a great website that helps you step through Python code line by line. +Check out [Python Tutor](http://pythontutor.com/), a great website that guides you through Python code line by line. ## Errata @@ -10,9 +10,9 @@ Also check out [Python Tutor](http://pythontutor.com/), a great website that hel ## Images -This repo also contains every image in Grokking Algorithms, in hi-res. These images are available for free for non-commercial use. If you use an image, please add "copyright Manning Publications, drawn by adit.io". You are welcome to use these images in any non-commercial teaching materials, presentations, etc. +This repository contains every image in Grokking Algorithms in high resolution. These images are available for non-commercial use. If you use an image, please add "copyright Manning Publications, drawn by adit.io". You are welcome to use these images in any non-commercial education (i.e. teaching materials, presentations, etc.) ## Contributing -- The examples in this book are in Python, but I'd like to get examples in Ruby, JavaScript, C, and other languages too. Please add examples in other languages! -- I'm pretty responsive to PRs. That is the quickest way to contribute to this repo. +- The examples in this book are witten in Python, but I'd like examples in Ruby, JavaScript, C, and other languages too. Please add examples in other languages! +- Pull request are the quickest way to contribute to this repository and I'm pretty responsive to them. From c849e75041fb269b2667551f66361a348910957a Mon Sep 17 00:00:00 2001 From: Timo J Date: Sun, 8 Dec 2019 12:03:15 +0100 Subject: [PATCH 028/140] More concise Rubyish code. Hash key checking is not necessary in this case. If a key doesn't exist in a Hash, Ruby returns nil by default and nil is falsy. Hash key checking would only be necessary if the Hash had been set up with a default value. --- 05_hash_tables/ruby/02_check_voter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/05_hash_tables/ruby/02_check_voter.rb b/05_hash_tables/ruby/02_check_voter.rb index 0832e526..b13f50b6 100644 --- a/05_hash_tables/ruby/02_check_voter.rb +++ b/05_hash_tables/ruby/02_check_voter.rb @@ -3,7 +3,7 @@ @voted = {} def check_voter(name) - if @voted.key?(name) && @voted[name] + if @voted[name] puts "kick them out!" else @voted[name] = true From b65c3de28399daed7eeacbcda821485475e60532 Mon Sep 17 00:00:00 2001 From: TimoSci Date: Sun, 8 Dec 2019 12:40:40 +0100 Subject: [PATCH 029/140] separate search functionality from seller checking fucntionality according to single responsibility principle --- .../ruby/01_breadth-first_search.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/06_breadth-first_search/ruby/01_breadth-first_search.rb b/06_breadth-first_search/ruby/01_breadth-first_search.rb index cb21b9fe..a47e0d08 100644 --- a/06_breadth-first_search/ruby/01_breadth-first_search.rb +++ b/06_breadth-first_search/ruby/01_breadth-first_search.rb @@ -1,4 +1,4 @@ -def person_is_seller(name) +def person_is_seller?(name) name[-1] == "m" end @@ -24,17 +24,13 @@ def search(name) person = search_queue.shift # Only search this person if you haven't already searched them. next if searched.member?(person) - if person_is_seller(person) - puts "#{person} is a mango seller!" - return true - else - search_queue += @graph[person] + return person if yield person + search_queue += @graph[person] # Marks this person as searched - searched.push(person) - end + searched.push(person) end false end -search("you") +search("you"){|person| person_is_seller?(person) }.tap{|person| puts "#{person} is a mango seller!" if person} From 70ddf46cb3254718fc371255eaba0773e52aa63c Mon Sep 17 00:00:00 2001 From: TimoSci Date: Sun, 8 Dec 2019 12:56:36 +0100 Subject: [PATCH 030/140] represent record of searched verices as a hash for O(1) lookup --- 06_breadth-first_search/ruby/01_breadth-first_search.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/06_breadth-first_search/ruby/01_breadth-first_search.rb b/06_breadth-first_search/ruby/01_breadth-first_search.rb index a47e0d08..2aa15f35 100644 --- a/06_breadth-first_search/ruby/01_breadth-first_search.rb +++ b/06_breadth-first_search/ruby/01_breadth-first_search.rb @@ -18,16 +18,16 @@ def search(name) search_queue = [] search_queue += @graph[name] # This array is how you keep track of which people you've searched before. - searched = [] + searched = {} until search_queue.empty? person = search_queue.shift # Only search this person if you haven't already searched them. - next if searched.member?(person) + next if searched[person] return person if yield person search_queue += @graph[person] # Marks this person as searched - searched.push(person) + searched[person] = true end false From 1f6cf7d460c51f0a3d74de94a8765bb901c4da27 Mon Sep 17 00:00:00 2001 From: TimoSci Date: Sun, 8 Dec 2019 13:07:44 +0100 Subject: [PATCH 031/140] avoid use of global variables; it is more rubyish to represent a graph as a class --- .../ruby/01_breadth-first_search.rb | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/06_breadth-first_search/ruby/01_breadth-first_search.rb b/06_breadth-first_search/ruby/01_breadth-first_search.rb index 2aa15f35..39e2fd79 100644 --- a/06_breadth-first_search/ruby/01_breadth-first_search.rb +++ b/06_breadth-first_search/ruby/01_breadth-first_search.rb @@ -2,35 +2,38 @@ def person_is_seller?(name) name[-1] == "m" end -@graph = {} +class Graph < Hash + def search(name) + search_queue = [] + search_queue += self[name] + # This array is how you keep track of which people you've searched before. + searched = {} -# %w(string1 string2 ...) is a shorter way to define arrays of strings -@graph["you"] = %w(alice bob claire) -@graph["bob"] = %w(anuj peggy) -@graph["alice"] = %w(peggy) -@graph["claire"] = %w(thom jonny) -@graph["anuj"] = [] -@graph["peggy"] = [] -@graph["thom"] = [] -@graph["jonny"] = [] - -def search(name) - search_queue = [] - search_queue += @graph[name] - # This array is how you keep track of which people you've searched before. - searched = {} + until search_queue.empty? + pp searched + person = search_queue.shift + # Only search this person if you haven't already searched them. + next if searched[person] + return person if yield person + search_queue += self[person] + # Marks this person as searched + searched[person] = true + end - until search_queue.empty? - person = search_queue.shift - # Only search this person if you haven't already searched them. - next if searched[person] - return person if yield person - search_queue += @graph[person] - # Marks this person as searched - searched[person] = true + false end - - false end -search("you"){|person| person_is_seller?(person) }.tap{|person| puts "#{person} is a mango seller!" if person} + +# %w(string1 string2 ...) is a shorter way to define arrays of strings +graph = Graph.new +graph["you"] = %w(alice bob claire) +graph["bob"] = %w(anuj peggy) +graph["alice"] = %w(peggy) +graph["claire"] = %w(thom jonny) +graph["anuj"] = [] +graph["peggy"] = [] +graph["thom"] = [] +graph["jonny"] = [] + +graph.search("you"){|person| person_is_seller?(person) }.tap{|person| puts "#{person} is a mango seller!" if person} From ff7ae962c173ae36c01f158a1ea178740356284a Mon Sep 17 00:00:00 2001 From: TimoSci Date: Sun, 8 Dec 2019 13:31:33 +0100 Subject: [PATCH 032/140] edit comments --- 06_breadth-first_search/ruby/01_breadth-first_search.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/06_breadth-first_search/ruby/01_breadth-first_search.rb b/06_breadth-first_search/ruby/01_breadth-first_search.rb index 39e2fd79..4436019c 100644 --- a/06_breadth-first_search/ruby/01_breadth-first_search.rb +++ b/06_breadth-first_search/ruby/01_breadth-first_search.rb @@ -6,17 +6,16 @@ class Graph < Hash def search(name) search_queue = [] search_queue += self[name] - # This array is how you keep track of which people you've searched before. + # The "searched" Hash is how you keep track of which people you've searched before. We use a hash because hash lookups are fast! searched = {} until search_queue.empty? - pp searched person = search_queue.shift # Only search this person if you haven't already searched them. next if searched[person] return person if yield person search_queue += self[person] - # Marks this person as searched + # Marks this person as searched searched[person] = true end @@ -36,4 +35,5 @@ def search(name) graph["thom"] = [] graph["jonny"] = [] -graph.search("you"){|person| person_is_seller?(person) }.tap{|person| puts "#{person} is a mango seller!" if person} +# we begin the search from vertex "you" and pass the match criterion in the block, then we tap the search result +graph.search("you"){|person| person_is_seller?(person)}.tap{|person| puts "#{person} is a mango seller!" if person} From d771cb21a00d5ebde4e3d49a309e5eba6dd6add4 Mon Sep 17 00:00:00 2001 From: Vladimir Pavlovic Date: Fri, 3 Jan 2020 00:46:37 +0100 Subject: [PATCH 033/140] Rename 01_longest_common_subsequence to 01_longest_common_subsequence.cpp --- .../\321\201++/01_longest_common_subsequence.cpp" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "09_dynamic_programming/\321\201++/01_longest_common_subsequence" => "09_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" (100%) diff --git "a/09_dynamic_programming/\321\201++/01_longest_common_subsequence" "b/09_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" similarity index 100% rename from "09_dynamic_programming/\321\201++/01_longest_common_subsequence" rename to "09_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" From 52a5a7cc24629d8d738f7f653a74f3f05fdf4037 Mon Sep 17 00:00:00 2001 From: Alexander Danilchenko <39950413+OlexanderD@users.noreply.github.com> Date: Sun, 12 Jan 2020 18:34:55 +0200 Subject: [PATCH 034/140] Changed code style according to new Java versions Changed long and ugly type declarations with "var" keyword (Java 10). Also fixed warning about raw usage of HashSet without type specification. --- .../java/01_set_covering/src/SetCovering.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java b/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java index 9afd2c82..c9cbff64 100644 --- a/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java +++ b/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java @@ -1,10 +1,9 @@ import java.util.*; public class SetCovering { - - public static void main(String[] args) { - Set statesNeeded = new HashSet(Arrays.asList("mt", "wa", "or", "id", "nv", "ut", "ca", "az")); - Map> stations = new LinkedHashMap<>(); + public static void main(String... args) { + var statesNeeded = new HashSet<>(Arrays.asList("mt", "wa", "or", "id", "nv", "ut", "ca", "az")); + var stations = new LinkedHashMap>(); stations.put("kone", new HashSet<>(Arrays.asList("id", "nv", "ut"))); stations.put("ktwo", new HashSet<>(Arrays.asList("wa", "id", "mt"))); @@ -12,13 +11,13 @@ public static void main(String[] args) { stations.put("kfour", new HashSet<>(Arrays.asList("nv", "ut"))); stations.put("kfive", new HashSet<>(Arrays.asList("ca", "az"))); - Set finalStations = new HashSet(); + var finalStations = new HashSet(); while (!statesNeeded.isEmpty()) { String bestStation = null; - Set statesCovered = new HashSet<>(); + var statesCovered = new HashSet(); - for (Map.Entry> station : stations.entrySet()) { - Set covered = new HashSet<>(statesNeeded); + for (var station : stations.entrySet()) { + var covered = new HashSet<>(statesNeeded); covered.retainAll(station.getValue()); if (covered.size() > statesCovered.size()) { From 891eec2873683e4c876b20c3cb3a7b3355caefb8 Mon Sep 17 00:00:00 2001 From: Ruslan Korolev Date: Fri, 17 Jan 2020 18:26:21 +0200 Subject: [PATCH 035/140] fix 04_recursive_max on ruby --- 04_quicksort/ruby/04_recursive_max.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/04_quicksort/ruby/04_recursive_max.rb b/04_quicksort/ruby/04_recursive_max.rb index fd4f90c8..4770b6b3 100644 --- a/04_quicksort/ruby/04_recursive_max.rb +++ b/04_quicksort/ruby/04_recursive_max.rb @@ -1,10 +1,12 @@ def max(list) - if list.empty? - nil - elsif list.length == 1 - numbers[0] + return nil if list.empty? + + if list.length == 1 + list[0] # base case else sub_max = max(list[1..-1]) list[0] > sub_max ? list[0] : sub_max end end + +puts max([2,3,8,5,5]) From 4fd96f6987ae8d2d67ae3a79201bc2f9c28e29be Mon Sep 17 00:00:00 2001 From: fhl43211 <7145936+fhl43211@users.noreply.github.com> Date: Thu, 20 Feb 2020 17:23:54 -0800 Subject: [PATCH 036/140] Create cpp file --- .../c++11/01_dijkstras_algorithm.cpp | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp diff --git a/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp b/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp new file mode 100644 index 00000000..39983938 --- /dev/null +++ b/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include + +namespace +{ + using node_t = std::string; + using node_cost_t = std::unordered_map; + using graph_t = std::unordered_map; + using parent_graph_t = std::unordered_map; + + std::vector processed; + auto max = std::numeric_limits::max(); + const node_t find_lowest_cost_node(const node_cost_t& costs) + { + auto lowest_cost = max; + node_t lowest_cost_node{}; + // Go through each node in the costs graph + for (const auto& nodeCost : costs) + { + const auto& cost = nodeCost.second; + const auto& node = nodeCost.first; + // Check if this node is processed or not; + bool isNotProcessed = std::find(processed.cbegin(), processed.cend(), node) == processed.cend(); + // Find the lowest cost node + if (cost < lowest_cost && isNotProcessed) + { + lowest_cost = cost; + lowest_cost_node = node; + } + } + return lowest_cost_node; + } +} + +int main(void) +{ + // Setup graph + graph_t graph; + graph.emplace("start", node_cost_t{{"a", 6}, {"b", 2}}); + graph.emplace("a", node_cost_t{{"finish", 1}}); + graph.emplace("b", node_cost_t{{"a", 3},{"finish", 5}}); + graph.emplace("finish", node_cost_t{}); + // Setup costs table + node_cost_t costs{{"a", 6},{"b", 2},{"finish", max}}; + // Setup parents table + parent_graph_t parents{{"a", "start"}, {"b", "start"}}; + // node is "b" at this time + auto node = find_lowest_cost_node(costs); + while (!node.empty()) + { + const auto costSoFar = costs[node]; + const auto& neighbours = graph[node]; + // Loop through all the nodes + for (const auto& neighbour : neighbours) + { + const auto newCost = costSoFar + neighbour.second; + const auto& currentNeighbourName = neighbour.first; + // If it is cheaper than the cost registered in the costs graph, update the costs graph + if (newCost < costs[currentNeighbourName]) + { + costs[currentNeighbourName] = newCost; + parents[currentNeighbourName] = node; + } + } + // Mark the current node as processed + processed.push_back(node); + // Find the next node to process. If they are all processed, this will return an empty string. + node = find_lowest_cost_node(costs); + } + std::cout << "Cost from the start to each node:" << std::endl; + std::for_each(costs.cbegin(), + costs.cend(), + [](const std::pair& cost) { std::cout << cost.first << " " << cost.second << std::endl; }); + return 0; +} From e6558351a88270f2e3d949dd7b63728b553babfb Mon Sep 17 00:00:00 2001 From: fhl43211 Date: Fri, 21 Feb 2020 09:06:58 -0800 Subject: [PATCH 037/140] Use lambda function --- .../c++11/01_dijkstras_algorithm.cpp | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp b/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp index 39983938..f0e069df 100644 --- a/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp +++ b/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp @@ -3,51 +3,51 @@ #include #include #include -#include -namespace +int main(void) { using node_t = std::string; using node_cost_t = std::unordered_map; using graph_t = std::unordered_map; using parent_graph_t = std::unordered_map; - std::vector processed; - auto max = std::numeric_limits::max(); - const node_t find_lowest_cost_node(const node_cost_t& costs) - { - auto lowest_cost = max; - node_t lowest_cost_node{}; - // Go through each node in the costs graph - for (const auto& nodeCost : costs) - { - const auto& cost = nodeCost.second; - const auto& node = nodeCost.first; - // Check if this node is processed or not; - bool isNotProcessed = std::find(processed.cbegin(), processed.cend(), node) == processed.cend(); - // Find the lowest cost node - if (cost < lowest_cost && isNotProcessed) - { - lowest_cost = cost; - lowest_cost_node = node; - } - } - return lowest_cost_node; - } -} - -int main(void) -{ // Setup graph graph_t graph; + graph.reserve(4U); graph.emplace("start", node_cost_t{{"a", 6}, {"b", 2}}); graph.emplace("a", node_cost_t{{"finish", 1}}); graph.emplace("b", node_cost_t{{"a", 3},{"finish", 5}}); graph.emplace("finish", node_cost_t{}); // Setup costs table - node_cost_t costs{{"a", 6},{"b", 2},{"finish", max}}; + node_cost_t costs{{"a", 6},{"b", 2},{"finish", std::numeric_limits::max()}}; // Setup parents table parent_graph_t parents{{"a", "start"}, {"b", "start"}}; + + // A vector of processed nodes + std::vector processed; + processed.reserve(3U); + // A lambda function to find the lowest cost node + const auto find_lowest_cost_node = [&processed](const node_cost_t& costs) + { + auto lowest_cost = std::numeric_limits::max(); + node_t lowest_cost_node{}; + // Go through each node in the costs graph + for (const auto& nodeCost : costs) + { + const auto& cost = nodeCost.second; + const auto& node = nodeCost.first; + // Check if this node is processed or not; + bool isNotProcessed = std::find(processed.cbegin(), processed.cend(), node) == processed.cend(); + // Find the lowest cost node + if (cost < lowest_cost && isNotProcessed) + { + lowest_cost = cost; + lowest_cost_node = node; + } + } + return lowest_cost_node; + }; + // node is "b" at this time auto node = find_lowest_cost_node(costs); while (!node.empty()) @@ -72,8 +72,10 @@ int main(void) node = find_lowest_cost_node(costs); } std::cout << "Cost from the start to each node:" << std::endl; - std::for_each(costs.cbegin(), - costs.cend(), - [](const std::pair& cost) { std::cout << cost.first << " " << cost.second << std::endl; }); + // prints finish 6 b 2 a 5 + for (const auto& cost : costs) + { + std::cout << cost.first << " " << cost.second << std::endl; + } return 0; } From 696a657c6f5b49d8169d748293adb77ffe9b1759 Mon Sep 17 00:00:00 2001 From: Joe Czarnecki <28707072+joeczar@users.noreply.github.com> Date: Tue, 3 Mar 2020 16:16:49 +0100 Subject: [PATCH 038/140] Create Scala Solutions I've been working through the book and I was surprised to see there wasn't a Scala Solution here. I created a mutable version as close to the original as possible and immutable recursive version. --- 06_breadth-first_search/Scala Solutions | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 06_breadth-first_search/Scala Solutions diff --git a/06_breadth-first_search/Scala Solutions b/06_breadth-first_search/Scala Solutions new file mode 100644 index 00000000..3ed42746 --- /dev/null +++ b/06_breadth-first_search/Scala Solutions @@ -0,0 +1,64 @@ +package SearchAndSort + +import scala.collection.immutable.HashMap +import scala.collection.{immutable, mutable} + + +object BreadthFirstSearch extends App { + + val graph = HashMap( + ("you" -> Vector("alice", "bob", "claire")), + ("bob" -> Vector("anuj", "peggy")), + ("alice" -> Vector("peggy")), + ("claire" -> Vector("thom", "johnny")), + ("anuj" -> Vector()), + ("peggy" -> Vector()), + ("thom" -> Vector()), + ("jonny" -> Vector()), + ) + + def personIsSeller(name: String): Boolean = + name.endsWith("y") + + def search(name: String): Unit = { + var searchQue = mutable.Queue[String]() + searchQue ++= graph(name) + var searched = Array() + var seller = false + while (!seller) { + val person = searchQue.dequeue() + if (!searched.contains(person)){ + if (personIsSeller(person)) { + println(person + " is a mango seller!") + seller = true + } + else { + searchQue ++= graph(person) + searched + person + } + } + } + } + + println(search("you")) + + def searchFunctional(name: String): String = { + var searchQue = immutable.Queue[String]() + + @scala.annotation.tailrec + def helper(searchQue: immutable.Queue[String], searched: Vector[String] = Vector()): String = { + if (searchQue.isEmpty) return "No Mango sellers" + val person = searchQue.dequeue._1 + if (searched.contains(person)) + helper(searchQue.tail) + else if (personIsSeller(person)) { + val result: String = s"$person is a mango seller!" + result + } else + helper(searchQue.tail ++ graph(person), searched :+ person) + } + helper(searchQue ++ graph(name)) + } + + println(searchFunctional("you")) +} From a6502e0af07c0fc80872725f3dd6f79c262d03ec Mon Sep 17 00:00:00 2001 From: Joe Czarnecki <28707072+joeczar@users.noreply.github.com> Date: Tue, 3 Mar 2020 16:46:16 +0100 Subject: [PATCH 039/140] Update Scala Solutions --- 06_breadth-first_search/Scala Solutions | 33 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/06_breadth-first_search/Scala Solutions b/06_breadth-first_search/Scala Solutions index 3ed42746..b2cedd5f 100644 --- a/06_breadth-first_search/Scala Solutions +++ b/06_breadth-first_search/Scala Solutions @@ -18,7 +18,7 @@ object BreadthFirstSearch extends App { ) def personIsSeller(name: String): Boolean = - name.endsWith("y") + name.endsWith("z") def search(name: String): Unit = { var searchQue = mutable.Queue[String]() @@ -26,16 +26,25 @@ object BreadthFirstSearch extends App { var searched = Array() var seller = false while (!seller) { - val person = searchQue.dequeue() - if (!searched.contains(person)){ - if (personIsSeller(person)) { - println(person + " is a mango seller!") - seller = true - } - else { - searchQue ++= graph(person) - searched + person - } + if (searchQue.isEmpty) + println("No Mango Sellers") + else { + val person = searchQue.dequeue() + if (!searched.contains(person)){ + if (personIsSeller(person)) { + println(person + " is a mango seller!") + seller = true + } + else { + if (searchQue.isEmpty) { + println("No Mango Sellers") + seller = true + } + else + searchQue ++= graph(person) + searched + person + } + } } } } @@ -47,7 +56,7 @@ object BreadthFirstSearch extends App { @scala.annotation.tailrec def helper(searchQue: immutable.Queue[String], searched: Vector[String] = Vector()): String = { - if (searchQue.isEmpty) return "No Mango sellers" + if (searchQue.length > 2) return "No Mango sellers" val person = searchQue.dequeue._1 if (searched.contains(person)) helper(searchQue.tail) From 4e5867cff1b40858d8f7f46e1dd43a1c05cf40e1 Mon Sep 17 00:00:00 2001 From: Joe Czarnecki <28707072+joeczar@users.noreply.github.com> Date: Tue, 3 Mar 2020 16:54:25 +0100 Subject: [PATCH 040/140] Update Scala Solutions --- 06_breadth-first_search/Scala Solutions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/06_breadth-first_search/Scala Solutions b/06_breadth-first_search/Scala Solutions index b2cedd5f..20c4b608 100644 --- a/06_breadth-first_search/Scala Solutions +++ b/06_breadth-first_search/Scala Solutions @@ -56,7 +56,7 @@ object BreadthFirstSearch extends App { @scala.annotation.tailrec def helper(searchQue: immutable.Queue[String], searched: Vector[String] = Vector()): String = { - if (searchQue.length > 2) return "No Mango sellers" + if (searchQue.length > 1) return "No Mango sellers" val person = searchQue.dequeue._1 if (searched.contains(person)) helper(searchQue.tail) From 43fb096e64d7eba5a426743f1760ad4d775527db Mon Sep 17 00:00:00 2001 From: Joe Czarnecki <28707072+joeczar@users.noreply.github.com> Date: Fri, 6 Mar 2020 14:39:52 +0100 Subject: [PATCH 041/140] removed an extra if clause --- 06_breadth-first_search/Scala Solutions | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/06_breadth-first_search/Scala Solutions b/06_breadth-first_search/Scala Solutions index 20c4b608..674fd85c 100644 --- a/06_breadth-first_search/Scala Solutions +++ b/06_breadth-first_search/Scala Solutions @@ -26,9 +26,6 @@ object BreadthFirstSearch extends App { var searched = Array() var seller = false while (!seller) { - if (searchQue.isEmpty) - println("No Mango Sellers") - else { val person = searchQue.dequeue() if (!searched.contains(person)){ if (personIsSeller(person)) { @@ -40,12 +37,13 @@ object BreadthFirstSearch extends App { println("No Mango Sellers") seller = true } - else + else { searchQue ++= graph(person) searched + person + } } } - } + } } From cad619574d1f4edbeb9d42e3bf350683b30cb2a5 Mon Sep 17 00:00:00 2001 From: ZGennadiy <56154440+ZGennadiy@users.noreply.github.com> Date: Tue, 17 Mar 2020 10:24:44 +0300 Subject: [PATCH 042/140] Update selection sort ES6 Added copy values from original array, because it must be immutable. Without that after call selectionSort origin array will become empty. --- 02_selection_sort/ES6/01_selection_sort.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/02_selection_sort/ES6/01_selection_sort.js b/02_selection_sort/ES6/01_selection_sort.js index fcb6919f..2de1581d 100644 --- a/02_selection_sort/ES6/01_selection_sort.js +++ b/02_selection_sort/ES6/01_selection_sort.js @@ -19,17 +19,21 @@ const findSmallestIndex = (array) => { // 2. Sorts the array const selectionSort = (array) => { + //Copy values from array, because it must be immutable. Without that after call selectionSort origin array will become empty. + const sortingArray = [...array]; const sortedArray = []; - const length = array.length; + const length = sortingArray.length; for (let i = 0; i < length; i++) { // Finds the smallest element in the given array - const smallestIndex = findSmallestIndex(array); + const smallestIndex = findSmallestIndex(sortingArray); // Adds the smallest element to new array - sortedArray.push(array.splice(smallestIndex, 1)[0]); + sortedArray.push(sortingArray.splice(smallestIndex, 1)[0]); } return sortedArray; }; -console.log(selectionSort([5, 3, 6, 2, 10])); // [2, 3, 5, 6, 10] +const array = [5, 3, 6, 2, 10]; +console.log(selectionSort(array)); // [2, 3, 5, 6, 10] +console.log(array); // [5, 3, 6, 2, 10] From b0414be22eecf7911a07954e50e18c80f19cd0c6 Mon Sep 17 00:00:00 2001 From: Alexander Launi Date: Sat, 21 Mar 2020 15:20:34 -0400 Subject: [PATCH 043/140] Add Rust examples to 02_selection_sort --- .../rust/01_selection_sort/.gitignore | 10 +++ .../rust/01_selection_sort/Cargo.toml | 7 ++ .../rust/01_selection_sort/src/main.rs | 68 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 02_selection_sort/rust/01_selection_sort/.gitignore create mode 100644 02_selection_sort/rust/01_selection_sort/Cargo.toml create mode 100644 02_selection_sort/rust/01_selection_sort/src/main.rs diff --git a/02_selection_sort/rust/01_selection_sort/.gitignore b/02_selection_sort/rust/01_selection_sort/.gitignore new file mode 100644 index 00000000..50c83018 --- /dev/null +++ b/02_selection_sort/rust/01_selection_sort/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk \ No newline at end of file diff --git a/02_selection_sort/rust/01_selection_sort/Cargo.toml b/02_selection_sort/rust/01_selection_sort/Cargo.toml new file mode 100644 index 00000000..673ae940 --- /dev/null +++ b/02_selection_sort/rust/01_selection_sort/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "selection-sort" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +[dependencies] diff --git a/02_selection_sort/rust/01_selection_sort/src/main.rs b/02_selection_sort/rust/01_selection_sort/src/main.rs new file mode 100644 index 00000000..2272dd06 --- /dev/null +++ b/02_selection_sort/rust/01_selection_sort/src/main.rs @@ -0,0 +1,68 @@ +// Swaps elements in an array +fn swap(list: &mut [T], index_a: usize, index_b: usize) { + let tmp = list[index_a]; + list[index_a] = list[index_b]; + list[index_b] = tmp; +} + +fn selection_sort(list: &mut [T]) { + for i in 0..list.len() { + for j in (i+1)..list.len() { + if list[j] > list[i] { + swap(list, i, j); + } + } + } +} + +fn main() { + let list = &mut [156, 141, 35, 94, 88, 61, 111]; + print!("{:?} => ", list); + selection_sort(list); + print!("{:?}\n", list); +} + +#[cfg(test)] +mod test { + use super::selection_sort; + + #[test] + fn sort_unsigned_list() { + let mut list : [u8; 7] = [156, 141, 35, 94, 88, 61, 111]; + let list_sorted : [u8; 7] = [156, 141, 111, 94, 88, 61, 35]; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } + + #[test] + fn sort_signed_list() { + let mut list : [i32; 10] = [75, 85, -26, 61, 20, -40, -72, 30, -27, 58]; + let list_sorted : [i32; 10] = [85, 75, 61, 58, 30, 20, -26, -27, -40, -72]; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } + + #[test] + fn sort_strings() { + let mut list : [&str; 7] = ["Radiohead", "Kishore Kumar", "The Black Keys", + "Neutral Milk Hotel", "Beck", "The Strokes", "Wilco" + ]; + let list_sorted : [&str; 7] = ["Wilco", "The Strokes", "The Black Keys", + "Radiohead", "Neutral Milk Hotel", "Kishore Kumar", "Beck" + ]; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } + + #[test] + fn sorts_an_empty_list() { + let mut list : [u8; 0] = []; + let list_sorted : [u8; 0] = []; + selection_sort(&mut list); + + assert_eq!(list, list_sorted); + } +} \ No newline at end of file From 858e1e71e77b42e8b21a537b27c619bc0b99e21d Mon Sep 17 00:00:00 2001 From: Alexander Launi Date: Sat, 21 Mar 2020 16:08:56 -0400 Subject: [PATCH 044/140] Add recursive countdown example in Rust --- 03_recursion/rust/01_countdown/.gitignore | 10 ++++++++++ 03_recursion/rust/01_countdown/Cargo.toml | 9 +++++++++ 03_recursion/rust/01_countdown/src/main.rs | 12 ++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 03_recursion/rust/01_countdown/.gitignore create mode 100644 03_recursion/rust/01_countdown/Cargo.toml create mode 100644 03_recursion/rust/01_countdown/src/main.rs diff --git a/03_recursion/rust/01_countdown/.gitignore b/03_recursion/rust/01_countdown/.gitignore new file mode 100644 index 00000000..088ba6ba --- /dev/null +++ b/03_recursion/rust/01_countdown/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/03_recursion/rust/01_countdown/Cargo.toml b/03_recursion/rust/01_countdown/Cargo.toml new file mode 100644 index 00000000..076bdcd6 --- /dev/null +++ b/03_recursion/rust/01_countdown/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "countdown" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/03_recursion/rust/01_countdown/src/main.rs b/03_recursion/rust/01_countdown/src/main.rs new file mode 100644 index 00000000..2fdb117d --- /dev/null +++ b/03_recursion/rust/01_countdown/src/main.rs @@ -0,0 +1,12 @@ +fn countdown(i: u32) { + println!("{}", i); + if i == 0 { + return + } + + countdown(i - 1); +} + +fn main() { + countdown(5); +} From 64e231a8c60478b04bffa66eae1fe513cf4b5f73 Mon Sep 17 00:00:00 2001 From: Alexander Launi Date: Sat, 21 Mar 2020 16:16:22 -0400 Subject: [PATCH 045/140] Add greet example in Rust --- 03_recursion/rust/02_greet/.gitignore | 10 ++++++++++ 03_recursion/rust/02_greet/Cargo.toml | 9 +++++++++ 03_recursion/rust/02_greet/src/main.rs | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 03_recursion/rust/02_greet/.gitignore create mode 100644 03_recursion/rust/02_greet/Cargo.toml create mode 100644 03_recursion/rust/02_greet/src/main.rs diff --git a/03_recursion/rust/02_greet/.gitignore b/03_recursion/rust/02_greet/.gitignore new file mode 100644 index 00000000..088ba6ba --- /dev/null +++ b/03_recursion/rust/02_greet/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/03_recursion/rust/02_greet/Cargo.toml b/03_recursion/rust/02_greet/Cargo.toml new file mode 100644 index 00000000..98268b0c --- /dev/null +++ b/03_recursion/rust/02_greet/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "greet" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/03_recursion/rust/02_greet/src/main.rs b/03_recursion/rust/02_greet/src/main.rs new file mode 100644 index 00000000..8f90eb07 --- /dev/null +++ b/03_recursion/rust/02_greet/src/main.rs @@ -0,0 +1,18 @@ +fn greet2(name: &str) { + println!("how are you {}?", name); +} + +fn bye() { + println!("ok bye!"); +} + +fn greet(name: &str) { + println!("hello {}!", name); + greet2(name); + println!("getting ready to say bye..."); + bye(); +} + +fn main() { + greet("adit"); +} From 2aa26293b0cf9242e0bde5850ef80f00d8bf35ab Mon Sep 17 00:00:00 2001 From: Alexander Launi Date: Sat, 21 Mar 2020 16:20:51 -0400 Subject: [PATCH 046/140] Add factorial examples in Rust --- 03_recursion/rust/03_factorial/.gitignore | 10 ++++++++++ 03_recursion/rust/03_factorial/Cargo.toml | 9 +++++++++ 03_recursion/rust/03_factorial/src/main.rs | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 03_recursion/rust/03_factorial/.gitignore create mode 100644 03_recursion/rust/03_factorial/Cargo.toml create mode 100644 03_recursion/rust/03_factorial/src/main.rs diff --git a/03_recursion/rust/03_factorial/.gitignore b/03_recursion/rust/03_factorial/.gitignore new file mode 100644 index 00000000..088ba6ba --- /dev/null +++ b/03_recursion/rust/03_factorial/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/03_recursion/rust/03_factorial/Cargo.toml b/03_recursion/rust/03_factorial/Cargo.toml new file mode 100644 index 00000000..cec2d7ed --- /dev/null +++ b/03_recursion/rust/03_factorial/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "factorial" +version = "0.1.0" +authors = ["Alexander Launi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/03_recursion/rust/03_factorial/src/main.rs b/03_recursion/rust/03_factorial/src/main.rs new file mode 100644 index 00000000..b9c74258 --- /dev/null +++ b/03_recursion/rust/03_factorial/src/main.rs @@ -0,0 +1,11 @@ +fn fact(x: u32) -> u32 { + if x == 1 { + return 1; + } + + return x * fact(x - 1); +} + +fn main() { + println!("{}", fact(3)); +} \ No newline at end of file From 2ff4f42d43c26671fe8fb22366122d8f722f2864 Mon Sep 17 00:00:00 2001 From: Alexander Launi Date: Sat, 21 Mar 2020 16:41:02 -0400 Subject: [PATCH 047/140] Implement countdown using generic mathematics --- 03_recursion/rust/01_countdown/Cargo.toml | 1 + 03_recursion/rust/01_countdown/src/main.rs | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/03_recursion/rust/01_countdown/Cargo.toml b/03_recursion/rust/01_countdown/Cargo.toml index 076bdcd6..9d582e32 100644 --- a/03_recursion/rust/01_countdown/Cargo.toml +++ b/03_recursion/rust/01_countdown/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +num-traits = "0.2" \ No newline at end of file diff --git a/03_recursion/rust/01_countdown/src/main.rs b/03_recursion/rust/01_countdown/src/main.rs index 2fdb117d..84ae0e76 100644 --- a/03_recursion/rust/01_countdown/src/main.rs +++ b/03_recursion/rust/01_countdown/src/main.rs @@ -1,10 +1,15 @@ -fn countdown(i: u32) { +use std::ops::Sub; +use std::fmt::Display; +use num_traits::identities::One; +use num_traits::identities::Zero; + +fn countdown>(i: T) { println!("{}", i); - if i == 0 { + if i.is_zero() { return } - countdown(i - 1); + countdown(i - T::one()); } fn main() { From 24c91a4a0b987a6889f6803e5390b79c4762418b Mon Sep 17 00:00:00 2001 From: Alexander Launi Date: Sat, 21 Mar 2020 17:20:03 -0400 Subject: [PATCH 048/140] Implement factorial using generic mathematics --- 03_recursion/rust/03_factorial/Cargo.toml | 1 + 03_recursion/rust/03_factorial/src/main.rs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/03_recursion/rust/03_factorial/Cargo.toml b/03_recursion/rust/03_factorial/Cargo.toml index cec2d7ed..223a6ece 100644 --- a/03_recursion/rust/03_factorial/Cargo.toml +++ b/03_recursion/rust/03_factorial/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +num-traits = "0.2" diff --git a/03_recursion/rust/03_factorial/src/main.rs b/03_recursion/rust/03_factorial/src/main.rs index b9c74258..5ebd5b2b 100644 --- a/03_recursion/rust/03_factorial/src/main.rs +++ b/03_recursion/rust/03_factorial/src/main.rs @@ -1,9 +1,17 @@ -fn fact(x: u32) -> u32 { - if x == 1 { - return 1; +use std::ops::Sub; +use std::fmt::Display; +use num_traits::identities::One; + +fn fact + Copy + Display>(x: T) -> T { + if x < T::one() { + panic!("Invalid number: {}", x); + } + + if x.is_one() { + return T::one(); } - return x * fact(x - 1); + return x * fact(x - T::one()); } fn main() { From 16a4ae12f6e86e95836d2178ef832e269db144a2 Mon Sep 17 00:00:00 2001 From: Alexander Launi Date: Sat, 21 Mar 2020 18:30:37 -0400 Subject: [PATCH 049/140] Small syntax change in 03_factorial --- 03_recursion/rust/03_factorial/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/03_recursion/rust/03_factorial/src/main.rs b/03_recursion/rust/03_factorial/src/main.rs index 5ebd5b2b..3c774651 100644 --- a/03_recursion/rust/03_factorial/src/main.rs +++ b/03_recursion/rust/03_factorial/src/main.rs @@ -5,9 +5,7 @@ use num_traits::identities::One; fn fact + Copy + Display>(x: T) -> T { if x < T::one() { panic!("Invalid number: {}", x); - } - - if x.is_one() { + } else if x.is_one() { return T::one(); } From 345d09b69e398ac20039af3ac6012fb99176f81d Mon Sep 17 00:00:00 2001 From: = Date: Wed, 3 Jun 2020 15:28:01 +0200 Subject: [PATCH 050/140] add recursive soln. --- 03_recursion/python/04_count.py | 4 ++++ 03_recursion/python/05_binary_search_recursive.py | 15 +++++++++++++++ 03_recursion/python/06_find_max.py | 5 +++++ 03_recursion/python/07_sum_array.py | 4 ++++ 4 files changed, 28 insertions(+) create mode 100644 03_recursion/python/04_count.py create mode 100644 03_recursion/python/05_binary_search_recursive.py create mode 100644 03_recursion/python/06_find_max.py create mode 100644 03_recursion/python/07_sum_array.py diff --git a/03_recursion/python/04_count.py b/03_recursion/python/04_count.py new file mode 100644 index 00000000..418fdc7f --- /dev/null +++ b/03_recursion/python/04_count.py @@ -0,0 +1,4 @@ +def count(arr): + if not arr: + return 0 + return 1 + count(arr[1:]) \ No newline at end of file diff --git a/03_recursion/python/05_binary_search_recursive.py b/03_recursion/python/05_binary_search_recursive.py new file mode 100644 index 00000000..7791559b --- /dev/null +++ b/03_recursion/python/05_binary_search_recursive.py @@ -0,0 +1,15 @@ +def binary_search(arr, target): + if not arr: + return -1 + if len(arr) == 1 and arr[0] == target: + return arr[0] + if len(arr) == 1 and arr[0] != target: + return -1 + low = 0 + high = len(arr) - 1 + mid = (low + high) // 2 + + if arr[mid] > target: + return binary_search(arr[:mid], target) + else: + return binary_search(arr[mid+1:], target) \ No newline at end of file diff --git a/03_recursion/python/06_find_max.py b/03_recursion/python/06_find_max.py new file mode 100644 index 00000000..9080084f --- /dev/null +++ b/03_recursion/python/06_find_max.py @@ -0,0 +1,5 @@ +def find_max(arr): + if len(arr) == 2: + return arr[0] if arr[0] > arr[1] else arr[1] + sub_max = find_max(arr[1:]) + return arr[0] if arr[0] > sub_max else sub_max \ No newline at end of file diff --git a/03_recursion/python/07_sum_array.py b/03_recursion/python/07_sum_array.py new file mode 100644 index 00000000..d71a0f28 --- /dev/null +++ b/03_recursion/python/07_sum_array.py @@ -0,0 +1,4 @@ +def sum_array(arr): + if not arr: + return 0 + return arr[0] + sum_array(arr[1:]) \ No newline at end of file From ad8e62d690d6e33481880a312fa0011883175a20 Mon Sep 17 00:00:00 2001 From: seanyu4296 Date: Fri, 31 Jul 2020 06:58:43 +0000 Subject: [PATCH 051/140] Add purescript solution for chapt 1 --- .../Purescript/BinarySearch.purs | 39 ++++++ .../Purescript/README.md | 3 + .../Purescript/packages.dhall | 128 ++++++++++++++++++ .../Purescript/spago.dhall | 9 ++ 4 files changed, 179 insertions(+) create mode 100644 01_introduction_to_algorithms/Purescript/BinarySearch.purs create mode 100644 01_introduction_to_algorithms/Purescript/README.md create mode 100644 01_introduction_to_algorithms/Purescript/packages.dhall create mode 100644 01_introduction_to_algorithms/Purescript/spago.dhall diff --git a/01_introduction_to_algorithms/Purescript/BinarySearch.purs b/01_introduction_to_algorithms/Purescript/BinarySearch.purs new file mode 100644 index 00000000..81ed644f --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/BinarySearch.purs @@ -0,0 +1,39 @@ +module GrokkingAlgos.BinarySearch where + +import Prelude +import Data.Array ((!!)) +import Data.Array as Array +import Data.Maybe (Maybe(..)) +import Effect (Effect) +import Effect.Class.Console (logShow) + +-- | Binary Search - input is a sorted list of elements +-- | Big o notation - log n +-- | Traveling salesman - O (n!) +binarysearch :: Int -> Array Int -> Int -> Int -> Maybe Int +binarysearch x arr low high + | low > high = Nothing + | otherwise = + let + mid = (high + low) / 2 + in + arr !! mid + >>= case _ of + item + | item == x -> Just mid + item + | item > x -> binarysearch x arr low (mid - 1) + item + | item < x -> binarysearch x arr (mid + 1) high + _ -> Nothing + +find :: Int -> Array Int -> Maybe Int +find x arr = binarysearch x arr low high + where + low = 0 + + high = (Array.length arr) - 1 + +main :: Effect Unit +main = do + logShow $ find 20 [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20 ] diff --git a/01_introduction_to_algorithms/Purescript/README.md b/01_introduction_to_algorithms/Purescript/README.md new file mode 100644 index 00000000..88bf8b6b --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/README.md @@ -0,0 +1,3 @@ +# Getting Started +1. Install `spago` and `purescript` through `yarn` or `npm` (e.g. `yarn global add spago` and `yarn global add purescript`) +2. Run file through `spago run --watch --main GrokkingAlgos.SelectionSort` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) \ No newline at end of file diff --git a/01_introduction_to_algorithms/Purescript/packages.dhall b/01_introduction_to_algorithms/Purescript/packages.dhall new file mode 100644 index 00000000..093fe82e --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/packages.dhall @@ -0,0 +1,128 @@ +{- +Welcome to your new Dhall package-set! + +Below are instructions for how to edit this file for most use +cases, so that you don't need to know Dhall to use it. + +## Warning: Don't Move This Top-Level Comment! + +Due to how `dhall format` currently works, this comment's +instructions cannot appear near corresponding sections below +because `dhall format` will delete the comment. However, +it will not delete a top-level comment like this one. + +## Use Cases + +Most will want to do one or both of these options: +1. Override/Patch a package's dependency +2. Add a package not already in the default package set + +This file will continue to work whether you use one or both options. +Instructions for each option are explained below. + +### Overriding/Patching a package + +Purpose: +- Change a package's dependency to a newer/older release than the + default package set's release +- Use your own modified version of some dependency that may + include new API, changed API, removed API by + using your custom git repo of the library rather than + the package set's repo + +Syntax: +Replace the overrides' "{=}" (an empty record) with the following idea +The "//" or "⫽" means "merge these two records and + when they have the same value, use the one on the right:" +------------------------------- +let override = + { packageName = + upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } + , packageName = + upstream.packageName // { version = "v4.0.0" } + , packageName = + upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } + } +------------------------------- + +Example: +------------------------------- +let overrides = + { halogen = + upstream.halogen // { version = "master" } + , halogen-vdom = + upstream.halogen-vdom // { version = "v4.0.0" } + } +------------------------------- + +### Additions + +Purpose: +- Add packages that aren't already included in the default package set + +Syntax: +Replace the additions' "{=}" (an empty record) with the following idea: +------------------------------- +let additions = + { package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , etc. + } +------------------------------- + +Example: +------------------------------- +let additions = + { benchotron = + { dependencies = + [ "arrays" + , "exists" + , "profunctor" + , "strings" + , "quickcheck" + , "lcg" + , "transformers" + , "foldable-traversable" + , "exceptions" + , "node-fs" + , "node-buffer" + , "node-readline" + , "datetime" + , "now" + ] + , repo = + "https://github.com/hdgarrood/purescript-benchotron.git" + , version = + "v7.0.0" + } + } +------------------------------- +-} + + +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.13.6-20200226/packages.dhall sha256:3a52562e05b31a7b51d12d5b228ccbe567c527781a88e9028ab42374ab55c0f1 + +let overrides = {=} + +let additions = {=} + +in upstream // overrides // additions diff --git a/01_introduction_to_algorithms/Purescript/spago.dhall b/01_introduction_to_algorithms/Purescript/spago.dhall new file mode 100644 index 00000000..721cd6d8 --- /dev/null +++ b/01_introduction_to_algorithms/Purescript/spago.dhall @@ -0,0 +1,9 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. +-} +{ name = "my-project" +, dependencies = [ "console", "effect", "psci-support", "arrays", "debug", "lists", "ordered-collections", "strings"] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} From a59a2b8886476ca291a8ccbc994081e96892f22f Mon Sep 17 00:00:00 2001 From: seanyu4296 Date: Fri, 31 Jul 2020 07:02:40 +0000 Subject: [PATCH 052/140] Fix Readme module name --- 01_introduction_to_algorithms/Purescript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_introduction_to_algorithms/Purescript/README.md b/01_introduction_to_algorithms/Purescript/README.md index 88bf8b6b..87f5a91b 100644 --- a/01_introduction_to_algorithms/Purescript/README.md +++ b/01_introduction_to_algorithms/Purescript/README.md @@ -1,3 +1,3 @@ # Getting Started 1. Install `spago` and `purescript` through `yarn` or `npm` (e.g. `yarn global add spago` and `yarn global add purescript`) -2. Run file through `spago run --watch --main GrokkingAlgos.SelectionSort` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) \ No newline at end of file +2. Run file through `spago run --watch --main ` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) \ No newline at end of file From 1a3782d950330ebb7d1ea892d7685df2b4003487 Mon Sep 17 00:00:00 2001 From: seanyu4296 Date: Fri, 31 Jul 2020 07:08:50 +0000 Subject: [PATCH 053/140] update readme with link to main repo --- 01_introduction_to_algorithms/Purescript/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/01_introduction_to_algorithms/Purescript/README.md b/01_introduction_to_algorithms/Purescript/README.md index 87f5a91b..a4476480 100644 --- a/01_introduction_to_algorithms/Purescript/README.md +++ b/01_introduction_to_algorithms/Purescript/README.md @@ -1,3 +1,6 @@ # Getting Started 1. Install `spago` and `purescript` through `yarn` or `npm` (e.g. `yarn global add spago` and `yarn global add purescript`) -2. Run file through `spago run --watch --main ` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) \ No newline at end of file +2. Run file through `spago run --watch --main ` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) + +# Main Repo +- https://github.com/seanyu4296/grokking-algo-in-purs \ No newline at end of file From 3f693b8cf2290272096da7b2979b3bbcd671456d Mon Sep 17 00:00:00 2001 From: seanyu4296 Date: Fri, 31 Jul 2020 07:10:55 +0000 Subject: [PATCH 054/140] update package set --- 01_introduction_to_algorithms/Purescript/packages.dhall | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_introduction_to_algorithms/Purescript/packages.dhall b/01_introduction_to_algorithms/Purescript/packages.dhall index 093fe82e..97dadbd8 100644 --- a/01_introduction_to_algorithms/Purescript/packages.dhall +++ b/01_introduction_to_algorithms/Purescript/packages.dhall @@ -119,7 +119,7 @@ let additions = let upstream = - https://github.com/purescript/package-sets/releases/download/psc-0.13.6-20200226/packages.dhall sha256:3a52562e05b31a7b51d12d5b228ccbe567c527781a88e9028ab42374ab55c0f1 + https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200724/packages.dhall sha256:bb941d30820a49345a0e88937094d2b9983d939c9fd3a46969b85ce44953d7d9 let overrides = {=} From 32fc3cec95ee804685d345a726040c624a2dcb44 Mon Sep 17 00:00:00 2001 From: seanyu4296 Date: Fri, 31 Jul 2020 07:25:32 +0000 Subject: [PATCH 055/140] Add chapter 2 selection sort solution --- 02_selection_sort/Purescript/README.md | 6 + .../Purescript/SelectionSort.purs | 46 +++++++ 02_selection_sort/Purescript/packages.dhall | 128 ++++++++++++++++++ 02_selection_sort/Purescript/spago.dhall | 9 ++ 4 files changed, 189 insertions(+) create mode 100644 02_selection_sort/Purescript/README.md create mode 100644 02_selection_sort/Purescript/SelectionSort.purs create mode 100644 02_selection_sort/Purescript/packages.dhall create mode 100644 02_selection_sort/Purescript/spago.dhall diff --git a/02_selection_sort/Purescript/README.md b/02_selection_sort/Purescript/README.md new file mode 100644 index 00000000..a4476480 --- /dev/null +++ b/02_selection_sort/Purescript/README.md @@ -0,0 +1,6 @@ +# Getting Started +1. Install `spago` and `purescript` through `yarn` or `npm` (e.g. `yarn global add spago` and `yarn global add purescript`) +2. Run file through `spago run --watch --main ` (e.g. `spago run --watch --main GrokkingAlgos.SelectionSort`) + +# Main Repo +- https://github.com/seanyu4296/grokking-algo-in-purs \ No newline at end of file diff --git a/02_selection_sort/Purescript/SelectionSort.purs b/02_selection_sort/Purescript/SelectionSort.purs new file mode 100644 index 00000000..d4da68f6 --- /dev/null +++ b/02_selection_sort/Purescript/SelectionSort.purs @@ -0,0 +1,46 @@ +module GrokkingAlgos.SelectionSort where + +import Prelude + +import Data.Foldable (minimum) +import Data.List (List(..), delete, (:)) +import Data.Maybe (Maybe(..), fromJust) +import Effect (Effect) +import Effect.Class.Console (logShow) +import Partial.Unsafe (unsafePartial) + +-- PARTIAL +selectionsort :: List Int -> List Int +selectionsort Nil = Nil + +selectionsort l = minVal : (selectionsort rest) + where + minVal :: Int + minVal = unsafePartial $ fromJust $ minimum l + + rest :: List Int + rest = delete minVal l + +-- TOTAL +selectionsort' :: List Int -> Maybe (List Int) +selectionsort' Nil = Just $ Nil + +selectionsort' l = do + mval <- minimum l + let + rest = delete mval l + restSort <- selectionsort' rest + pure $ mval : restSort + +-- +main :: Effect Unit +main = do + logShow $ selectionsort $ 1 : 2 : 3 : 5 : 4 : Nil + logShow $ selectionsort' $ 1 : 2 : 3 : 5 : 4 : Nil + + +{- + -- | Notes + -- | Array (Reading (O(1))) (Insertion (O(n))) + -- | Linked List (Reading - O(n)) (Insertion - O(1)) -- Constants in Big O???? + -} \ No newline at end of file diff --git a/02_selection_sort/Purescript/packages.dhall b/02_selection_sort/Purescript/packages.dhall new file mode 100644 index 00000000..97dadbd8 --- /dev/null +++ b/02_selection_sort/Purescript/packages.dhall @@ -0,0 +1,128 @@ +{- +Welcome to your new Dhall package-set! + +Below are instructions for how to edit this file for most use +cases, so that you don't need to know Dhall to use it. + +## Warning: Don't Move This Top-Level Comment! + +Due to how `dhall format` currently works, this comment's +instructions cannot appear near corresponding sections below +because `dhall format` will delete the comment. However, +it will not delete a top-level comment like this one. + +## Use Cases + +Most will want to do one or both of these options: +1. Override/Patch a package's dependency +2. Add a package not already in the default package set + +This file will continue to work whether you use one or both options. +Instructions for each option are explained below. + +### Overriding/Patching a package + +Purpose: +- Change a package's dependency to a newer/older release than the + default package set's release +- Use your own modified version of some dependency that may + include new API, changed API, removed API by + using your custom git repo of the library rather than + the package set's repo + +Syntax: +Replace the overrides' "{=}" (an empty record) with the following idea +The "//" or "⫽" means "merge these two records and + when they have the same value, use the one on the right:" +------------------------------- +let override = + { packageName = + upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } + , packageName = + upstream.packageName // { version = "v4.0.0" } + , packageName = + upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } + } +------------------------------- + +Example: +------------------------------- +let overrides = + { halogen = + upstream.halogen // { version = "master" } + , halogen-vdom = + upstream.halogen-vdom // { version = "v4.0.0" } + } +------------------------------- + +### Additions + +Purpose: +- Add packages that aren't already included in the default package set + +Syntax: +Replace the additions' "{=}" (an empty record) with the following idea: +------------------------------- +let additions = + { package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , etc. + } +------------------------------- + +Example: +------------------------------- +let additions = + { benchotron = + { dependencies = + [ "arrays" + , "exists" + , "profunctor" + , "strings" + , "quickcheck" + , "lcg" + , "transformers" + , "foldable-traversable" + , "exceptions" + , "node-fs" + , "node-buffer" + , "node-readline" + , "datetime" + , "now" + ] + , repo = + "https://github.com/hdgarrood/purescript-benchotron.git" + , version = + "v7.0.0" + } + } +------------------------------- +-} + + +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200724/packages.dhall sha256:bb941d30820a49345a0e88937094d2b9983d939c9fd3a46969b85ce44953d7d9 + +let overrides = {=} + +let additions = {=} + +in upstream // overrides // additions diff --git a/02_selection_sort/Purescript/spago.dhall b/02_selection_sort/Purescript/spago.dhall new file mode 100644 index 00000000..721cd6d8 --- /dev/null +++ b/02_selection_sort/Purescript/spago.dhall @@ -0,0 +1,9 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. +-} +{ name = "my-project" +, dependencies = [ "console", "effect", "psci-support", "arrays", "debug", "lists", "ordered-collections", "strings"] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} From 23f31b4f3f48f9ab669e369ed3addc909c6daca9 Mon Sep 17 00:00:00 2001 From: seanyu4296 Date: Tue, 4 Aug 2020 11:32:03 +0000 Subject: [PATCH 056/140] Cleanup packages dhall and remove notes --- .../Purescript/packages.dhall | 120 ------------------ .../Purescript/SelectionSort.purs | 7 - 02_selection_sort/Purescript/packages.dhall | 120 ------------------ 3 files changed, 247 deletions(-) diff --git a/01_introduction_to_algorithms/Purescript/packages.dhall b/01_introduction_to_algorithms/Purescript/packages.dhall index 97dadbd8..3ecb3c90 100644 --- a/01_introduction_to_algorithms/Purescript/packages.dhall +++ b/01_introduction_to_algorithms/Purescript/packages.dhall @@ -1,123 +1,3 @@ -{- -Welcome to your new Dhall package-set! - -Below are instructions for how to edit this file for most use -cases, so that you don't need to know Dhall to use it. - -## Warning: Don't Move This Top-Level Comment! - -Due to how `dhall format` currently works, this comment's -instructions cannot appear near corresponding sections below -because `dhall format` will delete the comment. However, -it will not delete a top-level comment like this one. - -## Use Cases - -Most will want to do one or both of these options: -1. Override/Patch a package's dependency -2. Add a package not already in the default package set - -This file will continue to work whether you use one or both options. -Instructions for each option are explained below. - -### Overriding/Patching a package - -Purpose: -- Change a package's dependency to a newer/older release than the - default package set's release -- Use your own modified version of some dependency that may - include new API, changed API, removed API by - using your custom git repo of the library rather than - the package set's repo - -Syntax: -Replace the overrides' "{=}" (an empty record) with the following idea -The "//" or "⫽" means "merge these two records and - when they have the same value, use the one on the right:" -------------------------------- -let override = - { packageName = - upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } - , packageName = - upstream.packageName // { version = "v4.0.0" } - , packageName = - upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } - } -------------------------------- - -Example: -------------------------------- -let overrides = - { halogen = - upstream.halogen // { version = "master" } - , halogen-vdom = - upstream.halogen-vdom // { version = "v4.0.0" } - } -------------------------------- - -### Additions - -Purpose: -- Add packages that aren't already included in the default package set - -Syntax: -Replace the additions' "{=}" (an empty record) with the following idea: -------------------------------- -let additions = - { package-name = - { dependencies = - [ "dependency1" - , "dependency2" - ] - , repo = - "https://example.com/path/to/git/repo.git" - , version = - "tag ('v4.0.0') or branch ('master')" - } - , package-name = - { dependencies = - [ "dependency1" - , "dependency2" - ] - , repo = - "https://example.com/path/to/git/repo.git" - , version = - "tag ('v4.0.0') or branch ('master')" - } - , etc. - } -------------------------------- - -Example: -------------------------------- -let additions = - { benchotron = - { dependencies = - [ "arrays" - , "exists" - , "profunctor" - , "strings" - , "quickcheck" - , "lcg" - , "transformers" - , "foldable-traversable" - , "exceptions" - , "node-fs" - , "node-buffer" - , "node-readline" - , "datetime" - , "now" - ] - , repo = - "https://github.com/hdgarrood/purescript-benchotron.git" - , version = - "v7.0.0" - } - } -------------------------------- --} - - let upstream = https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200724/packages.dhall sha256:bb941d30820a49345a0e88937094d2b9983d939c9fd3a46969b85ce44953d7d9 diff --git a/02_selection_sort/Purescript/SelectionSort.purs b/02_selection_sort/Purescript/SelectionSort.purs index d4da68f6..435fd69d 100644 --- a/02_selection_sort/Purescript/SelectionSort.purs +++ b/02_selection_sort/Purescript/SelectionSort.purs @@ -37,10 +37,3 @@ main :: Effect Unit main = do logShow $ selectionsort $ 1 : 2 : 3 : 5 : 4 : Nil logShow $ selectionsort' $ 1 : 2 : 3 : 5 : 4 : Nil - - -{- - -- | Notes - -- | Array (Reading (O(1))) (Insertion (O(n))) - -- | Linked List (Reading - O(n)) (Insertion - O(1)) -- Constants in Big O???? - -} \ No newline at end of file diff --git a/02_selection_sort/Purescript/packages.dhall b/02_selection_sort/Purescript/packages.dhall index 97dadbd8..3ecb3c90 100644 --- a/02_selection_sort/Purescript/packages.dhall +++ b/02_selection_sort/Purescript/packages.dhall @@ -1,123 +1,3 @@ -{- -Welcome to your new Dhall package-set! - -Below are instructions for how to edit this file for most use -cases, so that you don't need to know Dhall to use it. - -## Warning: Don't Move This Top-Level Comment! - -Due to how `dhall format` currently works, this comment's -instructions cannot appear near corresponding sections below -because `dhall format` will delete the comment. However, -it will not delete a top-level comment like this one. - -## Use Cases - -Most will want to do one or both of these options: -1. Override/Patch a package's dependency -2. Add a package not already in the default package set - -This file will continue to work whether you use one or both options. -Instructions for each option are explained below. - -### Overriding/Patching a package - -Purpose: -- Change a package's dependency to a newer/older release than the - default package set's release -- Use your own modified version of some dependency that may - include new API, changed API, removed API by - using your custom git repo of the library rather than - the package set's repo - -Syntax: -Replace the overrides' "{=}" (an empty record) with the following idea -The "//" or "⫽" means "merge these two records and - when they have the same value, use the one on the right:" -------------------------------- -let override = - { packageName = - upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } - , packageName = - upstream.packageName // { version = "v4.0.0" } - , packageName = - upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } - } -------------------------------- - -Example: -------------------------------- -let overrides = - { halogen = - upstream.halogen // { version = "master" } - , halogen-vdom = - upstream.halogen-vdom // { version = "v4.0.0" } - } -------------------------------- - -### Additions - -Purpose: -- Add packages that aren't already included in the default package set - -Syntax: -Replace the additions' "{=}" (an empty record) with the following idea: -------------------------------- -let additions = - { package-name = - { dependencies = - [ "dependency1" - , "dependency2" - ] - , repo = - "https://example.com/path/to/git/repo.git" - , version = - "tag ('v4.0.0') or branch ('master')" - } - , package-name = - { dependencies = - [ "dependency1" - , "dependency2" - ] - , repo = - "https://example.com/path/to/git/repo.git" - , version = - "tag ('v4.0.0') or branch ('master')" - } - , etc. - } -------------------------------- - -Example: -------------------------------- -let additions = - { benchotron = - { dependencies = - [ "arrays" - , "exists" - , "profunctor" - , "strings" - , "quickcheck" - , "lcg" - , "transformers" - , "foldable-traversable" - , "exceptions" - , "node-fs" - , "node-buffer" - , "node-readline" - , "datetime" - , "now" - ] - , repo = - "https://github.com/hdgarrood/purescript-benchotron.git" - , version = - "v7.0.0" - } - } -------------------------------- --} - - let upstream = https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20200724/packages.dhall sha256:bb941d30820a49345a0e88937094d2b9983d939c9fd3a46969b85ce44953d7d9 From 2f166a0ee16cc8cc6a82df03f8648204af67e473 Mon Sep 17 00:00:00 2001 From: seanyu4296 Date: Wed, 5 Aug 2020 12:58:43 +0000 Subject: [PATCH 057/140] Update selection sort --- .../Purescript/SelectionSort.purs | 30 +++---------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/02_selection_sort/Purescript/SelectionSort.purs b/02_selection_sort/Purescript/SelectionSort.purs index 435fd69d..6b55aff0 100644 --- a/02_selection_sort/Purescript/SelectionSort.purs +++ b/02_selection_sort/Purescript/SelectionSort.purs @@ -1,39 +1,17 @@ module GrokkingAlgos.SelectionSort where import Prelude - import Data.Foldable (minimum) import Data.List (List(..), delete, (:)) -import Data.Maybe (Maybe(..), fromJust) +import Data.Maybe (Maybe(..)) import Effect (Effect) import Effect.Class.Console (logShow) -import Partial.Unsafe (unsafePartial) --- PARTIAL selectionsort :: List Int -> List Int -selectionsort Nil = Nil - -selectionsort l = minVal : (selectionsort rest) - where - minVal :: Int - minVal = unsafePartial $ fromJust $ minimum l - - rest :: List Int - rest = delete minVal l - --- TOTAL -selectionsort' :: List Int -> Maybe (List Int) -selectionsort' Nil = Just $ Nil - -selectionsort' l = do - mval <- minimum l - let - rest = delete mval l - restSort <- selectionsort' rest - pure $ mval : restSort +selectionsort l = case minimum l of + Nothing -> Nil + Just min -> min : selectionsort (delete min l) --- main :: Effect Unit main = do logShow $ selectionsort $ 1 : 2 : 3 : 5 : 4 : Nil - logShow $ selectionsort' $ 1 : 2 : 3 : 5 : 4 : Nil From 977000eb868a45017c7b778c673f0dd7df875982 Mon Sep 17 00:00:00 2001 From: Almas Zaurbekov Date: Thu, 13 Aug 2020 01:50:19 +0600 Subject: [PATCH 058/140] python: unit tests for binary search --- .gitignore | 2 + .../python/01_binary_search.py | 28 ----- .../python/binary_search.py | 58 ++++++++++ .../python/items.json | 6 + .../python/test_binary_search.py | 107 ++++++++++++++++++ 5 files changed, 173 insertions(+), 28 deletions(-) delete mode 100644 01_introduction_to_algorithms/python/01_binary_search.py create mode 100644 01_introduction_to_algorithms/python/binary_search.py create mode 100644 01_introduction_to_algorithms/python/items.json create mode 100644 01_introduction_to_algorithms/python/test_binary_search.py diff --git a/.gitignore b/.gitignore index 938d3f90..c79d826b 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,5 @@ highlights/package-lock.json *.sublime-workspace /.env atlassian-ide-plugin.xml +__pycache__ +.vscode \ No newline at end of file diff --git a/01_introduction_to_algorithms/python/01_binary_search.py b/01_introduction_to_algorithms/python/01_binary_search.py deleted file mode 100644 index 35ed5cbe..00000000 --- a/01_introduction_to_algorithms/python/01_binary_search.py +++ /dev/null @@ -1,28 +0,0 @@ -def binary_search(list, item): - # low and high keep track of which part of the list you'll search in. - low = 0 - high = len(list) - 1 - - # While you haven't narrowed it down to one element ... - while low <= high: - # ... check the middle element - mid = (low + high) // 2 - guess = list[mid] - # Found the item. - if guess == item: - return mid - # The guess was too high. - if guess > item: - high = mid - 1 - # The guess was too low. - else: - low = mid + 1 - - # Item doesn't exist - return None - -my_list = [1, 3, 5, 7, 9] -print(binary_search(my_list, 3)) # => 1 - -# 'None' means nil in Python. We use to indicate that the item wasn't found. -print(binary_search(my_list, -1)) # => None diff --git a/01_introduction_to_algorithms/python/binary_search.py b/01_introduction_to_algorithms/python/binary_search.py new file mode 100644 index 00000000..4e3c10cd --- /dev/null +++ b/01_introduction_to_algorithms/python/binary_search.py @@ -0,0 +1,58 @@ +class BinarySearch(): + + def search_iterative(self, list, item): + # low and high keep track of which part of the list you'll search in. + low = 0 + high = len(list) - 1 + + # While you haven't narrowed it down to one element ... + while low <= high: + # ... check the middle element + mid = (low + high) // 2 + guess = list[mid] + # Found the item. + if guess == item: + return mid + # The guess was too high. + if guess > item: + high = mid - 1 + # The guess was too low. + else: + low = mid + 1 + + # Item doesn't exist + return None + + def search_recursive(self, list, low, high, item): + # Check base case + if high >= low: + + mid = (high + low) // 2 + guess = list[mid] + + # If element is present at the middle itself + if guess == item: + return mid + + # If element is smaller than mid, then it can only + # be present in left subarray + elif guess > item: + return self.search_recursive(list, low, mid - 1, item) + + # Else the element can only be present in right subarray + else: + return self.search_recursive(list, mid + 1, high, item) + + else: + # Element is not present in the array + return None + +if __name__ == "__main__": + # We must initialize the class to use the methods of this class + bs = BinarySearch() + my_list = [1, 3, 5, 7, 9] + + print(bs.search_iterative(my_list, 3)) # => 1 + + # 'None' means nil in Python. We use to indicate that the item wasn't found. + print(bs.search_iterative(my_list, -1)) # => None \ No newline at end of file diff --git a/01_introduction_to_algorithms/python/items.json b/01_introduction_to_algorithms/python/items.json new file mode 100644 index 00000000..bbff4dbd --- /dev/null +++ b/01_introduction_to_algorithms/python/items.json @@ -0,0 +1,6 @@ +{ + "simple_list": [2, 3, 4, 13, 40], + "list_with_10_items": [3, 9, 10, 11, 12, 13, 14, 17, 18, 19], + "list_with_100_items": [146, 161, 193, 217, 266, 276, 460, 487, 585, 756, 842, 889, 954, 985, 1061, 1114, 1169, 1256, 1509, 1533, 1680, 1829, 1917, 1995, 2013, 2085, 2134, 2182, 2249, 2261, 2306, 2499, 2543, 2723, 2731, 3196, 3253, 3271, 3351, 3514, 3557, 3629, 3755, 3884, 3935, 4163, 4236, 4296, 4298, 4420, 4661, 4764, 4901, 4912, 4943, 5043, 5224, 5247, 5444, 5485, 5569, 5742, 5778, 5862, 6064, 6096, 6122, 6425, 6455, 6472, 6493, 6656, 6764, 6778, 6946, 7126, 7165, 7208, 7211, 7283, 7407, 7584, 7675, 7827, 7992, 8155, 8309, 8439, 8482, 9180, 9198, 9292, 9335, 9383, 9509, 9537, 9631, 9727, 9780, 9795], + "list_with_1000_items": [7, 15, 18, 21, 32, 34, 37, 39, 45, 48, 55, 60, 65, 70, 86, 101, 112, 119, 120, 151, 152, 161, 170, 172, 200, 206, 223, 232, 233, 236, 270, 292, 300, 324, 333, 347, 354, 355, 363, 411, 419, 430, 443, 448, 457, 465, 497, 505, 508, 514, 526, 528, 534, 552, 555, 589, 597, 612, 627, 645, 654, 657, 663, 668, 670, 689, 692, 702, 703, 706, 726, 727, 732, 740, 743, 747, 756, 773, 777, 786, 787, 789, 794, 799, 801, 803, 842, 852, 856, 866, 901, 902, 904, 909, 912, 928, 929, 932, 939, 965, 984, 1006, 1019, 1045, 1050, 1078, 1080, 1094, 1103, 1105, 1119, 1121, 1132, 1137, 1145, 1166, 1169, 1174, 1183, 1188, 1194, 1199, 1202, 1223, 1227, 1237, 1241, 1255, 1265, 1279, 1290, 1291, 1310, 1315, 1317, 1324, 1326, 1342, 1350, 1362, 1363, 1366, 1371, 1376, 1392, 1393, 1395, 1399, 1406, 1415, 1429, 1446, 1448, 1453, 1466, 1469, 1471, 1480, 1500, 1518, 1520, 1521, 1529, 1548, 1558, 1560, 1561, 1565, 1569, 1573, 1593, 1597, 1599, 1616, 1618, 1645, 1646, 1693, 1694, 1713, 1714, 1717, 1734, 1740, 1742, 1763, 1780, 1806, 1814, 1823, 1828, 1844, 1849, 1853, 1860, 1867, 1869, 1870, 1882, 1889, 1895, 1904, 1908, 1934, 1951, 1980, 1991, 1993, 1996, 2005, 2021, 2028, 2033, 2038, 2044, 2047, 2053, 2054, 2061, 2067, 2087, 2091, 2096, 2101, 2119, 2128, 2132, 2133, 2136, 2160, 2175, 2186, 2201, 2202, 2207, 2209, 2211, 2219, 2222, 2240, 2278, 2288, 2322, 2327, 2339, 2342, 2360, 2367, 2386, 2392, 2394, 2405, 2409, 2416, 2436, 2443, 2476, 2478, 2491, 2493, 2494, 2496, 2524, 2525, 2541, 2557, 2562, 2584, 2618, 2623, 2625, 2627, 2637, 2661, 2674, 2678, 2692, 2703, 2704, 2711, 2715, 2716, 2722, 2730, 2766, 2781, 2786, 2802, 2835, 2836, 2857, 2859, 2873, 2878, 2880, 2923, 2948, 2975, 2980, 2994, 3003, 3009, 3013, 3019, 3020, 3043, 3050, 3056, 3073, 3074, 3078, 3083, 3084, 3093, 3100, 3102, 3112, 3121, 3145, 3153, 3159, 3187, 3202, 3247, 3250, 3264, 3283, 3284, 3288, 3290, 3292, 3299, 3301, 3326, 3333, 3338, 3341, 3361, 3377, 3389, 3393, 3401, 3435, 3454, 3456, 3467, 3474, 3482, 3485, 3490, 3491, 3498, 3504, 3530, 3534, 3545, 3552, 3564, 3574, 3586, 3606, 3615, 3619, 3622, 3636, 3647, 3655, 3688, 3711, 3725, 3739, 3760, 3765, 3774, 3780, 3791, 3822, 3826, 3828, 3830, 3841, 3849, 3854, 3857, 3863, 3885, 3888, 3889, 3903, 3911, 3916, 3961, 3981, 4045, 4080, 4082, 4089, 4122, 4134, 4145, 4151, 4152, 4176, 4193, 4200, 4205, 4211, 4213, 4215, 4227, 4237, 4238, 4249, 4257, 4275, 4281, 4294, 4297, 4299, 4310, 4316, 4326, 4328, 4338, 4341, 4357, 4359, 4363, 4364, 4396, 4414, 4435, 4437, 4442, 4470, 4471, 4484, 4486, 4489, 4493, 4512, 4515, 4524, 4527, 4543, 4550, 4553, 4555, 4560, 4568, 4571, 4587, 4600, 4613, 4627, 4633, 4668, 4673, 4676, 4686, 4691, 4710, 4719, 4731, 4767, 4775, 4780, 4803, 4815, 4831, 4834, 4879, 4882, 4914, 4918, 4922, 4925, 4941, 4954, 4967, 4981, 4982, 4985, 4993, 4999, 5013, 5026, 5033, 5038, 5044, 5052, 5055, 5066, 5086, 5089, 5098, 5103, 5118, 5146, 5147, 5148, 5164, 5177, 5180, 5190, 5196, 5201, 5217, 5221, 5263, 5271, 5278, 5280, 5286, 5295, 5316, 5319, 5320, 5344, 5371, 5376, 5380, 5384, 5391, 5406, 5415, 5436, 5439, 5446, 5451, 5465, 5474, 5485, 5504, 5507, 5511, 5519, 5522, 5544, 5548, 5567, 5572, 5591, 5595, 5618, 5619, 5621, 5627, 5635, 5659, 5678, 5682, 5690, 5703, 5714, 5716, 5719, 5721, 5742, 5760, 5771, 5774, 5786, 5827, 5843, 5845, 5853, 5871, 5874, 5877, 5878, 5887, 5900, 5904, 5923, 5925, 5945, 5967, 6004, 6005, 6006, 6009, 6027, 6038, 6047, 6053, 6057, 6061, 6067, 6075, 6079, 6080, 6088, 6089, 6106, 6113, 6145, 6151, 6155, 6165, 6171, 6179, 6182, 6192, 6198, 6207, 6220, 6232, 6234, 6240, 6243, 6252, 6258, 6270, 6274, 6286, 6300, 6301, 6314, 6316, 6322, 6325, 6326, 6339, 6349, 6354, 6365, 6371, 6384, 6387, 6402, 6412, 6430, 6436, 6447, 6452, 6463, 6464, 6467, 6480, 6487, 6539, 6559, 6565, 6566, 6567, 6572, 6581, 6588, 6592, 6604, 6614, 6623, 6640, 6642, 6648, 6649, 6653, 6682, 6694, 6710, 6733, 6748, 6761, 6769, 6774, 6779, 6780, 6781, 6793, 6846, 6861, 6880, 6898, 6922, 6930, 6938, 6949, 6964, 6977, 6983, 6993, 7001, 7009, 7010, 7015, 7019, 7023, 7025, 7028, 7033, 7049, 7051, 7060, 7076, 7080, 7114, 7118, 7119, 7129, 7131, 7134, 7137, 7168, 7169, 7183, 7219, 7242, 7257, 7258, 7299, 7301, 7304, 7306, 7310, 7317, 7318, 7322, 7326, 7337, 7346, 7358, 7382, 7388, 7389, 7390, 7392, 7398, 7400, 7415, 7423, 7425, 7427, 7429, 7444, 7450, 7475, 7486, 7490, 7491, 7499, 7526, 7532, 7536, 7549, 7562, 7570, 7578, 7579, 7583, 7597, 7600, 7605, 7626, 7628, 7630, 7636, 7639, 7645, 7648, 7661, 7680, 7681, 7694, 7706, 7717, 7723, 7732, 7734, 7738, 7740, 7762, 7773, 7802, 7829, 7846, 7847, 7878, 7903, 7915, 7922, 7926, 7932, 7938, 7960, 7967, 7975, 7985, 8002, 8013, 8031, 8039, 8040, 8046, 8071, 8073, 8075, 8082, 8098, 8099, 8105, 8139, 8148, 8159, 8165, 8171, 8187, 8188, 8197, 8204, 8220, 8222, 8226, 8247, 8248, 8263, 8267, 8274, 8283, 8299, 8301, 8315, 8361, 8370, 8372, 8373, 8395, 8396, 8400, 8406, 8421, 8427, 8437, 8447, 8456, 8458, 8467, 8470, 8474, 8506, 8513, 8514, 8522, 8525, 8542, 8543, 8544, 8562, 8570, 8577, 8580, 8586, 8590, 8602, 8607, 8614, 8624, 8630, 8634, 8650, 8666, 8667, 8671, 8677, 8688, 8699, 8713, 8723, 8724, 8733, 8734, 8736, 8742, 8744, 8746, 8749, 8764, 8774, 8786, 8803, 8807, 8849, 8853, 8861, 8865, 8869, 8875, 8882, 8900, 8904, 8905, 8916, 8919, 8947, 8965, 8969, 8981, 8988, 8997, 9004, 9019, 9028, 9037, 9044, 9071, 9074, 9076, 9079, 9152, 9163, 9164, 9166, 9182, 9199, 9227, 9230, 9238, 9247, 9258, 9269, 9290, 9307, 9314, 9351, 9361, 9362, 9367, 9376, 9382, 9395, 9412, 9426, 9430, 9434, 9439, 9453, 9465, 9474, 9481, 9491, 9494, 9502, 9504, 9524, 9539, 9542, 9550, 9573, 9579, 9596, 9600, 9632, 9633, 9641, 9663, 9674, 9684, 9693, 9697, 9700, 9706, 9708, 9710, 9713, 9716, 9747, 9751, 9753, 9767, 9772, 9773, 9775, 9776, 9783, 9788, 9789, 9805, 9808, 9819, 9822, 9827, 9833, 9838, 9840, 9847, 9852, 9857, 9866, 9874, 9881, 9887, 9901, 9917, 9931, 9945, 9949, 9952, 9991, 9997, 9999] +} \ No newline at end of file diff --git a/01_introduction_to_algorithms/python/test_binary_search.py b/01_introduction_to_algorithms/python/test_binary_search.py new file mode 100644 index 00000000..490e05d0 --- /dev/null +++ b/01_introduction_to_algorithms/python/test_binary_search.py @@ -0,0 +1,107 @@ +from binary_search import BinarySearch +import unittest +import json +import time + +bs = BinarySearch() + +# Unloading all lists from a file +with open("items.json", "r") as file: + data = json.load(file) + +# Setting values to created variables +simple_list = data["simple_list"] +list_with_10_items = data["list_with_10_items"] +list_with_100_items = data["list_with_100_items"] +list_with_1000_items = data["list_with_1000_items"] + + +# Test cases to test Binary Search algorithm +class TestBinarySearch(unittest.TestCase): + + def setUp(self): + print (".......... %s" % self._testMethodName) + + # Checking the implementation of iterative binary search + def test_iterative_binary_search_with_simple_list(self): + # ARRANGE + # You can check the index of each item in the items.json file + item, expected_index = 3, 1 + + # ACT + # Run the method we created and get the index of the item we were looking for + index = bs.search_iterative(simple_list, item) # => 1 + + # ASSERT + # Compare the resulting index with the expected index + self.assertEqual(expected_index, index) # => 1 == 1 + + def test_recoursive_binary_search_with_simple_list(self): + item, expected_index = 3, 1 + # To run recursive search for an item, + # we need to determine the minimum and maximum indexes of the list + low, high = 0, len(simple_list) - 1 + + index = bs.search_recursive(simple_list, low, high, item) + + self.assertEqual(expected_index, index) + + def test_search_for_nonexistent_item(self): + # Specifically set a number that is not in the list + item, expected_result = 100, None + + # Trying to find an item that doesn't exist + index = bs.search_iterative(simple_list, item) # => None + + self.assertEqual(expected_result, index) + + def test_binary_search_and_linear_search_execution_time(self): + item, expected_index = 9887, 990 + + # Time required to search + start_time = time.time() + binary_search_index = bs.search_iterative(list_with_1000_items, item) # => None + bs_time = time.time() - start_time + + # list.index(x) return the index in the list of the first item whose value is x. + # It is an error if there is no such item. + # Complexity of list.index(x) is O(n) + start_time = time.time() + linear_search_index = list_with_1000_items.index(item) + ls_time = time.time() - start_time + + self.assertEqual(expected_index, binary_search_index) + self.assertEqual(expected_index, linear_search_index) + self.assertTrue(bs_time < ls_time) + + # print("--- Time required to search item at the ending ---") + # print("--- Linear Search %f seconds ---" % (ls_time)) + # print("--- Binary Search %f seconds ---" % (bs_time)) + + def test_execution_time_for_item_at_the_beginning(self): + item, expected_index = 55, 10 + + # Binary search - time required to search + start_time = time.time() + binary_search_index = bs.search_iterative(list_with_1000_items, item) # => None + bs_time = time.time() - start_time + + # Linear search - time required to search + start_time = time.time() + linear_search_index = list_with_1000_items.index(item) + ls_time = time.time() - start_time + + self.assertEqual(expected_index, binary_search_index) + self.assertEqual(expected_index, linear_search_index) + + # linear search will be faster, since the item we are looking for + # is at the beginning of the list + self.assertTrue(bs_time > ls_time) + + # print("--- Time required to search item at the beginning ---") + # print("--- Linear Search %f seconds ---" % (ls_time)) + # print("--- Binary Search %f seconds ---" % (bs_time)) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From 58f1a6e3259796f9c82d30374a86cdbd71daf2ba Mon Sep 17 00:00:00 2001 From: Andrii Nyzhnyk Date: Sun, 23 Aug 2020 22:31:33 +0300 Subject: [PATCH 059/140] clear not needed boilerplate and add author name for the first example --- .../rust/01_binary_search/cargo.lock | 4 ---- .../rust/01_binary_search/cargo.toml | 6 ------ .../{01_binary_search/src/main.rs => main_example_1.rs} | 5 +++++ 3 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 01_introduction_to_algorithms/rust/01_binary_search/cargo.lock delete mode 100644 01_introduction_to_algorithms/rust/01_binary_search/cargo.toml rename 01_introduction_to_algorithms/rust/{01_binary_search/src/main.rs => main_example_1.rs} (96%) diff --git a/01_introduction_to_algorithms/rust/01_binary_search/cargo.lock b/01_introduction_to_algorithms/rust/01_binary_search/cargo.lock deleted file mode 100644 index 8a9c7c6c..00000000 --- a/01_introduction_to_algorithms/rust/01_binary_search/cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[[package]] -name = "binary-search" -version = "0.1.0" - diff --git a/01_introduction_to_algorithms/rust/01_binary_search/cargo.toml b/01_introduction_to_algorithms/rust/01_binary_search/cargo.toml deleted file mode 100644 index 0404e767..00000000 --- a/01_introduction_to_algorithms/rust/01_binary_search/cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "binary-search" -version = "0.1.0" -authors = ["giorgiodelgado "] - -[dependencies] diff --git a/01_introduction_to_algorithms/rust/01_binary_search/src/main.rs b/01_introduction_to_algorithms/rust/main_example_1.rs similarity index 96% rename from 01_introduction_to_algorithms/rust/01_binary_search/src/main.rs rename to 01_introduction_to_algorithms/rust/main_example_1.rs index 8ed4d15b..f45ce144 100644 --- a/01_introduction_to_algorithms/rust/01_binary_search/src/main.rs +++ b/01_introduction_to_algorithms/rust/main_example_1.rs @@ -1,3 +1,8 @@ +// name = "binary-search" +// version = "0.1.0" +// authors = ["giorgiodelgado "] +// + // to run tests, you must have rust and cargo installed // then run `cargo test` From 34df0a6d08f0a3a2157df5b55a9a831b696428da Mon Sep 17 00:00:00 2001 From: Alexandr Shulaev Date: Mon, 14 Sep 2020 19:46:30 +0400 Subject: [PATCH 060/140] Fixed formatting problems and JSDoc (#131) * Fixed formatting problems and JSDoc * Added returns for JSDoc --- 03_recursion/ES6/01_countdown.js | 9 +++++---- 03_recursion/ES6/02_greet.js | 19 +++++++++++++++---- 03_recursion/ES6/03_factorial.js | 11 +++++++---- 03_recursion/javascript/01_countdown.js | 9 +++++---- 03_recursion/javascript/02_greet.js | 21 ++++++++++++++++----- 03_recursion/javascript/03_factorial.js | 9 ++++++--- 6 files changed, 54 insertions(+), 24 deletions(-) diff --git a/03_recursion/ES6/01_countdown.js b/03_recursion/ES6/01_countdown.js index 46418877..b9a22f65 100644 --- a/03_recursion/ES6/01_countdown.js +++ b/03_recursion/ES6/01_countdown.js @@ -1,10 +1,11 @@ +/** + * Countdown + * @param {number} i Number + */ const countdown = i => { console.log(i); // base case - if (i <= 0) { - return; - } - + if (i <= 0) return; countdown(i - 1); }; diff --git a/03_recursion/ES6/02_greet.js b/03_recursion/ES6/02_greet.js index ffec6692..b6587430 100644 --- a/03_recursion/ES6/02_greet.js +++ b/03_recursion/ES6/02_greet.js @@ -1,12 +1,23 @@ +/** + * Displays a message to the console + * @param {string} name Name + */ const greet2 = name => console.log(`how are you, ${name}?`); -const bye = () => console.log('ok bye!'); +/** + * Displays a message to the console + */ +const bye = () => console.log("ok bye!"); -const greet = (name) => { +/** + * Displays a message to the console + * @param {string} name Name + */ +const greet = name => { console.log(`hello, ${name}!`); greet2(name); - console.log('getting ready to say bye...'); + console.log("getting ready to say bye..."); bye(); }; -greet('adit'); +greet("adit"); diff --git a/03_recursion/ES6/03_factorial.js b/03_recursion/ES6/03_factorial.js index 022a61df..74fa4dd7 100644 --- a/03_recursion/ES6/03_factorial.js +++ b/03_recursion/ES6/03_factorial.js @@ -1,7 +1,10 @@ -const fact = (x) => { - if (x === 1) { - return 1; - } +/** + * Consider the factorial of the number + * @param {number} x Number + * @returns {number} Result + */ +const fact = x => { + if (x === 1) return 1; return x * fact(x - 1); }; diff --git a/03_recursion/javascript/01_countdown.js b/03_recursion/javascript/01_countdown.js index 529d1c89..e4208c96 100644 --- a/03_recursion/javascript/01_countdown.js +++ b/03_recursion/javascript/01_countdown.js @@ -1,10 +1,11 @@ +/** + * Countdown + * @param {number} i Number + */ function countdown(i) { console.log(i); // base case - if (i <= 0) { - return; - } - + if (i <= 0) return; countdown(i - 1); } diff --git a/03_recursion/javascript/02_greet.js b/03_recursion/javascript/02_greet.js index 5161a086..54ec5fda 100644 --- a/03_recursion/javascript/02_greet.js +++ b/03_recursion/javascript/02_greet.js @@ -1,16 +1,27 @@ +/** + * Displays a message to the console + * @param {string} name Name + */ function greet2(name) { - console.log('how are you, ' + name + '?'); + console.log("how are you, " + name + "?"); } +/** + * Displays a message to the console + */ function bye() { - console.log('ok bye!'); + console.log("ok bye!"); } +/** + * Displays a message to the console + * @param {string} name Name + */ function greet(name) { - console.log('hello, ' + name + '!'); + console.log("hello, " + name + "!"); greet2(name); - console.log('getting ready to say bye...'); + console.log("getting ready to say bye..."); bye(); } -greet('adit'); +greet("adit"); diff --git a/03_recursion/javascript/03_factorial.js b/03_recursion/javascript/03_factorial.js index 89b8ab72..76d46e4e 100644 --- a/03_recursion/javascript/03_factorial.js +++ b/03_recursion/javascript/03_factorial.js @@ -1,7 +1,10 @@ +/** + * Consider the factorial of the number + * @param {number} x Number + * @returns {number} Result + */ function fact(x) { - if (x === 1) { - return 1; - } + if (x === 1) return 1; return x * fact(x - 1); } From e6b0d984433b2ee12c5cfa0ff18b42cb9e9adeb6 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Mon, 14 Sep 2020 10:51:36 -0500 Subject: [PATCH 061/140] not quite responsive enough anymore --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 73508514..3d541fb7 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ Check out [Python Tutor](http://pythontutor.com/), a great website that guides y ## Images -This repository contains every image in Grokking Algorithms in high resolution. These images are available for non-commercial use. If you use an image, please add "copyright Manning Publications, drawn by adit.io". You are welcome to use these images in any non-commercial education (i.e. teaching materials, presentations, etc.) +This repository contains every image in Grokking Algorithms in high resolution. These images are available for non-commercial use. If you use an image, please add "copyright Manning Publications, drawn by adit.io". You are welcome to use these images in any non-commercial materials (i.e. teaching materials, presentations, etc.) ## Contributing -- The examples in this book are witten in Python, but I'd like examples in Ruby, JavaScript, C, and other languages too. Please add examples in other languages! -- Pull request are the quickest way to contribute to this repository and I'm pretty responsive to them. +- The examples in this book are written in Python, but I'd like examples in Ruby, JavaScript, C, and other languages too. Please add examples in other languages! +- Pull request are the quickest way to contribute to this repository but unfortunately I am not as responsive to them as I'd like to be. I'll get to them but it might take a while! From 0c4fdddb122937a715ac819a939185e884dcf19a Mon Sep 17 00:00:00 2001 From: Yulia Kolupaeva Date: Tue, 16 Feb 2021 18:10:25 +0300 Subject: [PATCH 062/140] factorial formula adjustement The formula in book is incorrect because it doesn't include the factorial(0) case and leads to infinite recursion in this case. --- 03_recursion/javascript/03_factorial.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_recursion/javascript/03_factorial.js b/03_recursion/javascript/03_factorial.js index 76d46e4e..20d50a33 100644 --- a/03_recursion/javascript/03_factorial.js +++ b/03_recursion/javascript/03_factorial.js @@ -4,7 +4,7 @@ * @returns {number} Result */ function fact(x) { - if (x === 1) return 1; + if (x === 0) return 1; return x * fact(x - 1); } From 9f330a765a9dea4944dfd70207692ff2ebcd707a Mon Sep 17 00:00:00 2001 From: Ekram Mohamed Date: Thu, 18 Feb 2021 02:02:57 +0200 Subject: [PATCH 063/140] add great common divisor function --- 04_quicksort/csharp/06_GetGCD/program.cs | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 04_quicksort/csharp/06_GetGCD/program.cs diff --git a/04_quicksort/csharp/06_GetGCD/program.cs b/04_quicksort/csharp/06_GetGCD/program.cs new file mode 100644 index 00000000..64abed27 --- /dev/null +++ b/04_quicksort/csharp/06_GetGCD/program.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace GCD +{ + public class program + { + + //Get great Comman Divisor + public static int GetGCD(int FirstNumber, int SecondNumber) + => SecondNumber == default ? FirstNumber : GetGCD(SecondNumber, FirstNumber % SecondNumber); + + //Get great Comman Divisor of list + public static int GetGCDList(List lst) + { + var result = lst[0]; + result = GetGCD(result, lst.Skip(1).FirstOrDefault()); + return result; + } + + static void Main(string[] args) + { + var lst = new List { 32,696,40,50 }; + var GCD = GetGCD( 640, 1680); + var GCDList = GetGCDList(lst); + Console.WriteLine(GCD); + Console.WriteLine(GCDList); + } + } +} \ No newline at end of file From c1c68d9d2a54c2ecfe38943e64793f17b7d9ade6 Mon Sep 17 00:00:00 2001 From: Dani El-Ayyass Date: Sun, 14 Mar 2021 18:39:59 +0300 Subject: [PATCH 064/140] improve 01_breadth-first_search.py (#195) --- 06_breadth-first_search/python/01_breadth-first_search.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/06_breadth-first_search/python/01_breadth-first_search.py b/06_breadth-first_search/python/01_breadth-first_search.py index 4fefda87..47dd8d4b 100644 --- a/06_breadth-first_search/python/01_breadth-first_search.py +++ b/06_breadth-first_search/python/01_breadth-first_search.py @@ -16,8 +16,8 @@ def person_is_seller(name): def search(name): search_queue = deque() search_queue += graph[name] - # This array is how you keep track of which people you've searched before. - searched = [] + # This is how you keep track of which people you've searched before. + searched = set() while search_queue: person = search_queue.popleft() # Only search this person if you haven't already searched them. @@ -28,7 +28,7 @@ def search(name): else: search_queue += graph[person] # Marks this person as searched - searched.append(person) + searched.add(person) return False search("you") From fec65db129c22b03d1e49a5e72b6df0d3823aedf Mon Sep 17 00:00:00 2001 From: Kostarev Kirill <37106274+Kirchberg@users.noreply.github.com> Date: Sun, 14 Mar 2021 18:42:14 +0300 Subject: [PATCH 065/140] Few changes in Swift Code (#191) * Replaced the confusing construction * The algorithm works faster than the previous version --- .../swift/01_binary_search.swift | 2 +- 02_selection_sort/swift/01_selection_sort.swift | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/01_introduction_to_algorithms/swift/01_binary_search.swift b/01_introduction_to_algorithms/swift/01_binary_search.swift index 232c5525..91a0c9e8 100644 --- a/01_introduction_to_algorithms/swift/01_binary_search.swift +++ b/01_introduction_to_algorithms/swift/01_binary_search.swift @@ -8,7 +8,7 @@ func binarySearch (_ list: [T], item: T) -> Int? { // While you haven't narrowed it down to one element ... while low <= high { //... check the middle element - let mid = low + (high - low) / 2 + let mid = (low + high) / 2 let guess = list[mid] // Found the item. if guess == item { diff --git a/02_selection_sort/swift/01_selection_sort.swift b/02_selection_sort/swift/01_selection_sort.swift index df6edc74..e34f805f 100644 --- a/02_selection_sort/swift/01_selection_sort.swift +++ b/02_selection_sort/swift/01_selection_sort.swift @@ -4,13 +4,9 @@ import Foundation func findSmallestIndex (_ arr: [T]) -> Int { // Stores the smallest value var smallest = arr[0] - // We don't need any calculation if the array length is 1 - if arr.count == 1 { - return 0 - } // Stores the index of the smallest value var smallestIndex = 0 - for i in 1...arr.count-1 { + for i in 1.. (_ arr: [T]) -> Int { // Sort array func selectionSort (arr: [T]) -> [T] { + // We don't need any calculation if the array length is 1 + guard arr.count > 1 else { return arr } + var newArr: [T] = [] + // We have to make mutableArray reference copy of original array, because Swift 3 doesn't allow to get var parameter var mutableArr = arr - for _ in 0...mutableArr.count-1 { + for _ in 0.. Date: Sun, 14 Mar 2021 20:43:28 +0500 Subject: [PATCH 066/140] F# and C# addings (#189) * F# - Binary Search * C# - Double selection sort * quick sort - f# --- 01_introduction_to_algorithms/f#/Program.fs | 26 +++++++++++++ .../csharp/double_selection_sort/Program.cs | 39 +++++++++++++++++++ 04_quicksort/f#/QuickSort/Program.fs | 21 ++++++++++ 3 files changed, 86 insertions(+) create mode 100644 01_introduction_to_algorithms/f#/Program.fs create mode 100644 02_selection_sort/csharp/double_selection_sort/Program.cs create mode 100644 04_quicksort/f#/QuickSort/Program.fs diff --git a/01_introduction_to_algorithms/f#/Program.fs b/01_introduction_to_algorithms/f#/Program.fs new file mode 100644 index 00000000..f081473c --- /dev/null +++ b/01_introduction_to_algorithms/f#/Program.fs @@ -0,0 +1,26 @@ +// Learn more about F# at http://fsharp.org + +open System + +[] +let main argv = + let numbers = [|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|] + + let rec binarySearch(arr: int[], number: int, startIndex: int, endIndex: int) : int + = + let averageIndex = (startIndex + endIndex) / 2 + let middleElement = arr.[averageIndex] + + if (middleElement > number) + then binarySearch(arr, number, startIndex, averageIndex) + else if (middleElement < number) + then binarySearch(arr, number, averageIndex, endIndex) + else + averageIndex + + let binarySearch(arr: int[], number: int) + = binarySearch(arr, number, 0, arr.Length) + + let index = binarySearch(numbers, 7) + Console.WriteLine(index); + 0 diff --git a/02_selection_sort/csharp/double_selection_sort/Program.cs b/02_selection_sort/csharp/double_selection_sort/Program.cs new file mode 100644 index 00000000..153bb06a --- /dev/null +++ b/02_selection_sort/csharp/double_selection_sort/Program.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SelectionSort +{ + class Program + { + static void Main(string[] args) + { + var numbers = new int[] { 4, 5, 1, 3, 10, 9, 6, 8, 7, 2 }; + var sortedArr = SelectionSort(numbers); + + Console.WriteLine(string.Join(',', sortedArr)); + } + + private static int[] SelectionSort(int[] array) + => SelectionSort(new LinkedList(array)).ToArray(); + + private static IEnumerable SelectionSort(LinkedList list) + { + var minList = new LinkedList(); + var maxList = new LinkedList(); + + while (list.Count != 0) + { + var min = list.Min(); + list.Remove(min); + minList.AddLast(min); + + var max = list.Max(); + list.Remove(max); + maxList.AddFirst(max); + } + + return minList.Union(maxList); + } + } +} diff --git a/04_quicksort/f#/QuickSort/Program.fs b/04_quicksort/f#/QuickSort/Program.fs new file mode 100644 index 00000000..e4b8884b --- /dev/null +++ b/04_quicksort/f#/QuickSort/Program.fs @@ -0,0 +1,21 @@ +// Learn more about F# at http://fsharp.org + +open System + +[] +let main argv = + let numbers = [|3; 9; 10; 1; 4; 2; 6; 5; 8; 7|] + + let rec quickSort(arr: int[]) = + if arr.Length < 2 + then arr + else + let pivot = arr.[0] + let arrExcpetPivot = arr |> Seq.skip(1) |> Seq.toArray + let lessElements = quickSort arrExcpetPivot |> Seq.filter(fun n -> n <= pivot) |> Seq.toArray + let greaterElements = quickSort arrExcpetPivot |> Seq.filter(fun n -> n > pivot) |> Seq.toArray + + Seq.append (Seq.append lessElements [|pivot|]) greaterElements |> Seq.toArray + + let sorted = quickSort(numbers) + 0 From 04823be518b87b120333b090789009f2ffdd6349 Mon Sep 17 00:00:00 2001 From: Eric Weiss <40743521+kinnybot@users.noreply.github.com> Date: Sun, 14 Mar 2021 11:43:52 -0400 Subject: [PATCH 067/140] return position (#188) --- 01_introduction_to_algorithms/Golang/BinarySearch.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/01_introduction_to_algorithms/Golang/BinarySearch.go b/01_introduction_to_algorithms/Golang/BinarySearch.go index 04724d7d..988f541d 100644 --- a/01_introduction_to_algorithms/Golang/BinarySearch.go +++ b/01_introduction_to_algorithms/Golang/BinarySearch.go @@ -2,13 +2,13 @@ package main import "fmt" -func checkBin(list []int, i int) bool { +func checkBin(list []int, i int) int { low := 0 high := len(list) - 1 for low <= high { mid := (low + high) / 2 if list[mid] == i { - return true + return mid } if list[mid] < i { low = mid + 1 @@ -16,10 +16,10 @@ func checkBin(list []int, i int) bool { high = mid - 1 } } - return false + return -1 } func main() { - fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, 1)) // true - fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, -1)) //false + fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, 1)) // 0 + fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, -1)) // -1 } From efa1c0d975f924bd1251dfb9bb2f777f2014c0d9 Mon Sep 17 00:00:00 2001 From: ZhanSwift Date: Sun, 14 Mar 2021 10:44:12 -0500 Subject: [PATCH 068/140] Update 01_selection_sort.swift (#187) A new for loop statement From 85281425ebd3f55a3c013e536c358cf22e1c8682 Mon Sep 17 00:00:00 2001 From: AndriiNyzhnyk Date: Sun, 14 Mar 2021 17:46:00 +0200 Subject: [PATCH 069/140] Add more examples for countdown (#183) --- 03_recursion/rust/02_countdown/main.rs | 52 ++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 03_recursion/rust/02_countdown/main.rs diff --git a/03_recursion/rust/02_countdown/main.rs b/03_recursion/rust/02_countdown/main.rs new file mode 100644 index 00000000..9d6ddbe4 --- /dev/null +++ b/03_recursion/rust/02_countdown/main.rs @@ -0,0 +1,52 @@ +// Rust has three kinds of loops: loop, while, and for. Let’s try each one + recursive. +fn main() { + countdown_loop(5); + println!("------"); + + countdown_while(5); + println!("------"); + + countdown_for(5); + println!("------"); + + countdown_recursive(5); +} + + +fn countdown_loop(count: usize) { + let mut i = count; + + loop { + println!("{}", i); + i -= 1; + + if i <= 0 { + break; + } + } +} + +fn countdown_while(count: usize) { + let mut i = count; + + while i > 0 { + println!("{}", i); + + i -= 1; + } +} + + +fn countdown_for(count: usize) { + for i in (1..count + 1).rev() { + println!("{}", i); + } +} + +fn countdown_recursive(count: usize) { + println!("{}", count); + + if count > 1 { + return countdown_recursive(count - 1); + } +} From 7d27d15c0d26bb457f28dcb10be4e1f392ae757e Mon Sep 17 00:00:00 2001 From: TheDonrad <71816783+TheDonrad@users.noreply.github.com> Date: Sun, 14 Mar 2021 18:47:15 +0300 Subject: [PATCH 070/140] Create Module.bsl (#182) --- 01_introduction_to_algorithms/1C/Module.bsl | 54 +++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 01_introduction_to_algorithms/1C/Module.bsl diff --git a/01_introduction_to_algorithms/1C/Module.bsl b/01_introduction_to_algorithms/1C/Module.bsl new file mode 100644 index 00000000..9f6f0542 --- /dev/null +++ b/01_introduction_to_algorithms/1C/Module.bsl @@ -0,0 +1,54 @@ + +#Область ОбработчикиКомандФормы + +&НаКлиенте +Процедура НайтиЧисло(Команда) + ИскомоеЧисло = 75; + Сообщение = Новый СообщениеПользователю; + + КоличествоПопыток = БинарныйПоиск(ИскомоеЧисло); + + Если КоличествоПопыток = Неопределено Тогда + ТекстСообщения = НСтр("ru = 'Число не входит в диапозон 1..100'"); + Иначе + ШаблонСообщения = НСтр("ru = 'Число %1 найдено за %2 попыток'"); + ТекстСообщения = СтрШаблон(ШаблонСообщения, ИскомоеЧисло, КоличествоПопыток); + КонецЕсли; + + Сообщение.Текст = ТекстСообщения; + Сообщение.Сообщить(); +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +&НаКлиенте +Функция БинарныйПоиск(ИскомоеЧисло) + + Массив = Новый Массив; + + Для Счетчик = 1 По 100 Цикл + Массив.Добавить(Счетчик); + КонецЦикла; + + КоличествоПопыток = 0; + МинимальноеЧисло = Массив[0]; + МаксимальноеЧисло = Массив[Массив.Количество() - 1]; + Пока МинимальноеЧисло <= МаксимальноеЧисло Цикл + КоличествоПопыток = КоличествоПопыток + 1; + НайденноеЧисло = Цел((МинимальноеЧисло + МаксимальноеЧисло) / 2); + Если НайденноеЧисло = ИскомоеЧисло Тогда + Возврат КоличествоПопыток; + ИначеЕсли НайденноеЧисло > ИскомоеЧисло Тогда + МаксимальноеЧисло = НайденноеЧисло - 1; + Иначе // НайденноеЧисло < ИскомоеЧисло + МинимальноеЧисло = НайденноеЧисло + 1; + КонецЕсли; + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +#КонецОбласти From 2080afc740a5b389e4067eaa0a2d8d22be4ae601 Mon Sep 17 00:00:00 2001 From: antonlipilin Date: Wed, 6 Oct 2021 18:20:52 +0400 Subject: [PATCH 071/140] Add more ES6 examples --- 04_quicksort/ES6/04_loop_count.js | 21 +++++++++++++++++ .../ES6/05_loop_count_reduce_version.js | 9 ++++++++ ...4_recursive-max.js => 06_recursive-max.js} | 0 04_quicksort/ES6/07_loop_max.js | 23 +++++++++++++++++++ .../ES6/08_loop_max_reduce_version.js | 10 ++++++++ .../ES6/{05_quicksort.js => 09_quicksort.js} | 0 ... => 10_euclidean_algorithm_two_numbers.js} | 0 ... => 11_euclidean_algorithm_set_numbers.js} | 0 8 files changed, 63 insertions(+) create mode 100644 04_quicksort/ES6/04_loop_count.js create mode 100644 04_quicksort/ES6/05_loop_count_reduce_version.js rename 04_quicksort/ES6/{04_recursive-max.js => 06_recursive-max.js} (100%) create mode 100644 04_quicksort/ES6/07_loop_max.js create mode 100644 04_quicksort/ES6/08_loop_max_reduce_version.js rename 04_quicksort/ES6/{05_quicksort.js => 09_quicksort.js} (100%) rename 04_quicksort/ES6/{07_euclidean_algorithm_two_numbers.js => 10_euclidean_algorithm_two_numbers.js} (100%) rename 04_quicksort/ES6/{06_euclidean_algorithm_set_numbers.js => 11_euclidean_algorithm_set_numbers.js} (100%) diff --git a/04_quicksort/ES6/04_loop_count.js b/04_quicksort/ES6/04_loop_count.js new file mode 100644 index 00000000..676f8cc6 --- /dev/null +++ b/04_quicksort/ES6/04_loop_count.js @@ -0,0 +1,21 @@ +/** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ + const countLoop = (array) => { + let result = 0; + + if (array.length === 0) { + return result; + } + + for (let i = 0; i < array.length; i += 1) { + result += 1; + } + + return result; + } + + console.log(countLoop([3,5,8,11])) //4 + console.log(countLoop([])) // 0 \ No newline at end of file diff --git a/04_quicksort/ES6/05_loop_count_reduce_version.js b/04_quicksort/ES6/05_loop_count_reduce_version.js new file mode 100644 index 00000000..e96cec35 --- /dev/null +++ b/04_quicksort/ES6/05_loop_count_reduce_version.js @@ -0,0 +1,9 @@ + /** + * Count the number of elements in the array + * @param {Array} array Array of numbers + * @returns {number} The number of elements in the array + */ + const countReduce = (array) => array.reduce((count, next) => count += 1, 0); + + console.log(countReduce([5,8,11,13])) // 4 + console.log(countReduce([]))// 0 \ No newline at end of file diff --git a/04_quicksort/ES6/04_recursive-max.js b/04_quicksort/ES6/06_recursive-max.js similarity index 100% rename from 04_quicksort/ES6/04_recursive-max.js rename to 04_quicksort/ES6/06_recursive-max.js diff --git a/04_quicksort/ES6/07_loop_max.js b/04_quicksort/ES6/07_loop_max.js new file mode 100644 index 00000000..06f49da9 --- /dev/null +++ b/04_quicksort/ES6/07_loop_max.js @@ -0,0 +1,23 @@ +/** + * Calculate the largest number + * This solution works for arrays of any length + * @param {Array} array Array of numbers + * @returns {number} The argest number + */ + const maxLoop = (array) => { + let result = 0; + + if (array.length === 0) { + return result; + } + + for (let i = 0; i < array.length; i += 1) { + if (array[i] > result) { + result = array[i] + } + } + return result; + }; + + console.log(maxLoop([2,5,7,22,11])); // 22 + console.log(maxLoop([])) // 0 \ No newline at end of file diff --git a/04_quicksort/ES6/08_loop_max_reduce_version.js b/04_quicksort/ES6/08_loop_max_reduce_version.js new file mode 100644 index 00000000..ea9fb225 --- /dev/null +++ b/04_quicksort/ES6/08_loop_max_reduce_version.js @@ -0,0 +1,10 @@ +/** + * Calculate the largest number + * This solution works for arrays of any length + * @param {Array} array Array of numbers + * @returns {number} The argest number + */ + const maxReduce = (array) => array.reduce((curr, next) => next > curr ? next : curr, 0); + + console.log(maxReduce([1,3,11,7])) // 11 + console.log(maxReduce([])) // 0 \ No newline at end of file diff --git a/04_quicksort/ES6/05_quicksort.js b/04_quicksort/ES6/09_quicksort.js similarity index 100% rename from 04_quicksort/ES6/05_quicksort.js rename to 04_quicksort/ES6/09_quicksort.js diff --git a/04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js b/04_quicksort/ES6/10_euclidean_algorithm_two_numbers.js similarity index 100% rename from 04_quicksort/ES6/07_euclidean_algorithm_two_numbers.js rename to 04_quicksort/ES6/10_euclidean_algorithm_two_numbers.js diff --git a/04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js b/04_quicksort/ES6/11_euclidean_algorithm_set_numbers.js similarity index 100% rename from 04_quicksort/ES6/06_euclidean_algorithm_set_numbers.js rename to 04_quicksort/ES6/11_euclidean_algorithm_set_numbers.js From 0292985401df2662bfb75ca8bfc3c2337983d693 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Fri, 18 Nov 2022 14:18:55 -0600 Subject: [PATCH 072/140] cleaner max function, remove unnecessary duplication --- 04_quicksort/ES6/04_recursive-max.js | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/04_quicksort/ES6/04_recursive-max.js b/04_quicksort/ES6/04_recursive-max.js index e967c78b..6580e2ee 100644 --- a/04_quicksort/ES6/04_recursive-max.js +++ b/04_quicksort/ES6/04_recursive-max.js @@ -2,25 +2,15 @@ * Calculate the largest number * This solution only works for arrays longer than one * @param {Array} array Array of numbers - * @returns {number} The argest number + * @returns {number} The largest number */ -const max = array => { - if (array.length === 2) return array[0] > array[1] ? array[0] : array[1]; +const max = (array) => { + if (array.length === 0) return 0; + if (array.length === 1) { + return array[0]; + } const subMax = max(array.slice(1)); return array[0] > subMax ? array[0] : subMax; }; -/** - * Calculate the largest number - * This solution works for arrays of any length - * @param {Array} array Array of numbers - * @param {number} max Maximum value - * @returns {number} The argest number - */ -const alternativeSolutionMax = (array, max = 0) => - array.length === 0 - ? max - : alternativeSolutionMax(array.slice(1), array[0] > max ? array[0] : max); - console.log(max([1, 5, 10, 25, 16, 1])); // 25 -console.log(alternativeSolutionMax([1, 5, 10, 25, 16, 1])); // 25 From 64a09d6584503fae4e03275a939ff714f31d9dd1 Mon Sep 17 00:00:00 2001 From: NikitaLipatov Date: Fri, 18 Nov 2022 23:34:48 +0300 Subject: [PATCH 073/140] 05 & 06 exercises (#114) Co-authored-by: Aditya Bhargava --- .../kotlin/01_price_of_groceries.kt | 3 +- 05_hash_tables/kotlin/02_check_voter.kt | 2 +- .../kotlin/01_breadth-first_search.kt | 29 +++++++++++ .../kotlin/BreadthFirstSearch.kt | 50 ------------------- 4 files changed, 32 insertions(+), 52 deletions(-) create mode 100644 06_breadth-first_search/kotlin/01_breadth-first_search.kt delete mode 100644 06_breadth-first_search/kotlin/BreadthFirstSearch.kt diff --git a/05_hash_tables/kotlin/01_price_of_groceries.kt b/05_hash_tables/kotlin/01_price_of_groceries.kt index 3de68db6..e38091ff 100644 --- a/05_hash_tables/kotlin/01_price_of_groceries.kt +++ b/05_hash_tables/kotlin/01_price_of_groceries.kt @@ -1,3 +1,4 @@ + fun main(args: Array) { val book = hashMapOf( @@ -7,4 +8,4 @@ fun main(args: Array) { ) println(book) -} +} \ No newline at end of file diff --git a/05_hash_tables/kotlin/02_check_voter.kt b/05_hash_tables/kotlin/02_check_voter.kt index 97acaee6..09c9ec47 100644 --- a/05_hash_tables/kotlin/02_check_voter.kt +++ b/05_hash_tables/kotlin/02_check_voter.kt @@ -16,4 +16,4 @@ fun main(args: Array) { checkVoter("tom") checkVoter("mike") checkVoter("mike") -} +} \ No newline at end of file diff --git a/06_breadth-first_search/kotlin/01_breadth-first_search.kt b/06_breadth-first_search/kotlin/01_breadth-first_search.kt new file mode 100644 index 00000000..e8ffbfb1 --- /dev/null +++ b/06_breadth-first_search/kotlin/01_breadth-first_search.kt @@ -0,0 +1,29 @@ +import java.util.* + +val graph = hashMapOf( + "You" to listOf("Sergey", "Viktoria"), + "Viktoria" to listOf("Sergey", "Vladimir"), + "Vladimir" to listOf("Sergey", "Andrew", "Nikita", "Boris") +) + +private fun breadthFirstSearch(name: String) { + val queue = ArrayDeque(graph[name]) + val searched = arrayListOf() + while (queue.isNotEmpty()) { + val person = queue.poll() + if (!searched.contains(person)) { + if (personIsSeller(person)) { + println("$person is a mango seller!") + return + } else { + graph[person]?.let { queue.addAll(it) } + searched.add(person) + } + } + } + println("No mango sellers found!") +} + +private fun personIsSeller(name: String): Boolean = name.endsWith("s") + +fun main(args: Array) = println(breadthFirstSearch("You")) \ No newline at end of file diff --git a/06_breadth-first_search/kotlin/BreadthFirstSearch.kt b/06_breadth-first_search/kotlin/BreadthFirstSearch.kt deleted file mode 100644 index be7ea6f8..00000000 --- a/06_breadth-first_search/kotlin/BreadthFirstSearch.kt +++ /dev/null @@ -1,50 +0,0 @@ -typealias Graph = MutableMap> - -fun Graph.breadthFirstSearch(key: V, isSearched: (V) -> Boolean): Boolean { - val queue: Deque = LinkedList() - this[key]?.let { queue += it } - val searched = HashSet() - while (queue.isNotEmpty()) { - val value = queue.pop() - if (!searched.contains(value)) - if (isSearched(value)) { - println("value $value is here!") - return true - } else { - this[value]?.let { queue += it } - searched.add(value) - } - } - return false -} - -data class Person( - val name: String, - val isSellerMango: Boolean = false -) { - override fun equals(other: Any?): Boolean = - if (other is Person) other.name == name - else false - - - override fun hashCode(): Int { - return name.length - } -} - -fun main(args: Array) { - - val graph: Graph = HashMap() - - (graph as java.util.HashMap>).apply { - put(Person("John"), listOf(Person("Sergey"), Person("Viktoria"))) - put(Person("Viktoria"), listOf(Person("Sergey"), Person("Phara"))) - put(Person("Phara"), listOf(Person("Sergey"), Person("Thrall"), Person("Xul"), Person("Juncart", true))) - } - - println( - graph.breadthFirstSearch(Person("John"), Person::isSellerMango) - ) - - -} \ No newline at end of file From 5f416d1129ca45bef5b4ddb78e4bbd074c1157ed Mon Sep 17 00:00:00 2001 From: Alexandr Shulaev Date: Sat, 19 Nov 2022 00:46:18 +0400 Subject: [PATCH 074/140] Issues-126 - Fixed formatting, jsdoc and example for JavaScript/ES6 (#127) * Issues-126 - Fixed formatting, jsdoc and non-working example for JavaScript/ES6 * Issues-126 - Fixed jsdoc --- .../ES6/01_binary_search.js | 9 ++++- .../ES6/02_recursive_binary_search.js | 38 +++++++++---------- .../javascript/01_binary_search.js | 22 +++++++---- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/01_introduction_to_algorithms/ES6/01_binary_search.js b/01_introduction_to_algorithms/ES6/01_binary_search.js index 7b3e2183..83704d67 100644 --- a/01_introduction_to_algorithms/ES6/01_binary_search.js +++ b/01_introduction_to_algorithms/ES6/01_binary_search.js @@ -1,3 +1,9 @@ +/** + * Searches recursively number from the list + * @param {Array} list Source array + * @param {number} item Search item + * @returns {(number|null)} Number if the value is found or NULL otherwise + */ const binarySearch = (list, item) => { let low = 0; let high = list.length - 1; @@ -8,8 +14,7 @@ const binarySearch = (list, item) => { if (guess === item) { return mid; - } - if (guess > item) { + } else if (guess > item) { high = mid - 1; } else { low = mid + 1; diff --git a/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js index d203777d..fd96dada 100644 --- a/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js +++ b/01_introduction_to_algorithms/ES6/02_recursive_binary_search.js @@ -1,36 +1,34 @@ /** * Searches recursively number from the list - * @param {Array} list + * @param {Array} list Source array * @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 + * @returns {(number|null)} Number if the value is found or NULL otherwise */ -const binarySearch = ( list, item, low = 0, high = list.length - 1 ) => { - let mid = Math.floor((low + high) / 2); - let guess = list[mid]; +const binarySearch = (list, item, low = 0, high = list.length - 1) => { + if (low > high) return null; - if ( low > high ) return null; + const mid = Math.floor((low + high) / 2); + const guess = list[mid]; - if ( guess === item ) { - return mid; - } else if ( guess > item ) { - high = mid - 1; - return binarySearch( list, item, low, high ); - } else { - low = mid + 1; - return binarySearch( list, item, low, high ); - } + if (guess === item) { + return mid; + } else if (guess > item) { + return binarySearch(list, item, low, mid - 1); + } else { + return binarySearch(list, item, mid + 1, high); + } }; /** * Creates the array that contains numbers 1...N * @param {number} n - number N - * @return {Array} + * @returns {Array} Array that contains numbers 1...N */ -const createArr = ( n ) => Array.from({length: n}, (v, k) => k + 1); +const createArr = n => Array.from({ length: n }, (v, k) => k + 1); -const myList = createArr( 100 ); +const myList = createArr(100); -console.log( binarySearch( myList, 3 ) ); // 2 -console.log( binarySearch( myList, -1 ) ); // null +console.log(binarySearch(myList, 3)); // 2 +console.log(binarySearch(myList, -1)); // null diff --git a/01_introduction_to_algorithms/javascript/01_binary_search.js b/01_introduction_to_algorithms/javascript/01_binary_search.js index 1d5cc269..a9c27f4c 100644 --- a/01_introduction_to_algorithms/javascript/01_binary_search.js +++ b/01_introduction_to_algorithms/javascript/01_binary_search.js @@ -1,22 +1,28 @@ -'use strict'; +"use strict"; +/** + * Searches recursively number from the list + * @param {Array} list Source array + * @param {number} item Search item + * @returns {(number|null)} Number if the value is found or NULL otherwise + */ function binary_search(list, item) { let low = 0; let high = list.length - 1; - + while (low <= high) { - let mid = Math.floor((low + high) / 2); - let guess = list[mid]; -  if (guess === item) { + const mid = Math.floor((low + high) / 2); + const guess = list[mid]; + + if (guess === item) { return mid; - } - if (guess > item) { + } else if (guess > item) { high = mid - 1; } else { low = mid + 1; } } - + return null; } From c029201ab1743cbc8d5d9cf377eed7e5295fb52f Mon Sep 17 00:00:00 2001 From: Alexandr Shulaev Date: Sat, 19 Nov 2022 00:47:16 +0400 Subject: [PATCH 075/140] Fixed formatting problems, example and JSDoc (#129) --- 02_selection_sort/ES6/01_selection_sort.js | 36 ++++++++++--------- .../ES6/02_recursive_selection_sort.js | 36 +++++++++++++++++++ .../javascript/01_selection_sort.js | 30 ++++++++++------ 3 files changed, 76 insertions(+), 26 deletions(-) create mode 100644 02_selection_sort/ES6/02_recursive_selection_sort.js diff --git a/02_selection_sort/ES6/01_selection_sort.js b/02_selection_sort/ES6/01_selection_sort.js index 2de1581d..ec7861b4 100644 --- a/02_selection_sort/ES6/01_selection_sort.js +++ b/02_selection_sort/ES6/01_selection_sort.js @@ -1,8 +1,8 @@ -// Selection Sort - O(n^2) -// Parameter: -// 1. random array - -// 1. Finds the smallest value in an array +/** + * Finds the index of the element with the smallest value in the array + * @param {Array} array Source array + * @returns {number} Index of the element with the smallest value + */ const findSmallestIndex = (array) => { let smallestElement = array[0]; // Stores the smallest value let smallestIndex = 0; // Stores the index of the smallest value @@ -17,23 +17,27 @@ const findSmallestIndex = (array) => { return smallestIndex; }; -// 2. Sorts the array +/** + * Sort array by increment + * @param {Array} array Source array + * @returns {Array} New sorted array + */ const selectionSort = (array) => { - //Copy values from array, because it must be immutable. Without that after call selectionSort origin array will become empty. - const sortingArray = [...array]; const sortedArray = []; - const length = sortingArray.length; + const copyArray = [...array]; - for (let i = 0; i < length; i++) { - // Finds the smallest element in the given array - const smallestIndex = findSmallestIndex(sortingArray); + for (let i = 0; i < array.length; i++) { + // Finds the smallest element in the array + const smallestIndex = findSmallestIndex(copyArray); // Adds the smallest element to new array - sortedArray.push(sortingArray.splice(smallestIndex, 1)[0]); + sortedArray.push(copyArray.splice(smallestIndex, 1)[0]); } return sortedArray; }; -const array = [5, 3, 6, 2, 10]; -console.log(selectionSort(array)); // [2, 3, 5, 6, 10] -console.log(array); // [5, 3, 6, 2, 10] +const sourceArray = [5, 3, 6, 2, 10]; +const sourtedArray = selectionSort([5, 3, 6, 2, 10]); + +console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] +console.log("New sorted array - ", sourtedArray); // [2, 3, 5, 6, 10] diff --git a/02_selection_sort/ES6/02_recursive_selection_sort.js b/02_selection_sort/ES6/02_recursive_selection_sort.js new file mode 100644 index 00000000..116674ff --- /dev/null +++ b/02_selection_sort/ES6/02_recursive_selection_sort.js @@ -0,0 +1,36 @@ +/** + * Finds the index of the element with the smallest value in the array + * @param {Array} array Source array + * @returns {number} Index of the element with the smallest value + */ +const findSmallestIndex = array => { + let smallestElement = array[0]; // Stores the smallest value + let smallestIndex = 0; // Stores the index of the smallest value + + for (let i = 1; i < array.length; i++) { + if (array[i] < smallestElement) { + smallestElement = array[i]; + smallestIndex = i; + } + } + + return smallestIndex; +}; + +/** + * Sort array by increment + * @param {Array} array Source array + * @returns {Array} New sorted array + */ +const selectionSort = array => { + if (!array.length) return []; + const copyArray = [...array]; + const smallest = copyArray.splice(findSmallestIndex(copyArray), 1); + return smallest.concat(selectionSort(copyArray)); +}; + +const sourceArray = [5, 3, 6, 2, 10]; +const sourtedArray = selectionSort([5, 3, 6, 2, 10]); + +console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] +console.log("New sorted array - ", sourtedArray); // [2, 3, 5, 6, 10] diff --git a/02_selection_sort/javascript/01_selection_sort.js b/02_selection_sort/javascript/01_selection_sort.js index 9fce20d1..afc0a4b1 100644 --- a/02_selection_sort/javascript/01_selection_sort.js +++ b/02_selection_sort/javascript/01_selection_sort.js @@ -1,9 +1,10 @@ -'use strict'; -// Selection Sort - O(n^2) -// Parameter: -// 1. random array +"use strict"; -// 1. Finds the smallest value in an array +/** + * Finds the index of the element with the smallest value in the array + * @param {Array} array Source array + * @returns {number} Index of the element with the smallest value + */ function findSmallestIndex(array) { var smallestElement = array[0]; // Stores the smallest value var smallestIndex = 0; // Stores the index of the smallest value @@ -18,19 +19,28 @@ function findSmallestIndex(array) { return smallestIndex; } -// 2. Sort the array +/** + * Sort array by increment + * @param {Array} array Source array + * @returns {Array} New sorted array + */ function selectionSort(array) { var sortedArray = []; + var copyArray = array.slice(); var length = array.length; for (var i = 0; i < length; i++) { - // Finds the smallest element in the array - var smallestIndex = findSmallestIndex(array); + // Finds the smallest element in the array + var smallestIndex = findSmallestIndex(copyArray); // Adds the smallest element to new array - sortedArray.push(array.splice(smallestIndex, 1)[0]); + sortedArray.push(copyArray.splice(smallestIndex, 1)[0]); } return sortedArray; } -console.log(selectionSort([5, 3, 6, 2, 10])); // [2, 3, 5, 6, 10] +const sourceArray = [5, 3, 6, 2, 10]; +const sourtedArray = selectionSort([5, 3, 6, 2, 10]); + +console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] +console.log("New sorted array - ", sourtedArray); // [2, 3, 5, 6, 10] From 06a890c302113d3646d4e55da373073ab9b252a8 Mon Sep 17 00:00:00 2001 From: Pikachu Date: Sat, 19 Nov 2022 04:49:50 +0800 Subject: [PATCH 076/140] A pull request from cx (#164) * The original code did not consider the exit condition when the stations cannot perfectly cover the states_needed. * The code in 09_dynamic_programming/python/01_longest_common_subsequence.py is completed. And the 02_longest_common_substring.py is added. --- .../python/01_set_covering.py | 31 ++++++++++++------- .../python/01_longest_common_subsequence.py | 19 ++++++++---- .../python/02_longest_common_substring.py | 11 +++++++ 3 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 09_dynamic_programming/python/02_longest_common_substring.py diff --git a/08_greedy_algorithms/python/01_set_covering.py b/08_greedy_algorithms/python/01_set_covering.py index 1c77d41f..d2fa08ae 100644 --- a/08_greedy_algorithms/python/01_set_covering.py +++ b/08_greedy_algorithms/python/01_set_covering.py @@ -10,16 +10,23 @@ final_stations = set() -while states_needed: - best_station = None - states_covered = set() - for station, states_for_station in stations.items(): - covered = states_needed & states_for_station - if len(covered) > len(states_covered): - best_station = station - states_covered = covered +def my_set_covering(states_needed, stations): + final_stations = set() + #while states_needed is not None: 这个不对,Set()而不是None + while states_needed: + best_station = None + states_covered = set() + for station, states_for_station in stations.items(): + covered = states_needed & states_for_station + if len(covered) > len(states_covered) and station not in final_stations: + best_station = station + states_covered = covered + if best_station is not None: + states_needed -= states_covered + final_stations.add(best_station) + stations.pop(best_station) + else: + return None + return final_stations - states_needed -= states_covered - final_stations.add(best_station) - -print(final_stations) +print(my_set_covering(states_needed, stations)) diff --git a/09_dynamic_programming/python/01_longest_common_subsequence.py b/09_dynamic_programming/python/01_longest_common_subsequence.py index 9f74f936..61691a09 100644 --- a/09_dynamic_programming/python/01_longest_common_subsequence.py +++ b/09_dynamic_programming/python/01_longest_common_subsequence.py @@ -1,6 +1,13 @@ -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] = max(cell[i-1][j], cell[i][j-1]) +dp_table_blue = ["b", "l", "u", "e"] +dp_table_clues = ["c", "l", "u", "e", "s"] +dp_table = [[0 for i in range(len(dp_table_blue))] for i in range(len(dp_table_clues))] # (5,4) +print(dp_table) + +for i in range(0, len(dp_table_blue)): + for j in range(0, len(dp_table_clues)): + if dp_table_clues[j] == dp_table_blue[i]: + dp_table[j][i] = dp_table[j-1][i-1] + 1 + else: + dp_table[j][i] = max(dp_table[j-1][i], dp_table[j][i-1]) + +print(dp_table) diff --git a/09_dynamic_programming/python/02_longest_common_substring.py b/09_dynamic_programming/python/02_longest_common_substring.py new file mode 100644 index 00000000..0c27daeb --- /dev/null +++ b/09_dynamic_programming/python/02_longest_common_substring.py @@ -0,0 +1,11 @@ +dp_table_blue = ["b", "l", "u", "e"] +dp_table_clues = ["c", "l", "u", "e", "s"] +dp_table = [[0 for i in range(len(dp_table_blue))] for i in range(len(dp_table_clues))] # (5,4) +print(dp_table) + +for i in range(0, len(dp_table_blue)): + for j in range(0, len(dp_table_clues)): + if dp_table_clues[j] == dp_table_blue[i]: + dp_table[i][j] = dp_table[i-1][i-1] + 1 + +print(dp_table) \ No newline at end of file From 35bb758f5e926ce523b7c5e4470a20c73a432017 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Fri, 18 Nov 2022 14:53:39 -0600 Subject: [PATCH 077/140] Delete 07_dijkstras_algorithm/golang directory deleting to stop case insensitive issue on Mac --- .../golang/01_dijkstras_algorithm.go | 94 ------------------- 1 file changed, 94 deletions(-) delete mode 100644 07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go diff --git a/07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go b/07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go deleted file mode 100644 index 73b22743..00000000 --- a/07_dijkstras_algorithm/golang/01_dijkstras_algorithm.go +++ /dev/null @@ -1,94 +0,0 @@ -package main - -import ( - "fmt" - "math" -) - -var graph map[string]map[string]float64 -var costs map[string]float64 -var parents map[string]string -var processed []string - -func main() { - // the graph - graph = make(map[string]map[string]float64) - graph["start"] = make(map[string]float64) - graph["start"]["a"] = 6 - graph["start"]["b"] = 2 - - graph["a"] = make(map[string]float64) - graph["a"]["fin"] = 1 - - graph["b"] = make(map[string]float64) - graph["b"]["a"] = 3 - graph["b"]["fin"] = 5 - - graph["fin"] = make(map[string]float64) - - // the costs table - costs = make(map[string]float64) - costs["a"] = 6 - costs["b"] = 2 - costs["fin"] = math.Inf(1) - - // the parents table - parents = make(map[string]string) - parents["a"] = "start" - parents["b"] = "start" - parents["fin"] = "" - - // Find the lowest-cost node that you haven't processed yet. - node := find_lowest_cost_node(costs) - // If you've processed all the nodes, this while loop is done. - - for node != "" { - cost := costs[node] - // Go through all the neighbors of this node. - neighbors := graph[node] - - for node, _ := range neighbors { - new_cost := cost + neighbors[node] - // If it's cheaper to get to this neighbor by going through this node... - if costs[node] > new_cost { - // ... update the cost for this node. - costs[node] = new_cost - // This node becomes the new parent for this neighbor. - parents[node] = node - } - } - // Mark the node as processed. - processed = append(processed, node) - // Find the next node to process, and loop. - node = find_lowest_cost_node(costs) - } - - fmt.Println(costs) - -} - -func find_lowest_cost_node(costs map[string]float64) string { - lowest_cost := math.Inf(1) - lowest_cost_node := "" - - for node, _ := range costs { - // fmt.Println("Node:", node, "Value:", value) - cost := costs[node] - // If it's the lowest cost so far and hasn't been processed yet... - if cost < lowest_cost && !contains(processed, node) { - // ... set it as the new lowest-cost node. - lowest_cost = cost - lowest_cost_node = node - } - } - return lowest_cost_node -} - -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} From 788c54e92bd1ebfbe5fcf51c32733c93d46df357 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Fri, 18 Nov 2022 14:55:06 -0600 Subject: [PATCH 078/140] python lcs example needs to default to 0 if values dont match --- 09_dynamic_programming/python/02_longest_common_substring.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/09_dynamic_programming/python/02_longest_common_substring.py b/09_dynamic_programming/python/02_longest_common_substring.py index 0c27daeb..7cf05f45 100644 --- a/09_dynamic_programming/python/02_longest_common_substring.py +++ b/09_dynamic_programming/python/02_longest_common_substring.py @@ -7,5 +7,7 @@ for j in range(0, len(dp_table_clues)): if dp_table_clues[j] == dp_table_blue[i]: dp_table[i][j] = dp_table[i-1][i-1] + 1 + else: + dp_table[i][j] = 0 -print(dp_table) \ No newline at end of file +print(dp_table) From cf78943cefc566cd726a038e51883462a2566841 Mon Sep 17 00:00:00 2001 From: Rosana Rezende Date: Fri, 18 Nov 2022 17:58:08 -0300 Subject: [PATCH 079/140] Update 02_recursive_sum.js (#168) First, congratulations for the work, the book is very instructive. In this case, as described in the book, if the list is empty it returns zero, otherwise we apply recursion. Co-authored-by: Aditya Bhargava --- 04_quicksort/javascript/02_recursive_sum.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/04_quicksort/javascript/02_recursive_sum.js b/04_quicksort/javascript/02_recursive_sum.js index c74e1e5f..b48ca431 100644 --- a/04_quicksort/javascript/02_recursive_sum.js +++ b/04_quicksort/javascript/02_recursive_sum.js @@ -5,9 +5,9 @@ * @param {Array} array Array of numbers * @returns {number} Sum of the numbers */ -function sumRecursive(array) { - if (array.length == 1) return array[0]; - return array[0] + sumRecursive(array.slice(1)); +function sumRecursive(arr) { + if (arr.length == 0) return 0; + return arr[0] + sumRecursive(arr.slice(1)); } console.log(sumRecursive([1, 2, 3, 4])); // 10 From 3868623fcde97189690867a670492654721dfdcf Mon Sep 17 00:00:00 2001 From: Sergey Ivanov Date: Fri, 18 Nov 2022 23:58:46 +0300 Subject: [PATCH 080/140] Update SelectionSort2.java (#184) * Update SelectionSort2.java Small method * Update SelectionSort2.java --- .../java/src/SelectionSort2.java | 46 +++++-------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/02_selection_sort/java/src/SelectionSort2.java b/02_selection_sort/java/src/SelectionSort2.java index 8228d899..5b6b5668 100644 --- a/02_selection_sort/java/src/SelectionSort2.java +++ b/02_selection_sort/java/src/SelectionSort2.java @@ -3,45 +3,23 @@ public class SelectionSort2 { // this version uses raw arrays instead of ArrayList - private static int[] selectionSort(int[] arr) { - int[] newArr = new int[arr.length]; - - for (int i = 0; i < newArr.length; i++) { - int smallestIndex = findSmallest(arr); - newArr[i] = arr[smallestIndex]; - - arr = getNewArrWithoutSmallest(arr, smallestIndex); - } - - return newArr; - } - - private static int[] getNewArrWithoutSmallest(int[] arr, int smallestIndex) { - int[] newArrWithoutSmallest = new int[arr.length - 1]; - for (int i = 0; i < arr.length; i++) { - if (i < smallestIndex) { - newArrWithoutSmallest[i] = arr[i]; - } else if (i > smallestIndex) { - newArrWithoutSmallest[i - 1] = arr[i]; - } - } - return newArrWithoutSmallest; - } - - private static int findSmallest(int[] arr) { - int smallest = arr[0]; - int smallestIndex = 0; - for (int i = 0; i < arr.length; i++) { - if (arr[i] < smallest) { - smallest = arr[i]; - smallestIndex = i; + public static void selectionSort(int[] target) { + for (int i = 0; i < target.length - 1; i++) { + int left = target[i]; + for (int j = i + 1; j < target.length; j++) { + int right = target[j]; + if (left > right) { + target[i] = right; + target[j] = left; + left = right; + } } } - return smallestIndex; } public static void main(String[] args) { int[] arr = {5, 3, 6, 2, 10}; - System.out.println(Arrays.toString(selectionSort(arr))); // [2, 3, 5, 6, 10] + selectionSort(arr); + System.out.println(Arrays.toString(arr)); // [2, 3, 5, 6, 10] } } From 70d4d231bfa749dd2f0d5e59d0a139e99dde9949 Mon Sep 17 00:00:00 2001 From: Matvey <38750524+mtovts@users.noreply.github.com> Date: Sat, 19 Nov 2022 00:27:29 +0300 Subject: [PATCH 081/140] Fix/Python 06 bfs: case when entrypoint is target (#203) * Simplify cognitive complexity * Fix case when entrypoint is target * Simplyfy check for case: entrypoint is target --- .../python/01_breadth-first_search.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/06_breadth-first_search/python/01_breadth-first_search.py b/06_breadth-first_search/python/01_breadth-first_search.py index 47dd8d4b..0624f4ea 100644 --- a/06_breadth-first_search/python/01_breadth-first_search.py +++ b/06_breadth-first_search/python/01_breadth-first_search.py @@ -15,20 +15,20 @@ def person_is_seller(name): def search(name): search_queue = deque() - search_queue += graph[name] + search_queue += [name] # This is how you keep track of which people you've searched before. searched = set() while search_queue: person = search_queue.popleft() # Only search this person if you haven't already searched them. - if person not in searched: - if person_is_seller(person): - print(person + " is a mango seller!") - return True - else: - search_queue += graph[person] - # Marks this person as searched - searched.add(person) + if person in searched: + continue + if person_is_seller(person): + print(person + " is a mango seller!") + return True + search_queue += graph[person] + # Marks this person as searched + searched.add(person) return False search("you") From c91f1ad37f2f7d1f27a4fc480c9aa65e9f4f79ba Mon Sep 17 00:00:00 2001 From: Mikhail Bokov Date: Sat, 19 Nov 2022 04:28:15 +0700 Subject: [PATCH 082/140] Update 05_quicksort.php (#204) --- 04_quicksort/php/05_quicksort.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04_quicksort/php/05_quicksort.php b/04_quicksort/php/05_quicksort.php index 8bf43173..186505e3 100644 --- a/04_quicksort/php/05_quicksort.php +++ b/04_quicksort/php/05_quicksort.php @@ -6,7 +6,7 @@ function quicksort(array $array) { return $array; } else { // recursive case - $pivot = $array[0]; + $pivot = $array[array_key_first($array)]; var_dump($array); // sub-array of all the elements less than the pivot From 38f962f2a3725963fe07c8291d844f79c5d5b417 Mon Sep 17 00:00:00 2001 From: Vasilii Boldurean Date: Fri, 18 Nov 2022 21:28:46 +0000 Subject: [PATCH 083/140] Fix: dijkstras example for JavaScript ES6. (#205) --- 07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js b/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js index 5dc16e9c..396f7fe8 100644 --- a/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js +++ b/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js @@ -39,7 +39,7 @@ const findLowestCostNode = itCosts => { Object.keys(itCosts).forEach(node => { const cost = itCosts[node]; // If it's the lowest cost so far and hasn't been processed yet... - if (cost < lowestCost && processed.indexOf(node) === -1) { + if (cost < lowestCost && !processed.includes(node)) { // ... set it as the new lowest-cost node. lowestCost = cost; lowestCostNode = node; @@ -66,7 +66,7 @@ while (node !== null) { }); // Mark the node as processed - processed = processed.concat(node); + processed.push(node); // Find the next node to process, and loop node = findLowestCostNode(costs); From cd38dc146d09692f5c3d344046e0128d9b996d6e Mon Sep 17 00:00:00 2001 From: spring monkey <72025039+antonlipilin@users.noreply.github.com> Date: Sat, 19 Nov 2022 01:29:39 +0400 Subject: [PATCH 084/140] Fix formula (#206) The current version of the formula incorrectly handles the factorial(0) and causes an infinite loop --- 03_recursion/ES6/03_factorial.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_recursion/ES6/03_factorial.js b/03_recursion/ES6/03_factorial.js index 74fa4dd7..5a2a469d 100644 --- a/03_recursion/ES6/03_factorial.js +++ b/03_recursion/ES6/03_factorial.js @@ -4,7 +4,7 @@ * @returns {number} Result */ const fact = x => { - if (x === 1) return 1; + if (x === 0) return 1; return x * fact(x - 1); }; From b3a143a3ae2037e4fdfdd56af6d03fe6261288ae Mon Sep 17 00:00:00 2001 From: N3-M3-S1S Date: Sat, 19 Nov 2022 00:31:23 +0300 Subject: [PATCH 085/140] add dart examples for chapter 1 and 2 (#209) * add dart example for chapter 1 * add dart example for chapter 2 --- .../dart/binary_search.dart | 25 ++++++++++++++++ 02_selection_sort/dart/selection_sort.dart | 29 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 01_introduction_to_algorithms/dart/binary_search.dart create mode 100644 02_selection_sort/dart/selection_sort.dart diff --git a/01_introduction_to_algorithms/dart/binary_search.dart b/01_introduction_to_algorithms/dart/binary_search.dart new file mode 100644 index 00000000..a0bcf91e --- /dev/null +++ b/01_introduction_to_algorithms/dart/binary_search.dart @@ -0,0 +1,25 @@ +void main() { + final myList = [1, 3, 5, 7, 9]; + print(binarySearch(myList, 3)); + print(binarySearch(myList, -1)); +} + +int? binarySearch(List list, int item) { + int low = 0; + int high = list.length - 1; + + while (low <= high) { + final mid = (low + high) ~/ 2; + final guess = list[mid]; + + if (guess == item) { + return mid; + } + + if (guess > item) { + high = mid - 1; + } else { + low = mid + 1; + } + } +} diff --git a/02_selection_sort/dart/selection_sort.dart b/02_selection_sort/dart/selection_sort.dart new file mode 100644 index 00000000..4fd7553f --- /dev/null +++ b/02_selection_sort/dart/selection_sort.dart @@ -0,0 +1,29 @@ +main() { + print(selectionSort([5, 3, 6, 2, 10])); +} + +List selectionSort(List arr) { + final List newArr = List.empty(growable: true); + final arrLength = arr.length; + + for (int i = 0; i < arrLength; i++) { + final smallest = findSmallest(arr); + newArr.add(arr.removeAt(smallest)); + } + + return newArr; +} + +int findSmallest(List arr) { + int smallest = arr[0]; + int smallestIndex = 0; + + for (int i = 1; i < arr.length; i++) { + if (arr[i] < smallest) { + smallest = arr[i]; + smallestIndex = i; + } + } + + return smallestIndex; +} From 3f02143f7fb2e2eecc7622501f3545a53960486c Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Fri, 18 Nov 2022 15:35:44 -0600 Subject: [PATCH 086/140] Expand contributions section in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3d541fb7..7602c1c3 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,4 @@ This repository contains every image in Grokking Algorithms in high resolution. - The examples in this book are written in Python, but I'd like examples in Ruby, JavaScript, C, and other languages too. Please add examples in other languages! - Pull request are the quickest way to contribute to this repository but unfortunately I am not as responsive to them as I'd like to be. I'll get to them but it might take a while! +- This repo is for easy to read examples. So even though I love well tested, optimized code, I won't be merging PRs related to tests or optimization, since those will increase cognitive load for readers. From 308148653af51d87b8e8622383c63a4bda775d88 Mon Sep 17 00:00:00 2001 From: Udit Gupta Date: Fri, 18 Nov 2022 13:47:57 -0800 Subject: [PATCH 087/140] Enhances 'base case' logic (#227) Original function does not work when input array is empty or contains a single value. In the revised code, base case has been augmented to support those. Works successfully for all these test cases: find_max([1, 12, 8, 5]), find_max([]), find_max([1]) --- 03_recursion/python/06_find_max.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/03_recursion/python/06_find_max.py b/03_recursion/python/06_find_max.py index 9080084f..bb5afc54 100644 --- a/03_recursion/python/06_find_max.py +++ b/03_recursion/python/06_find_max.py @@ -1,5 +1,9 @@ def find_max(arr): - if len(arr) == 2: + if len(arr) == 0: + return 0 + elif len(arr) == 1: + return arr[0] + elif len(arr) == 2: return arr[0] if arr[0] > arr[1] else arr[1] sub_max = find_max(arr[1:]) - return arr[0] if arr[0] > sub_max else sub_max \ No newline at end of file + return arr[0] if arr[0] > sub_max else sub_max From 75e8e8cd9ee9f6566090fd29514e4a20deea883d Mon Sep 17 00:00:00 2001 From: David Choi <1777321+greatgumz@users.noreply.github.com> Date: Fri, 18 Nov 2022 13:48:41 -0800 Subject: [PATCH 088/140] Update 01_loop_sum_reduce_version.js (#232) the first parameter of the reduce function is `previousValue` and the second parameter is `currentValue` so these parameter names need to be fixed. --- 04_quicksort/ES6/01_loop_sum_reduce_version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04_quicksort/ES6/01_loop_sum_reduce_version.js b/04_quicksort/ES6/01_loop_sum_reduce_version.js index 7dc84dd0..ca41359c 100644 --- a/04_quicksort/ES6/01_loop_sum_reduce_version.js +++ b/04_quicksort/ES6/01_loop_sum_reduce_version.js @@ -3,6 +3,6 @@ * @param {Array} array Array of numbers * @returns {number} Sum of the numbers */ -const sumReduce = array => array.reduce((curr, prev) => curr + prev); +const sumReduce = array => array.reduce((prev, curr) => prev + curr); console.log(sumReduce([1, 2, 3, 4])); // 10 From 1b76ebb2f1b8f06f4763a1577b31f9332c407d8a Mon Sep 17 00:00:00 2001 From: kuznevia <56788347+kuznevia@users.noreply.github.com> Date: Sat, 19 Nov 2022 00:48:56 +0300 Subject: [PATCH 089/140] Update 01_loop_sum_reduce_version.js (#235) changing variables names to correct --- 04_quicksort/javascript/01_loop_sum_reduce_version.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/04_quicksort/javascript/01_loop_sum_reduce_version.js b/04_quicksort/javascript/01_loop_sum_reduce_version.js index c12aaa1d..801978ad 100644 --- a/04_quicksort/javascript/01_loop_sum_reduce_version.js +++ b/04_quicksort/javascript/01_loop_sum_reduce_version.js @@ -6,8 +6,8 @@ * @returns {number} Sum of the numbers */ function sumReduce(array) { - return array.reduce(function(curr, prev) { - return curr + prev; + return array.reduce(function(prev, cur) { + return prev + cur; }); } From 07a6d6b5063d1eb68195f8095ef9eaa83d1a3289 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Fri, 18 Nov 2022 16:33:17 -0600 Subject: [PATCH 090/140] fix broken case in binary search (python) and remove unneeded base cases --- .../python/05_binary_search_recursive.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/03_recursion/python/05_binary_search_recursive.py b/03_recursion/python/05_binary_search_recursive.py index 7791559b..3ed0b237 100644 --- a/03_recursion/python/05_binary_search_recursive.py +++ b/03_recursion/python/05_binary_search_recursive.py @@ -1,15 +1,18 @@ def binary_search(arr, target): if not arr: - return -1 - if len(arr) == 1 and arr[0] == target: - return arr[0] - if len(arr) == 1 and arr[0] != target: return -1 - low = 0 - high = len(arr) - 1 + + low = 0 + high = len(arr) - 1 mid = (low + high) // 2 - if arr[mid] > target: + if arr[mid] == target: + return target + elif arr[mid] > target: return binary_search(arr[:mid], target) else: - return binary_search(arr[mid+1:], target) \ No newline at end of file + return binary_search(arr[mid+1:], target) + + +print(binary_search([6, 7, 8, 9, 10], 8)) +print(binary_search([6, 7, 8, 9, 10], 6)) From f03841e79a886dadeaeeca9b37b788040834c04c Mon Sep 17 00:00:00 2001 From: Jinguang Date: Sat, 19 Nov 2022 06:35:04 +0800 Subject: [PATCH 091/140] Description:[fix] fixed the C++ compile error for std::find (#241) Bug: NA Test: 1. add "#include " on fisrt line of the file 2. It could be normally compiler, or it will report compile error --- 07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp b/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp index f0e069df..1d04a6d1 100644 --- a/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp +++ b/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp @@ -1,3 +1,4 @@ +#include #include #include #include From 5d9ae511d585eb00c5d6c6e55b41f51af53efef0 Mon Sep 17 00:00:00 2001 From: Paolo Grisoli Date: Fri, 18 Nov 2022 23:36:32 +0100 Subject: [PATCH 092/140] Add examples for Zig language (#242) * add zig examples * improved zig binary search This commit improves the binary search code in zig. The function has been made generic and the logic has been cleaned up a bit. The code has been updated to work with zig versions >= 0.9 * simplify zig selection sort This commit simplifies the logic of the zig selection sort. It now swaps in place the elements of the array instead of creating another array. This avoids allocating heap memory. The code has also been upgraded to zig version 0.9.1 * make zig recursion examples generic This commit modifies the zig examples for the recursion chapter to be generic. It also updates the code to zig version 0.9.1 * update chapter 4 examples This commit updates the zig examples in chapter 4. In particular examples have been made generic where possible. The code has been updated to zig version 0.9.1 * update zig hash table examples This commit updates the examples for the chapter 5 about hash tables. Some improvements have been done (using a set instead of a map). The code has been updated to zig version 0.9.1 * update breadth first search zig example This commit updates the zig example for the breadth first search algorithm. It adds a unit test and updates the code to zig version 0.9.1 * revamp zig dijkstra example * add comments in dijkstra zig * fix zig greedy algorithm * add test for zig dijkstra * add test for zig greedy algorithm * improve zig chapter 9 exercise This commit improves the zig exercise to comput the longest common subsequence. A main function has been added and the allocator code has been extracted from the `subsequence` function. --- .gitignore | 3 +- .../zig/binary-search.zig | 36 ++++ 02_selection_sort/zig/selection_sort.zig | 35 ++++ 03_recursion/zig/01_countdown.zig | 13 ++ 03_recursion/zig/02_greet.zig | 20 +++ 03_recursion/zig/03_factorial.zig | 11 ++ 03_recursion/zig/04_count.zig | 40 +++++ .../zig/05_binary_search_recursive.zig | 59 +++++++ 03_recursion/zig/06_find_max.zig | 47 +++++ 03_recursion/zig/07_sum_array.zig | 38 +++++ 04_quicksort/zig/01_loop_sum.zig | 38 +++++ 04_quicksort/zig/02_recursive_sum.zig | 37 ++++ 04_quicksort/zig/03_recursive_count.zig | 40 +++++ 04_quicksort/zig/04_recursive_max.zig | 47 +++++ 04_quicksort/zig/05_quicksort.zig | 79 +++++++++ 04_quicksort/zig/06_quicksort_parallel.zig | 86 ++++++++++ 05_hash_tables/zig/check_voter.zig | 22 +++ 05_hash_tables/zig/price_of_groceries.zig | 19 +++ .../zig/breadth_first_search.zig | 114 +++++++++++++ .../zig/dijkstras_algorithm.zig | 161 ++++++++++++++++++ 08_greedy_algorithms/zig/set_covering.zig | 158 +++++++++++++++++ .../zig/longest_common_subsequence.zig | 63 +++++++ 22 files changed, 1165 insertions(+), 1 deletion(-) create mode 100644 01_introduction_to_algorithms/zig/binary-search.zig create mode 100644 02_selection_sort/zig/selection_sort.zig create mode 100644 03_recursion/zig/01_countdown.zig create mode 100644 03_recursion/zig/02_greet.zig create mode 100644 03_recursion/zig/03_factorial.zig create mode 100644 03_recursion/zig/04_count.zig create mode 100644 03_recursion/zig/05_binary_search_recursive.zig create mode 100644 03_recursion/zig/06_find_max.zig create mode 100644 03_recursion/zig/07_sum_array.zig create mode 100644 04_quicksort/zig/01_loop_sum.zig create mode 100644 04_quicksort/zig/02_recursive_sum.zig create mode 100644 04_quicksort/zig/03_recursive_count.zig create mode 100644 04_quicksort/zig/04_recursive_max.zig create mode 100644 04_quicksort/zig/05_quicksort.zig create mode 100644 04_quicksort/zig/06_quicksort_parallel.zig create mode 100644 05_hash_tables/zig/check_voter.zig create mode 100644 05_hash_tables/zig/price_of_groceries.zig create mode 100644 06_breadth-first_search/zig/breadth_first_search.zig create mode 100644 07_dijkstras_algorithm/zig/dijkstras_algorithm.zig create mode 100644 08_greedy_algorithms/zig/set_covering.zig create mode 100644 09_dynamic_programming/zig/longest_common_subsequence.zig diff --git a/.gitignore b/.gitignore index c79d826b..0621ed79 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ highlights/node_modules highlights/atom-language-perl6/ .DS_store highlights/package-lock.json +zig-cache # IDE specific .scala_dependencies @@ -41,4 +42,4 @@ highlights/package-lock.json /.env atlassian-ide-plugin.xml __pycache__ -.vscode \ No newline at end of file +.vscode diff --git a/01_introduction_to_algorithms/zig/binary-search.zig b/01_introduction_to_algorithms/zig/binary-search.zig new file mode 100644 index 00000000..f0e9123d --- /dev/null +++ b/01_introduction_to_algorithms/zig/binary-search.zig @@ -0,0 +1,36 @@ +const std = @import("std"); +const print = std.debug.print; +const expect = std.testing.expect; + +pub fn main() void { + const my_list = &[_]i8{ 1, 3, 5, 7, 9 }; + + print("{?}\n", .{binarySearch(i8, my_list, 3)}); + print("{?}\n", .{binarySearch(i8, my_list, -1)}); +} + +fn binarySearch(comptime T: type, list: []const T, item: T) ?usize { + var low: i32 = 0; + var high: i32 = @intCast(i32, list.len) - 1; + + return while (low <= high) { + var mid = @divTrunc((low + high), 2); + var m = @intCast(usize, mid); + var guess = list[m]; + if (guess == item) break m; + if (guess > item) { + high = mid - 1; + } else low = mid + 1; + } else null; +} + +test "binarySearch" { + const my_list = &[_]i8{ 1, 3, 5, 7, 9 }; + + var i = binarySearch(i8, my_list, 3); + try expect(i != null); + try expect(i.? == 1); + + i = binarySearch(i8, my_list, -1); + try expect(i == null); +} diff --git a/02_selection_sort/zig/selection_sort.zig b/02_selection_sort/zig/selection_sort.zig new file mode 100644 index 00000000..19a2c10a --- /dev/null +++ b/02_selection_sort/zig/selection_sort.zig @@ -0,0 +1,35 @@ +const std = @import("std"); +const print = std.debug.print; +const expect = std.testing.expect; + +pub fn main() !void { + var s = [_]i32{ 5, 3, 6, 2, 10 }; + + selectionSort(i32, s[0..]); + print("{d}\n", .{s}); +} + +fn selectionSort(comptime T: type, list: []T) void { + for (list) |_, i| { + var j = i + 1; + while (j < list.len) : (j += 1) { + if (list[i] > list[j]) { + // swap + var tmp = list[i]; + list[i] = list[j]; + list[j] = tmp; + } + } + } +} + +test "selectionSort" { + var s = [_]i32{ 5, 3, 6, 2, 10 }; + const exp = [_]i32{ 2, 3, 5, 6, 10 }; + + selectionSort(i32, s[0..]); + + try expect(s.len == exp.len); + for (s) |e, i| + try expect(e == exp[i]); +} diff --git a/03_recursion/zig/01_countdown.zig b/03_recursion/zig/01_countdown.zig new file mode 100644 index 00000000..43fd2eee --- /dev/null +++ b/03_recursion/zig/01_countdown.zig @@ -0,0 +1,13 @@ +const print = @import("std").debug.print; + +fn countdown(comptime T: type, i: T) void { + print("{} ", .{i}); + if (i <= 0) { + print("\n", .{}); + return; + } else countdown(T, i - 1); +} + +pub fn main() void { + countdown(u32, 5); +} diff --git a/03_recursion/zig/02_greet.zig b/03_recursion/zig/02_greet.zig new file mode 100644 index 00000000..19b403d9 --- /dev/null +++ b/03_recursion/zig/02_greet.zig @@ -0,0 +1,20 @@ +const print = @import("std").debug.print; + +pub fn main() void { + greet("adit"); +} + +fn bye() void { + print("ok bye!\n", .{}); +} + +fn greet(name: []const u8) void { + print("hello, {s}!\n", .{name}); + greet2(name); + print("getting ready to say bye...\n", .{}); + bye(); +} + +fn greet2(name: []const u8) void { + print("how are you, {s}?\n", .{name}); +} diff --git a/03_recursion/zig/03_factorial.zig b/03_recursion/zig/03_factorial.zig new file mode 100644 index 00000000..6e015cbf --- /dev/null +++ b/03_recursion/zig/03_factorial.zig @@ -0,0 +1,11 @@ +const print = @import("std").debug.print; + +fn fact(comptime T: type, x: T) T { + if (x == 1) { + return x; + } else return x * fact(T, x - 1); +} + +pub fn main() void { + print("{}\n", .{fact(i32, 5)}); +} diff --git a/03_recursion/zig/04_count.zig b/03_recursion/zig/04_count.zig new file mode 100644 index 00000000..914c4f25 --- /dev/null +++ b/03_recursion/zig/04_count.zig @@ -0,0 +1,40 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var arr = [_]i32{ 4, 3, 2, 1 }; + print("{}\n", .{count(i32, arr[0..])}); +} + +fn count(comptime T: type, arr: []T) T { + if (arr.len == 0) { + return 0; + } else return 1 + count(T, arr[1..]); +} + +test "count" { + var arr0 = [_]i32{}; + var arr1 = [_]i32{42}; + var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + var tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 0, + }, + .{ + .arr = &arr1, + .exp = 1, + }, + .{ + .arr = &arr2, + .exp = 9, + }, + }; + + for (tests) |t| { + try expect(count(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/03_recursion/zig/05_binary_search_recursive.zig b/03_recursion/zig/05_binary_search_recursive.zig new file mode 100644 index 00000000..99e521d3 --- /dev/null +++ b/03_recursion/zig/05_binary_search_recursive.zig @@ -0,0 +1,59 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{binarySearch(i32, &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 2)}); +} + +fn binarySearch(comptime T: type, arr: []const T, target: T) bool { + switch (arr.len) { + 0 => return false, + 1 => return arr[0] == target, + else => { + const mid = arr.len / 2; + if (arr[mid] > target) { + return binarySearch(T, arr[0..mid], target); + } else { + return binarySearch(T, arr[mid..], target); + } + }, + } +} + +test "binary search recursive" { + const tests = [_]struct { + arr: []const i32, + target: i32, + exp: bool, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + .target = 7, + .exp = true, + }, + .{ + .arr = &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + .target = 42, + .exp = false, + }, + .{ + .arr = &[_]i32{42}, + .target = 42, + .exp = true, + }, + .{ + .arr = &[_]i32{1}, + .target = 42, + .exp = false, + }, + .{ + .arr = &[_]i32{}, + .target = 42, + .exp = false, + }, + }; + + for (tests) |t| { + try expect(binarySearch(@TypeOf(t.target), t.arr, t.target) == t.exp); + } +} diff --git a/03_recursion/zig/06_find_max.zig b/03_recursion/zig/06_find_max.zig new file mode 100644 index 00000000..58170ae9 --- /dev/null +++ b/03_recursion/zig/06_find_max.zig @@ -0,0 +1,47 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{findMax(i32, &[_]i32{ 1, 2, 3, 4 })}); +} + +fn findMax(comptime T: type, arr: []const T) T { + switch (arr.len) { + 0 => return 0, + 1 => return arr[0], + else => { + const x = findMax(T, arr[1..]); + if (arr[0] > x) { + return arr[0]; + } else return x; + }, + } +} + +test "find max" { + const tests = [_]struct { + arr: []const i32, + exp: i32, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4 }, + .exp = 4, + }, + .{ + .arr = &[_]i32{ 8, 42, 3, 1 }, + .exp = 42, + }, + .{ + .arr = &[_]i32{42}, + .exp = 42, + }, + .{ + .arr = &[_]i32{}, + .exp = 0, + }, + }; + + for (tests) |t| { + try expect(findMax(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/03_recursion/zig/07_sum_array.zig b/03_recursion/zig/07_sum_array.zig new file mode 100644 index 00000000..104c22dd --- /dev/null +++ b/03_recursion/zig/07_sum_array.zig @@ -0,0 +1,38 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{sumArray(i32, &[_]i32{ 1, 2, 3, 4 })}); +} + +fn sumArray(comptime T: type, arr: []const T) T { + switch (arr.len) { + 0 => return 0, + 1 => return arr[0], + else => return arr[0] + sumArray(T, arr[1..]), + } +} + +test "sum array" { + const tests = [_]struct { + arr: []const i32, + exp: i32, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4 }, + .exp = 10, + }, + .{ + .arr = &[_]i32{42}, + .exp = 42, + }, + .{ + .arr = &[_]i32{}, + .exp = 0, + }, + }; + + for (tests) |t| { + try expect(sumArray(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/04_quicksort/zig/01_loop_sum.zig b/04_quicksort/zig/01_loop_sum.zig new file mode 100644 index 00000000..13c0d0a1 --- /dev/null +++ b/04_quicksort/zig/01_loop_sum.zig @@ -0,0 +1,38 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var arr = [_]i32{ 1, 2, 3, 4 }; + print("{}\n", .{sum(i32, &arr)}); +} + +fn sum(comptime T: type, arr: []T) T { + var total: T = 0; + for (arr) |x| { + total += x; + } + return total; +} + +test "sum" { + var arr0 = [_]i32{ 1, 2, 3, 4 }; + var arr1 = [_]i32{}; + var tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 10, + }, + .{ + .arr = &arr1, + .exp = 0, + }, + }; + + for (tests) |t| { + var n = sum(@TypeOf(t.exp), t.arr); + try expect(n == t.exp); + } +} diff --git a/04_quicksort/zig/02_recursive_sum.zig b/04_quicksort/zig/02_recursive_sum.zig new file mode 100644 index 00000000..a015ceb3 --- /dev/null +++ b/04_quicksort/zig/02_recursive_sum.zig @@ -0,0 +1,37 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var list = [_]i32{ 1, 2, 3, 4 }; + print("{}\n", .{sum(i32, &list)}); +} + +fn sum(comptime T: type, list: []T) T { + if (list.len == 0) { + return 0; + } + return list[0] + sum(T, list[1..]); +} + +test "sum" { + var arr0 = [_]i32{ 1, 2, 3, 4 }; + var arr1 = [_]i32{}; + var tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 10, + }, + .{ + .arr = &arr1, + .exp = 0, + }, + }; + + for (tests) |t| { + var n = sum(@TypeOf(t.exp), t.arr); + try expect(n == t.exp); + } +} diff --git a/04_quicksort/zig/03_recursive_count.zig b/04_quicksort/zig/03_recursive_count.zig new file mode 100644 index 00000000..914c4f25 --- /dev/null +++ b/04_quicksort/zig/03_recursive_count.zig @@ -0,0 +1,40 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + var arr = [_]i32{ 4, 3, 2, 1 }; + print("{}\n", .{count(i32, arr[0..])}); +} + +fn count(comptime T: type, arr: []T) T { + if (arr.len == 0) { + return 0; + } else return 1 + count(T, arr[1..]); +} + +test "count" { + var arr0 = [_]i32{}; + var arr1 = [_]i32{42}; + var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + var tests = [_]struct { + arr: []i32, + exp: i32, + }{ + .{ + .arr = &arr0, + .exp = 0, + }, + .{ + .arr = &arr1, + .exp = 1, + }, + .{ + .arr = &arr2, + .exp = 9, + }, + }; + + for (tests) |t| { + try expect(count(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/04_quicksort/zig/04_recursive_max.zig b/04_quicksort/zig/04_recursive_max.zig new file mode 100644 index 00000000..58170ae9 --- /dev/null +++ b/04_quicksort/zig/04_recursive_max.zig @@ -0,0 +1,47 @@ +const print = @import("std").debug.print; +const expect = @import("std").testing.expect; + +pub fn main() void { + print("{}\n", .{findMax(i32, &[_]i32{ 1, 2, 3, 4 })}); +} + +fn findMax(comptime T: type, arr: []const T) T { + switch (arr.len) { + 0 => return 0, + 1 => return arr[0], + else => { + const x = findMax(T, arr[1..]); + if (arr[0] > x) { + return arr[0]; + } else return x; + }, + } +} + +test "find max" { + const tests = [_]struct { + arr: []const i32, + exp: i32, + }{ + .{ + .arr = &[_]i32{ 1, 2, 3, 4 }, + .exp = 4, + }, + .{ + .arr = &[_]i32{ 8, 42, 3, 1 }, + .exp = 42, + }, + .{ + .arr = &[_]i32{42}, + .exp = 42, + }, + .{ + .arr = &[_]i32{}, + .exp = 0, + }, + }; + + for (tests) |t| { + try expect(findMax(@TypeOf(t.exp), t.arr) == t.exp); + } +} diff --git a/04_quicksort/zig/05_quicksort.zig b/04_quicksort/zig/05_quicksort.zig new file mode 100644 index 00000000..83c78e3c --- /dev/null +++ b/04_quicksort/zig/05_quicksort.zig @@ -0,0 +1,79 @@ +const std = @import("std"); +const print = std.debug.print; +const expect = std.testing.expect; +const heap = std.heap; +const mem = std.mem; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + var s = [_]u8{ 5, 3, 6, 2, 10 }; + + print("{d}\n", .{try quicksort(u8, arena.allocator(), &s)}); +} + +fn quicksort(comptime T: type, allocator: mem.Allocator, s: []const T) anyerror![]const T { + // base case, arrays with 0 or 1 element are already "sorted" + if (s.len < 2) { + return s; + } + + var lower = std.ArrayList(T).init(allocator); + var higher = std.ArrayList(T).init(allocator); + + const pivot = s[0]; + for (s[1..]) |item| { + if (item <= pivot) { + try lower.append(item); + } else { + try higher.append(item); + } + } + + var low = try quicksort(T, allocator, lower.items); + var high = try quicksort(T, allocator, higher.items); + + var res = std.ArrayList(T).init(allocator); + try res.appendSlice(low); + try res.append(pivot); + try res.appendSlice(high); + + return res.items; +} + +test "quicksort" { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer { + arena.deinit(); + const leaked = gpa.deinit(); + if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return + } + + const tests = [_]struct { + s: []const u8, + exp: []const u8, + }{ + .{ + .s = &[_]u8{}, + .exp = &[_]u8{}, + }, + .{ + .s = &[_]u8{42}, + .exp = &[_]u8{42}, + }, + .{ + .s = &[_]u8{ 3, 2, 1 }, + .exp = &[_]u8{ 1, 2, 3 }, + }, + }; + + for (tests) |t| { + var res = try quicksort(u8, arena.allocator(), t.s); + try expect(res.len == t.exp.len); + for (res) |e, i| + try expect(e == t.exp[i]); + } +} diff --git a/04_quicksort/zig/06_quicksort_parallel.zig b/04_quicksort/zig/06_quicksort_parallel.zig new file mode 100644 index 00000000..8c4991a7 --- /dev/null +++ b/04_quicksort/zig/06_quicksort_parallel.zig @@ -0,0 +1,86 @@ +const std = @import("std"); +const print = std.debug.print; +const expect = std.testing.expect; +const heap = std.heap; +const mem = std.mem; + +pub const io_mode = .evented; + +pub const Error = error{OutOfMemory}; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + var s = [_]u8{ 5, 3, 6, 2, 10 }; + + print("{d}\n", .{try quicksort(arena.allocator(), &s)}); +} + +// NOTE: this async version cannot be generic because allocating a frame for a +// generic function is not trivial. +fn quicksort(allocator: mem.Allocator, s: []const u8) Error![]const u8 { + if (s.len < 2) { + return s; + } + + var lower = std.ArrayList(u8).init(allocator); + var higher = std.ArrayList(u8).init(allocator); + + const pivot = s[0]; + for (s[1..]) |item| { + if (item <= pivot) { + try lower.append(item); + } else { + try higher.append(item); + } + } + + const low_frame = try allocator.create(@Frame(quicksort)); + low_frame.* = async quicksort(allocator, lower.items); + var high = try quicksort(allocator, higher.items); + var low = try await low_frame; + + var res = std.ArrayList(u8).init(allocator); + try res.appendSlice(low); + try res.append(pivot); + try res.appendSlice(high); + + return res.items; +} + +test "quicksort" { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer { + arena.deinit(); + const leaked = gpa.deinit(); + if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return + } + + const tests = [_]struct { + s: []const u8, + exp: []const u8, + }{ + .{ + .s = &[_]u8{}, + .exp = &[_]u8{}, + }, + .{ + .s = &[_]u8{42}, + .exp = &[_]u8{42}, + }, + .{ + .s = &[_]u8{ 3, 2, 1 }, + .exp = &[_]u8{ 1, 2, 3 }, + }, + }; + + for (tests) |t| { + var res = try quicksort(arena.allocator(), t.s); + try expect(res.len == t.exp.len); + for (res) |e, i| + try expect(e == t.exp[i]); + } +} diff --git a/05_hash_tables/zig/check_voter.zig b/05_hash_tables/zig/check_voter.zig new file mode 100644 index 00000000..1cc7bc86 --- /dev/null +++ b/05_hash_tables/zig/check_voter.zig @@ -0,0 +1,22 @@ +const std = @import("std"); +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + + var map = std.StringHashMap(void).init(gpa.allocator()); + defer map.deinit(); + + try checkVoter(&map, "tom"); + try checkVoter(&map, "mike"); + try checkVoter(&map, "mike"); +} + +fn checkVoter(voted: *std.StringHashMap(void), name: []const u8) !void { + if (voted.contains(name)) { + std.debug.print("kick them out!\n", .{}); + } else { + try voted.put(name, {}); + std.debug.print("let them vote!\n", .{}); + } +} diff --git a/05_hash_tables/zig/price_of_groceries.zig b/05_hash_tables/zig/price_of_groceries.zig new file mode 100644 index 00000000..91b42a2f --- /dev/null +++ b/05_hash_tables/zig/price_of_groceries.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + + var map = std.StringHashMap(f32).init(gpa.allocator()); + defer map.deinit(); + + try map.put("apple", 0.67); + try map.put("milk", 1.49); + try map.put("avocado", 1.49); + + var iterator = map.iterator(); + + while (iterator.next()) |entry| { + std.debug.print("{s}: {d:.2}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); + } +} diff --git a/06_breadth-first_search/zig/breadth_first_search.zig b/06_breadth-first_search/zig/breadth_first_search.zig new file mode 100644 index 00000000..2404c9eb --- /dev/null +++ b/06_breadth-first_search/zig/breadth_first_search.zig @@ -0,0 +1,114 @@ +const std = @import("std"); +const mem = std.mem; +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + + var graph = std.StringHashMap([][]const u8).init(gpa.allocator()); + defer graph.deinit(); + + var you = [_][]const u8{ "alice", "bob", "claire" }; + var bob = [_][]const u8{ "anuj", "peggy" }; + var alice = [_][]const u8{"peggy"}; + var claire = [_][]const u8{ "thom", "jonny" }; + var anuj = [_][]const u8{}; + var peggy = [_][]const u8{}; + var thom = [_][]const u8{}; + var jonny = [_][]const u8{}; + + try graph.put("you", &you); + try graph.put("bob", &bob); + try graph.put("alice", &alice); + try graph.put("claire", &claire); + try graph.put("anuj", &anuj); + try graph.put("peggy", &peggy); + try graph.put("thom", &thom); + try graph.put("jonny", &jonny); + + try search(gpa.allocator(), &graph, "you"); +} + +fn search( + allocator: mem.Allocator, + graph: *std.StringHashMap([][]const u8), + name: []const u8, +) !void { + var arena = heap.ArenaAllocator.init(allocator); + defer arena.deinit(); + var searched = std.BufSet.init(arena.allocator()); + const Q = std.TailQueue([]const u8); + var queue = Q{}; + + var name_edges = graph.get(name); + if (name_edges) |edges| { + var nodes = try arena.allocator().alloc(Q.Node, edges.len); + var i: usize = 0; + while (i < edges.len) : (i += 1) { + nodes[i].data = edges[i]; + } + for (nodes) |*node| { + queue.append(node); + } + } + + while (queue.len > 0) { + var first = queue.popFirst(); + if (first) |person| { + if (!searched.contains(person.data)) { + if (personIsSeller(person.data)) { + std.debug.print("{s} is a mango seller!\n", .{person.data}); + return; + } else { + var ee = graph.get(person.data); + if (ee) |edges| { + var nodes = try arena.allocator().alloc(Q.Node, edges.len); + var i: usize = 0; + while (i < edges.len) : (i += 1) { + nodes[i].data = edges[i]; + } + for (nodes) |*node| { + queue.append(node); + } + } + try searched.insert(person.data); + } + } + } + } +} + +fn personIsSeller(name: []const u8) bool { + return name[name.len - 1] == 'm'; +} + +test "search" { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + + var graph = std.StringHashMap([][]const u8).init(gpa.allocator()); + defer { + graph.deinit(); + const leaked = gpa.deinit(); + if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return + } + + var you = [_][]const u8{ "alice", "bob", "claire" }; + var bob = [_][]const u8{ "anuj", "peggy" }; + var alice = [_][]const u8{"peggy"}; + var claire = [_][]const u8{ "thom", "jonny" }; + var anuj = [_][]const u8{}; + var peggy = [_][]const u8{}; + var thom = [_][]const u8{}; + var jonny = [_][]const u8{}; + + try graph.put("you", &you); + try graph.put("bob", &bob); + try graph.put("alice", &alice); + try graph.put("claire", &claire); + try graph.put("anuj", &anuj); + try graph.put("peggy", &peggy); + try graph.put("thom", &thom); + try graph.put("jonny", &jonny); + + try search(gpa.allocator(), &graph, "you"); +} diff --git a/07_dijkstras_algorithm/zig/dijkstras_algorithm.zig b/07_dijkstras_algorithm/zig/dijkstras_algorithm.zig new file mode 100644 index 00000000..2a038d01 --- /dev/null +++ b/07_dijkstras_algorithm/zig/dijkstras_algorithm.zig @@ -0,0 +1,161 @@ +const std = @import("std"); +const mem = std.mem; +const heap = std.heap; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator()); + + var start = std.StringHashMap(f32).init(arena.allocator()); + try start.put("a", 6); + try start.put("b", 2); + try graph.put("start", &start); + + var a = std.StringHashMap(f32).init(arena.allocator()); + try a.put("finish", 1); + try graph.put("a", &a); + + var b = std.StringHashMap(f32).init(arena.allocator()); + try b.put("a", 3); + try b.put("finish", 5); + try graph.put("b", &b); + + var fin = std.StringHashMap(f32).init(arena.allocator()); + try graph.put("finish", &fin); + + var result = try dijkstra(arena.allocator(), &graph, "start", "finish"); + + std.debug.print("Cost from the start to each node:\n", .{}); + var costs_it = result.costs.iterator(); + while (costs_it.next()) |cost| { + std.debug.print("{s}: {d} ", .{ cost.key_ptr.*, cost.value_ptr.* }); + } + std.debug.print("\n", .{}); + std.debug.print("\n", .{}); + std.debug.print("Path from start to finish:\n", .{}); + var path_it = result.path.iterator(); + while (path_it.next()) |parent| { + std.debug.print("{s} = {?s}\n", .{ parent.key_ptr.*, parent.value_ptr.* }); + } +} + +/// this struct is needed because coercing an anonymous struct literal to an +/// error union is not supported by zig yet. Once this is fixed (with the +/// self-hosted compiler, see https://github.com/ziglang/zig/issues/11443), the +/// dijkstra function could just return: +/// ```zig +/// return { +/// .costs = costs, +/// .path = parents, +/// }; +/// ``` +const dijkstraResult = struct { + costs: std.StringHashMap(f32), + path: std.StringHashMap(?[]const u8), +}; + +/// applies the dijkstra algorithm on the provided graph using +/// the provided start anf finish nodes. +fn dijkstra( + allocator: mem.Allocator, + graph: *std.StringHashMap(*std.StringHashMap(f32)), + start: []const u8, + finish: []const u8, +) !dijkstraResult { + var costs = std.StringHashMap(f32).init(allocator); + var parents = std.StringHashMap(?[]const u8).init(allocator); + try costs.put(finish, std.math.inf_f32); + try parents.put(finish, null); + + // initialize costs and parents maps for the nodes having start as parent + var start_graph = graph.get(start); + if (start_graph) |sg| { + var it = sg.iterator(); + while (it.next()) |elem| { + try costs.put(elem.key_ptr.*, elem.value_ptr.*); + try parents.put(elem.key_ptr.*, start); + } + } + + var processed = std.BufSet.init(allocator); + + var n = findCheapestNode(&costs, &processed); + while (n) |node| : (n = findCheapestNode(&costs, &processed)) { + var cost = costs.get(node).?; + var neighbors = graph.get(node); + if (neighbors) |nbors| { + var it = nbors.iterator(); + while (it.next()) |neighbor| { + var new_cost = cost + neighbor.value_ptr.*; + if (costs.get(neighbor.key_ptr.*).? > new_cost) { + // update maps if we found a cheaper path + try costs.put(neighbor.key_ptr.*, new_cost); + try parents.put(neighbor.key_ptr.*, node); + } + } + } + try processed.insert(node); + } + + return dijkstraResult{ + .costs = costs, + .path = parents, + }; +} + +/// finds the cheapest node among the not yet processed ones. +fn findCheapestNode(costs: *std.StringHashMap(f32), processed: *std.BufSet) ?[]const u8 { + var lowest_cost = std.math.inf_f32; + var lowest_cost_node: ?[]const u8 = null; + + var it = costs.iterator(); + while (it.next()) |node| { + if (node.value_ptr.* < lowest_cost and !processed.contains(node.key_ptr.*)) { + lowest_cost = node.value_ptr.*; + lowest_cost_node = node.key_ptr.*; + } + } + + return lowest_cost_node; +} + +test "dijkstra" { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer { + arena.deinit(); + const leaked = gpa.deinit(); + if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return + } + + var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator()); + + var start = std.StringHashMap(f32).init(arena.allocator()); + try start.put("a", 6); + try start.put("b", 2); + try graph.put("start", &start); + + var a = std.StringHashMap(f32).init(arena.allocator()); + try a.put("finish", 1); + try graph.put("a", &a); + + var b = std.StringHashMap(f32).init(arena.allocator()); + try b.put("a", 3); + try b.put("finish", 5); + try graph.put("b", &b); + + var fin = std.StringHashMap(f32).init(arena.allocator()); + try graph.put("finish", &fin); + + var result = try dijkstra(arena.allocator(), &graph, "start", "finish"); + + try std.testing.expectEqual(result.costs.get("a").?, 5); + try std.testing.expectEqual(result.costs.get("b").?, 2); + try std.testing.expectEqual(result.costs.get("finish").?, 6); + try std.testing.expectEqual(result.path.get("b").?, "start"); + try std.testing.expectEqual(result.path.get("a").?, "b"); + try std.testing.expectEqual(result.path.get("finish").?, "a"); +} diff --git a/08_greedy_algorithms/zig/set_covering.zig b/08_greedy_algorithms/zig/set_covering.zig new file mode 100644 index 00000000..cf13ab33 --- /dev/null +++ b/08_greedy_algorithms/zig/set_covering.zig @@ -0,0 +1,158 @@ +const std = @import("std"); +const heap = std.heap; +const mem = std.mem; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + var states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; + var states_needed = std.BufSet.init(arena.allocator()); + for (states_needed_array) |sn| { + try states_needed.insert(sn); + } + + var stations = std.StringHashMap(*std.BufSet).init(arena.allocator()); + + var kone = std.BufSet.init(arena.allocator()); + try kone.insert("id"); + try kone.insert("nv"); + try kone.insert("ut"); + try stations.put("kone", &kone); + + var ktwo = std.BufSet.init(arena.allocator()); + try ktwo.insert("wa"); + try ktwo.insert("id"); + try ktwo.insert("mt"); + try stations.put("ktwo", &ktwo); + + var kthree = std.BufSet.init(arena.allocator()); + try kthree.insert("or"); + try kthree.insert("nv"); + try kthree.insert("ca"); + try stations.put("kthree", &kthree); + + var kfour = std.BufSet.init(arena.allocator()); + try kfour.insert("nv"); + try kfour.insert("ut"); + try stations.put("kfour", &kfour); + + var kfive = std.BufSet.init(arena.allocator()); + try kfive.insert("ca"); + try kfive.insert("az"); + try stations.put("kfive", &kfive); + + var stations_covering = try setCovering(arena.allocator(), &stations, &states_needed); + + for (stations_covering) |sc| { + std.debug.print("{s}\n", .{sc}); + } +} + +fn setCovering(allocator: mem.Allocator, stations: *std.StringHashMap(*std.BufSet), states_needed: *std.BufSet) ![][]const u8 { + var final_stations = std.BufSet.init(allocator); + + while (states_needed.count() > 0) { + var best_station: []const u8 = undefined; + var states_covered: [][]const u8 = &[_][]const u8{}; + + var it = stations.iterator(); + while (it.next()) |station| { + var covered = &std.ArrayList([]const u8).init(allocator); + try intersect(states_needed, station.value_ptr.*, covered); + if (covered.items.len > states_covered.len) { + best_station = station.key_ptr.*; + states_covered = covered.items; + } else covered.deinit(); + } + + difference(states_needed, states_covered); + try final_stations.insert(best_station); + } + + var final_array = std.ArrayList([]const u8).init(allocator); + var i = final_stations.iterator(); + while (i.next()) |key| { + try final_array.append(key.*); + } + + return final_array.toOwnedSlice(); +} + +fn intersect(left: *std.BufSet, right: *std.BufSet, intersection: *std.ArrayList([]const u8)) !void { + var l_it = left.iterator(); + var r_it = right.iterator(); + while (l_it.next()) |l| { + while (r_it.next()) |r| { + if (std.mem.eql(u8, l.*, r.*)) { + try intersection.append(l.*); + } + } + } +} + +fn difference(lessening: *std.BufSet, subtracting: [][]const u8) void { + var less_it = lessening.iterator(); + + while (less_it.next()) |less| { + for (subtracting) |sub| { + if (std.mem.eql(u8, less.*, sub)) { + lessening.remove(less.*); + } + } + } +} + +test "setCovering" { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer { + arena.deinit(); + const leaked = gpa.deinit(); + if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return + } + + var states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; + var states_needed = std.BufSet.init(arena.allocator()); + for (states_needed_array) |sn| { + try states_needed.insert(sn); + } + + var stations = std.StringHashMap(*std.BufSet).init(arena.allocator()); + + var kone = std.BufSet.init(arena.allocator()); + try kone.insert("id"); + try kone.insert("nv"); + try kone.insert("ut"); + try stations.put("kone", &kone); + + var ktwo = std.BufSet.init(arena.allocator()); + try ktwo.insert("wa"); + try ktwo.insert("id"); + try ktwo.insert("mt"); + try stations.put("ktwo", &ktwo); + + var kthree = std.BufSet.init(arena.allocator()); + try kthree.insert("or"); + try kthree.insert("nv"); + try kthree.insert("ca"); + try stations.put("kthree", &kthree); + + var kfour = std.BufSet.init(arena.allocator()); + try kfour.insert("nv"); + try kfour.insert("ut"); + try stations.put("kfour", &kfour); + + var kfive = std.BufSet.init(arena.allocator()); + try kfive.insert("ca"); + try kfive.insert("az"); + try stations.put("kfive", &kfive); + + var stations_covering = try setCovering(arena.allocator(), &stations, &states_needed); + + var expectedStations = &[_][]const u8{ "kone", "ktwo", "kfive", "kthree" }; + for (stations_covering) |sc, i| { + try std.testing.expectEqualStrings(expectedStations[i], sc); + } +} diff --git a/09_dynamic_programming/zig/longest_common_subsequence.zig b/09_dynamic_programming/zig/longest_common_subsequence.zig new file mode 100644 index 00000000..b0d59094 --- /dev/null +++ b/09_dynamic_programming/zig/longest_common_subsequence.zig @@ -0,0 +1,63 @@ +const std = @import("std"); +const heap = std.heap; +const math = std.math; +const expect = std.testing.expect; + +pub fn main() !void { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer arena.deinit(); + + var n = try subsequence(arena.allocator(), "fish", "fosh"); + std.debug.print("{d}\n", .{n}); +} + +fn subsequence(allocator: std.mem.Allocator, a: []const u8, b: []const u8) !u32 { + var grid = try allocator.alloc([]u32, a.len + 1); + + for (grid) |*row| { + row.* = try allocator.alloc(u32, b.len + 1); + for (row.*) |*cell| { + cell.* = 0; + } + } + + var i: usize = 1; + while (i <= a.len) : (i += 1) { + var j: usize = 1; + while (j <= b.len) : (j += 1) { + if (a[i - 1] == b[j - 1]) { + grid[i][j] = grid[i - 1][j - 1] + 1; + } else { + grid[i][j] = math.max(grid[i][j - 1], grid[i - 1][j]); + } + } + } + + return grid[a.len][b.len]; +} + +test "subsequence" { + var tests = [_]struct { + a: []const u8, + b: []const u8, + exp: u32, + }{ + .{ .a = "abc", .b = "abcd", .exp = 3 }, + .{ .a = "pera", .b = "mela", .exp = 2 }, + .{ .a = "banana", .b = "kiwi", .exp = 0 }, + }; + + for (tests) |t| { + var gpa = heap.GeneralPurposeAllocator(.{}){}; + var arena = heap.ArenaAllocator.init(gpa.allocator()); + defer { + arena.deinit(); + const leaked = gpa.deinit(); + if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return + } + + var n = try subsequence(arena.allocator(), t.a, t.b); + try expect(n == t.exp); + } +} From 73e5711b738e33fffae6b71069403238126d309c Mon Sep 17 00:00:00 2001 From: phunghocong <48580858+phunghocong@users.noreply.github.com> Date: Sat, 19 Nov 2022 05:52:21 +0700 Subject: [PATCH 093/140] Quick_sort_in sorting (#224) * Update 01_dijkstras_algorithm.go * Create Test_report.binary_quick_sort.cpp.docx * 1 fix * fix it better --- .../{ => quick_sort}/05_quicksort.js | 2 +- .../Test_report.binary_quick_sort.docx | Bin 0 -> 178595 bytes .../Golang/01_dijkstras_algorithm.go | 109 +++++++++++------- 3 files changed, 66 insertions(+), 45 deletions(-) rename 04_quicksort/javascript/{ => quick_sort}/05_quicksort.js (91%) create mode 100644 04_quicksort/javascript/quick_sort/Test_report.binary_quick_sort.docx diff --git a/04_quicksort/javascript/05_quicksort.js b/04_quicksort/javascript/quick_sort/05_quicksort.js similarity index 91% rename from 04_quicksort/javascript/05_quicksort.js rename to 04_quicksort/javascript/quick_sort/05_quicksort.js index 5c45388b..6a8f6a6a 100644 --- a/04_quicksort/javascript/05_quicksort.js +++ b/04_quicksort/javascript/quick_sort/05_quicksort.js @@ -21,4 +21,4 @@ function quicksort(array) { return quicksort(less).concat([pivot], quicksort(greater)); } -console.log(quicksort([10, 5, 2, 3])); // [2, 3, 5, 10] +console.log(quicksort([10, 5, 2, 3])); diff --git a/04_quicksort/javascript/quick_sort/Test_report.binary_quick_sort.docx b/04_quicksort/javascript/quick_sort/Test_report.binary_quick_sort.docx new file mode 100644 index 0000000000000000000000000000000000000000..042c1977a746a772f8d50f9e6d5cb7a8ad1e9c10 GIT binary patch literal 178595 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 TzafD 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%0At8jLqL6#bQ3*9e(MH9SbI=2FWw#Ld%n-WV89BuM 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 literal 0 HcmV?d00001 diff --git a/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go b/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go index b25fb001..73b22743 100644 --- a/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go +++ b/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go @@ -5,69 +5,90 @@ import ( "math" ) +var graph map[string]map[string]float64 +var costs map[string]float64 +var parents map[string]string +var processed []string + func main() { - graph := make(map[string]map[string]int) - graph["start"] = map[string]int{} + // the graph + graph = make(map[string]map[string]float64) + graph["start"] = make(map[string]float64) graph["start"]["a"] = 6 graph["start"]["b"] = 2 - graph["a"] = map[string]int{} - graph["a"]["finish"] = 1 + graph["a"] = make(map[string]float64) + graph["a"]["fin"] = 1 - graph["b"] = map[string]int{} + graph["b"] = make(map[string]float64) graph["b"]["a"] = 3 - graph["b"]["finish"] = 5 + graph["b"]["fin"] = 5 - graph["finish"] = map[string]int{} + graph["fin"] = make(map[string]float64) - costs, parents := findShortestPath(graph, "start", "finish") - fmt.Println(costs, parents) -} + // the costs table + costs = make(map[string]float64) + costs["a"] = 6 + costs["b"] = 2 + costs["fin"] = math.Inf(1) -// Finds shortest path using dijkstra algorithm -func findShortestPath(graph map[string]map[string]int, startNode string, finishNode string) (map[string]int, map[string]string) { - costs := make(map[string]int) - costs[finishNode] = math.MaxInt32 + // the parents table + parents = make(map[string]string) + parents["a"] = "start" + parents["b"] = "start" + parents["fin"] = "" - parents := make(map[string]string) - parents[finishNode] = "" + // Find the lowest-cost node that you haven't processed yet. + node := find_lowest_cost_node(costs) + // If you've processed all the nodes, this while loop is done. - processed := make(map[string]bool) + for node != "" { + cost := costs[node] + // Go through all the neighbors of this node. + neighbors := graph[node] - // Initialization of costs and parents - for node, cost := range graph[startNode] { - costs[node] = cost - parents[node] = startNode - } - - lowestCostNode := findLowestCostNode(costs, processed) - for ; lowestCostNode != "" ; { - // Calculation costs for neighbours - for node, cost := range graph[lowestCostNode] { - newCost := costs[lowestCostNode] + cost - if newCost < costs[node] { - // Set new cost for this node - costs[node] = newCost - parents[node] = lowestCostNode + for node, _ := range neighbors { + new_cost := cost + neighbors[node] + // If it's cheaper to get to this neighbor by going through this node... + if costs[node] > new_cost { + // ... update the cost for this node. + costs[node] = new_cost + // This node becomes the new parent for this neighbor. + parents[node] = node } } - - processed[lowestCostNode] = true - lowestCostNode = findLowestCostNode(costs, processed) + // Mark the node as processed. + processed = append(processed, node) + // Find the next node to process, and loop. + node = find_lowest_cost_node(costs) } - return costs, parents + fmt.Println(costs) + } -func findLowestCostNode(costs map[string]int, processed map[string]bool) string { - lowestCost := math.MaxInt32 - lowestCostNode := "" - for node, cost := range costs { - if _, inProcessed := processed[node]; cost < lowestCost && !inProcessed { - lowestCost = cost - lowestCostNode = node +func find_lowest_cost_node(costs map[string]float64) string { + lowest_cost := math.Inf(1) + lowest_cost_node := "" + + for node, _ := range costs { + // fmt.Println("Node:", node, "Value:", value) + cost := costs[node] + // If it's the lowest cost so far and hasn't been processed yet... + if cost < lowest_cost && !contains(processed, node) { + // ... set it as the new lowest-cost node. + lowest_cost = cost + lowest_cost_node = node } } + return lowest_cost_node +} - return lowestCostNode +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false } From fa75dc144dd52c906543f1fe5e40e49b5e8d343c Mon Sep 17 00:00:00 2001 From: Carlos <110995013+crr004@users.noreply.github.com> Date: Mon, 30 Jan 2023 17:38:56 +0100 Subject: [PATCH 094/140] Added #include to support the use of INT_MAX (#251) --- 02_selection_sort/c/01_selection_sort.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/02_selection_sort/c/01_selection_sort.c b/02_selection_sort/c/01_selection_sort.c index c0a511ee..169e3e5c 100644 --- a/02_selection_sort/c/01_selection_sort.c +++ b/02_selection_sort/c/01_selection_sort.c @@ -1,5 +1,6 @@ #include #include +#include #define SIZE 5 // Finds the smallest value in an array @@ -37,4 +38,4 @@ int main(void) { printf("%d ", sortarr[i]); } return 0; -} \ No newline at end of file +} From f53fe3b98abfc85b0d9201747caf0f6959ae7cfe Mon Sep 17 00:00:00 2001 From: Pere Frontera Date: Wed, 19 Jul 2023 17:49:01 +0200 Subject: [PATCH 095/140] SelectionSort csharp using array as input (#226) Co-authored-by: Pere --- .../csharp/01_selection_sort/Program.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/02_selection_sort/csharp/01_selection_sort/Program.cs b/02_selection_sort/csharp/01_selection_sort/Program.cs index 4b5a1bd0..77d0a09a 100644 --- a/02_selection_sort/csharp/01_selection_sort/Program.cs +++ b/02_selection_sort/csharp/01_selection_sort/Program.cs @@ -37,5 +37,24 @@ private static int FindSmallest(List arr) } return smallestIndex; } + + public static int[] SelectionSort(int[] unorderedArray) + { + for (var i = 0; i < unorderedArray.Length; i++) + { + var smallestIndex = i; + + for (var remainingIndex = i + 1; remainingIndex < unorderedArray.Length; remainingIndex++) + { + if (unorderedArray[remainingIndex] < unorderedArray[smallestIndex]) + { + smallestIndex = remainingIndex; + } + } + (unorderedArray[i], unorderedArray[smallestIndex]) = (unorderedArray[smallestIndex], unorderedArray[i]); + } + + return unorderedArray; + } } -} +} \ No newline at end of file From ed5a723fa5782057f604be2156a643fff3faf168 Mon Sep 17 00:00:00 2001 From: Alexandr <32848544+ManSnowThe@users.noreply.github.com> Date: Wed, 19 Jul 2023 21:49:54 +0600 Subject: [PATCH 096/140] Csharp updates for 4, 9 chapters (#245) * GetGCDList fix * Csharp longest_common_subsequence update * Csharp levenshtein added * Couple changes in levenshtein --- 04_quicksort/csharp/06_GetGCD/program.cs | 39 +++++++----- .../01_longest_common_subsequence/Program.cs | 60 +++++++++++++++++-- .../csharp/02_levenshtein/Program.cs | 46 ++++++++++++++ 3 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 09_dynamic_programming/csharp/02_levenshtein/Program.cs diff --git a/04_quicksort/csharp/06_GetGCD/program.cs b/04_quicksort/csharp/06_GetGCD/program.cs index 64abed27..51bc3851 100644 --- a/04_quicksort/csharp/06_GetGCD/program.cs +++ b/04_quicksort/csharp/06_GetGCD/program.cs @@ -4,28 +4,37 @@ namespace GCD { - public class program + public class Program { + static void Main(string[] args) + { + var lst = new List { 32, 696, 40, 50 }; + var GCD = GetGCD(640, 1680); + var GCDList = GetGCDList(lst); + + Console.WriteLine(GCD); + Console.WriteLine(GCDList); + } //Get great Comman Divisor - public static int GetGCD(int FirstNumber, int SecondNumber) - => SecondNumber == default ? FirstNumber : GetGCD(SecondNumber, FirstNumber % SecondNumber); + public static int GetGCD(int firstNumber, int secondNumber) + => secondNumber == default ? firstNumber : GetGCD(secondNumber, firstNumber % secondNumber); //Get great Comman Divisor of list - public static int GetGCDList(List lst) + public static int GetGCDList(IEnumerable lst) { - var result = lst[0]; - result = GetGCD(result, lst.Skip(1).FirstOrDefault()); - return result; - } + var result = lst.FirstOrDefault(); - static void Main(string[] args) - { - var lst = new List { 32,696,40,50 }; - var GCD = GetGCD( 640, 1680); - var GCDList = GetGCDList(lst); - Console.WriteLine(GCD); - Console.WriteLine(GCDList); + if (lst.Count() > 2) + { + result = GetGCD(result, GetGCDList(lst.Skip(1))); + } + else + { + result = GetGCD(result, lst.Skip((1)).FirstOrDefault()); + } + + return result; } } } \ No newline at end of file diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs b/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs index 63ebdbae..83f10d49 100644 --- a/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs +++ b/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs @@ -6,15 +6,67 @@ public class Program { public static void Main(string[] args) { + var result = LongestCommonSubsequence("fish", "vistafh"); + Console.WriteLine($"{result.Item1}: {result.Item2}"); // ish: 3 + } + + public static (string, int) LongestCommonSubsequence(string word1, string word2) + { + if (string.IsNullOrEmpty(word1) || string.IsNullOrEmpty(word2)) + return ("", 0); - if (word_a[i] == word_b[1]) + string subSeq; + var matrix = new int[word1.Length + 1, word2.Length + 1]; + + for (int i = 1; i <= word1.Length; i++) { - cell[i][j] = cell[i - 1][j - 1] + 1; + for (int j = 1; j <= word2.Length; j++) + { + if (word1[i - 1] == word2[j - 1]) + { + matrix[i, j] = matrix[i - 1, j - 1] + 1; + } + else + { + matrix[i, j] = Math.Max(matrix[i, j - 1], matrix[i - 1, j]); + } + } } - else + + subSeq = Read(matrix, word1, word2); + + return (subSeq, subSeq.Length); + } + + private static string Read(int[,] matrix, string word1, string word2) + { + string subSeq = null; + int x = word1.Length; + int y = word2.Length; + + while (x > 0 && y > 0) { - cell[i][j] = Math.Max(cell[i - 1][j], cell[i][j - 1]); + if (word1[x - 1] == word2[y - 1]) + { + subSeq += word1[x - 1]; + x--; + y--; + } + else if (matrix[x - 1, y] > matrix[x, y - 1]) + { + x--; + } + else + { + y--; + } } + + var charArray = subSeq.ToCharArray(); + Array.Reverse(charArray); + subSeq = new string(charArray); + + return subSeq; } } } diff --git a/09_dynamic_programming/csharp/02_levenshtein/Program.cs b/09_dynamic_programming/csharp/02_levenshtein/Program.cs new file mode 100644 index 00000000..29704c63 --- /dev/null +++ b/09_dynamic_programming/csharp/02_levenshtein/Program.cs @@ -0,0 +1,46 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static int LevenshteinDistance(string source, string target) + { + var matrix = CreateMatrix(source, target); + + for (int i = 1; i <= source.Length; i++) + { + for (int j = 1; j <= target.Length; j++) + { + matrix[i, j] = Math.Min(matrix[i, j - 1] + 1, Math.Min( + matrix[i - 1, j] + 1, + matrix[i - 1, j - 1] + (source[i - 1] != target[j - 1] ? 1 : 0))); + } + } + + return matrix[source.Length, target.Length]; + } + + private static int[,] CreateMatrix(string source, string target) + { + var matrix = new int[source.Length + 1, target.Length + 1]; + + if (source.Length < target.Length) + { + (source, target) = (target, source); + } + + for (int i = 0; i <= source.Length; i++) + { + matrix[i, 0] = i; + + if (i <= target.Length) + { + matrix[0, i] = i; + } + } + + return matrix; + } + } +} From 4d324e464d40d91888492b81b099a8a714879bb9 Mon Sep 17 00:00:00 2001 From: Nikita Date: Wed, 19 Jul 2023 18:51:10 +0300 Subject: [PATCH 097/140] small refactoring for better code readability (#247) --- 02_selection_sort/java/src/SelectionSort2.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/02_selection_sort/java/src/SelectionSort2.java b/02_selection_sort/java/src/SelectionSort2.java index 5b6b5668..9c389997 100644 --- a/02_selection_sort/java/src/SelectionSort2.java +++ b/02_selection_sort/java/src/SelectionSort2.java @@ -3,15 +3,13 @@ public class SelectionSort2 { // this version uses raw arrays instead of ArrayList - public static void selectionSort(int[] target) { - for (int i = 0; i < target.length - 1; i++) { - int left = target[i]; - for (int j = i + 1; j < target.length; j++) { - int right = target[j]; - if (left > right) { - target[i] = right; - target[j] = left; - left = right; + public static void selectionSort(int[] arr) { + for (int i = 0; i < arr.length-1; i++) { + for (int j = i+1; j < arr.length; j++) { + if (arr[j] < arr[i]) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; } } } From f6cd99c88be4aa19fd761b880f8e9353d4bf9092 Mon Sep 17 00:00:00 2001 From: k1borgG <69363313+k1borgG@users.noreply.github.com> Date: Wed, 19 Jul 2023 18:51:46 +0300 Subject: [PATCH 098/140] Create 04_recursive_max.py (#249) Problem with max definition. If in input list last element is the biggest, the present algorithm is'n count it. I solved this problem by changing the return in the case if length == 1 from return 1 to first element of list. --- 04_quicksort/python/04_recursive_max.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/04_quicksort/python/04_recursive_max.py b/04_quicksort/python/04_recursive_max.py index 908c31ac..717e4f95 100644 --- a/04_quicksort/python/04_recursive_max.py +++ b/04_quicksort/python/04_recursive_max.py @@ -1,8 +1,8 @@ -def max_(lst): - if len(lst) == 0: - return None - if len(lst) == 1: - return lst[0] - else: - sub_max = max_(lst[1:]) - return lst[0] if lst[0] > sub_max else sub_max +def max(lst): + if len(lst) == 0: + return None + if len(lst) == 1: + return lst[0] + else: + max_num = max(lst[1:]) + return lst[0] if lst[0] > max_num else max_num From 60b34a01d56d11d621e70f386cdfca3af5455c56 Mon Sep 17 00:00:00 2001 From: Carlos <110995013+crr004@users.noreply.github.com> Date: Wed, 19 Jul 2023 17:53:01 +0200 Subject: [PATCH 099/140] Line removed (#252) * Added #include to support the use of INT_MAX * Removed unnecesary (and maybe confusing) initialization of the set --- 08_greedy_algorithms/python/01_set_covering.py | 1 - 1 file changed, 1 deletion(-) diff --git a/08_greedy_algorithms/python/01_set_covering.py b/08_greedy_algorithms/python/01_set_covering.py index d2fa08ae..10d919eb 100644 --- a/08_greedy_algorithms/python/01_set_covering.py +++ b/08_greedy_algorithms/python/01_set_covering.py @@ -8,7 +8,6 @@ stations["kfour"] = set(["nv", "ut"]) stations["kfive"] = set(["ca", "az"]) -final_stations = set() def my_set_covering(states_needed, stations): final_stations = set() From 7620449322d93beb2c62c3226e3851f867bf4e5f Mon Sep 17 00:00:00 2001 From: Robson Cruz Date: Wed, 19 Jul 2023 12:53:24 -0300 Subject: [PATCH 100/140] Added R version of the binary_search function (#253) --- .../R/binary_search.R | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 01_introduction_to_algorithms/R/binary_search.R diff --git a/01_introduction_to_algorithms/R/binary_search.R b/01_introduction_to_algorithms/R/binary_search.R new file mode 100644 index 00000000..7d914075 --- /dev/null +++ b/01_introduction_to_algorithms/R/binary_search.R @@ -0,0 +1,37 @@ +binary_search <- function(list, item) { + # low and high keep track of which part of the list you'll search in. + # Every data structure in R indexed by starting at 1. + low <- 1 + high <- length(list) + + # While you haven't narrowed it down to one element ... + while (low <= high) { + # ... check the middle element + mid <- (low + high) %/% 2 + guess <- list[mid] + # Found the item. + if (guess == item) { + return(mid) + } + # The guess was too high. + else if (guess > item) { + high <- mid - 1 + } + else{ # The guess was too low. + low <- mid + 1 + } + } + # Item doesn't exist + return(NULL) +} + + +# Set a list +my_list <- list(1, 3, 5, 7, 9) + +# Call the function +binary_search(my_list, 3) # => 1 +binary_search(my_list, -1) # => NULL + +# All above code can be simplified by using "which" function +which(my_list == 3) # => 1 From 4dddd5aa830040e9525ba34b30314f6e34560ec8 Mon Sep 17 00:00:00 2001 From: TheDexire <80020807+TheDexire@users.noreply.github.com> Date: Wed, 19 Jul 2023 21:56:17 +0600 Subject: [PATCH 101/140] Update 05_quicksort.swift (#257) --- 04_quicksort/swift/05_quicksort.swift | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/04_quicksort/swift/05_quicksort.swift b/04_quicksort/swift/05_quicksort.swift index e017b4d8..9449921e 100644 --- a/04_quicksort/swift/05_quicksort.swift +++ b/04_quicksort/swift/05_quicksort.swift @@ -2,20 +2,17 @@ import Foundation //The following implementation of quick sort is little more classic than described in the book, but we have two use this one because of some “slice” feature limitation with array on Swift 3. Main concept is the same func quicksort (_ array : [T]) -> [T] { - if (array.count < 2) { - // base case, arrays with 0 or 1 element are already "sorted" - return array - } else { - // recursive case - let pivot = array[0] - // sub-array of all the elements less than the pivot - let less = array.filter { $0 < pivot } - // sub-array of all the elements equal to the pivot - let equal = array.filter { $0 == pivot } - // sub-array of all the elements greater than the pivot - let greater = array.filter { $0 > pivot } - return quicksort(less) + equal + quicksort(greater) - } + // base case, arrays with 0 or 1 element are already "sorted" + guard array.count > 1 else { return array } + // recursive case + let pivot = array[0] + // sub-array of all the elements less than the pivot + let less = array.filter { $0 < pivot } + // sub-array of all the elements equal to the pivot + let equal = array.filter { $0 == pivot } + // sub-array of all the elements greater than the pivot + let greater = array.filter { $0 > pivot } + return quicksort(less) + equal + quicksort(greater) } print(quicksort([1, 5, 10, 25, 16, 1])) // => [1, 1, 5, 10, 16, 25] From 022d97a56d3e4b56dce958b55f9652660717d292 Mon Sep 17 00:00:00 2001 From: Aslan Autlev Date: Wed, 19 Jul 2023 18:56:40 +0300 Subject: [PATCH 102/140] Add examples on scheme. Chapters: 1, 2 (#258) * add 01_binary_search.scm in 01_introduction_to_algorithms * any fix * add 01_selection_sort.scm to 02_selection_sort * any fix --- .../scheme/01_binarysearch.scm | 14 +++++++ .../scheme/01_selection_sort.scm | 37 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 01_introduction_to_algorithms/scheme/01_binarysearch.scm create mode 100644 02_selection_sort/scheme/01_selection_sort.scm diff --git a/01_introduction_to_algorithms/scheme/01_binarysearch.scm b/01_introduction_to_algorithms/scheme/01_binarysearch.scm new file mode 100644 index 00000000..66525103 --- /dev/null +++ b/01_introduction_to_algorithms/scheme/01_binarysearch.scm @@ -0,0 +1,14 @@ +(define (binary-search my-list item) + (iter my-list item 0 (- (length my-list) 1))) + +(define (iter my-list item low high) + (if (> low high) 'nill + (let* ((mid (floor (/ (+ low high) 2))) + (guess (list-ref my-list mid))) + (cond ((eqv? guess item) mid) + ((> guess item) (iter my-list item low (- mid 1))) + (else (iter my-list item (+ mid 1) high)))))) + + +(display (binary-search (list 1 3 5 7 9) 3)) ;; 1 +(display (binary-search (list 1 3 5 7 9) -1)) ;; nill diff --git a/02_selection_sort/scheme/01_selection_sort.scm b/02_selection_sort/scheme/01_selection_sort.scm new file mode 100644 index 00000000..e6d3e723 --- /dev/null +++ b/02_selection_sort/scheme/01_selection_sort.scm @@ -0,0 +1,37 @@ +(define (find-smallest my-list) + (let ((smallest (list-ref my-list 0)) + (smallest-i 0) + (i 0) + (last-index (- (length my-list) 1))) + (iter-find my-list smallest-i smallest i last-index))) + +(define (iter-find my-list smallest-i smallest i last-index) + (if (> i last-index) + smallest-i + (let ((my-list-i (list-ref my-list i))) + (if (< my-list-i smallest) + (iter-find my-list i my-list-i (+ i 1) last-index) + (iter-find my-list smallest-i smallest (+ i 1) last-index))))) + + +(define (selection-sort my-list) + (let* ((my-list-length (length my-list)) + (result (list)) + (i 0) + (last-i (- my-list-length 1))) + (iter-sort my-list i last-i result))) + +(define (iter-sort my-list i last-i result) + (if (> i last-i) + result + (let* ((smallest-i (find-smallest my-list)) + (smallest (list-ref my-list smallest-i)) + (filtered-list (filter (lambda (n) (not (= n smallest))) + my-list)) + (new-result (append result (list smallest)))) + (iter-sort filtered-list (+ i 1) last-i new-result)))) + + +(display (selection-sort (list 1 3 5 7 9))) ;; #(1 3 5 7 9) +(display (selection-sort (list 9 7 5 3 1))) ;; #(1 3 5 7 9) +(display (selection-sort (list 9 5 7 1 3))) ;; #(1 3 5 7 9) From 182f89b2c4435e614bd9e208c153b4a06efccc03 Mon Sep 17 00:00:00 2001 From: aestheticw3 <48285878+aestheticw3@users.noreply.github.com> Date: Wed, 9 Aug 2023 06:09:34 +0700 Subject: [PATCH 103/140] square brackets fix (#263) --- .../javascript/quick_sort/05_quicksort.js | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/04_quicksort/javascript/quick_sort/05_quicksort.js b/04_quicksort/javascript/quick_sort/05_quicksort.js index 6a8f6a6a..483baf30 100644 --- a/04_quicksort/javascript/quick_sort/05_quicksort.js +++ b/04_quicksort/javascript/quick_sort/05_quicksort.js @@ -6,19 +6,19 @@ * @returns {Array} Sorted array */ function quicksort(array) { - // base case, arrays with 0 or 1 element are already "sorted" - if (array.length < 2) return array; - // recursive case - let pivot = array[0]; - // sub-array of all the elements less than the pivot - let less = array.slice(1).filter(function(el) { - return el <= pivot; - }); - // sub-array of all the elements greater than the pivot - let greater = array.slice(1).filter(function(el) { - return el > pivot; - }); - return quicksort(less).concat([pivot], quicksort(greater)); + // base case, arrays with 0 or 1 element are already "sorted" + if (array.length < 2) return array; + // recursive case + let pivot = array[0]; + // sub-array of all the elements less than the pivot + let less = array.slice(1).filter(function (el) { + return el <= pivot; + }); + // sub-array of all the elements greater than the pivot + let greater = array.slice(1).filter(function (el) { + return el > pivot; + }); + return quicksort(less).concat(pivot, quicksort(greater)); } -console.log(quicksort([10, 5, 2, 3])); +console.log(quicksort([10, 5, 2, 3])); From 3e99cccfc08b22895de53218e94401504f94a6b0 Mon Sep 17 00:00:00 2001 From: Gabriel Santos <87038139+01Explorer@users.noreply.github.com> Date: Tue, 8 Aug 2023 20:10:15 -0300 Subject: [PATCH 104/140] Added Dart examples for chapter 3 to chapter 9 (#265) * fix: corrected method return value following Dart's newest linter version * feat: added Dart recursion examples for chapter 3 * feat: added quicksort example in Dart for chapter 4 * feat: added examples in Dart for the chapter 5 * feat: added Dart example for chapter 6 bfs * feat: added djikstra example in Dart for chapter 7 * feat: added example of set covering in Dart for chapter 8 * feat: added examples for dynamic programming in dart for chapter 9 --- .../dart/binary_search.dart | 1 + 03_recursion/dart/01_countdown/countdown.dart | 14 ++++ 03_recursion/dart/02_sum/sum.dart | 14 ++++ 03_recursion/dart/03_factorial/factorial.dart | 13 ++++ 04_quicksort/dart/04_quicksort/quicksort.dart | 21 ++++++ .../dart/01_price_of_groceries.dart | 15 ++++ 05_hash_tables/dart/02_check_voter.dart | 16 +++++ .../dart/01_breadth-first_search.dart | 42 +++++++++++ .../dart/01_djikstra_algorithm.dart | 72 +++++++++++++++++++ .../dart/01_set_covering.dart | 52 ++++++++++++++ .../dart/01_longest_common_subsequence.dart | 27 +++++++ .../dart/02_longest_common_substring.dart | 25 +++++++ 12 files changed, 312 insertions(+) create mode 100644 03_recursion/dart/01_countdown/countdown.dart create mode 100644 03_recursion/dart/02_sum/sum.dart create mode 100644 03_recursion/dart/03_factorial/factorial.dart create mode 100644 04_quicksort/dart/04_quicksort/quicksort.dart create mode 100644 05_hash_tables/dart/01_price_of_groceries.dart create mode 100644 05_hash_tables/dart/02_check_voter.dart create mode 100644 06_breadth-first_search/dart/01_breadth-first_search.dart create mode 100644 07_dijkstras_algorithm/dart/01_djikstra_algorithm.dart create mode 100644 08_greedy_algorithms/dart/01_set_covering.dart create mode 100644 09_dynamic_programming/dart/01_longest_common_subsequence.dart create mode 100644 09_dynamic_programming/dart/02_longest_common_substring.dart diff --git a/01_introduction_to_algorithms/dart/binary_search.dart b/01_introduction_to_algorithms/dart/binary_search.dart index a0bcf91e..62041392 100644 --- a/01_introduction_to_algorithms/dart/binary_search.dart +++ b/01_introduction_to_algorithms/dart/binary_search.dart @@ -22,4 +22,5 @@ int? binarySearch(List list, int item) { low = mid + 1; } } + return null; } diff --git a/03_recursion/dart/01_countdown/countdown.dart b/03_recursion/dart/01_countdown/countdown.dart new file mode 100644 index 00000000..9c93f39d --- /dev/null +++ b/03_recursion/dart/01_countdown/countdown.dart @@ -0,0 +1,14 @@ +main() { + final Stopwatch stopwatch = Stopwatch()..start(); + print(recursiveCount([0, 21, 3, 1, 6, 5, 81, 2, 14, 56, 32, 1, 9, 8])); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +int recursiveCount(List array) { + if (array.isEmpty) { + return 0; + } + final List newArray = [...array]..removeAt(0); + return 1 + recursiveCount(newArray); +} diff --git a/03_recursion/dart/02_sum/sum.dart b/03_recursion/dart/02_sum/sum.dart new file mode 100644 index 00000000..b1d4c8a3 --- /dev/null +++ b/03_recursion/dart/02_sum/sum.dart @@ -0,0 +1,14 @@ +void main(List args) { + final Stopwatch stopwatch = Stopwatch()..start(); + print(recursiveSum([0, 21, 3, 1, 6, 5, 81, 2, 14, 56, 32, 1, 9, 8])); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +int recursiveSum(List array) { + if (array.isEmpty) { + return 0; + } + final List newArray = [...array]..removeAt(0); + return array[0] + recursiveSum(newArray); +} diff --git a/03_recursion/dart/03_factorial/factorial.dart b/03_recursion/dart/03_factorial/factorial.dart new file mode 100644 index 00000000..b6bce640 --- /dev/null +++ b/03_recursion/dart/03_factorial/factorial.dart @@ -0,0 +1,13 @@ +void main(List args) { + final Stopwatch stopwatch = Stopwatch()..start(); + print(recursiveFactorial(5)); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +int recursiveFactorial(int value) { + if (value == 1) { + return 1; + } + return value * recursiveFactorial(value - 1); +} diff --git a/04_quicksort/dart/04_quicksort/quicksort.dart b/04_quicksort/dart/04_quicksort/quicksort.dart new file mode 100644 index 00000000..a7803072 --- /dev/null +++ b/04_quicksort/dart/04_quicksort/quicksort.dart @@ -0,0 +1,21 @@ +void main(List args) { + final Stopwatch stopwatch = Stopwatch()..start(); + print(quickSort([0, 21, 3, 1, 6, 5, 0, 81, 2, 14, 56, 32, 1, 9, 8])); + stopwatch.stop(); + print(stopwatch.elapsedMilliseconds); +} + +List quickSort(List toOrder) { + if (toOrder.length < 2) { + return toOrder; + } + final int mid = toOrder.length ~/ 2; + + final int pivot = toOrder[mid]; + toOrder.removeAt(mid); + final List lowers = + List.from(toOrder.where((element) => element <= pivot)); + final List highers = + List.from(toOrder.where((element) => element > pivot)); + return quickSort(lowers) + [pivot] + quickSort(highers); +} diff --git a/05_hash_tables/dart/01_price_of_groceries.dart b/05_hash_tables/dart/01_price_of_groceries.dart new file mode 100644 index 00000000..1aff6ad4 --- /dev/null +++ b/05_hash_tables/dart/01_price_of_groceries.dart @@ -0,0 +1,15 @@ +void main(List args) { + final book = {}; + book.addAll( + { + 'apple': 0.67, + 'milk': 1.49, + 'avocado': 1.49, + }, + ); + + print(book); + print(book['apple']); + print(book['milk']); + print(book['avocado']); +} diff --git a/05_hash_tables/dart/02_check_voter.dart b/05_hash_tables/dart/02_check_voter.dart new file mode 100644 index 00000000..b4912949 --- /dev/null +++ b/05_hash_tables/dart/02_check_voter.dart @@ -0,0 +1,16 @@ +void main(List args) { + final voted = {}; + + checkVoter('tom', voted); + checkVoter('mike', voted); + checkVoter('mike', voted); +} + +void checkVoter(String name, Map voted) { + if (voted[name] != null) { + print('Kick them out!'); + } else { + voted[name] = true; + print('Let them vote'); + } +} diff --git a/06_breadth-first_search/dart/01_breadth-first_search.dart b/06_breadth-first_search/dart/01_breadth-first_search.dart new file mode 100644 index 00000000..4b741c4c --- /dev/null +++ b/06_breadth-first_search/dart/01_breadth-first_search.dart @@ -0,0 +1,42 @@ +import 'dart:collection'; + +void main(List args) { + final graph = >{}; + graph.addAll( + >{ + 'you': ['alice', 'bob', 'claire'], + 'bob': ['anuj', 'peggy'], + 'alice': ['peggy'], + 'claire': ['thom', 'jonny'], + 'anuj': [], + 'peggy': [], + 'thom': [], + 'jonny': [], + }, + ); + + search(graph, 'you'); +} + +bool search(Map> graph, String name) { + final searchQueue = Queue()..addAll(graph[name] ?? []); + final searched = List.empty(growable: true); + + while (searchQueue.isNotEmpty) { + final String person = searchQueue.removeFirst(); + if (searched.contains(person) == false) { + if (_personIsSeller(person)) { + print('$person is a Mango seller!'); + return true; + } else { + searchQueue.addAll(graph[person] ?? []); + searched.add(person); + } + } + } + return false; +} + +bool _personIsSeller(String name) { + return name.endsWith('m'); +} diff --git a/07_dijkstras_algorithm/dart/01_djikstra_algorithm.dart b/07_dijkstras_algorithm/dart/01_djikstra_algorithm.dart new file mode 100644 index 00000000..35612870 --- /dev/null +++ b/07_dijkstras_algorithm/dart/01_djikstra_algorithm.dart @@ -0,0 +1,72 @@ +void main(List args) { + final graph = >{}..addAll( + { + 'start': { + 'a': 6, + 'b': 2, + }, + 'a': { + 'end': 1, + }, + 'b': { + 'a': 3, + 'end': 5, + }, + 'end': {}, + }, + ); + + final costs = { + 'a': 6, + 'b': 2, + 'end': double.infinity, + }; + + final parents = { + 'a': 'start', + 'b': 'start', + 'end': null, + }; + + djikstra(graph, costs, parents); + print(graph); + print(costs); + print(parents); +} + +void djikstra( + Map> graph, + Map costs, + Map parents, +) { + final processeds = []; + String? node = findTheCheapestOne(costs, processeds); + + while (node != null) { + final cost = costs[node]; + final neighbors = graph[node]; + for (String neighbor in neighbors!.keys) { + final double newCost = cost! + neighbors[neighbor]!; + if (costs[neighbor]! > newCost) { + costs[neighbor] = newCost; + parents[neighbor] = node; + } + } + processeds.add(node); + node = findTheCheapestOne(costs, processeds); + } +} + +String? findTheCheapestOne(Map costs, List processed) { + double cheapestCost = double.infinity; + String? cheapestNode; + + for (String node in costs.keys) { + final double cost = costs[node]!; + if (cost < cheapestCost && !processed.contains(node)) { + cheapestCost = cost; + cheapestNode = node; + } + } + return cheapestNode; +} diff --git a/08_greedy_algorithms/dart/01_set_covering.dart b/08_greedy_algorithms/dart/01_set_covering.dart new file mode 100644 index 00000000..de3a9644 --- /dev/null +++ b/08_greedy_algorithms/dart/01_set_covering.dart @@ -0,0 +1,52 @@ +void main(List args) { + final fruits = {'avocado', 'tomato', 'banana'}; + final vegetables = {'beet', 'carrot', 'tomato'}; + + print(fruits.union(vegetables)); + print(fruits.intersection(vegetables)); + print(fruits.difference(vegetables)); + print(vegetables.difference(fruits)); + + final coverStates = { + 'mt', + 'wa', + 'or', + 'id', + 'nv', + 'ut', + 'ca', + 'az', + }; + + final stations = >{}..addAll( + { + 'kone': {'id', 'nv', 'uy'}, + 'ktwo': {'wa', 'id', 'mt'}, + 'kthree': {'or', 'nv', 'ca'}, + 'kfour': {'nv', 'ut'}, + 'kfive': {'ca', 'az'}, + }, + ); + + final finalStations = stationSet(coverStates, stations); + print(finalStations); +} + +Set stationSet( + Set coverStates, Map> stations) { + final finalStations = {}; + while (coverStates.isNotEmpty) { + String? bestStation; + Set coveredStates = {}; + for (String station in stations.keys) { + final covered = coverStates.intersection(stations[station] ?? {}); + if (covered.length > coveredStates.length) { + bestStation = station; + coveredStates = covered; + } + } + coverStates.removeWhere((element) => coveredStates.contains(element)); + finalStations.add(bestStation!); + } + return finalStations; +} diff --git a/09_dynamic_programming/dart/01_longest_common_subsequence.dart b/09_dynamic_programming/dart/01_longest_common_subsequence.dart new file mode 100644 index 00000000..ae621ab0 --- /dev/null +++ b/09_dynamic_programming/dart/01_longest_common_subsequence.dart @@ -0,0 +1,27 @@ +void main(List args) { + final table = longestCommonSubsequence('blue', 'clues'); + + for (List element in table) { + print(element); + } +} + +List> longestCommonSubsequence(String word1, String word2) { + final tableWord1 = word1.split(''); + final tableWord2 = word2.split(''); + final table = List.generate( + tableWord2.length, (index) => List.filled(tableWord1.length, 0)); + + for (int i = 0; i < tableWord1.length; i++) { + for (int j = 0; j < tableWord2.length; j++) { + if (tableWord2[j] == tableWord1[i]) { + table[j][i] = (j - 1 >= 0 && i - 1 >= 0) ? table[j - 1][i - 1] + 1 : 1; + } else { + final top = (j - 1 >= 0) ? table[j - 1][i] : 0; + final left = (i - 1 >= 0) ? table[j][i - 1] : 0; + table[j][i] = (top > left) ? top : left; + } + } + } + return table; +} diff --git a/09_dynamic_programming/dart/02_longest_common_substring.dart b/09_dynamic_programming/dart/02_longest_common_substring.dart new file mode 100644 index 00000000..7a7d9582 --- /dev/null +++ b/09_dynamic_programming/dart/02_longest_common_substring.dart @@ -0,0 +1,25 @@ +void main(List args) { + final table = longestCommonSubstring('fish', 'hish'); + + for (List element in table) { + print(element); + } +} + +List> longestCommonSubstring(String word1, String word2) { + final tableWord1 = word1.split(''); + final tableWord2 = word2.split(''); + final table = List.generate( + tableWord2.length, (index) => List.filled(tableWord1.length, 0)); + + for (int i = 0; i < tableWord1.length; i++) { + for (int j = 0; j < tableWord2.length; j++) { + if (tableWord2[j] == tableWord1[i]) { + table[j][i] = table[j - 1][j - 1] + 1; + } else { + table[j][i] = 0; + } + } + } + return table; +} From 8969269a10e2ed194b9b8b163ff91f2a75bee6c6 Mon Sep 17 00:00:00 2001 From: Adnan Date: Wed, 9 Aug 2023 02:40:53 +0330 Subject: [PATCH 105/140] Update 04_recursive_max.kt (#266) add an argument to when block --- 04_quicksort/kotlin/04_recursive_max.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/04_quicksort/kotlin/04_recursive_max.kt b/04_quicksort/kotlin/04_recursive_max.kt index ab887521..f7b39330 100644 --- a/04_quicksort/kotlin/04_recursive_max.kt +++ b/04_quicksort/kotlin/04_recursive_max.kt @@ -1,5 +1,5 @@ -private fun max(list: IntArray): Int = when { - list.size == 2 -> if (list[0] > list[1]) list[0] else list[1] +private fun max(list: IntArray): Int = when (list.size) { + 2 -> if (list[0] > list[1]) list[0] else list[1] else -> { val subMax = max(list.copyOfRange(1, list.size)) if (list[0] > subMax) list[0] else subMax From 9306432a1b51dce356bf90b1e3db03749da13f0f Mon Sep 17 00:00:00 2001 From: Adnan Date: Wed, 9 Aug 2023 02:41:22 +0330 Subject: [PATCH 106/140] Update 05_quicksort.kt (#267) remove unnecessary line --- 04_quicksort/kotlin/05_quicksort.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/04_quicksort/kotlin/05_quicksort.kt b/04_quicksort/kotlin/05_quicksort.kt index 3a0c76b9..67507129 100644 --- a/04_quicksort/kotlin/05_quicksort.kt +++ b/04_quicksort/kotlin/05_quicksort.kt @@ -3,10 +3,9 @@ fun quickSort(list: List): List { if (list.size <= 1) return list // recursive case val pivot = list[list.size / 2] - val equal = list.filter { it == pivot } val less = list.filter { it < pivot } val greater = list.filter { it > pivot } - return quickSort(less) + equal + quickSort(greater) + return quickSort(less) + pivot + quickSort(greater) } fun main(args: Array) = println(quickSort(listOf(10, 5, 2, 3))) // [2, 3, 5, 10] From 933acafaf3efbf474bcd35b1a7bbc01efb418d99 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Wed, 9 Aug 2023 08:20:19 -0500 Subject: [PATCH 107/140] reorg and add code for second edition --- .../.vscode/launch.json | 23 ------------------ .../01_dijkstras_algorithm/.vscode/tasks.json | 16 ------------ 07_trees/python/01_filesystem_dfs.py | 18 ++++++++++++++ .../01_set_covering/.vscode/launch.json | 23 ------------------ .../csharp/01_set_covering/.vscode/tasks.json | 16 ------------ .../ES6/01_dijkstras_algorithm.js | 0 .../Golang/01_dijkstras_algorithm.go | 0 .../Haskell/01_dijkstras_algorithm.hs | 0 .../PowerShell/01_dijkstras_algorithm.ps1 | 0 .../c++11/01_dijkstras_algorithm.cpp | 0 .../csharp/01_dijkstras_algorithm/.gitignore | 0 .../csharp/01_dijkstras_algorithm/Program.cs | 0 .../01_dijkstras_algorithm/project.json | 0 .../01_dijkstras_algorithm/project.lock.json | 0 .../dart/01_djikstra_algorithm.dart | 0 .../elixir/01_dijkstras_algorithm.exs | 0 .../src/DijkstrasAlgorithm.java | 0 .../javascript/01_dijkstras_algorithm.js | 0 .../julia/01_dijkstras_algorithm.jl | 0 .../lua/01_dijkstras_algorithm.lua | 0 .../php/01_dijkstras_algorithm.php | 0 .../python/01_dijkstras_algorithm.py | 0 .../ruby/01_dijkstras_algorithm.rb | 0 .../swift/01_dijkstras_algorithm.swift | 0 .../zig/dijkstras_algorithm.zig | 0 .../.vscode/launch.json | 23 ------------------ .../.vscode/tasks.json | 16 ------------ .../ES6/01_set_covering.js | 0 .../Haskell/01_powerset-covering.hs | 0 .../Haskell/01_set_convering.hs | 0 .../PowerShell/01_set_covering.ps1 | 0 .../c++11/01_set_covering.cpp | 0 .../csharp/01_set_covering/.gitignore | 0 .../csharp/01_set_covering/Program.cs | 0 .../csharp/01_set_covering/project.json | 0 .../csharp/01_set_covering/project.lock.json | 0 .../dart/01_set_covering.dart | 0 .../elixir/01_set_covering.exs | 0 .../golang/01_set_covering.go | 0 .../java/01_set_covering/src/SetCovering.java | 0 .../javascript/01_set_covering.js | 0 .../kotlin/01_set_covering.kt | 0 .../lua/01_set_covering.lua | 0 .../lua/set.lua | 0 .../php/01_set_covering.php | 0 .../python/01_set_covering.py | 0 .../ruby/01_set_covering.rb | 0 .../swift/01_set_covering.swift | 0 .../zig/set_covering.zig | 0 .../ES6/01_longest_common_subsequence.js | 0 .../Haskell/01_knapsack-powerset.hs | 0 .../Haskell/01_knapsack_dynamic_prog.hs | 0 .../01_longest_common_subsequence.ps1 | 0 .../01_longest_common_subsequence/.gitignore | 0 .../01_longest_common_subsequence/Program.cs | 0 .../project.json | 0 .../project.lock.json | 0 .../csharp/02_levenshtein/Program.cs | 0 .../dart/01_longest_common_subsequence.dart | 0 .../dart/02_longest_common_substring.dart | 0 .../elixir/01_longest_common_subsequence.exs | 0 .../golang/01_longest_common_subsequence.go | 0 .../01_longest_common_subsequence_test.go | 0 .../src/LongestCommonSubsequence.java | 0 .../01_longest_common_subsequence.js | 0 .../javascript/02_levenstein.js | 0 .../javascript/examples/base.js | 0 .../javascript/examples/diff_two_words.js | 0 .../lua/01_longest_common_subsequence.lua | 0 .../php/01_longest_common_subsequence.php | 0 .../python/01_longest_common_subsequence.py | 0 .../python/02_longest_common_substring.py | 0 .../ruby/01_longest_common_subsequence.rb | 0 .../swift/01_longest_common_subsequence.swift | 0 .../zig/longest_common_subsequence.zig | 0 .../01_longest_common_subsequence.cpp" | 0 {10_knn => 12_knn}/README.md | 0 .../images/13_correct_50_comparisons.tif | Bin .../images/16_correct_500_comparisons.tif | Bin .../images/17_correct_500_comparisons.png | Bin .../images/18_correct_5000_comparisons.tif | Bin .../images/19_correct_50000_comparisons.tif | Bin {10_knn => 12_knn}/main.m | 0 .../mnistHelper/loadMNISTImages.m | 0 .../mnistHelper/loadMNISTLabels.m | 0 {10_knn => 12_knn}/t10k-images-idx3-ubyte | Bin {10_knn => 12_knn}/t10k-labels-idx1-ubyte | Bin {10_knn => 12_knn}/train-images-idx3-ubyte | Bin {10_knn => 12_knn}/train-labels-idx1-ubyte | Bin 89 files changed, 18 insertions(+), 117 deletions(-) delete mode 100644 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/launch.json delete mode 100644 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/tasks.json create mode 100644 07_trees/python/01_filesystem_dfs.py delete mode 100644 08_greedy_algorithms/csharp/01_set_covering/.vscode/launch.json delete mode 100644 08_greedy_algorithms/csharp/01_set_covering/.vscode/tasks.json rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/ES6/01_dijkstras_algorithm.js (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/Golang/01_dijkstras_algorithm.go (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/Haskell/01_dijkstras_algorithm.hs (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/PowerShell/01_dijkstras_algorithm.ps1 (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/c++11/01_dijkstras_algorithm.cpp (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/csharp/01_dijkstras_algorithm/.gitignore (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/csharp/01_dijkstras_algorithm/Program.cs (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/csharp/01_dijkstras_algorithm/project.json (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/csharp/01_dijkstras_algorithm/project.lock.json (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/dart/01_djikstra_algorithm.dart (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/elixir/01_dijkstras_algorithm.exs (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/javascript/01_dijkstras_algorithm.js (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/julia/01_dijkstras_algorithm.jl (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/lua/01_dijkstras_algorithm.lua (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/php/01_dijkstras_algorithm.php (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/python/01_dijkstras_algorithm.py (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/ruby/01_dijkstras_algorithm.rb (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/swift/01_dijkstras_algorithm.swift (100%) rename {07_dijkstras_algorithm => 09_dijkstras_algorithm}/zig/dijkstras_algorithm.zig (100%) delete mode 100644 09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/launch.json delete mode 100644 09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/tasks.json rename {08_greedy_algorithms => 10_greedy_algorithms}/ES6/01_set_covering.js (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/Haskell/01_powerset-covering.hs (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/Haskell/01_set_convering.hs (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/PowerShell/01_set_covering.ps1 (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/c++11/01_set_covering.cpp (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/csharp/01_set_covering/.gitignore (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/csharp/01_set_covering/Program.cs (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/csharp/01_set_covering/project.json (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/csharp/01_set_covering/project.lock.json (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/dart/01_set_covering.dart (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/elixir/01_set_covering.exs (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/golang/01_set_covering.go (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/java/01_set_covering/src/SetCovering.java (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/javascript/01_set_covering.js (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/kotlin/01_set_covering.kt (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/lua/01_set_covering.lua (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/lua/set.lua (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/php/01_set_covering.php (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/python/01_set_covering.py (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/ruby/01_set_covering.rb (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/swift/01_set_covering.swift (100%) rename {08_greedy_algorithms => 10_greedy_algorithms}/zig/set_covering.zig (100%) rename {09_dynamic_programming => 11_dynamic_programming}/ES6/01_longest_common_subsequence.js (100%) rename {09_dynamic_programming => 11_dynamic_programming}/Haskell/01_knapsack-powerset.hs (100%) rename {09_dynamic_programming => 11_dynamic_programming}/Haskell/01_knapsack_dynamic_prog.hs (100%) rename {09_dynamic_programming => 11_dynamic_programming}/PowerShell/01_longest_common_subsequence.ps1 (100%) rename {09_dynamic_programming => 11_dynamic_programming}/csharp/01_longest_common_subsequence/.gitignore (100%) rename {09_dynamic_programming => 11_dynamic_programming}/csharp/01_longest_common_subsequence/Program.cs (100%) rename {09_dynamic_programming => 11_dynamic_programming}/csharp/01_longest_common_subsequence/project.json (100%) rename {09_dynamic_programming => 11_dynamic_programming}/csharp/01_longest_common_subsequence/project.lock.json (100%) rename {09_dynamic_programming => 11_dynamic_programming}/csharp/02_levenshtein/Program.cs (100%) rename {09_dynamic_programming => 11_dynamic_programming}/dart/01_longest_common_subsequence.dart (100%) rename {09_dynamic_programming => 11_dynamic_programming}/dart/02_longest_common_substring.dart (100%) rename {09_dynamic_programming => 11_dynamic_programming}/elixir/01_longest_common_subsequence.exs (100%) rename {09_dynamic_programming => 11_dynamic_programming}/golang/01_longest_common_subsequence.go (100%) rename {09_dynamic_programming => 11_dynamic_programming}/golang/01_longest_common_subsequence_test.go (100%) rename {09_dynamic_programming => 11_dynamic_programming}/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java (100%) rename {09_dynamic_programming => 11_dynamic_programming}/javascript/01_longest_common_subsequence.js (100%) rename {09_dynamic_programming => 11_dynamic_programming}/javascript/02_levenstein.js (100%) rename {09_dynamic_programming => 11_dynamic_programming}/javascript/examples/base.js (100%) rename {09_dynamic_programming => 11_dynamic_programming}/javascript/examples/diff_two_words.js (100%) rename {09_dynamic_programming => 11_dynamic_programming}/lua/01_longest_common_subsequence.lua (100%) rename {09_dynamic_programming => 11_dynamic_programming}/php/01_longest_common_subsequence.php (100%) rename {09_dynamic_programming => 11_dynamic_programming}/python/01_longest_common_subsequence.py (100%) rename {09_dynamic_programming => 11_dynamic_programming}/python/02_longest_common_substring.py (100%) rename {09_dynamic_programming => 11_dynamic_programming}/ruby/01_longest_common_subsequence.rb (100%) rename {09_dynamic_programming => 11_dynamic_programming}/swift/01_longest_common_subsequence.swift (100%) rename {09_dynamic_programming => 11_dynamic_programming}/zig/longest_common_subsequence.zig (100%) rename "09_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" => "11_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" (100%) rename {10_knn => 12_knn}/README.md (100%) rename {10_knn => 12_knn}/images/13_correct_50_comparisons.tif (100%) rename {10_knn => 12_knn}/images/16_correct_500_comparisons.tif (100%) rename {10_knn => 12_knn}/images/17_correct_500_comparisons.png (100%) rename {10_knn => 12_knn}/images/18_correct_5000_comparisons.tif (100%) rename {10_knn => 12_knn}/images/19_correct_50000_comparisons.tif (100%) rename {10_knn => 12_knn}/main.m (100%) rename {10_knn => 12_knn}/mnistHelper/loadMNISTImages.m (100%) rename {10_knn => 12_knn}/mnistHelper/loadMNISTLabels.m (100%) rename {10_knn => 12_knn}/t10k-images-idx3-ubyte (100%) rename {10_knn => 12_knn}/t10k-labels-idx1-ubyte (100%) rename {10_knn => 12_knn}/train-images-idx3-ubyte (100%) rename {10_knn => 12_knn}/train-labels-idx1-ubyte (100%) diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/launch.json b/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/launch.json deleted file mode 100644 index df95188b..00000000 --- a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/01_dijkstras_algorithm.dll", - "args": [], - "cwd": "${workspaceRoot}", - "externalConsole": false, - "stopAtEntry": false, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command.pickProcess}" - } - ] -} \ No newline at end of file diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/tasks.json b/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/tasks.json deleted file mode 100644 index adc66239..00000000 --- a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "tasks": [ - { - "taskName": "build", - "args": [ - "${workspaceRoot}/project.json" - ], - "isBuildCommand": true, - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/07_trees/python/01_filesystem_dfs.py b/07_trees/python/01_filesystem_dfs.py new file mode 100644 index 00000000..052709a8 --- /dev/null +++ b/07_trees/python/01_filesystem_dfs.py @@ -0,0 +1,18 @@ +from os import listdir +from os.path import isfile, join + + +def printnames(dir): + # loop through every file and folder in the current folder + for file in sorted(listdir(dir)): + fullpath = join(dir, file) + if isfile(fullpath): + # if it is a file, print out the name + print(file) + else: + # if it is a folder, call this function recursively on it + # to look for files and folders + printnames(fullpath) + + +printnames("pics") diff --git a/08_greedy_algorithms/csharp/01_set_covering/.vscode/launch.json b/08_greedy_algorithms/csharp/01_set_covering/.vscode/launch.json deleted file mode 100644 index d033d6f1..00000000 --- a/08_greedy_algorithms/csharp/01_set_covering/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/01_set_covering.dll", - "args": [], - "cwd": "${workspaceRoot}", - "externalConsole": false, - "stopAtEntry": false, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command.pickProcess}" - } - ] -} \ No newline at end of file diff --git a/08_greedy_algorithms/csharp/01_set_covering/.vscode/tasks.json b/08_greedy_algorithms/csharp/01_set_covering/.vscode/tasks.json deleted file mode 100644 index adc66239..00000000 --- a/08_greedy_algorithms/csharp/01_set_covering/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "tasks": [ - { - "taskName": "build", - "args": [ - "${workspaceRoot}/project.json" - ], - "isBuildCommand": true, - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js b/09_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js similarity index 100% rename from 07_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js rename to 09_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js diff --git a/07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go b/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go similarity index 100% rename from 07_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go rename to 09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go diff --git a/07_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs b/09_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs similarity index 100% rename from 07_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs rename to 09_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs diff --git a/07_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 b/09_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 similarity index 100% rename from 07_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 rename to 09_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1 diff --git a/07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp b/09_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp similarity index 100% rename from 07_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp rename to 09_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/Program.cs diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.json diff --git a/07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json b/09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json similarity index 100% rename from 07_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json rename to 09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/project.lock.json diff --git a/07_dijkstras_algorithm/dart/01_djikstra_algorithm.dart b/09_dijkstras_algorithm/dart/01_djikstra_algorithm.dart similarity index 100% rename from 07_dijkstras_algorithm/dart/01_djikstra_algorithm.dart rename to 09_dijkstras_algorithm/dart/01_djikstra_algorithm.dart diff --git a/07_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs b/09_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs similarity index 100% rename from 07_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs rename to 09_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs diff --git a/07_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java b/09_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java similarity index 100% rename from 07_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java rename to 09_dijkstras_algorithm/java/01_dijkstras_algorithm/src/DijkstrasAlgorithm.java diff --git a/07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js b/09_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js similarity index 100% rename from 07_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js rename to 09_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js diff --git a/07_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl b/09_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl similarity index 100% rename from 07_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl rename to 09_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl diff --git a/07_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua b/09_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua similarity index 100% rename from 07_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua rename to 09_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua diff --git a/07_dijkstras_algorithm/php/01_dijkstras_algorithm.php b/09_dijkstras_algorithm/php/01_dijkstras_algorithm.php similarity index 100% rename from 07_dijkstras_algorithm/php/01_dijkstras_algorithm.php rename to 09_dijkstras_algorithm/php/01_dijkstras_algorithm.php diff --git a/07_dijkstras_algorithm/python/01_dijkstras_algorithm.py b/09_dijkstras_algorithm/python/01_dijkstras_algorithm.py similarity index 100% rename from 07_dijkstras_algorithm/python/01_dijkstras_algorithm.py rename to 09_dijkstras_algorithm/python/01_dijkstras_algorithm.py diff --git a/07_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb b/09_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb similarity index 100% rename from 07_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb rename to 09_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb diff --git a/07_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift b/09_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift similarity index 100% rename from 07_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift rename to 09_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift diff --git a/07_dijkstras_algorithm/zig/dijkstras_algorithm.zig b/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig similarity index 100% rename from 07_dijkstras_algorithm/zig/dijkstras_algorithm.zig rename to 09_dijkstras_algorithm/zig/dijkstras_algorithm.zig diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/launch.json b/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/launch.json deleted file mode 100644 index 5706467a..00000000 --- a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/01_longest_common_subsequence.dll", - "args": [], - "cwd": "${workspaceRoot}", - "externalConsole": false, - "stopAtEntry": false, - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command.pickProcess}" - } - ] -} \ No newline at end of file diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/tasks.json b/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/tasks.json deleted file mode 100644 index adc66239..00000000 --- a/09_dynamic_programming/csharp/01_longest_common_subsequence/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": "0.1.0", - "command": "dotnet", - "isShellCommand": true, - "args": [], - "tasks": [ - { - "taskName": "build", - "args": [ - "${workspaceRoot}/project.json" - ], - "isBuildCommand": true, - "problemMatcher": "$msCompile" - } - ] -} \ No newline at end of file diff --git a/08_greedy_algorithms/ES6/01_set_covering.js b/10_greedy_algorithms/ES6/01_set_covering.js similarity index 100% rename from 08_greedy_algorithms/ES6/01_set_covering.js rename to 10_greedy_algorithms/ES6/01_set_covering.js diff --git a/08_greedy_algorithms/Haskell/01_powerset-covering.hs b/10_greedy_algorithms/Haskell/01_powerset-covering.hs similarity index 100% rename from 08_greedy_algorithms/Haskell/01_powerset-covering.hs rename to 10_greedy_algorithms/Haskell/01_powerset-covering.hs diff --git a/08_greedy_algorithms/Haskell/01_set_convering.hs b/10_greedy_algorithms/Haskell/01_set_convering.hs similarity index 100% rename from 08_greedy_algorithms/Haskell/01_set_convering.hs rename to 10_greedy_algorithms/Haskell/01_set_convering.hs diff --git a/08_greedy_algorithms/PowerShell/01_set_covering.ps1 b/10_greedy_algorithms/PowerShell/01_set_covering.ps1 similarity index 100% rename from 08_greedy_algorithms/PowerShell/01_set_covering.ps1 rename to 10_greedy_algorithms/PowerShell/01_set_covering.ps1 diff --git a/08_greedy_algorithms/c++11/01_set_covering.cpp b/10_greedy_algorithms/c++11/01_set_covering.cpp similarity index 100% rename from 08_greedy_algorithms/c++11/01_set_covering.cpp rename to 10_greedy_algorithms/c++11/01_set_covering.cpp diff --git a/08_greedy_algorithms/csharp/01_set_covering/.gitignore b/10_greedy_algorithms/csharp/01_set_covering/.gitignore similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/.gitignore rename to 10_greedy_algorithms/csharp/01_set_covering/.gitignore diff --git a/08_greedy_algorithms/csharp/01_set_covering/Program.cs b/10_greedy_algorithms/csharp/01_set_covering/Program.cs similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/Program.cs rename to 10_greedy_algorithms/csharp/01_set_covering/Program.cs diff --git a/08_greedy_algorithms/csharp/01_set_covering/project.json b/10_greedy_algorithms/csharp/01_set_covering/project.json similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/project.json rename to 10_greedy_algorithms/csharp/01_set_covering/project.json diff --git a/08_greedy_algorithms/csharp/01_set_covering/project.lock.json b/10_greedy_algorithms/csharp/01_set_covering/project.lock.json similarity index 100% rename from 08_greedy_algorithms/csharp/01_set_covering/project.lock.json rename to 10_greedy_algorithms/csharp/01_set_covering/project.lock.json diff --git a/08_greedy_algorithms/dart/01_set_covering.dart b/10_greedy_algorithms/dart/01_set_covering.dart similarity index 100% rename from 08_greedy_algorithms/dart/01_set_covering.dart rename to 10_greedy_algorithms/dart/01_set_covering.dart diff --git a/08_greedy_algorithms/elixir/01_set_covering.exs b/10_greedy_algorithms/elixir/01_set_covering.exs similarity index 100% rename from 08_greedy_algorithms/elixir/01_set_covering.exs rename to 10_greedy_algorithms/elixir/01_set_covering.exs diff --git a/08_greedy_algorithms/golang/01_set_covering.go b/10_greedy_algorithms/golang/01_set_covering.go similarity index 100% rename from 08_greedy_algorithms/golang/01_set_covering.go rename to 10_greedy_algorithms/golang/01_set_covering.go diff --git a/08_greedy_algorithms/java/01_set_covering/src/SetCovering.java b/10_greedy_algorithms/java/01_set_covering/src/SetCovering.java similarity index 100% rename from 08_greedy_algorithms/java/01_set_covering/src/SetCovering.java rename to 10_greedy_algorithms/java/01_set_covering/src/SetCovering.java diff --git a/08_greedy_algorithms/javascript/01_set_covering.js b/10_greedy_algorithms/javascript/01_set_covering.js similarity index 100% rename from 08_greedy_algorithms/javascript/01_set_covering.js rename to 10_greedy_algorithms/javascript/01_set_covering.js diff --git a/08_greedy_algorithms/kotlin/01_set_covering.kt b/10_greedy_algorithms/kotlin/01_set_covering.kt similarity index 100% rename from 08_greedy_algorithms/kotlin/01_set_covering.kt rename to 10_greedy_algorithms/kotlin/01_set_covering.kt diff --git a/08_greedy_algorithms/lua/01_set_covering.lua b/10_greedy_algorithms/lua/01_set_covering.lua similarity index 100% rename from 08_greedy_algorithms/lua/01_set_covering.lua rename to 10_greedy_algorithms/lua/01_set_covering.lua diff --git a/08_greedy_algorithms/lua/set.lua b/10_greedy_algorithms/lua/set.lua similarity index 100% rename from 08_greedy_algorithms/lua/set.lua rename to 10_greedy_algorithms/lua/set.lua diff --git a/08_greedy_algorithms/php/01_set_covering.php b/10_greedy_algorithms/php/01_set_covering.php similarity index 100% rename from 08_greedy_algorithms/php/01_set_covering.php rename to 10_greedy_algorithms/php/01_set_covering.php diff --git a/08_greedy_algorithms/python/01_set_covering.py b/10_greedy_algorithms/python/01_set_covering.py similarity index 100% rename from 08_greedy_algorithms/python/01_set_covering.py rename to 10_greedy_algorithms/python/01_set_covering.py diff --git a/08_greedy_algorithms/ruby/01_set_covering.rb b/10_greedy_algorithms/ruby/01_set_covering.rb similarity index 100% rename from 08_greedy_algorithms/ruby/01_set_covering.rb rename to 10_greedy_algorithms/ruby/01_set_covering.rb diff --git a/08_greedy_algorithms/swift/01_set_covering.swift b/10_greedy_algorithms/swift/01_set_covering.swift similarity index 100% rename from 08_greedy_algorithms/swift/01_set_covering.swift rename to 10_greedy_algorithms/swift/01_set_covering.swift diff --git a/08_greedy_algorithms/zig/set_covering.zig b/10_greedy_algorithms/zig/set_covering.zig similarity index 100% rename from 08_greedy_algorithms/zig/set_covering.zig rename to 10_greedy_algorithms/zig/set_covering.zig diff --git a/09_dynamic_programming/ES6/01_longest_common_subsequence.js b/11_dynamic_programming/ES6/01_longest_common_subsequence.js similarity index 100% rename from 09_dynamic_programming/ES6/01_longest_common_subsequence.js rename to 11_dynamic_programming/ES6/01_longest_common_subsequence.js diff --git a/09_dynamic_programming/Haskell/01_knapsack-powerset.hs b/11_dynamic_programming/Haskell/01_knapsack-powerset.hs similarity index 100% rename from 09_dynamic_programming/Haskell/01_knapsack-powerset.hs rename to 11_dynamic_programming/Haskell/01_knapsack-powerset.hs diff --git a/09_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs b/11_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs similarity index 100% rename from 09_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs rename to 11_dynamic_programming/Haskell/01_knapsack_dynamic_prog.hs diff --git a/09_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 b/11_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 similarity index 100% rename from 09_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 rename to 11_dynamic_programming/PowerShell/01_longest_common_subsequence.ps1 diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore b/11_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore similarity index 100% rename from 09_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore rename to 11_dynamic_programming/csharp/01_longest_common_subsequence/.gitignore diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs b/11_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs similarity index 100% rename from 09_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs rename to 11_dynamic_programming/csharp/01_longest_common_subsequence/Program.cs diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/project.json b/11_dynamic_programming/csharp/01_longest_common_subsequence/project.json similarity index 100% rename from 09_dynamic_programming/csharp/01_longest_common_subsequence/project.json rename to 11_dynamic_programming/csharp/01_longest_common_subsequence/project.json diff --git a/09_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json b/11_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json similarity index 100% rename from 09_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json rename to 11_dynamic_programming/csharp/01_longest_common_subsequence/project.lock.json diff --git a/09_dynamic_programming/csharp/02_levenshtein/Program.cs b/11_dynamic_programming/csharp/02_levenshtein/Program.cs similarity index 100% rename from 09_dynamic_programming/csharp/02_levenshtein/Program.cs rename to 11_dynamic_programming/csharp/02_levenshtein/Program.cs diff --git a/09_dynamic_programming/dart/01_longest_common_subsequence.dart b/11_dynamic_programming/dart/01_longest_common_subsequence.dart similarity index 100% rename from 09_dynamic_programming/dart/01_longest_common_subsequence.dart rename to 11_dynamic_programming/dart/01_longest_common_subsequence.dart diff --git a/09_dynamic_programming/dart/02_longest_common_substring.dart b/11_dynamic_programming/dart/02_longest_common_substring.dart similarity index 100% rename from 09_dynamic_programming/dart/02_longest_common_substring.dart rename to 11_dynamic_programming/dart/02_longest_common_substring.dart diff --git a/09_dynamic_programming/elixir/01_longest_common_subsequence.exs b/11_dynamic_programming/elixir/01_longest_common_subsequence.exs similarity index 100% rename from 09_dynamic_programming/elixir/01_longest_common_subsequence.exs rename to 11_dynamic_programming/elixir/01_longest_common_subsequence.exs diff --git a/09_dynamic_programming/golang/01_longest_common_subsequence.go b/11_dynamic_programming/golang/01_longest_common_subsequence.go similarity index 100% rename from 09_dynamic_programming/golang/01_longest_common_subsequence.go rename to 11_dynamic_programming/golang/01_longest_common_subsequence.go diff --git a/09_dynamic_programming/golang/01_longest_common_subsequence_test.go b/11_dynamic_programming/golang/01_longest_common_subsequence_test.go similarity index 100% rename from 09_dynamic_programming/golang/01_longest_common_subsequence_test.go rename to 11_dynamic_programming/golang/01_longest_common_subsequence_test.go diff --git a/09_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java b/11_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java similarity index 100% rename from 09_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java rename to 11_dynamic_programming/java/01_longest_common_subsequence/src/LongestCommonSubsequence.java diff --git a/09_dynamic_programming/javascript/01_longest_common_subsequence.js b/11_dynamic_programming/javascript/01_longest_common_subsequence.js similarity index 100% rename from 09_dynamic_programming/javascript/01_longest_common_subsequence.js rename to 11_dynamic_programming/javascript/01_longest_common_subsequence.js diff --git a/09_dynamic_programming/javascript/02_levenstein.js b/11_dynamic_programming/javascript/02_levenstein.js similarity index 100% rename from 09_dynamic_programming/javascript/02_levenstein.js rename to 11_dynamic_programming/javascript/02_levenstein.js diff --git a/09_dynamic_programming/javascript/examples/base.js b/11_dynamic_programming/javascript/examples/base.js similarity index 100% rename from 09_dynamic_programming/javascript/examples/base.js rename to 11_dynamic_programming/javascript/examples/base.js diff --git a/09_dynamic_programming/javascript/examples/diff_two_words.js b/11_dynamic_programming/javascript/examples/diff_two_words.js similarity index 100% rename from 09_dynamic_programming/javascript/examples/diff_two_words.js rename to 11_dynamic_programming/javascript/examples/diff_two_words.js diff --git a/09_dynamic_programming/lua/01_longest_common_subsequence.lua b/11_dynamic_programming/lua/01_longest_common_subsequence.lua similarity index 100% rename from 09_dynamic_programming/lua/01_longest_common_subsequence.lua rename to 11_dynamic_programming/lua/01_longest_common_subsequence.lua diff --git a/09_dynamic_programming/php/01_longest_common_subsequence.php b/11_dynamic_programming/php/01_longest_common_subsequence.php similarity index 100% rename from 09_dynamic_programming/php/01_longest_common_subsequence.php rename to 11_dynamic_programming/php/01_longest_common_subsequence.php diff --git a/09_dynamic_programming/python/01_longest_common_subsequence.py b/11_dynamic_programming/python/01_longest_common_subsequence.py similarity index 100% rename from 09_dynamic_programming/python/01_longest_common_subsequence.py rename to 11_dynamic_programming/python/01_longest_common_subsequence.py diff --git a/09_dynamic_programming/python/02_longest_common_substring.py b/11_dynamic_programming/python/02_longest_common_substring.py similarity index 100% rename from 09_dynamic_programming/python/02_longest_common_substring.py rename to 11_dynamic_programming/python/02_longest_common_substring.py diff --git a/09_dynamic_programming/ruby/01_longest_common_subsequence.rb b/11_dynamic_programming/ruby/01_longest_common_subsequence.rb similarity index 100% rename from 09_dynamic_programming/ruby/01_longest_common_subsequence.rb rename to 11_dynamic_programming/ruby/01_longest_common_subsequence.rb diff --git a/09_dynamic_programming/swift/01_longest_common_subsequence.swift b/11_dynamic_programming/swift/01_longest_common_subsequence.swift similarity index 100% rename from 09_dynamic_programming/swift/01_longest_common_subsequence.swift rename to 11_dynamic_programming/swift/01_longest_common_subsequence.swift diff --git a/09_dynamic_programming/zig/longest_common_subsequence.zig b/11_dynamic_programming/zig/longest_common_subsequence.zig similarity index 100% rename from 09_dynamic_programming/zig/longest_common_subsequence.zig rename to 11_dynamic_programming/zig/longest_common_subsequence.zig diff --git "a/09_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" "b/11_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" similarity index 100% rename from "09_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" rename to "11_dynamic_programming/\321\201++/01_longest_common_subsequence.cpp" diff --git a/10_knn/README.md b/12_knn/README.md similarity index 100% rename from 10_knn/README.md rename to 12_knn/README.md diff --git a/10_knn/images/13_correct_50_comparisons.tif b/12_knn/images/13_correct_50_comparisons.tif similarity index 100% rename from 10_knn/images/13_correct_50_comparisons.tif rename to 12_knn/images/13_correct_50_comparisons.tif diff --git a/10_knn/images/16_correct_500_comparisons.tif b/12_knn/images/16_correct_500_comparisons.tif similarity index 100% rename from 10_knn/images/16_correct_500_comparisons.tif rename to 12_knn/images/16_correct_500_comparisons.tif diff --git a/10_knn/images/17_correct_500_comparisons.png b/12_knn/images/17_correct_500_comparisons.png similarity index 100% rename from 10_knn/images/17_correct_500_comparisons.png rename to 12_knn/images/17_correct_500_comparisons.png diff --git a/10_knn/images/18_correct_5000_comparisons.tif b/12_knn/images/18_correct_5000_comparisons.tif similarity index 100% rename from 10_knn/images/18_correct_5000_comparisons.tif rename to 12_knn/images/18_correct_5000_comparisons.tif diff --git a/10_knn/images/19_correct_50000_comparisons.tif b/12_knn/images/19_correct_50000_comparisons.tif similarity index 100% rename from 10_knn/images/19_correct_50000_comparisons.tif rename to 12_knn/images/19_correct_50000_comparisons.tif diff --git a/10_knn/main.m b/12_knn/main.m similarity index 100% rename from 10_knn/main.m rename to 12_knn/main.m diff --git a/10_knn/mnistHelper/loadMNISTImages.m b/12_knn/mnistHelper/loadMNISTImages.m similarity index 100% rename from 10_knn/mnistHelper/loadMNISTImages.m rename to 12_knn/mnistHelper/loadMNISTImages.m diff --git a/10_knn/mnistHelper/loadMNISTLabels.m b/12_knn/mnistHelper/loadMNISTLabels.m similarity index 100% rename from 10_knn/mnistHelper/loadMNISTLabels.m rename to 12_knn/mnistHelper/loadMNISTLabels.m diff --git a/10_knn/t10k-images-idx3-ubyte b/12_knn/t10k-images-idx3-ubyte similarity index 100% rename from 10_knn/t10k-images-idx3-ubyte rename to 12_knn/t10k-images-idx3-ubyte diff --git a/10_knn/t10k-labels-idx1-ubyte b/12_knn/t10k-labels-idx1-ubyte similarity index 100% rename from 10_knn/t10k-labels-idx1-ubyte rename to 12_knn/t10k-labels-idx1-ubyte diff --git a/10_knn/train-images-idx3-ubyte b/12_knn/train-images-idx3-ubyte similarity index 100% rename from 10_knn/train-images-idx3-ubyte rename to 12_knn/train-images-idx3-ubyte diff --git a/10_knn/train-labels-idx1-ubyte b/12_knn/train-labels-idx1-ubyte similarity index 100% rename from 10_knn/train-labels-idx1-ubyte rename to 12_knn/train-labels-idx1-ubyte From cf6b035069742a28aad703d53a57f2aaf19f480c Mon Sep 17 00:00:00 2001 From: Mikhail <64309136+MAGistR-bit@users.noreply.github.com> Date: Fri, 22 Mar 2024 22:50:11 +0300 Subject: [PATCH 108/140] Add Dijkstra's algorithm to Kotlin (#268) --- .../kotlin/DijkstraAlgorithm.kt | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 09_dijkstras_algorithm/kotlin/DijkstraAlgorithm.kt diff --git a/09_dijkstras_algorithm/kotlin/DijkstraAlgorithm.kt b/09_dijkstras_algorithm/kotlin/DijkstraAlgorithm.kt new file mode 100644 index 00000000..b17fde03 --- /dev/null +++ b/09_dijkstras_algorithm/kotlin/DijkstraAlgorithm.kt @@ -0,0 +1,77 @@ +// Граф +private val graph: MutableMap> = HashMap() + +// Список отслеживания обработанных узлов +private val processed: MutableList = ArrayList() + +fun main() { + graph["start"] = HashMap() + graph["start"]!!["a"] = 6.0 + graph["start"]!!["b"] = 2.0 + graph["a"] = HashMap() + graph["a"]!!["fin"] = 1.0 + graph["b"] = HashMap() + graph["b"]!!["a"] = 3.0 + graph["b"]!!["fin"] = 5.0 + graph["fin"] = HashMap() + + // Стоимость узлов + val costs: MutableMap = HashMap() + costs["a"] = 6.0 + costs["b"] = 2.0 + costs["fin"] = Double.POSITIVE_INFINITY + + // Таблица родителей + val parents: MutableMap = HashMap() + parents["a"] = "start" + parents["b"] = "start" + parents["fin"] = null + + + println("Cost from the start to each node:") + println(dijkstraAlgorithm(costs, parents)) +} + +fun dijkstraAlgorithm(costs: MutableMap, + parents: MutableMap): MutableMap { + + var node = findLowestCostNode(costs) + while (node != null) { + val cost = costs[node] + // Перебрать всех соседей текущего узла + val neighbors: Map = graph[node]!! + for (n in neighbors.keys) { + val newCost = cost!! + neighbors[n]!! + // Если к соседу можно быстрее добраться через текущий узел... + if (costs[n]!! > newCost) { + // ... обновить стоимость для этого узла + costs[n] = newCost + // Этот узел становится новым родителем для соседа + parents[n] = node + } + } + // Узел помечается как обработанный + processed.add(node) + + // Найти следующий узел для обработки и повторить цикл + node = findLowestCostNode(costs) + } + return costs // { a: 5, b: 2, fin: 6 } +} + +private fun findLowestCostNode(costs: Map): String? { + var lowestCost = Double.POSITIVE_INFINITY + var lowestCostNode: String? = null + + // Перебрать все узлы + for ((key, cost) in costs) { + // Если это узел с наименьшей стоимостью из уже виденных и + // он еще не был обработан... + if (cost < lowestCost && !processed.contains(key)) { + // ... он назначается новым узлом с наименьшей стоимостью + lowestCost = cost + lowestCostNode = key + } + } + return lowestCostNode +} \ No newline at end of file From 7d166566745de9f32cef6ff38ba765578147365a Mon Sep 17 00:00:00 2001 From: Mikhail <64309136+MAGistR-bit@users.noreply.github.com> Date: Fri, 22 Mar 2024 22:51:00 +0300 Subject: [PATCH 109/140] Add a solution to the problem on Kotlin (#269) * Solution. Longest Common Subsequence --- .../kotlin/LongestCommonSubsequence.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 11_dynamic_programming/kotlin/LongestCommonSubsequence.kt diff --git a/11_dynamic_programming/kotlin/LongestCommonSubsequence.kt b/11_dynamic_programming/kotlin/LongestCommonSubsequence.kt new file mode 100644 index 00000000..8e22281e --- /dev/null +++ b/11_dynamic_programming/kotlin/LongestCommonSubsequence.kt @@ -0,0 +1,37 @@ +import kotlin.math.max + +fun main() { + val wordA = "hish" + val wordB = "fish" + getLongestCommonSubSequence(wordA, wordB) +} + +private fun getLongestCommonSubSequence(wordA: String, wordB: String) { + val cell = Array(wordA.length) { IntArray(wordB.length) } + for (i in wordA.indices) { + for (j in wordB.indices) { + // Буквы совпадают + if (wordA[i] == wordB[j]) { + if (i > 0 && j > 0) { + cell[i][j] = cell[i - 1][j - 1] + 1 + } else { + cell[i][j] = 1 + } + } else { + // Буквы не совпадают + if (i > 0 && j > 0) { + cell[i][j] = max(cell[i - 1][j], cell[i][j - 1]) + } else { + cell[i][j] = 0 + } + } + } + } + printResult(cell) +} + +fun printResult(array: Array) { + for (row in array) { + println(row.contentToString()) + } +} From 5d068870bf5ca10bfada3a409dce67005968ae8b Mon Sep 17 00:00:00 2001 From: spainn <148598154+spainn@users.noreply.github.com> Date: Fri, 22 Mar 2024 15:02:03 -0500 Subject: [PATCH 110/140] Update 02_longest_common_substring.py (#276) The original code did not work correctly out of the box. It generated a (4,5) grid instead of a (5,4) grid as the book's answer grid shows. Also on line 10 of my code I changed `dp_table[i-1][i-1] + 1` to `dp_table[i-1][j-1] +1`. I also updated the display to display by row. Co-authored-by: WhileRested <148598154+WhileRested@users.noreply.github.com> --- .../python/02_longest_common_substring.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/11_dynamic_programming/python/02_longest_common_substring.py b/11_dynamic_programming/python/02_longest_common_substring.py index 7cf05f45..1e879a58 100644 --- a/11_dynamic_programming/python/02_longest_common_substring.py +++ b/11_dynamic_programming/python/02_longest_common_substring.py @@ -1,13 +1,16 @@ dp_table_blue = ["b", "l", "u", "e"] dp_table_clues = ["c", "l", "u", "e", "s"] -dp_table = [[0 for i in range(len(dp_table_blue))] for i in range(len(dp_table_clues))] # (5,4) -print(dp_table) +dp_table = [[0 for i in range(len(dp_table_clues))] for i in range(len(dp_table_blue))] # (5,4) +# for each row for i in range(0, len(dp_table_blue)): + # for each col for j in range(0, len(dp_table_clues)): if dp_table_clues[j] == dp_table_blue[i]: - dp_table[i][j] = dp_table[i-1][i-1] + 1 + dp_table[i][j] = dp_table[i-1][j-1] + 1 else: dp_table[i][j] = 0 -print(dp_table) +# display table +for i in dp_table: + print(i) From 11a2de7473807093fe4c4a1b5b256a399734ba8a Mon Sep 17 00:00:00 2001 From: spainn <148598154+spainn@users.noreply.github.com> Date: Fri, 22 Mar 2024 15:03:28 -0500 Subject: [PATCH 111/140] Update 01_longest_common_subsequence.py (#277) The original code was creating a 4x5 grid instead of 5x4. I also made it display by row. Co-authored-by: WhileRested <148598154+WhileRested@users.noreply.github.com> --- .../python/01_longest_common_subsequence.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/11_dynamic_programming/python/01_longest_common_subsequence.py b/11_dynamic_programming/python/01_longest_common_subsequence.py index 61691a09..315b2336 100644 --- a/11_dynamic_programming/python/01_longest_common_subsequence.py +++ b/11_dynamic_programming/python/01_longest_common_subsequence.py @@ -1,13 +1,15 @@ dp_table_blue = ["b", "l", "u", "e"] dp_table_clues = ["c", "l", "u", "e", "s"] -dp_table = [[0 for i in range(len(dp_table_blue))] for i in range(len(dp_table_clues))] # (5,4) -print(dp_table) +dp_table = [[0 for i in range(len(dp_table_clues))] for i in range(len(dp_table_blue))] # (5,4) +# for each row for i in range(0, len(dp_table_blue)): + # for each column for j in range(0, len(dp_table_clues)): if dp_table_clues[j] == dp_table_blue[i]: - dp_table[j][i] = dp_table[j-1][i-1] + 1 + dp_table[i][j] = dp_table[i-1][j-1] + 1 else: - dp_table[j][i] = max(dp_table[j-1][i], dp_table[j][i-1]) + dp_table[i][j] = max(dp_table[i-1][j], dp_table[i][j-1]) -print(dp_table) +for i in dp_table: + print(i) From cfb59254fbb5ab2774592ab8a730c9dc55f24d95 Mon Sep 17 00:00:00 2001 From: gweno Date: Fri, 22 Mar 2024 21:04:27 +0100 Subject: [PATCH 112/140] 04 recursive_max in C (#278) --- 04_quicksort/c/04_recursive_max.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 04_quicksort/c/04_recursive_max.c diff --git a/04_quicksort/c/04_recursive_max.c b/04_quicksort/c/04_recursive_max.c new file mode 100644 index 00000000..f64cc4ca --- /dev/null +++ b/04_quicksort/c/04_recursive_max.c @@ -0,0 +1,19 @@ +#include + +int max(int *arr, int index, int size){ + //base case + if (index == size - 1) + return arr[index]; + + int sub_max = max(arr, index + 1, size); + + return (arr[index] > sub_max) ? arr[index] : sub_max; +} + +int main(void){ + int arr[] = {2,3,6,5,5}; + // the C way of calculating the size of an array + int size = sizeof(arr) / sizeof(arr[0]); + printf("%d", max(arr, 0, size)); + return 0; +} From 256625afd77769b3c60acf1c53606fd654f5522c Mon Sep 17 00:00:00 2001 From: Yi-Jen Chen <89930807+yi-jenc@users.noreply.github.com> Date: Fri, 22 Mar 2024 21:06:55 +0100 Subject: [PATCH 113/140] fix recursive solution for binary search in python (#279) --- .../python/05_binary_search_recursive.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/03_recursion/python/05_binary_search_recursive.py b/03_recursion/python/05_binary_search_recursive.py index 3ed0b237..c6461d6b 100644 --- a/03_recursion/python/05_binary_search_recursive.py +++ b/03_recursion/python/05_binary_search_recursive.py @@ -1,17 +1,20 @@ def binary_search(arr, target): - if not arr: - return -1 + if len(arr) == 0: + return None - low = 0 - high = len(arr) - 1 - mid = (low + high) // 2 + mid = len(arr) // 2 if arr[mid] == target: - return target + return mid elif arr[mid] > target: return binary_search(arr[:mid], target) else: - return binary_search(arr[mid+1:], target) + recursive_response = binary_search(arr[(mid + 1) :], target) + return ( + (mid + 1) + recursive_response + if recursive_response is not None + else recursive_response + ) print(binary_search([6, 7, 8, 9, 10], 8)) From f7ccf02e001c06f39a65684bfd3540c0f8476ba7 Mon Sep 17 00:00:00 2001 From: ViMaCode <59506333+Vitalii-Maevskii@users.noreply.github.com> Date: Fri, 22 Mar 2024 23:10:02 +0300 Subject: [PATCH 114/140] Array variable (#259) The array is set in one place. --- 02_selection_sort/javascript/01_selection_sort.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02_selection_sort/javascript/01_selection_sort.js b/02_selection_sort/javascript/01_selection_sort.js index afc0a4b1..c9cf695c 100644 --- a/02_selection_sort/javascript/01_selection_sort.js +++ b/02_selection_sort/javascript/01_selection_sort.js @@ -40,7 +40,7 @@ function selectionSort(array) { } const sourceArray = [5, 3, 6, 2, 10]; -const sourtedArray = selectionSort([5, 3, 6, 2, 10]); +const sourtedArray = selectionSort(sourceArray); console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] console.log("New sorted array - ", sourtedArray); // [2, 3, 5, 6, 10] From 775022b848df1b0afb9145363ec0145eab7a92e7 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Fri, 22 Mar 2024 15:10:42 -0500 Subject: [PATCH 115/140] typo --- 02_selection_sort/javascript/01_selection_sort.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/02_selection_sort/javascript/01_selection_sort.js b/02_selection_sort/javascript/01_selection_sort.js index c9cf695c..ba3ed7a0 100644 --- a/02_selection_sort/javascript/01_selection_sort.js +++ b/02_selection_sort/javascript/01_selection_sort.js @@ -40,7 +40,7 @@ function selectionSort(array) { } const sourceArray = [5, 3, 6, 2, 10]; -const sourtedArray = selectionSort(sourceArray); +const sortedArray = selectionSort(sourceArray); console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] -console.log("New sorted array - ", sourtedArray); // [2, 3, 5, 6, 10] +console.log("New sorted array - ", sortedArray); // [2, 3, 5, 6, 10] From 9d20fbff3765de92e6f1b7de299bf310c107bb5c Mon Sep 17 00:00:00 2001 From: Punpun <86565283+ppskpunpun@users.noreply.github.com> Date: Wed, 11 Sep 2024 04:47:59 +0700 Subject: [PATCH 116/140] Add recursive example for finding a key in nested boxes (Python) (#290) --- 03_recursion/python/08_look_for_key.py | 50 ++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 03_recursion/python/08_look_for_key.py diff --git a/03_recursion/python/08_look_for_key.py b/03_recursion/python/08_look_for_key.py new file mode 100644 index 00000000..8367b899 --- /dev/null +++ b/03_recursion/python/08_look_for_key.py @@ -0,0 +1,50 @@ +# Item have 2 types: key or box +class Item: + def __init__(self, is_key=False): + self.is_key = is_key + + # If not a key, it's a box that can hold items + self.items_in_box = [] + + def is_a_box(self): + return not self.is_key + + def is_a_key(self): + return self.is_key + + +def look_for_key(box: Item): + for item in box.items_in_box: + if item.is_a_box(): + # recursive case + look_for_key(item) + elif item.is_a_key(): + # base case + print("found the key!") + + +""" +main_box +├── box_A +│ ├── box_B +│ └── box_C +└── box_D + └── box_E + └── key +""" +main_box = Item() + +box_A = Item() +box_B = Item() +box_C = Item() +box_A.items_in_box = [box_B, box_C] + +box_D = Item() +box_E = Item() +key = Item(is_key = True) +box_E.items_in_box = [key] +box_D.items_in_box = [box_E] + +main_box.items_in_box = [box_A, box_D] + +look_for_key(main_box) \ No newline at end of file From 177581a9a4d4679824fb81abfc692b3f44f29097 Mon Sep 17 00:00:00 2001 From: "Christine P. Chai" Date: Sat, 7 Dec 2024 05:27:24 -0800 Subject: [PATCH 117/140] Removed a comment with Chinese characters (#283) Removed a comment with Chinese characters --- 10_greedy_algorithms/python/01_set_covering.py | 1 - 1 file changed, 1 deletion(-) diff --git a/10_greedy_algorithms/python/01_set_covering.py b/10_greedy_algorithms/python/01_set_covering.py index 10d919eb..6e2f9f77 100644 --- a/10_greedy_algorithms/python/01_set_covering.py +++ b/10_greedy_algorithms/python/01_set_covering.py @@ -11,7 +11,6 @@ def my_set_covering(states_needed, stations): final_stations = set() - #while states_needed is not None: 这个不对,Set()而不是None while states_needed: best_station = None states_covered = set() From 8a13efde831a5b44ea0d833c2ca77efbf692a68b Mon Sep 17 00:00:00 2001 From: Paolo Grisoli Date: Sat, 7 Dec 2024 14:29:48 +0100 Subject: [PATCH 118/140] Update examples for Zig (#287) * update zig in chapters 1-6 * fix zig dijkstras algo * fix zig greedy algo * fix longest_common_subsequence in zig * cleanup * test: use testing allocator --- .../zig/binary-search.zig | 9 +- 02_selection_sort/zig/selection_sort.zig | 6 +- 03_recursion/zig/04_count.zig | 2 +- 04_quicksort/zig/01_loop_sum.zig | 4 +- 04_quicksort/zig/02_recursive_sum.zig | 4 +- 04_quicksort/zig/03_recursive_count.zig | 2 +- 04_quicksort/zig/05_quicksort.zig | 17 +- 04_quicksort/zig/06_quicksort_parallel.zig | 82 +++--- .../zig/breadth_first_search.zig | 55 ++-- .../Golang/01_dijkstras_algorithm.go | 4 +- .../zig/dijkstras_algorithm.zig | 148 ++++++----- 10_greedy_algorithms/zig/set_covering.zig | 240 ++++++++++++------ .../zig/longest_common_subsequence.zig | 38 +-- 13 files changed, 354 insertions(+), 257 deletions(-) diff --git a/01_introduction_to_algorithms/zig/binary-search.zig b/01_introduction_to_algorithms/zig/binary-search.zig index f0e9123d..56513143 100644 --- a/01_introduction_to_algorithms/zig/binary-search.zig +++ b/01_introduction_to_algorithms/zig/binary-search.zig @@ -11,12 +11,13 @@ pub fn main() void { fn binarySearch(comptime T: type, list: []const T, item: T) ?usize { var low: i32 = 0; - var high: i32 = @intCast(i32, list.len) - 1; + const u_high: u32 = @truncate(list.len); + var high: i32 = @intCast(u_high - 1); return while (low <= high) { - var mid = @divTrunc((low + high), 2); - var m = @intCast(usize, mid); - var guess = list[m]; + const mid = @divTrunc((low + high), 2); + const m: usize = @intCast(mid); + const guess = list[m]; if (guess == item) break m; if (guess > item) { high = mid - 1; diff --git a/02_selection_sort/zig/selection_sort.zig b/02_selection_sort/zig/selection_sort.zig index 19a2c10a..e1f29942 100644 --- a/02_selection_sort/zig/selection_sort.zig +++ b/02_selection_sort/zig/selection_sort.zig @@ -10,12 +10,12 @@ pub fn main() !void { } fn selectionSort(comptime T: type, list: []T) void { - for (list) |_, i| { + for (0..list.len) |i| { var j = i + 1; while (j < list.len) : (j += 1) { if (list[i] > list[j]) { // swap - var tmp = list[i]; + const tmp = list[i]; list[i] = list[j]; list[j] = tmp; } @@ -30,6 +30,6 @@ test "selectionSort" { selectionSort(i32, s[0..]); try expect(s.len == exp.len); - for (s) |e, i| + for (s, 0..) |e, i| try expect(e == exp[i]); } diff --git a/03_recursion/zig/04_count.zig b/03_recursion/zig/04_count.zig index 914c4f25..487bb67e 100644 --- a/03_recursion/zig/04_count.zig +++ b/03_recursion/zig/04_count.zig @@ -16,7 +16,7 @@ test "count" { var arr0 = [_]i32{}; var arr1 = [_]i32{42}; var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - var tests = [_]struct { + const tests = [_]struct { arr: []i32, exp: i32, }{ diff --git a/04_quicksort/zig/01_loop_sum.zig b/04_quicksort/zig/01_loop_sum.zig index 13c0d0a1..a9b94e6a 100644 --- a/04_quicksort/zig/01_loop_sum.zig +++ b/04_quicksort/zig/01_loop_sum.zig @@ -17,7 +17,7 @@ fn sum(comptime T: type, arr: []T) T { test "sum" { var arr0 = [_]i32{ 1, 2, 3, 4 }; var arr1 = [_]i32{}; - var tests = [_]struct { + const tests = [_]struct { arr: []i32, exp: i32, }{ @@ -32,7 +32,7 @@ test "sum" { }; for (tests) |t| { - var n = sum(@TypeOf(t.exp), t.arr); + const n = sum(@TypeOf(t.exp), t.arr); try expect(n == t.exp); } } diff --git a/04_quicksort/zig/02_recursive_sum.zig b/04_quicksort/zig/02_recursive_sum.zig index a015ceb3..781cfe6e 100644 --- a/04_quicksort/zig/02_recursive_sum.zig +++ b/04_quicksort/zig/02_recursive_sum.zig @@ -16,7 +16,7 @@ fn sum(comptime T: type, list: []T) T { test "sum" { var arr0 = [_]i32{ 1, 2, 3, 4 }; var arr1 = [_]i32{}; - var tests = [_]struct { + const tests = [_]struct { arr: []i32, exp: i32, }{ @@ -31,7 +31,7 @@ test "sum" { }; for (tests) |t| { - var n = sum(@TypeOf(t.exp), t.arr); + const n = sum(@TypeOf(t.exp), t.arr); try expect(n == t.exp); } } diff --git a/04_quicksort/zig/03_recursive_count.zig b/04_quicksort/zig/03_recursive_count.zig index 914c4f25..487bb67e 100644 --- a/04_quicksort/zig/03_recursive_count.zig +++ b/04_quicksort/zig/03_recursive_count.zig @@ -16,7 +16,7 @@ test "count" { var arr0 = [_]i32{}; var arr1 = [_]i32{42}; var arr2 = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - var tests = [_]struct { + const tests = [_]struct { arr: []i32, exp: i32, }{ diff --git a/04_quicksort/zig/05_quicksort.zig b/04_quicksort/zig/05_quicksort.zig index 83c78e3c..6c99bb13 100644 --- a/04_quicksort/zig/05_quicksort.zig +++ b/04_quicksort/zig/05_quicksort.zig @@ -32,8 +32,8 @@ fn quicksort(comptime T: type, allocator: mem.Allocator, s: []const T) anyerror! } } - var low = try quicksort(T, allocator, lower.items); - var high = try quicksort(T, allocator, higher.items); + const low = try quicksort(T, allocator, lower.items); + const high = try quicksort(T, allocator, higher.items); var res = std.ArrayList(T).init(allocator); try res.appendSlice(low); @@ -44,13 +44,8 @@ fn quicksort(comptime T: type, allocator: mem.Allocator, s: []const T) anyerror! } test "quicksort" { - var gpa = heap.GeneralPurposeAllocator(.{}){}; - var arena = heap.ArenaAllocator.init(gpa.allocator()); - defer { - arena.deinit(); - const leaked = gpa.deinit(); - if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return - } + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); const tests = [_]struct { s: []const u8, @@ -71,9 +66,9 @@ test "quicksort" { }; for (tests) |t| { - var res = try quicksort(u8, arena.allocator(), t.s); + const res = try quicksort(u8, arena.allocator(), t.s); try expect(res.len == t.exp.len); - for (res) |e, i| + for (res, 0..) |e, i| try expect(e == t.exp[i]); } } diff --git a/04_quicksort/zig/06_quicksort_parallel.zig b/04_quicksort/zig/06_quicksort_parallel.zig index 8c4991a7..8c88c8a1 100644 --- a/04_quicksort/zig/06_quicksort_parallel.zig +++ b/04_quicksort/zig/06_quicksort_parallel.zig @@ -4,32 +4,31 @@ const expect = std.testing.expect; const heap = std.heap; const mem = std.mem; -pub const io_mode = .evented; - -pub const Error = error{OutOfMemory}; +// pub const io_mode = .evented; pub fn main() !void { var gpa = heap.GeneralPurposeAllocator(.{}){}; var arena = heap.ArenaAllocator.init(gpa.allocator()); defer arena.deinit(); - var s = [_]u8{ 5, 3, 6, 2, 10 }; + var u = [_]u8{ 5, 3, 6, 2, 10 }; - print("{d}\n", .{try quicksort(arena.allocator(), &s)}); + var s = try std.ArrayList(u8).initCapacity(arena.allocator(), u.len); + try quicksort(u8, arena.allocator(), &u, &s); + print("{d}\n", .{s.items}); } -// NOTE: this async version cannot be generic because allocating a frame for a -// generic function is not trivial. -fn quicksort(allocator: mem.Allocator, s: []const u8) Error![]const u8 { - if (s.len < 2) { - return s; +fn quicksort(comptime T: type, allocator: mem.Allocator, u: []const T, s: *std.ArrayList(T)) !void { + if (u.len < 2) { + try s.appendSlice(u); + return; } - var lower = std.ArrayList(u8).init(allocator); - var higher = std.ArrayList(u8).init(allocator); + var lower = std.ArrayList(T).init(allocator); + var higher = std.ArrayList(T).init(allocator); - const pivot = s[0]; - for (s[1..]) |item| { + const pivot = u[0]; + for (u[1..]) |item| { if (item <= pivot) { try lower.append(item); } else { @@ -37,27 +36,41 @@ fn quicksort(allocator: mem.Allocator, s: []const u8) Error![]const u8 { } } - const low_frame = try allocator.create(@Frame(quicksort)); - low_frame.* = async quicksort(allocator, lower.items); - var high = try quicksort(allocator, higher.items); - var low = try await low_frame; + // NOTE: zig has temporary removed the async/await syntax since v0.11.0 + // + // const low_frame = try allocator.create(@Frame(quicksort)); + // low_frame.* = async quicksort(allocator, lower.items); + // const high = try quicksort(allocator, higher.items); + // const low = try await low_frame; + + var low = try std.ArrayList(T).initCapacity(allocator, lower.items.len); + var high = try std.ArrayList(T).initCapacity(allocator, higher.items.len); - var res = std.ArrayList(u8).init(allocator); - try res.appendSlice(low); - try res.append(pivot); - try res.appendSlice(high); + var low_handle = try std.Thread.spawn( + .{}, + quicksort, + .{ T, allocator, lower.items, &low }, + ); + var high_handle = try std.Thread.spawn( + .{}, + quicksort, + .{ T, allocator, higher.items, &high }, + ); + low_handle.join(); + high_handle.join(); - return res.items; + const lows = try low.toOwnedSlice(); + const highs = try high.toOwnedSlice(); + try s.appendSlice(lows); + try s.append(pivot); + try s.appendSlice(highs); + + return; } test "quicksort" { - var gpa = heap.GeneralPurposeAllocator(.{}){}; - var arena = heap.ArenaAllocator.init(gpa.allocator()); - defer { - arena.deinit(); - const leaked = gpa.deinit(); - if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return - } + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); const tests = [_]struct { s: []const u8, @@ -78,9 +91,10 @@ test "quicksort" { }; for (tests) |t| { - var res = try quicksort(arena.allocator(), t.s); - try expect(res.len == t.exp.len); - for (res) |e, i| - try expect(e == t.exp[i]); + var res = std.ArrayList(u8).init(arena.allocator()); + try quicksort(u8, arena.allocator(), t.s, &res); + try expect(res.items.len == t.exp.len); // length not matching + for (res.items, 0..) |e, i| + try expect(e == t.exp[i]); // element not matching } } diff --git a/06_breadth-first_search/zig/breadth_first_search.zig b/06_breadth-first_search/zig/breadth_first_search.zig index 2404c9eb..c3b84cc9 100644 --- a/06_breadth-first_search/zig/breadth_first_search.zig +++ b/06_breadth-first_search/zig/breadth_first_search.zig @@ -37,10 +37,10 @@ fn search( var arena = heap.ArenaAllocator.init(allocator); defer arena.deinit(); var searched = std.BufSet.init(arena.allocator()); - const Q = std.TailQueue([]const u8); + const Q = std.DoublyLinkedList([]const u8); var queue = Q{}; - var name_edges = graph.get(name); + const name_edges = graph.get(name); if (name_edges) |edges| { var nodes = try arena.allocator().alloc(Q.Node, edges.len); var i: usize = 0; @@ -53,28 +53,26 @@ fn search( } while (queue.len > 0) { - var first = queue.popFirst(); - if (first) |person| { - if (!searched.contains(person.data)) { - if (personIsSeller(person.data)) { - std.debug.print("{s} is a mango seller!\n", .{person.data}); - return; - } else { - var ee = graph.get(person.data); - if (ee) |edges| { - var nodes = try arena.allocator().alloc(Q.Node, edges.len); - var i: usize = 0; - while (i < edges.len) : (i += 1) { - nodes[i].data = edges[i]; - } - for (nodes) |*node| { - queue.append(node); - } - } - try searched.insert(person.data); - } + const person = queue.popFirst() orelse unreachable; // we always have at least one node if len > 0 + if (searched.contains(person.data)) { + continue; + } + if (personIsSeller(person.data)) { + std.debug.print("{s} is a mango seller!\n", .{person.data}); + return; + } + const ee = graph.get(person.data); + if (ee) |edges| { + var nodes = try arena.allocator().alloc(Q.Node, edges.len); + var i: usize = 0; + while (i < edges.len) : (i += 1) { + nodes[i].data = edges[i]; + } + for (nodes) |*node| { + queue.append(node); } } + try searched.insert(person.data); } } @@ -83,14 +81,9 @@ fn personIsSeller(name: []const u8) bool { } test "search" { - var gpa = heap.GeneralPurposeAllocator(.{}){}; - - var graph = std.StringHashMap([][]const u8).init(gpa.allocator()); - defer { - graph.deinit(); - const leaked = gpa.deinit(); - if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return - } + const allocator = std.testing.allocator; + var graph = std.StringHashMap([][]const u8).init(allocator); + defer graph.deinit(); var you = [_][]const u8{ "alice", "bob", "claire" }; var bob = [_][]const u8{ "anuj", "peggy" }; @@ -110,5 +103,5 @@ test "search" { try graph.put("thom", &thom); try graph.put("jonny", &jonny); - try search(gpa.allocator(), &graph, "you"); + try search(allocator, &graph, "you"); } diff --git a/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go b/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go index 73b22743..0a5fa3c0 100644 --- a/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go +++ b/09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go @@ -47,7 +47,7 @@ func main() { // Go through all the neighbors of this node. neighbors := graph[node] - for node, _ := range neighbors { + for node := range neighbors { new_cost := cost + neighbors[node] // If it's cheaper to get to this neighbor by going through this node... if costs[node] > new_cost { @@ -71,7 +71,7 @@ func find_lowest_cost_node(costs map[string]float64) string { lowest_cost := math.Inf(1) lowest_cost_node := "" - for node, _ := range costs { + for node := range costs { // fmt.Println("Node:", node, "Value:", value) cost := costs[node] // If it's the lowest cost so far and hasn't been processed yet... diff --git a/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig b/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig index 2a038d01..62fe9471 100644 --- a/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig +++ b/09_dijkstras_algorithm/zig/dijkstras_algorithm.zig @@ -6,109 +6,109 @@ pub fn main() !void { var gpa = heap.GeneralPurposeAllocator(.{}){}; var arena = heap.ArenaAllocator.init(gpa.allocator()); defer arena.deinit(); + const alloc = arena.allocator(); - var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator()); + var graph = std.StringHashMap(*std.StringHashMap(f32)).init(alloc); - var start = std.StringHashMap(f32).init(arena.allocator()); + var start = std.StringHashMap(f32).init(alloc); try start.put("a", 6); try start.put("b", 2); + try start.put("c", 42); try graph.put("start", &start); - var a = std.StringHashMap(f32).init(arena.allocator()); + var a = std.StringHashMap(f32).init(alloc); try a.put("finish", 1); try graph.put("a", &a); - var b = std.StringHashMap(f32).init(arena.allocator()); + var b = std.StringHashMap(f32).init(alloc); try b.put("a", 3); try b.put("finish", 5); try graph.put("b", &b); - var fin = std.StringHashMap(f32).init(arena.allocator()); + var c = std.StringHashMap(f32).init(alloc); + try c.put("finish", 42); + try graph.put("c", &c); + + var fin = std.StringHashMap(f32).init(alloc); try graph.put("finish", &fin); - var result = try dijkstra(arena.allocator(), &graph, "start", "finish"); + var costs, var path = try dijkstra(alloc, &graph, "start", "finish"); + + // Traverse the path hashmap backwards from finish to start and store the + // steps in an ordered list. + // The hashmap is unordered so there is no guarantee to print the path in + // the correct order only by iterating through key/value(s). + var dir = std.ArrayList([]const u8).init(alloc); - std.debug.print("Cost from the start to each node:\n", .{}); - var costs_it = result.costs.iterator(); - while (costs_it.next()) |cost| { - std.debug.print("{s}: {d} ", .{ cost.key_ptr.*, cost.value_ptr.* }); + var v: []const u8 = "finish"; + try dir.append(v); + var node = path.get(v); + while (node) |n| : (node = path.get(v)) { + try dir.append(n.?); + v = n.?; } - std.debug.print("\n", .{}); - std.debug.print("\n", .{}); std.debug.print("Path from start to finish:\n", .{}); - var path_it = result.path.iterator(); - while (path_it.next()) |parent| { - std.debug.print("{s} = {?s}\n", .{ parent.key_ptr.*, parent.value_ptr.* }); + std.debug.print("start =(", .{}); + var i = dir.items.len - 2; + var prev_cost: f32 = 0; + while (i > 0) : (i -= 1) { + const d = dir.items[i]; + const cost = costs.get(d).?; + std.debug.print("{d})=> {s:<6}: {d}\n{s:<5} =(", .{ cost - prev_cost, d, cost, d }); + prev_cost = cost; } + const fin_cost = costs.get("finish").?; + std.debug.print("{d})=> finish: {d}\n", .{ fin_cost - prev_cost, fin_cost }); } -/// this struct is needed because coercing an anonymous struct literal to an -/// error union is not supported by zig yet. Once this is fixed (with the -/// self-hosted compiler, see https://github.com/ziglang/zig/issues/11443), the -/// dijkstra function could just return: -/// ```zig -/// return { -/// .costs = costs, -/// .path = parents, -/// }; -/// ``` -const dijkstraResult = struct { - costs: std.StringHashMap(f32), - path: std.StringHashMap(?[]const u8), -}; - -/// applies the dijkstra algorithm on the provided graph using -/// the provided start anf finish nodes. +/// applies the dijkstra algorithm on graph using start and finish nodes. +/// Returns a tuple with the costs and the path. fn dijkstra( allocator: mem.Allocator, graph: *std.StringHashMap(*std.StringHashMap(f32)), start: []const u8, finish: []const u8, -) !dijkstraResult { +) !struct { + std.StringHashMap(f32), // costs + std.StringHashMap(?[]const u8), // path +} { var costs = std.StringHashMap(f32).init(allocator); var parents = std.StringHashMap(?[]const u8).init(allocator); - try costs.put(finish, std.math.inf_f32); + try costs.put(finish, std.math.inf(f32)); try parents.put(finish, null); // initialize costs and parents maps for the nodes having start as parent - var start_graph = graph.get(start); - if (start_graph) |sg| { - var it = sg.iterator(); - while (it.next()) |elem| { - try costs.put(elem.key_ptr.*, elem.value_ptr.*); - try parents.put(elem.key_ptr.*, start); - } + const start_graph = graph.get(start) orelse return error.MissingNode; + var sg_it = start_graph.iterator(); + while (sg_it.next()) |elem| { + try parents.put(elem.key_ptr.*, start); + try costs.put(elem.key_ptr.*, elem.value_ptr.*); } var processed = std.BufSet.init(allocator); var n = findCheapestNode(&costs, &processed); while (n) |node| : (n = findCheapestNode(&costs, &processed)) { - var cost = costs.get(node).?; - var neighbors = graph.get(node); - if (neighbors) |nbors| { - var it = nbors.iterator(); - while (it.next()) |neighbor| { - var new_cost = cost + neighbor.value_ptr.*; - if (costs.get(neighbor.key_ptr.*).? > new_cost) { - // update maps if we found a cheaper path - try costs.put(neighbor.key_ptr.*, new_cost); - try parents.put(neighbor.key_ptr.*, node); - } + const cost = costs.get(node).?; + const neighbors = graph.get(node) orelse return error.MissingNode; + var it = neighbors.iterator(); + while (it.next()) |neighbor| { + const new_cost = cost + neighbor.value_ptr.*; + if (costs.get(neighbor.key_ptr.*).? > new_cost) { + // update maps if we found a cheaper path + try costs.put(neighbor.key_ptr.*, new_cost); + try parents.put(neighbor.key_ptr.*, node); } } try processed.insert(node); } - return dijkstraResult{ - .costs = costs, - .path = parents, - }; + return .{ costs, parents }; } /// finds the cheapest node among the not yet processed ones. fn findCheapestNode(costs: *std.StringHashMap(f32), processed: *std.BufSet) ?[]const u8 { - var lowest_cost = std.math.inf_f32; + var lowest_cost = std.math.inf(f32); var lowest_cost_node: ?[]const u8 = null; var it = costs.iterator(); @@ -123,39 +123,35 @@ fn findCheapestNode(costs: *std.StringHashMap(f32), processed: *std.BufSet) ?[]c } test "dijkstra" { - var gpa = heap.GeneralPurposeAllocator(.{}){}; - var arena = heap.ArenaAllocator.init(gpa.allocator()); - defer { - arena.deinit(); - const leaked = gpa.deinit(); - if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return - } + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const alloc = arena.allocator(); - var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator()); + var graph = std.StringHashMap(*std.StringHashMap(f32)).init(alloc); - var start = std.StringHashMap(f32).init(arena.allocator()); + var start = std.StringHashMap(f32).init(alloc); try start.put("a", 6); try start.put("b", 2); try graph.put("start", &start); - var a = std.StringHashMap(f32).init(arena.allocator()); + var a = std.StringHashMap(f32).init(alloc); try a.put("finish", 1); try graph.put("a", &a); - var b = std.StringHashMap(f32).init(arena.allocator()); + var b = std.StringHashMap(f32).init(alloc); try b.put("a", 3); try b.put("finish", 5); try graph.put("b", &b); - var fin = std.StringHashMap(f32).init(arena.allocator()); + var fin = std.StringHashMap(f32).init(alloc); try graph.put("finish", &fin); - var result = try dijkstra(arena.allocator(), &graph, "start", "finish"); + var costs, var path = try dijkstra(alloc, &graph, "start", "finish"); - try std.testing.expectEqual(result.costs.get("a").?, 5); - try std.testing.expectEqual(result.costs.get("b").?, 2); - try std.testing.expectEqual(result.costs.get("finish").?, 6); - try std.testing.expectEqual(result.path.get("b").?, "start"); - try std.testing.expectEqual(result.path.get("a").?, "b"); - try std.testing.expectEqual(result.path.get("finish").?, "a"); + try std.testing.expectEqual(costs.get("a").?, 5); + try std.testing.expectEqual(costs.get("b").?, 2); + try std.testing.expectEqual(costs.get("finish").?, 6); + try std.testing.expectEqual(path.get("b").?, "start"); + try std.testing.expectEqual(path.get("a").?, "b"); + try std.testing.expectEqual(path.get("finish").?, "a"); } diff --git a/10_greedy_algorithms/zig/set_covering.zig b/10_greedy_algorithms/zig/set_covering.zig index cf13ab33..e8431bf5 100644 --- a/10_greedy_algorithms/zig/set_covering.zig +++ b/10_greedy_algorithms/zig/set_covering.zig @@ -7,43 +7,45 @@ pub fn main() !void { var arena = heap.ArenaAllocator.init(gpa.allocator()); defer arena.deinit(); - var states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; - var states_needed = std.BufSet.init(arena.allocator()); + const ally = arena.allocator(); + const states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; + var states_needed = std.BufSet.init(ally); for (states_needed_array) |sn| { try states_needed.insert(sn); } - var stations = std.StringHashMap(*std.BufSet).init(arena.allocator()); + var stations = std.StringHashMap(*std.BufSet).init(ally); - var kone = std.BufSet.init(arena.allocator()); - try kone.insert("id"); - try kone.insert("nv"); - try kone.insert("ut"); - try stations.put("kone", &kone); + var k_one = std.BufSet.init(ally); + try k_one.insert("id"); + try k_one.insert("nv"); + try k_one.insert("ut"); - var ktwo = std.BufSet.init(arena.allocator()); - try ktwo.insert("wa"); - try ktwo.insert("id"); - try ktwo.insert("mt"); - try stations.put("ktwo", &ktwo); + var k_two = std.BufSet.init(ally); + try k_two.insert("wa"); + try k_two.insert("id"); + try k_two.insert("mt"); - var kthree = std.BufSet.init(arena.allocator()); - try kthree.insert("or"); - try kthree.insert("nv"); - try kthree.insert("ca"); - try stations.put("kthree", &kthree); + var k_three = std.BufSet.init(ally); + try k_three.insert("or"); + try k_three.insert("nv"); + try k_three.insert("ca"); - var kfour = std.BufSet.init(arena.allocator()); - try kfour.insert("nv"); - try kfour.insert("ut"); - try stations.put("kfour", &kfour); + var k_four = std.BufSet.init(ally); + try k_four.insert("nv"); + try k_four.insert("ut"); - var kfive = std.BufSet.init(arena.allocator()); - try kfive.insert("ca"); - try kfive.insert("az"); - try stations.put("kfive", &kfive); + var k_five = std.BufSet.init(ally); + try k_five.insert("ca"); + try k_five.insert("az"); + + try stations.put("kone", &k_one); + try stations.put("ktwo", &k_two); + try stations.put("kthree", &k_three); + try stations.put("kfour", &k_four); + try stations.put("kfive", &k_five); - var stations_covering = try setCovering(arena.allocator(), &stations, &states_needed); + const stations_covering = try setCovering(ally, &stations, &states_needed); for (stations_covering) |sc| { std.debug.print("{s}\n", .{sc}); @@ -59,8 +61,8 @@ fn setCovering(allocator: mem.Allocator, stations: *std.StringHashMap(*std.BufSe var it = stations.iterator(); while (it.next()) |station| { - var covered = &std.ArrayList([]const u8).init(allocator); - try intersect(states_needed, station.value_ptr.*, covered); + var covered = std.ArrayList([]const u8).init(allocator); + try intersect(states_needed, station.value_ptr.*, &covered); if (covered.items.len > states_covered.len) { best_station = station.key_ptr.*; states_covered = covered.items; @@ -80,79 +82,175 @@ fn setCovering(allocator: mem.Allocator, stations: *std.StringHashMap(*std.BufSe return final_array.toOwnedSlice(); } -fn intersect(left: *std.BufSet, right: *std.BufSet, intersection: *std.ArrayList([]const u8)) !void { - var l_it = left.iterator(); - var r_it = right.iterator(); - while (l_it.next()) |l| { - while (r_it.next()) |r| { - if (std.mem.eql(u8, l.*, r.*)) { - try intersection.append(l.*); - } - } - } -} - -fn difference(lessening: *std.BufSet, subtracting: [][]const u8) void { - var less_it = lessening.iterator(); - - while (less_it.next()) |less| { - for (subtracting) |sub| { - if (std.mem.eql(u8, less.*, sub)) { - lessening.remove(less.*); - } - } - } -} - test "setCovering" { - var gpa = heap.GeneralPurposeAllocator(.{}){}; - var arena = heap.ArenaAllocator.init(gpa.allocator()); - defer { - arena.deinit(); - const leaked = gpa.deinit(); - if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return - } + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const ally = arena.allocator(); - var states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; - var states_needed = std.BufSet.init(arena.allocator()); + const states_needed_array = [_][]const u8{ "mt", "wa", "or", "id", "nv", "ut", "ca", "az" }; + var states_needed = std.BufSet.init(ally); for (states_needed_array) |sn| { try states_needed.insert(sn); } - var stations = std.StringHashMap(*std.BufSet).init(arena.allocator()); + var stations = std.StringHashMap(*std.BufSet).init(ally); - var kone = std.BufSet.init(arena.allocator()); + var kone = std.BufSet.init(ally); try kone.insert("id"); try kone.insert("nv"); try kone.insert("ut"); try stations.put("kone", &kone); - var ktwo = std.BufSet.init(arena.allocator()); + var ktwo = std.BufSet.init(ally); try ktwo.insert("wa"); try ktwo.insert("id"); try ktwo.insert("mt"); try stations.put("ktwo", &ktwo); - var kthree = std.BufSet.init(arena.allocator()); + var kthree = std.BufSet.init(ally); try kthree.insert("or"); try kthree.insert("nv"); try kthree.insert("ca"); try stations.put("kthree", &kthree); - var kfour = std.BufSet.init(arena.allocator()); + var kfour = std.BufSet.init(ally); try kfour.insert("nv"); try kfour.insert("ut"); try stations.put("kfour", &kfour); - var kfive = std.BufSet.init(arena.allocator()); + var kfive = std.BufSet.init(ally); try kfive.insert("ca"); try kfive.insert("az"); try stations.put("kfive", &kfive); - var stations_covering = try setCovering(arena.allocator(), &stations, &states_needed); + const stations_covering = try setCovering(ally, &stations, &states_needed); - var expectedStations = &[_][]const u8{ "kone", "ktwo", "kfive", "kthree" }; - for (stations_covering) |sc, i| { + // The order of the keys in the hashmap affects the final result. + // StringHashMap always produces the same order and we can assert over it. + const expectedStations = &[_][]const u8{ "kfour", "ktwo", "kthree", "kfive" }; + for (stations_covering, 0..) |sc, i| { try std.testing.expectEqualStrings(expectedStations[i], sc); } } + +fn intersect(left: *std.BufSet, right: *std.BufSet, intersection: *std.ArrayList([]const u8)) !void { + var l_it = left.iterator(); + while (l_it.next()) |l| { + var r_it = right.iterator(); + while (r_it.next()) |r| { + if (std.mem.eql(u8, l.*, r.*)) { + try intersection.append(l.*); + } + } + } +} + +test "intersect" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const ally = arena.allocator(); + + var left = std.BufSet.init(ally); + try left.insert("banana"); + try left.insert("mango"); + try left.insert("papaya"); + + var right = std.BufSet.init(ally); + try right.insert("banana"); + try right.insert("mango"); + try right.insert("avocado"); + + { + // partial intersection + const expected = &[2][]const u8{ "banana", "mango" }; + var actual = std.ArrayList([]const u8).init(ally); + + try intersect(&left, &right, &actual); + + for (actual.items, expected) |a, e| { + try std.testing.expectEqualStrings(e, a); + } + } + { + // full intersection + const expected = &[3][]const u8{ "banana", "mango", "papaya" }; + var actual = std.ArrayList([]const u8).init(ally); + + try intersect(&left, &left, &actual); + + for (actual.items, expected) |a, e| { + try std.testing.expectEqualStrings(e, a); + } + } + { + // no intersection + var empty = std.BufSet.init(ally); + var actual = std.ArrayList([]const u8).init(ally); + + try intersect(&left, &empty, &actual); + + try std.testing.expect(actual.items.len == 0); + } +} + +fn difference(lessening: *std.BufSet, subtracting: [][]const u8) void { + var less_it = lessening.iterator(); + + while (less_it.next()) |less| { + for (subtracting) |sub| { + if (std.mem.eql(u8, less.*, sub)) { + lessening.remove(less.*); + } + } + } +} + +test "difference" { + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const ally = arena.allocator(); + + { + // partial diff + var less = std.BufSet.init(ally); + try less.insert("banana"); + try less.insert("mango"); + try less.insert("papaya"); + + var sub = [_][]const u8{ "banana", "mango" }; + + difference(&less, &sub); + + try std.testing.expect(less.count() == 1); + try std.testing.expect(less.contains("papaya")); + } + { + // full diff + var less = std.BufSet.init(ally); + try less.insert("banana"); + try less.insert("mango"); + try less.insert("papaya"); + + var sub = [_][]const u8{ "avocado", "kiwi", "ananas" }; + + difference(&less, &sub); + + try std.testing.expect(less.count() == 3); + try std.testing.expect(less.contains("banana")); + try std.testing.expect(less.contains("mango")); + try std.testing.expect(less.contains("papaya")); + } + { + // no diff + var less = std.BufSet.init(ally); + try less.insert("banana"); + try less.insert("mango"); + try less.insert("papaya"); + + var sub = [_][]const u8{ "mango", "papaya", "banana" }; + + difference(&less, &sub); + + try std.testing.expect(less.count() == 0); + } +} diff --git a/11_dynamic_programming/zig/longest_common_subsequence.zig b/11_dynamic_programming/zig/longest_common_subsequence.zig index b0d59094..8ad71000 100644 --- a/11_dynamic_programming/zig/longest_common_subsequence.zig +++ b/11_dynamic_programming/zig/longest_common_subsequence.zig @@ -2,18 +2,20 @@ const std = @import("std"); const heap = std.heap; const math = std.math; const expect = std.testing.expect; +const expectEqualStrings = std.testing.expectEqualStrings; pub fn main() !void { var gpa = heap.GeneralPurposeAllocator(.{}){}; var arena = heap.ArenaAllocator.init(gpa.allocator()); defer arena.deinit(); - var n = try subsequence(arena.allocator(), "fish", "fosh"); - std.debug.print("{d}\n", .{n}); + const n, const sub = try subsequence(arena.allocator(), "fish", "fosh"); + std.debug.print("{d}: {s}\n", .{ n, sub }); } -fn subsequence(allocator: std.mem.Allocator, a: []const u8, b: []const u8) !u32 { +fn subsequence(allocator: std.mem.Allocator, a: []const u8, b: []const u8) !struct { u32, []const u8 } { var grid = try allocator.alloc([]u32, a.len + 1); + var subseq = try std.ArrayList(u8).initCapacity(allocator, @max(a.len, b.len)); for (grid) |*row| { row.* = try allocator.alloc(u32, b.len + 1); @@ -28,36 +30,34 @@ fn subsequence(allocator: std.mem.Allocator, a: []const u8, b: []const u8) !u32 while (j <= b.len) : (j += 1) { if (a[i - 1] == b[j - 1]) { grid[i][j] = grid[i - 1][j - 1] + 1; + try subseq.append(a[i - 1]); } else { - grid[i][j] = math.max(grid[i][j - 1], grid[i - 1][j]); + grid[i][j] = @max(grid[i][j - 1], grid[i - 1][j]); } } } - return grid[a.len][b.len]; + const sub = try subseq.toOwnedSlice(); + return .{ grid[a.len][b.len], sub }; } test "subsequence" { - var tests = [_]struct { + const tests = [_]struct { a: []const u8, b: []const u8, - exp: u32, + expected: struct { u32, []const u8 }, }{ - .{ .a = "abc", .b = "abcd", .exp = 3 }, - .{ .a = "pera", .b = "mela", .exp = 2 }, - .{ .a = "banana", .b = "kiwi", .exp = 0 }, + .{ .a = "abc", .b = "abcd", .expected = .{ 3, "abc" } }, + .{ .a = "pera", .b = "mela", .expected = .{ 2, "ea" } }, + .{ .a = "banana", .b = "kiwi", .expected = .{ 0, "" } }, }; for (tests) |t| { - var gpa = heap.GeneralPurposeAllocator(.{}){}; - var arena = heap.ArenaAllocator.init(gpa.allocator()); - defer { - arena.deinit(); - const leaked = gpa.deinit(); - if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return - } + var arena = heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + + const actual = try subsequence(arena.allocator(), t.a, t.b); - var n = try subsequence(arena.allocator(), t.a, t.b); - try expect(n == t.exp); + try std.testing.expectEqualDeep(t.expected, actual); } } From 1d5567fe9a20adc29acf1672511bce5323d917cb Mon Sep 17 00:00:00 2001 From: Renan Duarte Leal <104607462+Renan-Leal@users.noreply.github.com> Date: Sat, 7 Dec 2024 10:30:04 -0300 Subject: [PATCH 119/140] Update 02_check_voter.go (#288) fix voting status --- 05_hash_tables/golang/02_check_voter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/05_hash_tables/golang/02_check_voter.go b/05_hash_tables/golang/02_check_voter.go index 4da95446..296371f4 100644 --- a/05_hash_tables/golang/02_check_voter.go +++ b/05_hash_tables/golang/02_check_voter.go @@ -13,9 +13,9 @@ func main() { func check_voter(name string) { if voted[name] { - fmt.Println("kick tem out!") + fmt.Println("kick them out!") } else { voted[name] = true - fmt.Println("let tem vote!") + fmt.Println("let them vote!") } } From add60334fbe45402053f46b3379228f1556fc524 Mon Sep 17 00:00:00 2001 From: Renan Duarte Leal <104607462+Renan-Leal@users.noreply.github.com> Date: Sat, 7 Dec 2024 10:34:16 -0300 Subject: [PATCH 120/140] Add Dijkstra's algorithm to Typescript (#291) --- .../ts/dijkstras_algorithm.ts | 59 +++++++++++++++++++ 09_dijkstras_algorithm/ts/iterable_graph.ts | 26 ++++++++ 2 files changed, 85 insertions(+) create mode 100644 09_dijkstras_algorithm/ts/dijkstras_algorithm.ts create mode 100644 09_dijkstras_algorithm/ts/iterable_graph.ts diff --git a/09_dijkstras_algorithm/ts/dijkstras_algorithm.ts b/09_dijkstras_algorithm/ts/dijkstras_algorithm.ts new file mode 100644 index 00000000..67ed3189 --- /dev/null +++ b/09_dijkstras_algorithm/ts/dijkstras_algorithm.ts @@ -0,0 +1,59 @@ +import { Graph, GraphIterable } from "./iterable_graph"; + +const dijkstraGraph: Graph> = { + start: { a: 6, b: 2 }, + a: { fin: 1 }, + b: { a: 3, fin: 5 }, + fin: {}, +}; + +const costs: Graph = { + a: 6, + b: 2, + fin: Infinity, +}; + +const parents: Graph = { + a: "start", + b: "start", + fin: null, +}; + +let processed: string[] = []; + +const findLowestCostNode = (costs: Graph): string | null => { + let lowestCost = Infinity; + let lowestCostNode: string | null = null; + + const iterableGraph = new GraphIterable(costs); + + for (const node of iterableGraph) { + const cost = costs[node]; + if (cost < lowestCost && !processed.includes(node)) { + lowestCost = cost; + lowestCostNode = node; + } + } + return lowestCostNode; +}; + +let node = findLowestCostNode(costs); + +while (node !== null) { + const cost = costs[node]; + + const neighbors = dijkstraGraph[node]; + Object.keys(neighbors).forEach((n: string) => { + const newCost = cost + neighbors[n]; + if (costs[n] > newCost) { + costs[n] = newCost; + parents[n] = node; + } + }); + + processed.push(node); + node = findLowestCostNode(costs); +} + +console.log("Cost from the start to each node:"); +console.log(costs); // { a: 5, b: 2, fin: 6 } diff --git a/09_dijkstras_algorithm/ts/iterable_graph.ts b/09_dijkstras_algorithm/ts/iterable_graph.ts new file mode 100644 index 00000000..7ba10b4b --- /dev/null +++ b/09_dijkstras_algorithm/ts/iterable_graph.ts @@ -0,0 +1,26 @@ +export interface Graph { + [key: string]: T; +} + +export class GraphIterable implements Iterable { + private graph: Graph; + + constructor(graph: Graph) { + this.graph = graph; + } + + [Symbol.iterator](): Iterator { + const keys = Object.keys(this.graph); + let index = 0; + + return { + next: (): IteratorResult => { + if (index < keys.length) { + return { value: keys[index++], done: false }; + } else { + return { value: undefined, done: true }; + } + }, + }; + } +} From 741c11bac6f787d34e33d1de79bc9befe071f8e5 Mon Sep 17 00:00:00 2001 From: Artem Chernyak Date: Sat, 7 Dec 2024 07:36:33 -0600 Subject: [PATCH 121/140] add rust breadth first search (#293) --- 06_breadth-first_search/rust/Cargo.lock | 7 +++ 06_breadth-first_search/rust/Cargo.toml | 6 +++ 06_breadth-first_search/rust/src/main.rs | 68 ++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 06_breadth-first_search/rust/Cargo.lock create mode 100644 06_breadth-first_search/rust/Cargo.toml create mode 100644 06_breadth-first_search/rust/src/main.rs diff --git a/06_breadth-first_search/rust/Cargo.lock b/06_breadth-first_search/rust/Cargo.lock new file mode 100644 index 00000000..3c57ea9e --- /dev/null +++ b/06_breadth-first_search/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "breadth_first" +version = "0.1.0" diff --git a/06_breadth-first_search/rust/Cargo.toml b/06_breadth-first_search/rust/Cargo.toml new file mode 100644 index 00000000..7fa294fc --- /dev/null +++ b/06_breadth-first_search/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "breadth_first" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/06_breadth-first_search/rust/src/main.rs b/06_breadth-first_search/rust/src/main.rs new file mode 100644 index 00000000..936cb6bd --- /dev/null +++ b/06_breadth-first_search/rust/src/main.rs @@ -0,0 +1,68 @@ +use std::collections::{HashMap, VecDeque}; +use std::fmt; + +#[derive(Eq, Hash, PartialEq)] +struct Person(String); + +impl Person { + fn is_seller(&self) -> bool { + self.0.ends_with('m') + } +} + +impl fmt::Display for Person { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.0) + } +} + +fn search(graph: &HashMap<&Person, Vec<&Person>>, start: &Person) { + let mut search_queue = VecDeque::new(); + search_queue.push_back(start); + + let mut searched: Vec<&Person> = Vec::with_capacity(graph.len()); + loop { + match search_queue.pop_front() { + Some(person) => { + if !searched.contains(&person) { + if person.is_seller() { + println!("{} is a mango seller!", person); + break; + } else { + for p in graph.get(&person).unwrap() { + search_queue.push_back(p); + searched.push(person); + } + } + } + } + None => { + println!("no mango seller found!"); + break; + } + } + } +} + +fn main() { + let you = Person("you".to_string()); + let alice = Person("alice".to_string()); + let bob = Person("bob".to_string()); + let claire = Person("claire".to_string()); + let anuj = Person("anuj".to_string()); + let peggy = Person("peggy".to_string()); + let thom = Person("thom".to_string()); + let jonny = Person("jonny".to_string()); + + let mut graph = HashMap::new(); + graph.insert(&you, vec![&alice, &bob, &claire]); + graph.insert(&bob, vec![&anuj, &peggy]); + graph.insert(&alice, vec![&peggy]); + graph.insert(&claire, vec![&thom, &jonny]); + graph.insert(&anuj, vec![]); + graph.insert(&peggy, vec![]); + graph.insert(&thom, vec![]); + graph.insert(&jonny, vec![]); + + search(&graph, &you); +} From 93a7b227b336b65592ccfab2ec3291f566a0545d Mon Sep 17 00:00:00 2001 From: Artem Chernyak Date: Sat, 7 Dec 2024 07:36:57 -0600 Subject: [PATCH 122/140] add dijkstra's algorithm in rust (#294) --- 09_dijkstras_algorithm/rust/Cargo.lock | 7 +++ 09_dijkstras_algorithm/rust/Cargo.toml | 6 +++ 09_dijkstras_algorithm/rust/src/main.rs | 70 +++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 09_dijkstras_algorithm/rust/Cargo.lock create mode 100644 09_dijkstras_algorithm/rust/Cargo.toml create mode 100644 09_dijkstras_algorithm/rust/src/main.rs diff --git a/09_dijkstras_algorithm/rust/Cargo.lock b/09_dijkstras_algorithm/rust/Cargo.lock new file mode 100644 index 00000000..8ba83558 --- /dev/null +++ b/09_dijkstras_algorithm/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "dijkstra" +version = "0.1.0" diff --git a/09_dijkstras_algorithm/rust/Cargo.toml b/09_dijkstras_algorithm/rust/Cargo.toml new file mode 100644 index 00000000..e23f0cba --- /dev/null +++ b/09_dijkstras_algorithm/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "dijkstra" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/09_dijkstras_algorithm/rust/src/main.rs b/09_dijkstras_algorithm/rust/src/main.rs new file mode 100644 index 00000000..80e593ca --- /dev/null +++ b/09_dijkstras_algorithm/rust/src/main.rs @@ -0,0 +1,70 @@ +use std::{collections::HashMap, u64}; + +fn find_lowest_cost_node(processed: &Vec, costs: &HashMap) -> Option { + let mut lowest_cost = u64::MAX; + let mut lowest_cost_node = None; + for (node, cost) in costs.iter() { + if *cost < lowest_cost && !processed.contains(node) { + lowest_cost = *cost; + lowest_cost_node = Some(node); + } + } + return lowest_cost_node.cloned(); +} + +fn main() { + // Graph Setup + let mut graph = HashMap::new(); + + let mut start_edges: HashMap = HashMap::new(); + start_edges.insert("a".to_string(), 6); + start_edges.insert("b".to_string(), 2); + graph.insert("start".to_string(), start_edges); + + let mut a_edges = HashMap::new(); + a_edges.insert("fin".to_string(), 1); + graph.insert("a".to_string(), a_edges); + + let mut b_edges = HashMap::new(); + b_edges.insert("a".to_string(), 3); + b_edges.insert("fin".to_string(), 5); + graph.insert("b".to_string(), b_edges); + + let fin_edges = HashMap::new(); + graph.insert("fin".to_string(), fin_edges); + + // Costs Setup + let mut costs: HashMap = HashMap::new(); + costs.insert("a".to_string(), 6); + costs.insert("b".to_string(), 2); + costs.insert("fin".to_string(), u64::MAX); + + // Parents Setup + let mut parents = HashMap::new(); + parents.insert("a".to_string(), Some("start".to_string())); + parents.insert("b".to_string(), Some("start".to_string())); + parents.insert("fin".to_string(), None); + + let mut processed: Vec = vec![]; + + loop { + let node = find_lowest_cost_node(&processed, &costs); + match node { + Some(node) => { + let cost = *costs.get(&node).unwrap(); + let neighbors = graph.get(&node).unwrap(); + for (n, ncost) in neighbors.iter() { + let new_cost = cost + *ncost; + if *costs.get(n).unwrap() > new_cost { + costs.insert(n.to_string(), new_cost); + parents.insert(n.to_string(), Some(node.clone())); + } + } + processed.push(node) + } + None => break, + } + } + println!("costs: {:?}", costs); + println!("parents: {:?}", parents); +} From 25b308ff5f5f5dcbe8d8b5ca5a4305f457c259e2 Mon Sep 17 00:00:00 2001 From: Artem Chernyak Date: Sat, 7 Dec 2024 07:37:26 -0600 Subject: [PATCH 123/140] add greedy algorithms example in rust (#295) --- 10_greedy_algorithms/rust/Cargo.lock | 7 +++++ 10_greedy_algorithms/rust/Cargo.toml | 6 ++++ 10_greedy_algorithms/rust/src/main.rs | 42 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 10_greedy_algorithms/rust/Cargo.lock create mode 100644 10_greedy_algorithms/rust/Cargo.toml create mode 100644 10_greedy_algorithms/rust/src/main.rs diff --git a/10_greedy_algorithms/rust/Cargo.lock b/10_greedy_algorithms/rust/Cargo.lock new file mode 100644 index 00000000..957b7a80 --- /dev/null +++ b/10_greedy_algorithms/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "greedy_algorithms" +version = "0.1.0" diff --git a/10_greedy_algorithms/rust/Cargo.toml b/10_greedy_algorithms/rust/Cargo.toml new file mode 100644 index 00000000..c4e8ff31 --- /dev/null +++ b/10_greedy_algorithms/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "greedy_algorithms" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/10_greedy_algorithms/rust/src/main.rs b/10_greedy_algorithms/rust/src/main.rs new file mode 100644 index 00000000..220df521 --- /dev/null +++ b/10_greedy_algorithms/rust/src/main.rs @@ -0,0 +1,42 @@ +use std::collections::{HashMap, HashSet}; + +fn main() { + let mut states_needed = HashSet::from(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); + + let mut stations = HashMap::from([ + ("kone", HashSet::from(["id", "nv", "ut"])), + ("ktwo", HashSet::from(["wa", "id", "mt"])), + ("kthree", HashSet::from(["or", "nv", "ca"])), + ("kfour", HashSet::from(["nv", "ut"])), + ("kfive", HashSet::from(["ca", "az"])), + ]); + + let mut final_stations = HashSet::new(); + while !states_needed.is_empty() { + let mut best_station = None; + let mut states_covered = HashSet::new(); + for (station, states_for_station) in &stations { + let covered: HashSet<_> = states_needed + .intersection(&states_for_station) + .cloned() + .collect(); + if covered.len() > states_covered.len() && !final_stations.contains(station) { + best_station = Some(*station); + states_covered = covered; + } + } + match best_station { + Some(station) => { + states_needed = states_needed.difference(&states_covered).cloned().collect(); + final_stations.insert(station); + stations.remove(station); + } + None => { + println!("Coold not complete: {:?}", final_stations); + break; + } + } + } + + println!("{:?}", final_stations); +} From f4910688db48624a35d702292dbb0e9df0122f5b Mon Sep 17 00:00:00 2001 From: Artem Chernyak Date: Sat, 7 Dec 2024 07:38:07 -0600 Subject: [PATCH 124/140] add dynamic programming examples in rust (#296) --- 11_dynamic_programming/rust/Cargo.lock | 7 +++ 11_dynamic_programming/rust/Cargo.toml | 6 +++ 11_dynamic_programming/rust/src/main.rs | 65 +++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 11_dynamic_programming/rust/Cargo.lock create mode 100644 11_dynamic_programming/rust/Cargo.toml create mode 100644 11_dynamic_programming/rust/src/main.rs diff --git a/11_dynamic_programming/rust/Cargo.lock b/11_dynamic_programming/rust/Cargo.lock new file mode 100644 index 00000000..1cf52686 --- /dev/null +++ b/11_dynamic_programming/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "longest_common" +version = "0.1.0" diff --git a/11_dynamic_programming/rust/Cargo.toml b/11_dynamic_programming/rust/Cargo.toml new file mode 100644 index 00000000..91aa97f3 --- /dev/null +++ b/11_dynamic_programming/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "longest_common" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/11_dynamic_programming/rust/src/main.rs b/11_dynamic_programming/rust/src/main.rs new file mode 100644 index 00000000..dffbe91b --- /dev/null +++ b/11_dynamic_programming/rust/src/main.rs @@ -0,0 +1,65 @@ +use std::cmp; + +fn build_dp_table(table1: &[T], table2: &[T]) -> Vec> { + let mut dp_table = vec![]; + for i in 0..table1.len() { + dp_table.push(vec![]); + for _ in 0..table2.len() { + dp_table[i].push(0); + } + } + + dp_table +} + +fn longest_common_substring(table1: &[T], table2: &[T]) -> Vec> { + let mut dp_table = build_dp_table(table1, table2); + + for (i, c1) in table1.into_iter().enumerate() { + for (j, c2) in table2.into_iter().enumerate() { + if c1 == c2 { + dp_table[i][j] = + dp_table[i.checked_sub(1).unwrap_or(0)][j.checked_sub(1).unwrap_or(0)] + 1; + } else { + dp_table[i][j] = 0; + } + } + } + + dp_table +} + +fn longest_common_subsequence(table1: &[T], table2: &[T]) -> Vec> { + let mut dp_table = build_dp_table(table1, table2); + + for (i, c1) in table1.into_iter().enumerate() { + for (j, c2) in table2.into_iter().enumerate() { + if c1 == c2 { + dp_table[i][j] = + dp_table[i.checked_sub(1).unwrap_or(0)][j.checked_sub(1).unwrap_or(0)] + 1; + } else { + dp_table[i][j] = cmp::max( + dp_table[i.checked_sub(1).unwrap_or(0)][j], + dp_table[i][j.checked_sub(1).unwrap_or(0)], + ); + } + } + } + + dp_table +} + +fn main() { + let dp_table_blue = ['b', 'l', 'u', 'e']; + let dp_table_clues = ['c', 'l', 'u', 'e', 's']; + + println!("Longest substring:"); + for line in longest_common_substring(&dp_table_blue, &dp_table_clues) { + println!("{:?}", line) + } + + println!("Longest subsequence:"); + for line in longest_common_subsequence(&dp_table_blue, &dp_table_clues) { + println!("{:?}", line) + } +} From c8ff601c527789a76a5ba6b4979f9e06960013e5 Mon Sep 17 00:00:00 2001 From: Armin Date: Sat, 7 Dec 2024 17:09:40 +0330 Subject: [PATCH 125/140] feat: enhance recursive binary search to correctly return found index (#298) Co-authored-by: armin --- .../Golang/BinarySearch.go | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/01_introduction_to_algorithms/Golang/BinarySearch.go b/01_introduction_to_algorithms/Golang/BinarySearch.go index 988f541d..d360d1aa 100644 --- a/01_introduction_to_algorithms/Golang/BinarySearch.go +++ b/01_introduction_to_algorithms/Golang/BinarySearch.go @@ -19,7 +19,26 @@ func checkBin(list []int, i int) int { return -1 } +func RecursiveCheckBin(list []int, item int, high, low int) int { + if high >= low { + mid := (high + low) / 2 + + if list[mid] == item { + return mid + } else if list[mid] > item { + return RecursiveCheckBin(list, item, mid-1, low) + } else { + return RecursiveCheckBin(list, item, high, mid+1) + } + + } + return -1 +} + func main() { - fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, 1)) // 0 - fmt.Println(checkBin([]int{1, 2, 3, 4, 5}, -1)) // -1 + list := []int{1, 2, 3, 4, 5} + fmt.Println(checkBin(list, 2)) // 0 + fmt.Println(checkBin(list, -1)) // -1 + fmt.Println(RecursiveCheckBin([]int{1, 2, 3, 4, 5}, 2, len(list)-1, 0)) // 1 + fmt.Println(RecursiveCheckBin([]int{1, 2, 3, 4, 5}, 0, len(list)-1, 0)) //-1 } From 22c23551cb08383269bf52e678997bfb7945d5f8 Mon Sep 17 00:00:00 2001 From: Ismayil Mammadov <88452800+7empestGit@users.noreply.github.com> Date: Sat, 7 Dec 2024 17:40:21 +0400 Subject: [PATCH 126/140] Added 01_filesystem_dfs for 07_trees in C# (#299) --- 07_trees/csharp/01_filesystem_dfs/Program.cs | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 07_trees/csharp/01_filesystem_dfs/Program.cs diff --git a/07_trees/csharp/01_filesystem_dfs/Program.cs b/07_trees/csharp/01_filesystem_dfs/Program.cs new file mode 100644 index 00000000..f2b2da1d --- /dev/null +++ b/07_trees/csharp/01_filesystem_dfs/Program.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using System.Linq; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + string dir = Path.Combine(Directory.GetCurrentDirectory(), "pics"); + + PrintNames(dir); + } + + private static void PrintNames(string dir) + { + var filesAndDirs = Directory.GetFileSystemEntries(dir).OrderBy(f => f, StringComparer.OrdinalIgnoreCase); + + // loop through every file and folder in the current folder + foreach (var path in filesAndDirs) + { + if (File.Exists(path)) + { + // if it is a file, print out the name + Console.WriteLine(Path.GetFileName(path)); + } + else + { + // if it is a folder, call this function recursively on it + // to look for files and folders + PrintNames(path); + } + } + } + } +} \ No newline at end of file From 440db4ff11c93fe37646a7e87f993968509b095c Mon Sep 17 00:00:00 2001 From: Toheeb Oyekola <77902937+To-heeb@users.noreply.github.com> Date: Sat, 7 Dec 2024 14:43:11 +0100 Subject: [PATCH 127/140] Added sum with recursion to 03_recursion, java folder (#254) * added sum with recursion to 03_recursion, java folder * Update .gitignore * update list not to be modified during recursion * fixed update --- 03_recursion/java/04_sum/src/Sum.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 03_recursion/java/04_sum/src/Sum.java diff --git a/03_recursion/java/04_sum/src/Sum.java b/03_recursion/java/04_sum/src/Sum.java new file mode 100644 index 00000000..0abcb2da --- /dev/null +++ b/03_recursion/java/04_sum/src/Sum.java @@ -0,0 +1,19 @@ +import java.util.*; + +public class Sum { + public static int sum(ArrayList num_list, int index) { + + if (num_list.size() == index) { + return 0; + } else { + int num = num_list.get(index); + return num + sum(num_list, index + 1); + } + + } + + public static void main(String[] args) { + int total = sum(new ArrayList(Arrays.asList(2, 4, 6)), 0); + System.out.println(total); + } +} From 00b28478ce17b8b6d08b07adc9bb12d1dd153739 Mon Sep 17 00:00:00 2001 From: Poliakov Ilia Date: Sat, 7 Dec 2024 17:44:23 +0400 Subject: [PATCH 128/140] Update 04_recursive_max.js with fix for alternative solution (#262) * Update 04_recursive_max.js with fix for alternative solution Current alternative solution works only for arrays of natural numbers and for empty arrays it returns 0 instead of null or Error. This commit fixes these problems. * Considering comments from the author --------- Co-authored-by: Ilia Poliakov --- 04_quicksort/javascript/04_recursive_max.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/04_quicksort/javascript/04_recursive_max.js b/04_quicksort/javascript/04_recursive_max.js index f3c15f9b..c51aebfe 100644 --- a/04_quicksort/javascript/04_recursive_max.js +++ b/04_quicksort/javascript/04_recursive_max.js @@ -14,12 +14,12 @@ function max(array) { /** * Calculate the largest number - * This solution works for arrays of any length + * This solution works for arrays of any length and returns the smallest possible number for empty arrays * @param {Array} array Array of numbers * @param {number} max Maximum value - * @returns {number} The argest number + * @returns {number} The largest number */ -function alternativeSolutionMax(array, max = 0) { +function alternativeSolutionMax(array, max = Number.MIN_VALUE) { return array.length === 0 ? max : alternativeSolutionMax(array.slice(1), array[0] > max ? array[0] : max); @@ -27,3 +27,6 @@ function alternativeSolutionMax(array, max = 0) { console.log(max([1, 5, 10, 25, 16, 1])); // 25 console.log(alternativeSolutionMax([1, 5, 10, 25, 16, 1])); // 25 + +console.log(max([])); // RangeError: Maximum call stack size exceeded +console.log(alternativeSolutionMax([])); // Number.MIN_VALUE From c06ad954f0db53c2b9d07cb67c1f109df96db7a5 Mon Sep 17 00:00:00 2001 From: Mahmoud Hamdy Date: Sat, 7 Dec 2024 15:45:03 +0200 Subject: [PATCH 129/140] Update 01_binary_search.cpp (#271) use template to the item that we are search for --- 01_introduction_to_algorithms/c++11/01_binary_search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_introduction_to_algorithms/c++11/01_binary_search.cpp b/01_introduction_to_algorithms/c++11/01_binary_search.cpp index f0e06e51..b56f945f 100644 --- a/01_introduction_to_algorithms/c++11/01_binary_search.cpp +++ b/01_introduction_to_algorithms/c++11/01_binary_search.cpp @@ -5,7 +5,7 @@ using std::cout; using std::endl; template -int binary_search(const std::vector& list, const int& item) { +int binary_search(const std::vector& list, const T& item) { int low = 0; int high = list.size() - 1; From 45bf3c086d2fd09608da1e4f701587c0c06ed003 Mon Sep 17 00:00:00 2001 From: Timur Sevimli Date: Sat, 7 Dec 2024 16:48:14 +0300 Subject: [PATCH 130/140] Increase readability, update code style and optimise for modern JavaScript (#273) * Remove loops on recursive example, increase readability and optimise * Update style and optimise * Update 01_loop_sum_reduce_version.js Update style * Update style * Rename identificators * Rename identificators * Convert shift to splice --- .../javascript/01_selection_sort.js | 49 ++++++++----------- .../javascript/02_recursive_selection_sort.js | 38 +++++++------- .../javascript/01_loop_sum_reduce_version.js | 6 +-- 04_quicksort/javascript/02_recursive_sum.js | 9 ++-- 4 files changed, 46 insertions(+), 56 deletions(-) diff --git a/02_selection_sort/javascript/01_selection_sort.js b/02_selection_sort/javascript/01_selection_sort.js index ba3ed7a0..18567c46 100644 --- a/02_selection_sort/javascript/01_selection_sort.js +++ b/02_selection_sort/javascript/01_selection_sort.js @@ -1,46 +1,39 @@ -"use strict"; - +'use strict'; /** * Finds the index of the element with the smallest value in the array * @param {Array} array Source array * @returns {number} Index of the element with the smallest value */ -function findSmallestIndex(array) { - var smallestElement = array[0]; // Stores the smallest value - var smallestIndex = 0; // Stores the index of the smallest value - - for (var i = 1; i < array.length; i++) { - if (array[i] < smallestElement) { - smallestElement = array[i]; - smallestIndex = i; - } +const findSmallest = (arr) => { + let [smallestElement] = arr; + let smallestIndex = 0; + for (let i = 1; i < arr.length; i++) { + const el = arr[i]; + if (el >= smallestElement) continue; + smallestElement = el; + smallestIndex = i; } - return smallestIndex; -} +}; /** * Sort array by increment * @param {Array} array Source array * @returns {Array} New sorted array */ -function selectionSort(array) { - var sortedArray = []; - var copyArray = array.slice(); - var length = array.length; - - for (var i = 0; i < length; i++) { - // Finds the smallest element in the array - var smallestIndex = findSmallestIndex(copyArray); - // Adds the smallest element to new array - sortedArray.push(copyArray.splice(smallestIndex, 1)[0]); +const selectionSort = (arr) => { + const size = arr.length; + const result = new Array(size).fill(0); + for (let i = 0; i < size; i++) { + const smallestIndex = findSmallest(arr); + const [smallestElement] = arr.splice(smallestIndex, 1); + result[i] = smallestElement; } - - return sortedArray; -} + return result; +}; const sourceArray = [5, 3, 6, 2, 10]; const sortedArray = selectionSort(sourceArray); -console.log("Source array - ", sourceArray); // [5, 3, 6, 2, 10] -console.log("New sorted array - ", sortedArray); // [2, 3, 5, 6, 10] +console.log('Source array - ', sourceArray); // [5, 3, 6, 2, 10] +console.log('New sorted array - ', sourtedArray); // [2, 3, 5, 6, 10] \ No newline at end of file diff --git a/02_selection_sort/javascript/02_recursive_selection_sort.js b/02_selection_sort/javascript/02_recursive_selection_sort.js index 69e2abc5..276e7308 100644 --- a/02_selection_sort/javascript/02_recursive_selection_sort.js +++ b/02_selection_sort/javascript/02_recursive_selection_sort.js @@ -1,20 +1,17 @@ +'use strict'; /** * 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; +const findSmallest = (arr, smallest = arr[0], smallestIndex = 0, i = 1) => { + if (arr.length <= i) return smallestIndex; + const curr = arr[i]; + if (curr < smallest) { + smallest = curr; + smallestIndex = i; + } + return findSmallest(arr, smallest, smallestIndex, i + 1); }; /** @@ -22,12 +19,15 @@ const findSmallest = ( arr ) => { * @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 ) ); +const selectionSort = (arr, result = []) => { + if (arr.length > 0) { + const smallestIndex = findSmallest(arr); + const [smallest] = arr.splice(smallestIndex, 1); + result.push(smallest); + return selectionSort(arr, result); + } + return result; }; -let arr = [5, 3, 6, 2, 10]; - -console.log( selectionSort(arr) ); +const arr = [5, 3, 6, 2, 10]; +console.log(selectionSort(arr)); diff --git a/04_quicksort/javascript/01_loop_sum_reduce_version.js b/04_quicksort/javascript/01_loop_sum_reduce_version.js index 801978ad..e36ebfd8 100644 --- a/04_quicksort/javascript/01_loop_sum_reduce_version.js +++ b/04_quicksort/javascript/01_loop_sum_reduce_version.js @@ -5,10 +5,6 @@ * @param {Array} array Array of numbers * @returns {number} Sum of the numbers */ -function sumReduce(array) { - return array.reduce(function(prev, cur) { - return prev + cur; - }); -} +const sumReduce = (array) => array.reduce((prev, cur) => prev + cur, 0); console.log(sumReduce([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/javascript/02_recursive_sum.js b/04_quicksort/javascript/02_recursive_sum.js index b48ca431..ab745631 100644 --- a/04_quicksort/javascript/02_recursive_sum.js +++ b/04_quicksort/javascript/02_recursive_sum.js @@ -1,13 +1,14 @@ -"use strict"; +'use strict'; /** * Sums values in the array by recursive * @param {Array} array Array of numbers * @returns {number} Sum of the numbers */ -function sumRecursive(arr) { - if (arr.length == 0) return 0; +const sumRecursive = (arr = []) => { + if (!arr.length) return 0; return arr[0] + sumRecursive(arr.slice(1)); -} +}; + console.log(sumRecursive([1, 2, 3, 4])); // 10 From 1de675efe114a02560225ed01d0f96bd6902e27a Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Sat, 7 Dec 2024 08:28:56 -0600 Subject: [PATCH 131/140] Contributing guidelines update --- README.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7602c1c3..7d130980 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,19 @@ This repository contains every image in Grokking Algorithms in high resolution. ## Contributing -- The examples in this book are written in Python, but I'd like examples in Ruby, JavaScript, C, and other languages too. Please add examples in other languages! -- Pull request are the quickest way to contribute to this repository but unfortunately I am not as responsive to them as I'd like to be. I'll get to them but it might take a while! -- This repo is for easy to read examples. So even though I love well tested, optimized code, I won't be merging PRs related to tests or optimization, since those will increase cognitive load for readers. +Thanks for wanting to contribute to this repo! + +If you have found a mistake in the book or have a question, please email me as that will be the best way to get a response. My email is listed on my website, adit.io. +If you would like to make a change, please go ahead and open a PR with your suggested change. I am quicker at responding to those than I am to issues. + +It takes me a long time to respond to PRs. It's something I'm trying to get better at, but I apologize in advance for how long it will take. I will eventually get to it. + +The contributions that are most useful are: +- fixing errors in existing code +- adding examples to new languages +- modernizing code as the language evolves +- making code easier to read. + +I'm less likely to merge code that involves stylistic changes, and I'm very unlikely to merge PRs that add complex optimizations, as the main purpose of this repo is to have easy to read examples that help people understand concepts. + +Thanks for contributing and I hope you're enjoying the book! \ No newline at end of file From a9d98d826ac5241294c379f29c215becd6e1dc67 Mon Sep 17 00:00:00 2001 From: Artem Chernyak Date: Sun, 15 Dec 2024 19:35:58 -0600 Subject: [PATCH 132/140] add rust quicksort (#292) * add rust quicksort * remove binary search from quicksort --- 04_quicksort/rust/Cargo.lock | 7 +++ 04_quicksort/rust/Cargo.toml | 6 +++ 04_quicksort/rust/src/main.rs | 98 +++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 04_quicksort/rust/Cargo.lock create mode 100644 04_quicksort/rust/Cargo.toml create mode 100644 04_quicksort/rust/src/main.rs diff --git a/04_quicksort/rust/Cargo.lock b/04_quicksort/rust/Cargo.lock new file mode 100644 index 00000000..fee3150d --- /dev/null +++ b/04_quicksort/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "quicksort" +version = "0.1.0" diff --git a/04_quicksort/rust/Cargo.toml b/04_quicksort/rust/Cargo.toml new file mode 100644 index 00000000..c33b5101 --- /dev/null +++ b/04_quicksort/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "quicksort" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/04_quicksort/rust/src/main.rs b/04_quicksort/rust/src/main.rs new file mode 100644 index 00000000..18843232 --- /dev/null +++ b/04_quicksort/rust/src/main.rs @@ -0,0 +1,98 @@ +fn rec_sum(list: &[usize]) -> usize { + match list.get(0) { + Some(x) => x + rec_sum(&list[1..]), + None => 0, + } +} + +fn rec_count(list: &[T]) -> usize { + match list.get(0) { + Some(_) => 1 + rec_count(&list[1..]), + None => 0, + } +} + +fn maximum(list: &[T]) -> Option<&T> { + match list.get(0) { + Some(x) => match maximum(&list[1..]) { + Some(max) => { + if x > max { + Some(x) + } else { + Some(max) + } + } + None => Some(x), + }, + None => None, + } +} + +fn quicksort(list: &Vec) -> Vec { + if list.len() < 2 { + list.to_vec() + } else { + let pivot = &list[0]; + + let mut less = vec![]; + let mut greater = vec![]; + + for x in &list[1..] { + if x <= pivot { + less.push(x.clone()); + } else { + greater.push(x.clone()); + } + } + + let mut new = Vec::with_capacity(list.len()); + new.append(&mut quicksort(&less)); + new.push(pivot.clone()); + new.append(&mut quicksort(&greater)); + new + } +} + +fn main() { + let list = vec![10, 5, 2, 12, 3]; + + println!("quicksort: {:?}", quicksort(&list)); + println!("sum: {}", rec_sum(&list)); + println!("count: {}", rec_count(&list)); + println!("maximum: {:?}", maximum(&list)); +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn simple_rec_sum() { + let list = [2, 4, 6]; + let expected = 12; + + let result = rec_sum(&list); + + assert_eq!(result, expected); + } + + #[test] + fn simple_rec_count() { + let list = [2, 4, 6]; + let expected = 3; + + let result = rec_count(&list); + + assert_eq!(result, expected); + } + + #[test] + fn simple_maximum() { + let list = [2, 4, 6, 3]; + let expected = 6; + + let result = maximum(&list); + + assert_eq!(result, Some(&expected)); + } +} From 182947e5fb0c5093eecc82ebf51b90297e5f78cf Mon Sep 17 00:00:00 2001 From: Igor Moraes Date: Thu, 1 May 2025 20:22:19 -0300 Subject: [PATCH 133/140] Add TypeScript examples for chapters 10 and 11 (#311) --- 10_greedy_algorithms/ts/01_set_covering.ts | 34 +++++++++ 10_greedy_algorithms/ts/tsconfig.json | 12 ++++ .../ts/01_longest_common_subsequence.ts | 69 +++++++++++++++++++ 11_dynamic_programming/ts/tsconfig.json | 12 ++++ 4 files changed, 127 insertions(+) create mode 100644 10_greedy_algorithms/ts/01_set_covering.ts create mode 100644 10_greedy_algorithms/ts/tsconfig.json create mode 100644 11_dynamic_programming/ts/01_longest_common_subsequence.ts create mode 100644 11_dynamic_programming/ts/tsconfig.json diff --git a/10_greedy_algorithms/ts/01_set_covering.ts b/10_greedy_algorithms/ts/01_set_covering.ts new file mode 100644 index 00000000..eb2e7415 --- /dev/null +++ b/10_greedy_algorithms/ts/01_set_covering.ts @@ -0,0 +1,34 @@ +// You pass an array in, and it gets converted to a set. +let statesNeeded: Set = new Set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]); + +const stations: Record> = {}; +stations["kone"] = new Set(["id", "nv", "ut"]); +stations["ktwo"] = new Set(["wa", "id", "mt"]); +stations["kthree"] = new Set(["or", "nv", "ca"]); +stations["kfour"] = new Set(["nv", "ut"]); +stations["kfive"] = new Set(["ca", "az"]); + +const finalStations: Set = new Set(); + +while (statesNeeded.size) { + let bestStation: string | null = null; + let statesCovered: Set = new Set(); + + for (let station in stations) { + const states = stations[station]; + const covered = new Set([...statesNeeded].filter(x => states.has(x))); + + if (covered.size > statesCovered.size) { + bestStation = station; + statesCovered = covered; + } + } + + statesNeeded = new Set([...statesNeeded].filter(x => !statesCovered.has(x))); + + if (bestStation !== null) { + finalStations.add(bestStation); + } +} + +console.log(finalStations); // Set { 'kone', 'ktwo', 'kthree', 'kfive' } \ No newline at end of file diff --git a/10_greedy_algorithms/ts/tsconfig.json b/10_greedy_algorithms/ts/tsconfig.json new file mode 100644 index 00000000..d4027c48 --- /dev/null +++ b/10_greedy_algorithms/ts/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "es2015", + "es2016", + "es2017" + ], + "target": "es2015" + } + } + \ No newline at end of file diff --git a/11_dynamic_programming/ts/01_longest_common_subsequence.ts b/11_dynamic_programming/ts/01_longest_common_subsequence.ts new file mode 100644 index 00000000..3483c090 --- /dev/null +++ b/11_dynamic_programming/ts/01_longest_common_subsequence.ts @@ -0,0 +1,69 @@ +/** + * Search for LCS + * + * @param {string} string1 first string + * @param {string} string2 second string + * + * @return {object} with keys: lcs, offset, sequence + */ +function lcs(string1: string, string2: string): { lcs: number; offset: number; sequence: string } { + if (typeof string1 !== "string" || typeof string2 !== "string" || !string1 || !string2) { + return { + lcs: 0, + offset: 0, + sequence: "" + }; + } + + let lcs = 0; + let lastSubIndex = 0; + + const table: number[][] = []; + const len1 = string1.length; + const len2 = string2.length; + + let row: number; + let col: number; + + for (row = 0; row <= len1; row++) { + table[row] = []; + for (col = 0; col <= len2; col++) { + table[row][col] = 0; + } + } + + let i: number; + let j: number; + + for (i = 0; i < len1; i++) { + for (j = 0; j < len2; j++) { + if (string1[i] === string2[j]) { + if (table[i][j] === 0) { + table[i + 1][j + 1] = 1; + } else { + table[i + 1][j + 1] = table[i][j] + 1; + } + + if (table[i + 1][j + 1] > lcs) { + lcs = table[i + 1][j + 1]; + lastSubIndex = i; + } + } else { + table[i + 1][j + 1] = 0; + } + } + } + + return { + lcs: lcs, + offset: lastSubIndex - lcs + 1, + sequence: string1.slice(lastSubIndex - lcs + 1, lastSubIndex + 1) + }; +} + +// Test cases +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: 1, offset: 0, sequence: '0' } +console.log(lcs("0", 0 as any)); // { lcs: 0, offset: 0, sequence: '' } \ No newline at end of file diff --git a/11_dynamic_programming/ts/tsconfig.json b/11_dynamic_programming/ts/tsconfig.json new file mode 100644 index 00000000..d4027c48 --- /dev/null +++ b/11_dynamic_programming/ts/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "lib": [ + "dom", + "es2015", + "es2016", + "es2017" + ], + "target": "es2015" + } + } + \ No newline at end of file From df180e6f7b9c3fce82302e8ea84a0de39b6fa43c Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Fri, 2 May 2025 01:23:06 +0200 Subject: [PATCH 134/140] Add elixir longest common substring implementation (#307) --- .../elixir/02_longest_common_substring.exs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 11_dynamic_programming/elixir/02_longest_common_substring.exs diff --git a/11_dynamic_programming/elixir/02_longest_common_substring.exs b/11_dynamic_programming/elixir/02_longest_common_substring.exs new file mode 100644 index 00000000..ddbaad94 --- /dev/null +++ b/11_dynamic_programming/elixir/02_longest_common_substring.exs @@ -0,0 +1,49 @@ +defmodule LCSubstring do + def generate_table(word_a, word_b) do + word_a + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + nested_map = + word_b + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + Map.put(acc, index, 0) + end) + + Map.put(acc, index, nested_map) + end) + end + + def compute(table, word_a, word_b) do + for i <- 0..(length(word_a) - 1), reduce: table do + table -> + for j <- 0..(length(word_b) - 1), reduce: table do + table -> + if Enum.at(word_a, i) == Enum.at(word_b, j) do + value = (table[i - 1][j - 1] || 0) + 1 + put_in(table[i][j], value) + else + put_in(table[i][j], 0) + end + end + end + end +end + +word_a = ["b", "l", "u", "e"] +word_b = ["c", "l", "u", "e", "s"] + +result = + word_a + |> LCSubstring.generate_table(word_b) + |> LCSubstring.compute(word_a, word_b) + +Enum.each(result, fn {_index, value} -> + IO.inspect(Map.values(value)) +end) + +# Output +# [0, 0, 0, 0, 0] +# [0, 1, 0, 0, 0] +# [0, 0, 2, 0, 0] +# [0, 0, 0, 3, 0] From 9ff7468e9e1f5b84b23dd7749ed3f6b8eae72795 Mon Sep 17 00:00:00 2001 From: Serg Gini Date: Fri, 2 May 2025 02:24:42 +0300 Subject: [PATCH 135/140] D solutions (#305) * Added 1 and 2 chapters for D lang * [D] Added recursion code All examples were ported from the Python code directly to D. Naming convention of Dlang is not allowing to run code files, which started with numbers. To run examples rename the files * [D] quicksort code * [D] Added hashtable example Based on the Python code * Create 01_breadth_first_search.d Added D example for breadth-first search * Create 01_filesystem_dfs.d Filesystem example in D * Create 01_dijkstras_algorithm.d Added Dijkstras algorithm implementation for D * Create 01_set_covering.d Added greedy algorythm for D * Create 01_longest_common_sub.d Added dynamic programming example for D language. The code is based on Rust example * Added modules definition Required to run code with names starting with numbers * Fixed proper unsigned handling --- .../d/01_binary_search.d | 27 ++++++++ 02_selection_sort/d/01_selection_sort.d | 32 ++++++++++ 03_recursion/d/01_countdown.d | 18 ++++++ 03_recursion/d/02_greet.d | 22 +++++++ 03_recursion/d/03_factorial.d | 14 +++++ 03_recursion/d/04_count.d | 9 +++ 03_recursion/d/05_binary_search_recursive.d | 23 +++++++ 03_recursion/d/06_find_max.d | 10 +++ 03_recursion/d/07_sum_array.d | 5 ++ 03_recursion/d/08_look_for_key.d | 61 ++++++++++++++++++ 04_quicksort/d/01_loop_sum.d | 14 +++++ 04_quicksort/d/02_recursive_sum.d | 13 ++++ 04_quicksort/d/03_recursive_count.d | 13 ++++ 04_quicksort/d/04_recursive_max.d | 19 ++++++ 04_quicksort/d/05_quicksort.d | 18 ++++++ 05_hash_tables/d/01_price_of_groceries.d | 8 +++ 05_hash_tables/d/02_check_voter.d | 21 +++++++ .../d/01_breadth_first_search.d | 42 +++++++++++++ 07_trees/d/01_filesystem_dfs.d | 19 ++++++ .../d/01_dijkstras_algorithm.d | 63 +++++++++++++++++++ 10_greedy_algorithms/d/01_set_covering.d | 40 ++++++++++++ .../d/01_longest_common_sub.d | 53 ++++++++++++++++ 22 files changed, 544 insertions(+) create mode 100644 01_introduction_to_algorithms/d/01_binary_search.d create mode 100644 02_selection_sort/d/01_selection_sort.d create mode 100644 03_recursion/d/01_countdown.d create mode 100644 03_recursion/d/02_greet.d create mode 100644 03_recursion/d/03_factorial.d create mode 100644 03_recursion/d/04_count.d create mode 100644 03_recursion/d/05_binary_search_recursive.d create mode 100644 03_recursion/d/06_find_max.d create mode 100644 03_recursion/d/07_sum_array.d create mode 100644 03_recursion/d/08_look_for_key.d create mode 100644 04_quicksort/d/01_loop_sum.d create mode 100644 04_quicksort/d/02_recursive_sum.d create mode 100644 04_quicksort/d/03_recursive_count.d create mode 100644 04_quicksort/d/04_recursive_max.d create mode 100644 04_quicksort/d/05_quicksort.d create mode 100644 05_hash_tables/d/01_price_of_groceries.d create mode 100644 05_hash_tables/d/02_check_voter.d create mode 100644 06_breadth-first_search/d/01_breadth_first_search.d create mode 100644 07_trees/d/01_filesystem_dfs.d create mode 100644 09_dijkstras_algorithm/d/01_dijkstras_algorithm.d create mode 100644 10_greedy_algorithms/d/01_set_covering.d create mode 100644 11_dynamic_programming/d/01_longest_common_sub.d diff --git a/01_introduction_to_algorithms/d/01_binary_search.d b/01_introduction_to_algorithms/d/01_binary_search.d new file mode 100644 index 00000000..7d9e1377 --- /dev/null +++ b/01_introduction_to_algorithms/d/01_binary_search.d @@ -0,0 +1,27 @@ +module app; + +import std.stdio: writeln; +import std.range: assumeSorted, SortedRange; + +long binary_search(T)(SortedRange!(T[]) list, T item) { + long low = 0; + long high = list.length - 1; + + while (low <= high) { + auto mid = (low + high) / 2; + T guess = list[mid]; + if (guess == item) + return mid; + else if (guess > item) + high = mid - 1; + else + low = mid + 1; + } + return -1; +} + +void main() { + auto my_list = [1, 3, 5, 7, 9]; + writeln(binary_search(assumeSorted(my_list), 3)); + writeln(binary_search(assumeSorted(my_list), -1)); +} diff --git a/02_selection_sort/d/01_selection_sort.d b/02_selection_sort/d/01_selection_sort.d new file mode 100644 index 00000000..53d81bb3 --- /dev/null +++ b/02_selection_sort/d/01_selection_sort.d @@ -0,0 +1,32 @@ +module app; + +import std.stdio: writeln; +import std.algorithm: minIndex, remove; + + +// or it is possible to use minIndex +T findSmallest(T)(T[] arr) { + auto smallest = arr[0]; + auto smallest_index = 0; + foreach(i; 0 .. cast(int)arr.length) { + if (arr[i] < smallest) { + smallest = arr[i]; + smallest_index = i; + } + } + return smallest_index; +} + +T[] selectionSort(T)(T[] arr) { + T[] newArr = []; + foreach(i; 0 .. cast(int)arr.length) { + auto smallest = findSmallest(arr); // or use minIndex(arr); + newArr ~= arr[smallest]; + arr = arr.remove(smallest); + } + return newArr; +} + +void main() { + writeln(selectionSort([5, 3, 6, 2, 10])); +} diff --git a/03_recursion/d/01_countdown.d b/03_recursion/d/01_countdown.d new file mode 100644 index 00000000..6662a763 --- /dev/null +++ b/03_recursion/d/01_countdown.d @@ -0,0 +1,18 @@ +module app; + +import std; + +void countdown(int i) { + // base case + if (i <= 0) + return 0; + // recursive case + else { + writeln(i); + return countdown(i-1); + } +} + +void main() { + countdown(5); +} diff --git a/03_recursion/d/02_greet.d b/03_recursion/d/02_greet.d new file mode 100644 index 00000000..e1d58653 --- /dev/null +++ b/03_recursion/d/02_greet.d @@ -0,0 +1,22 @@ +module app; + +import std; + +void greet2(string name) { + writeln(i"how are you $(name)?"); +} + +void bye() { + writeln("ok bye!"); +} + +void greet(string name) { + writeln(i"hello, #(name)!"); + greet2(name); + writeln("gettin ready to say bye..."); + bye(); +} + +void main() { + greet("adit"); +} diff --git a/03_recursion/d/03_factorial.d b/03_recursion/d/03_factorial.d new file mode 100644 index 00000000..aa360c58 --- /dev/null +++ b/03_recursion/d/03_factorial.d @@ -0,0 +1,14 @@ +module app; + +import std; + +T fact(T x) { + if (x == 1) + return 1; + else + return x * fact(x-1); +} + +void main() { + writeln(fact(5)); +} diff --git a/03_recursion/d/04_count.d b/03_recursion/d/04_count.d new file mode 100644 index 00000000..65ce37f7 --- /dev/null +++ b/03_recursion/d/04_count.d @@ -0,0 +1,9 @@ +module app; + +import std; + +int count(T[] arr) { + if (arr.empty) + return 0; + return 1 + count(arr[1..$]); +} diff --git a/03_recursion/d/05_binary_search_recursive.d b/03_recursion/d/05_binary_search_recursive.d new file mode 100644 index 00000000..261b2e6d --- /dev/null +++ b/03_recursion/d/05_binary_search_recursive.d @@ -0,0 +1,23 @@ +module app; + +import std; + +int binary_search(T)(T[] arr, T target) { + if (arr.length == 0) + return -1; + + int mid = cast(int)arr.length / 2; + if (arr[mid] == target) + return mid; + else if (arr[mid] > target) + return binary_search(arr[0..mid], target); + else { + int recursive_response = binary_search(arr[mid + 1 .. $], target); + return recursive_response == -1 ? recursive_response : (mid + 1) + recursive_response; + } +} + +void main() { + writeln(binary_search([6, 7, 8, 9, 10], 8)); + writeln(binary_search([6, 7, 8, 9, 10], 6)); +} diff --git a/03_recursion/d/06_find_max.d b/03_recursion/d/06_find_max.d new file mode 100644 index 00000000..d09a1459 --- /dev/null +++ b/03_recursion/d/06_find_max.d @@ -0,0 +1,10 @@ +T find_max(T)(T[] arr) { + if (arr.length == 0) + return 0; + else if (arr.length == 1) + return arr[0]; + else if (arr.length == 2) + return arr[0] > arr[1] ? arr[0] : arr[1]; + auto sub_max = find_max(arr[1..$]); + return arr[0] > sub_max ? arr[0] : sub_max; +} diff --git a/03_recursion/d/07_sum_array.d b/03_recursion/d/07_sum_array.d new file mode 100644 index 00000000..22e5e344 --- /dev/null +++ b/03_recursion/d/07_sum_array.d @@ -0,0 +1,5 @@ +T sum_array(T)(T[] arr) { + if (arr.empty) + return 0; + return arr[0] + sum_array(arr[1..$]); +} diff --git a/03_recursion/d/08_look_for_key.d b/03_recursion/d/08_look_for_key.d new file mode 100644 index 00000000..68c7ecb4 --- /dev/null +++ b/03_recursion/d/08_look_for_key.d @@ -0,0 +1,61 @@ +modeul app; + +import std; + +class Item { + bool is_key = false; + Item[] items_in_box; + + this() { + this.is_key = false; + } + + this(bool key) { + this.is_key = key; + } + + bool is_a_box() { + return !this.is_key; + } + + bool is_a_key() { + return this.is_key; + } +} + +void look_for_key(Item box) { + foreach(item; box.items_in_box) + if (item.is_a_box()) + // recursive case + look_for_key(item); + else if (item.is_a_key()) + // base case + writeln("found the key!"); +} + +/* +main_box +├── box_A +│ ├── box_B +│ └── box_C +└── box_D + └── box_E + └── key +*/ +void main() { + auto main_box = new Item(); + auto box_A = new Item(); + auto box_B = new Item(); + auto box_C = new Item(); + box_A.items_in_box = [box_B, box_C]; + + auto box_D = new Item(); + auto box_E = new Item(); + auto key = new Item(true); + box_E.items_in_box = [key]; + box_D.items_in_box = [box_E]; + + main_box.items_in_box = [box_A, box_D]; + + look_for_key(main_box); +} diff --git a/04_quicksort/d/01_loop_sum.d b/04_quicksort/d/01_loop_sum.d new file mode 100644 index 00000000..df5bc29a --- /dev/null +++ b/04_quicksort/d/01_loop_sum.d @@ -0,0 +1,14 @@ +module app; + +import std; + +T loop_sum(T[] arr) { + T total; + foreach(x; arr) + total += x; + return total; +} + +void main() { + writeln(loop_sum([1,2,3,4])); +} diff --git a/04_quicksort/d/02_recursive_sum.d b/04_quicksort/d/02_recursive_sum.d new file mode 100644 index 00000000..891b6861 --- /dev/null +++ b/04_quicksort/d/02_recursive_sum.d @@ -0,0 +1,13 @@ +module app; + +import std; + +T rec_sum(T[] list) { + if (list.empty) + return 0; + return list[0] + sum(list[1..$]); +} + +void main() { + writeln(rec_sum([1,2,3,4])); +} diff --git a/04_quicksort/d/03_recursive_count.d b/04_quicksort/d/03_recursive_count.d new file mode 100644 index 00000000..b197479c --- /dev/null +++ b/04_quicksort/d/03_recursive_count.d @@ -0,0 +1,13 @@ +module app; + +import std; + +T rec_count(T[] list) { + if (list.empty) + return 0; + return 1 + rec_count(list[1..$]); +} + +void main() { + writeln(rec_count([1,2,3,4])); +} diff --git a/04_quicksort/d/04_recursive_max.d b/04_quicksort/d/04_recursive_max.d new file mode 100644 index 00000000..2f176d12 --- /dev/null +++ b/04_quicksort/d/04_recursive_max.d @@ -0,0 +1,19 @@ +module app; + +import std; + +T rec_max(T)(T[] list) { + if (list.empty) + return T.init; + if (list.length == 1) + return list[0]; + else { + auto max_num = rec_max(list[1..$]); + return list[0] > max_num ? list[0] : max_num; + } +} + +void main() { + writeln(rec_max([1,2,3])); +} + diff --git a/04_quicksort/d/05_quicksort.d b/04_quicksort/d/05_quicksort.d new file mode 100644 index 00000000..7b943a78 --- /dev/null +++ b/04_quicksort/d/05_quicksort.d @@ -0,0 +1,18 @@ +module app; + +import std; + +T[] quicksort(T[] arr) { + if (arr.length < 2) + return arr; + else { + auto pivot = arr[0]; + auto less = arr.filter!(el => el < pivot).array; + auto greater = arr.filter!(el => el > pivot).array; + return quicksort(less) ~ arr.filter!(el => el == pivot).array ~ quicksort(greater); + } +} + +void main() { + writeln(quicksort([10, 5, 2, 3])); +} diff --git a/05_hash_tables/d/01_price_of_groceries.d b/05_hash_tables/d/01_price_of_groceries.d new file mode 100644 index 00000000..04f0b6b9 --- /dev/null +++ b/05_hash_tables/d/01_price_of_groceries.d @@ -0,0 +1,8 @@ +module app; + +import std; + +void main() { + float[string] book = ["apple": 0.67, "milk": 1.49, "avocado": 1.49]; + writeln(book); +} diff --git a/05_hash_tables/d/02_check_voter.d b/05_hash_tables/d/02_check_voter.d new file mode 100644 index 00000000..e7232279 --- /dev/null +++ b/05_hash_tables/d/02_check_voter.d @@ -0,0 +1,21 @@ +module app; + +import std; + +bool[string] voted; + +void check_voter(string name) { + auto p = name in voted; + if (p !is null) + writeln("Kick them out!"); + else { + voted[name] = true; + writeln("Let them vote!"); + } +} + +void main() { + check_voter("tom"); + check_voter("mike"); + check_voter("mike"); +} diff --git a/06_breadth-first_search/d/01_breadth_first_search.d b/06_breadth-first_search/d/01_breadth_first_search.d new file mode 100644 index 00000000..6fdae877 --- /dev/null +++ b/06_breadth-first_search/d/01_breadth_first_search.d @@ -0,0 +1,42 @@ +module app; + +import std; + +bool personIsSeller(string name) { + return name[name.length - 1] == 'm'; +} + +bool search(string name) { + auto search_queue = DList!string(); + search_queue.insertBack(name); + bool[string] searched; + while (!search_queue.empty) { + auto person = search_queue.front(); + search_queue.removeFront(); + auto found = person in searched; + if (found !is null) + continue; + if (personIsSeller(person)) { + writeln(person, " is a mango seller!"); + return true; + } + search_queue.insertBack(graph[person]); + searched[person] = true; + } + return false; +} + +string[][string] graph; + +void main() { + graph["you"] = ["alice", "bob", "claire"]; + graph["bob"] = ["anuj", "peggy"]; + graph["alice"] = ["peggy"]; + graph["claire"] = ["thom", "jonny"]; + graph["anuj"] = []; + graph["peggy"] = []; + graph["thom"] = []; + graph["jonny"] = []; + + search("you"); +} diff --git a/07_trees/d/01_filesystem_dfs.d b/07_trees/d/01_filesystem_dfs.d new file mode 100644 index 00000000..1974b49e --- /dev/null +++ b/07_trees/d/01_filesystem_dfs.d @@ -0,0 +1,19 @@ +module app; + +import std; + +void printnames(string dir) +{ + foreach(DirEntry name; dirEntries(dir, SpanMode.shallow)) + { + if (name.isFile) + writeln(name); + else + printnames(name); + } +} + +void main() +{ + printnames("test1"); +} diff --git a/09_dijkstras_algorithm/d/01_dijkstras_algorithm.d b/09_dijkstras_algorithm/d/01_dijkstras_algorithm.d new file mode 100644 index 00000000..be548ea4 --- /dev/null +++ b/09_dijkstras_algorithm/d/01_dijkstras_algorithm.d @@ -0,0 +1,63 @@ +module app; + +import std; + +alias Costs = double[string]; +alias Graph = Costs[string]; + +Graph graph; +string[] processed; + +string find_lowest_cost_node(const Costs costs) +{ + double lowestCost = double.infinity; + string lowestCostNode; + foreach(node; costs.byPair) + { + auto cost = node.value; + if (cost < lowestCost && (!processed.canFind(node.key))) + { + lowestCost = cost; + lowestCostNode = node.key; + } + } + return lowestCostNode; +} + +void main() +{ + graph["start"] = ["a": 6, "b": 2]; + graph["a"] = ["finish": 1]; + graph["b"] = ["a": 3, "finish": 5]; + graph["finish"] = new Costs; + + Costs costs; + costs["a"] = 6; + costs["b"] = 2; + costs["finish"] = double.infinity; + + string[string] parents; + parents["a"] = "start"; + parents["b"] = "start"; + + auto node = find_lowest_cost_node(costs); + while (!node.empty) + { + double cost = costs[node]; + auto neighbors = graph[node]; + foreach(n; neighbors.byKey()) + { + double newCost = cost + neighbors[n]; + if (costs[n] > newCost) + { + costs[n] = newCost; + parents[n] = node; + } + } + processed ~= node; + node = find_lowest_cost_node(costs); + } + + writeln("Cost from the start to each node:"); + writeln(costs); +} diff --git a/10_greedy_algorithms/d/01_set_covering.d b/10_greedy_algorithms/d/01_set_covering.d new file mode 100644 index 00000000..837233a1 --- /dev/null +++ b/10_greedy_algorithms/d/01_set_covering.d @@ -0,0 +1,40 @@ +module app; + +import std; + +alias Set = bool[string]; + +void main() +{ + Set statesNeeded = assocArray(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"], true.repeat); + Set[string] stations; + stations["kone"] = assocArray(["id", "nv", "ut"], true.repeat); + stations["ktwo"] = assocArray(["wa", "id", "mt"], true.repeat); + stations["kthree"] = assocArray(["or", "nv", "ca"], true.repeat); + stations["kfour"] = assocArray(["nv", "ut"], true.repeat); + stations["kfive"] = assocArray(["ca", "az"], true.repeat); + + Set finalStations; + + while (!statesNeeded.empty) + { + string bestStation; + Set statesCovered; + foreach(station; stations.byPair) + { + auto coverage = setIntersection(station.value.keys.sort, statesNeeded.keys.sort).array; + if (coverage.length > statesCovered.keys.length) + { + bestStation = station.key; + statesCovered = assocArray(coverage, true.repeat); + } + } + if (statesCovered.length) + { + foreach(st; statesCovered.keys) + statesNeeded.remove(st); + } + finalStations[bestStation] = true; + } + writeln(finalStations.keys); +} diff --git a/11_dynamic_programming/d/01_longest_common_sub.d b/11_dynamic_programming/d/01_longest_common_sub.d new file mode 100644 index 00000000..35f9aa36 --- /dev/null +++ b/11_dynamic_programming/d/01_longest_common_sub.d @@ -0,0 +1,53 @@ +module app; + +import std; + +alias DpTable = ulong[][]; + +DpTable longest_common_substring(T)(T[] table1, T[] table2) +{ + DpTable dp_table = new DpTable(table1.length, table2.length); + + foreach(i, c1; table1) + foreach(j, c2; table2) + { + if (c1 == c2) + dp_table[i][j] = dp_table[i > 0 ? i - 1 : 0][j > 0 ? j - 1 : 0] + 1; + else + dp_table[i][j] = 0; + } + return dp_table; +} + + +DpTable longest_common_subsequence(T)(T[] table1, T[] table2) +{ + DpTable dp_table = new DpTable(table1.length, table2.length); + + foreach(i, c1; table1) + foreach(j, c2; table2) + { + if (c1 == c2) + dp_table[i][j] = dp_table[i > 0 ? i-1 : 0][j > 0 ? j-1 : 0] + 1; + else + { + dp_table[i][j] = max(dp_table[i > 0 ? i-1 : 0][j], + dp_table[i][j > 0 ? j-1 : 0]); + } + } + return dp_table; +} + +void main() +{ + auto dp_table_blue = "blue"; + auto dp_table_clues = "clues"; + + writeln("Longest substring:"); + foreach(line; longest_common_substring(dp_table_blue.array, dp_table_clues.array)) + writeln(line); + + writeln("Longest subsequence:"); + foreach(line; longest_common_subsequence(dp_table_blue.array, dp_table_clues.array)) + writeln(line); +} From 9ed0658636905f7d6a4b6206f57ebd3856f03b85 Mon Sep 17 00:00:00 2001 From: Vladyslav <108009204+gmoinbong@users.noreply.github.com> Date: Fri, 2 May 2025 02:25:03 +0300 Subject: [PATCH 136/140] Fix typo in variable name in selection sort example (#304) --- 02_selection_sort/javascript/01_selection_sort.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02_selection_sort/javascript/01_selection_sort.js b/02_selection_sort/javascript/01_selection_sort.js index 18567c46..b1e37c6c 100644 --- a/02_selection_sort/javascript/01_selection_sort.js +++ b/02_selection_sort/javascript/01_selection_sort.js @@ -36,4 +36,4 @@ const sourceArray = [5, 3, 6, 2, 10]; const sortedArray = selectionSort(sourceArray); console.log('Source array - ', sourceArray); // [5, 3, 6, 2, 10] -console.log('New sorted array - ', sourtedArray); // [2, 3, 5, 6, 10] \ No newline at end of file +console.log('New sorted array - ', sortedArray); // [2, 3, 5, 6, 10] From 5bbef9bce7f9cbeba0575f4a2daf31d6c3596b64 Mon Sep 17 00:00:00 2001 From: "Christine P. Chai" Date: Thu, 1 May 2025 16:25:36 -0700 Subject: [PATCH 137/140] Update .gitignore (#302) Added Python and R specific parts to .gitignore --- .gitignore | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0621ed79..fb741484 100644 --- a/.gitignore +++ b/.gitignore @@ -41,5 +41,14 @@ zig-cache *.sublime-workspace /.env atlassian-ide-plugin.xml -__pycache__ .vscode + +# Python specific +__pycache__ +.ipynb_checkpoints/ + +# R specific +.Rproj.user +.Rhistory +.RData +.Ruserdata From f6932eebaa6f27439d6fee9f9f7914830c3ed08f Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Fri, 2 May 2025 01:30:12 +0200 Subject: [PATCH 138/140] Add elixir longest common subsequence implementation (#306) --- .../elixir/01_longest_common_subsequence.exs | 61 +++++++++++++++---- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/11_dynamic_programming/elixir/01_longest_common_subsequence.exs b/11_dynamic_programming/elixir/01_longest_common_subsequence.exs index c9bcb66f..1cfe0c5d 100644 --- a/11_dynamic_programming/elixir/01_longest_common_subsequence.exs +++ b/11_dynamic_programming/elixir/01_longest_common_subsequence.exs @@ -1,12 +1,51 @@ -# `cell` is a map of maps here, e.g. -# cell = %{ -# 0 => %{0 => 0, ...}, -# 1 => %{...}, -# ... -# } - -if String.at(word_a, i) == String.at(word_a, j) do - put_in(cell[i - 1][j - 1], cell[i - 1][j - 1] + 1) -else - put_in(cell[i - 1][j - 1], max(cell[i - 1][j], cell[i][j - 1])) +defmodule LCSubsequence do + def generate_table(word_a, word_b) do + word_a + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + nested_map = + word_b + |> Enum.with_index() + |> Enum.reduce(%{}, fn {_x, index}, acc -> + Map.put(acc, index, 0) + end) + + Map.put(acc, index, nested_map) + end) + end + + def compute(table, word_a, word_b) do + for i <- 0..(length(word_a) - 1), reduce: table do + table -> + for j <- 0..(length(word_b) - 1), reduce: table do + table -> + if Enum.at(word_a, i) == Enum.at(word_b, j) do + value = (table[i - 1][j - 1] || 0) + 1 + put_in(table[i][j], value) + else + first = table[i - 1][j] || 0 + second = table[i][j - 1] || 0 + put_in(table[i][j], max(first, second)) + end + end + end + end end + +word_a = ["b", "l", "u", "e"] +word_b = ["c", "l", "u", "e", "s"] + +result = + word_a + |> LCSubsequence.generate_table(word_b) + |> LCSubsequence.compute(word_a, word_b) + +Enum.each(result, fn {_index, value} -> + IO.inspect(Map.values(value)) +end) + +# Output +# [0, 0, 0, 0, 0] +# [0, 1, 1, 1, 1] +# [0, 1, 2, 2, 2] +# [0, 1, 2, 3, 3] From ceea225d2ef73265876e169dc01e648d950195d2 Mon Sep 17 00:00:00 2001 From: "Christine P. Chai" Date: Thu, 1 May 2025 16:30:45 -0700 Subject: [PATCH 139/140] added selection sort for R (#301) --- 02_selection_sort/R/01_selection_sort.R | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 02_selection_sort/R/01_selection_sort.R diff --git a/02_selection_sort/R/01_selection_sort.R b/02_selection_sort/R/01_selection_sort.R new file mode 100644 index 00000000..47741b4e --- /dev/null +++ b/02_selection_sort/R/01_selection_sort.R @@ -0,0 +1,30 @@ +# Finds the smallest value in an array +find_smallest <- function(arr) { + # Stores the smallest value + smallest = arr[1] + # Stores the index of the smallest value + smallest_index = 1 + for (i in 1:length(arr)) { + if (arr[i] < smallest) { + smallest_index = i + smallest = arr[i] + } + } + return(smallest_index) +} + +# Sort array +selection_sort <- function(arr) { + newArr = c() + for (i in 1:length(arr)) { + # Finds the smallest element in the array and adds it to the new array + smallest = find_smallest(arr) + newArr = c(newArr, arr[smallest]) + # Removes that smallest element from the original array + arr = arr[-smallest] + } + return(newArr) +} + +print(selection_sort(c(5, 3, 6, 2, 10))) + \ No newline at end of file From b3dbf79d051473895027384d4f2999984da97d7e Mon Sep 17 00:00:00 2001 From: RyanM-Dev <148889570+RyanM-Dev@users.noreply.github.com> Date: Fri, 2 May 2025 03:02:08 +0330 Subject: [PATCH 140/140] Added my simpler implementation for the recursive max function (#300) --- 04_quicksort/golang/04_recursive_max.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/04_quicksort/golang/04_recursive_max.go b/04_quicksort/golang/04_recursive_max.go index dd98eca6..9ada753c 100644 --- a/04_quicksort/golang/04_recursive_max.go +++ b/04_quicksort/golang/04_recursive_max.go @@ -2,21 +2,18 @@ package main import "fmt" -func max(list []int) int { - if len(list) == 2 { - if list[0] > list[1] { - return list[0] - } - return list[1] - } +func main() { + fmt.Println(max([]int{1, 5, 10, 25, 16, 1})) +} + +func max(arr []int) int { - subMax := max(list[1:]) - if list[0] > subMax { - return list[0] + if len(arr) == 1 { + return arr[0] } - return subMax -} -func main() { - fmt.Println(max([]int{1, 5, 10, 25, 16, 1})) + if arr[0] > max(arr[1:]) { + return arr[0] + } + return max(arr[1:]) }