From 5b675cc2e8cfc5f10143a2bbc639ed83104f02b8 Mon Sep 17 00:00:00 2001 From: Max Beatty Date: Thu, 28 Mar 2019 14:52:55 -0700 Subject: [PATCH] Complete "longest common ..." examples (#100) * no else return * fix var ref * fix importing/requiring dependencies * complete longest common examples --- 03_recursion/ES6/01_countdown.js | 6 +- 03_recursion/Golang/01_countdown/Countdown.go | 4 +- 03_recursion/Golang/03_factorial/Factorial.go | 4 +- 03_recursion/javascript/01_countdown.js | 4 +- 03_recursion/javascript/03_factorial.js | 3 +- 04_quicksort/ES6/01_loop_sum.js | 18 +++--- .../ES6/01_loop_sum_reduce_version.js | 12 +--- .../javascript/01_loop_sum_reduce_version.js | 14 ++--- 04_quicksort/javascript/02_recursive_sum.js | 14 ++--- 04_quicksort/javascript/05_quicksort.js | 21 +++---- 05_hash_tables/ES6/01_price_of_groceries.js | 2 +- .../Golang/01_breadth-first_search.go | 7 ++- 06_breadth-first_search/golang/bfs.go | 6 +- .../javascript/01_breadth-first_search.js | 18 +++--- .../ES6/01_longest_common_subsequence.js | 59 +++++++++++++++++-- 09_dynamic_programming/ES6/examples/base.js | 4 +- .../ES6/examples/diff_two_words.js | 6 +- .../golang/01_longest_common_subsequence.go | 56 +++++++++++++++--- .../01_longest_common_subsequence_test.go | 42 +++++++++++++ .../javascript/examples/base.js | 14 ++--- .../javascript/examples/diff_two_words.js | 44 +++++++------- README.md | 2 +- 22 files changed, 235 insertions(+), 125 deletions(-) create mode 100644 09_dynamic_programming/golang/01_longest_common_subsequence_test.go diff --git a/03_recursion/ES6/01_countdown.js b/03_recursion/ES6/01_countdown.js index 8f14484..4641887 100644 --- a/03_recursion/ES6/01_countdown.js +++ b/03_recursion/ES6/01_countdown.js @@ -1,11 +1,11 @@ -const countdown = (i) => { +const countdown = i => { console.log(i); // base case if (i <= 0) { - return null; + return; } + countdown(i - 1); - return null; }; countdown(5); diff --git a/03_recursion/Golang/01_countdown/Countdown.go b/03_recursion/Golang/01_countdown/Countdown.go index 7a351b4..06e0230 100644 --- a/03_recursion/Golang/01_countdown/Countdown.go +++ b/03_recursion/Golang/01_countdown/Countdown.go @@ -6,9 +6,9 @@ func countdown(i int) { fmt.Println(i) if i <= 0 { return - } else { - countdown(i - 1) } + + countdown(i - 1) } func main() { diff --git a/03_recursion/Golang/03_factorial/Factorial.go b/03_recursion/Golang/03_factorial/Factorial.go index c2c4d97..5a0a6e1 100644 --- a/03_recursion/Golang/03_factorial/Factorial.go +++ b/03_recursion/Golang/03_factorial/Factorial.go @@ -5,9 +5,9 @@ import "fmt" func fact(x int) int { if x == 1 { return 1 - } else { - return x * fact(x-1) } + + return x * fact(x-1) } func main() { diff --git a/03_recursion/javascript/01_countdown.js b/03_recursion/javascript/01_countdown.js index a93a3a6..529d1c8 100644 --- a/03_recursion/javascript/01_countdown.js +++ b/03_recursion/javascript/01_countdown.js @@ -3,9 +3,9 @@ function countdown(i) { // base case if (i <= 0) { return; - } else { - countdown(i-1); } + + countdown(i - 1); } countdown(5); diff --git a/03_recursion/javascript/03_factorial.js b/03_recursion/javascript/03_factorial.js index 9ae69ad..89b8ab7 100644 --- a/03_recursion/javascript/03_factorial.js +++ b/03_recursion/javascript/03_factorial.js @@ -1,9 +1,8 @@ function fact(x) { if (x === 1) { return 1; - } else { - return x * fact(x-1); } + return x * fact(x - 1); } console.log(fact(5)); diff --git a/04_quicksort/ES6/01_loop_sum.js b/04_quicksort/ES6/01_loop_sum.js index b4affdc..e02fa91 100644 --- a/04_quicksort/ES6/01_loop_sum.js +++ b/04_quicksort/ES6/01_loop_sum.js @@ -3,16 +3,12 @@ * @param {Array} arr Array of numbers * @return {number} Sum of the numbers */ -const sumLoop = ( arr ) => { - let result = 0; - - for ( let i = 0; i < newArr.length; i++ ) { - result += newArr[i]; - } - - return result; +const sumLoop = arr => { + let result = 0; + for (let i = 0; i < arr.length; i++) { + result += arr[i]; + } + return result; }; -let arr = [1, 2, 3, 4]; - -console.log( sumLoop( arr ) ); // 10 +console.log(sumLoop([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/ES6/01_loop_sum_reduce_version.js b/04_quicksort/ES6/01_loop_sum_reduce_version.js index b280792..22de0b3 100644 --- a/04_quicksort/ES6/01_loop_sum_reduce_version.js +++ b/04_quicksort/ES6/01_loop_sum_reduce_version.js @@ -3,14 +3,6 @@ * @param {Array} arr Array of numbers * @return {number} Sum of the numbers */ -const sumReduce = ( arr ) => { - let result = newArr.reduce( ( curr, prev ) => { - return curr + prev; - } ); +const sumReduce = arr => arr.reduce((curr, prev) => curr + prev); - return result; -}; - -let arr = [1, 2, 3, 4]; - -console.log( sumReduce( arr ) ); // 10 +console.log(sumReduce([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 cd42997..101871d 100644 --- a/04_quicksort/javascript/01_loop_sum_reduce_version.js +++ b/04_quicksort/javascript/01_loop_sum_reduce_version.js @@ -3,14 +3,10 @@ * @param {Array} arr Array of numbers * @return {number} Sum of the numbers */ -function sumReduce( arr ) { - var result = newArr.reduce( ( curr, prev ) => { - return curr + prev; - } ); - - return result; +function sumReduce(arr) { + return arr.reduce(function(curr, prev) { + return curr + prev; + }); } -var arr = [1, 2, 3, 4]; - -console.log( sumReduce( arr ) ); // 10 +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 1d458a2..06c9dc3 100644 --- a/04_quicksort/javascript/02_recursive_sum.js +++ b/04_quicksort/javascript/02_recursive_sum.js @@ -1,13 +1,13 @@ -const arr = [1, 2, 3, 4]; - /** * Sums values in array recursively * @param {Array} arr Array of numbers * @return {number} Sum of the numbers */ -const sumRecursive = ( arr ) => { - if ( arr.length == 1 ) return arr[0]; - return arr[0] + sumRecursive( arr.slice( 1 ) ); -}; +function sumRecursive(arr) { + if (arr.length == 1) { + return arr[0]; + } + return arr[0] + sumRecursive(arr.slice(1)); +} -console.log( sumRecursive( arr ) ); // 10 +console.log(sumRecursive([1, 2, 3, 4])); // 10 diff --git a/04_quicksort/javascript/05_quicksort.js b/04_quicksort/javascript/05_quicksort.js index c3c61ae..e31a949 100644 --- a/04_quicksort/javascript/05_quicksort.js +++ b/04_quicksort/javascript/05_quicksort.js @@ -1,18 +1,19 @@ -'use strict'; - function quicksort(array) { if (array.length < 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.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)); } + // 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])); // [2, 3, 5, 10] diff --git a/05_hash_tables/ES6/01_price_of_groceries.js b/05_hash_tables/ES6/01_price_of_groceries.js index fdf883a..388e5df 100644 --- a/05_hash_tables/ES6/01_price_of_groceries.js +++ b/05_hash_tables/ES6/01_price_of_groceries.js @@ -3,6 +3,6 @@ const book = {}; book.apple = 0.67; // milk costs $1.49 book.milk = 1.49; -book.avokado = 1.49; +book.avocado = 1.49; console.log(book); // { apple: 0.67, milk: 1.49, avocado: 1.49 } diff --git a/06_breadth-first_search/Golang/01_breadth-first_search.go b/06_breadth-first_search/Golang/01_breadth-first_search.go index 26510ba..515fcf4 100644 --- a/06_breadth-first_search/Golang/01_breadth-first_search.go +++ b/06_breadth-first_search/Golang/01_breadth-first_search.go @@ -31,10 +31,11 @@ func search(name string) bool { if person_is_seller(person) { println(person + " is mango seller!") return true - } else { - search_queue = append(search_queue, graph[person]...) - searched = append(searched, person) } + + search_queue = append(search_queue, graph[person]...) + searched = append(searched, person) + } } return false diff --git a/06_breadth-first_search/golang/bfs.go b/06_breadth-first_search/golang/bfs.go index 061cec4..a362431 100644 --- a/06_breadth-first_search/golang/bfs.go +++ b/06_breadth-first_search/golang/bfs.go @@ -39,10 +39,10 @@ func search(name string) bool { if PersonIsSeller(person) { fmt.Println(person + " is the mango seller!") return true - } else { - search_queue = append(search_queue, graph[person]...) - searched = append(searched, person) } + + search_queue = append(search_queue, graph[person]...) + searched = append(searched, person) } } 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 8daa592..c3f478f 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,5 @@ -'use strict'; - function person_is_seller(name) { - return name[name.length-1] === 'm'; + return name[name.length - 1] === "m"; } const graph = {}; @@ -14,7 +12,6 @@ graph["peggy"] = []; graph["thom"] = []; graph["jonny"] = []; - function search(name) { let search_queue = []; search_queue = search_queue.concat(graph[name]); @@ -25,17 +22,16 @@ function search(name) { // Only search this person if you haven't already searched them if (searched.indexOf(person) === -1) { if (person_is_seller(person)) { - console.log(person + ' is a mango seller!'); + console.log(person + " is a mango seller!"); return true; - } else { - search_queue = search_queue.concat(graph[person]); - // Marks this person as searched - searched.push(person); } + + search_queue = search_queue.concat(graph[person]); + // Marks this person as searched + searched.push(person); } } return false; } - -search('you'); // thom is a mango seller! +search("you"); // thom is a mango seller! diff --git a/09_dynamic_programming/ES6/01_longest_common_subsequence.js b/09_dynamic_programming/ES6/01_longest_common_subsequence.js index c5bc2a3..366d23e 100644 --- a/09_dynamic_programming/ES6/01_longest_common_subsequence.js +++ b/09_dynamic_programming/ES6/01_longest_common_subsequence.js @@ -1,7 +1,54 @@ -if (word_a[i] === word_b[j]) { - // The letters match - cell[i][j] = cell[i - 1][j - 1] + 1; -} else { - // The letters don't match - cell[i][j] = Math.max(cell[i - 1][j], cell[i][j - 1]); +function createMatrix(rows, cols) { + const matrix = new Array(rows); + + for (let i = 0; i < matrix.length; i++) { + matrix[i] = new Array(cols).fill(0); + } + + return matrix; } + +function substring(a, b) { + const cell = createMatrix(a.length + 1, b.length + 1); + let lcs = 0; + let lastSubIndex = 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; + + if (cell[i][j] > lcs) { + lcs = cell[i][j]; + lastSubIndex = i; + } + } else { + cell[i][j] = 0; + } + } + } + + return a.slice(lastSubIndex - lcs, lastSubIndex); +} + +substring("vista", "hish"); // "is" +substring("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; + } else { + cell[i][j] = Math.max(cell[i - 1][j], cell[i][j - 1]); + } + } + } + + return cell[a.length][b.length]; +} + +subsequence("fish", "fosh"); // 3 +subsequence("fort", "fosh"); // 2 diff --git a/09_dynamic_programming/ES6/examples/base.js b/09_dynamic_programming/ES6/examples/base.js index e972c98..d50dda8 100644 --- a/09_dynamic_programming/ES6/examples/base.js +++ b/09_dynamic_programming/ES6/examples/base.js @@ -1,9 +1,7 @@ -const initializeMatrix = (rows, cols) => { +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; }; - -export default initializeMatrix; diff --git a/09_dynamic_programming/ES6/examples/diff_two_words.js b/09_dynamic_programming/ES6/examples/diff_two_words.js index 30c40c1..1ac7d02 100644 --- a/09_dynamic_programming/ES6/examples/diff_two_words.js +++ b/09_dynamic_programming/ES6/examples/diff_two_words.js @@ -1,8 +1,8 @@ -import base from './base'; +import { initializeMatrix } from "./base"; const diff = (firstWord, secondWord) => { - const arr1 = firstWord.split(''); - const arr2 = secondWord.split(''); + 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) { diff --git a/09_dynamic_programming/golang/01_longest_common_subsequence.go b/09_dynamic_programming/golang/01_longest_common_subsequence.go index 1082f28..ba2def7 100644 --- a/09_dynamic_programming/golang/01_longest_common_subsequence.go +++ b/09_dynamic_programming/golang/01_longest_common_subsequence.go @@ -1,11 +1,53 @@ package main -import "fmt" - -func main() { - if word_a[i] == word_b[j] { - cell[i][j] = cell[i-1][j-1] + 1 - } else { - cell[i][j] = max(cell[i-1][j], cell[i][j-1]) +func createMatrix(rows, cols int) [][]int { + cell := make([][]int, rows) + for i := range cell { + cell[i] = make([]int, cols) } + + return cell +} + +func substring(a, b string) string { + lcs := 0 + lastSubIndex := 0 + cell := createMatrix(len(a)+1, len(b)+1) + + for i := 1; i <= len(a); i++ { + for j := 1; j <= len(b); j++ { + if a[i-1] == b[j-1] { + cell[i][j] = cell[i-1][j-1] + 1 + + if cell[i][j] > lcs { + lcs = cell[i][j] + lastSubIndex = i + } + } else { + cell[i][j] = 0 + } + } + } + + return a[lastSubIndex-lcs : lastSubIndex] +} + +func subsequence(a, b string) int { + cell := createMatrix(len(a)+1, len(b)+1) + + for i := 1; i <= len(a); i++ { + for j := 1; j <= len(b); j++ { + if a[i-1] == b[j-1] { + cell[i][j] = cell[i-1][j-1] + 1 + } else { + cell[i][j] = cell[i-1][j] + + if cell[i][j] < cell[i][j-1] { + cell[i][j] = cell[i][j-1] + } + } + } + } + + return cell[len(a)][len(b)] } diff --git a/09_dynamic_programming/golang/01_longest_common_subsequence_test.go b/09_dynamic_programming/golang/01_longest_common_subsequence_test.go new file mode 100644 index 0000000..263941f --- /dev/null +++ b/09_dynamic_programming/golang/01_longest_common_subsequence_test.go @@ -0,0 +1,42 @@ +package main + +import "testing" + +func TestSubstring(t *testing.T) { + var stests = []struct { + name, a, b, expected string + }{ + {"hish-vista", "vista", "hish", "is"}, + {"hish-fish", "fish", "hish", "ish"}, + } + + for _, tt := range stests { + t.Run(tt.name, func(t *testing.T) { + actual := substring(tt.a, tt.b) + + if actual != tt.expected { + t.Errorf("Expected %s but received %s", tt.expected, actual) + } + }) + } +} + +func TestSubsequence(t *testing.T) { + var stests = []struct { + name, a, b string + expected int + }{ + {"fosh-fish", "fish", "fosh", 3}, + {"fosh-fort", "fort", "fosh", 2}, + } + + for _, tt := range stests { + t.Run(tt.name, func(t *testing.T) { + actual := subsequence(tt.a, tt.b) + + if actual != tt.expected { + t.Errorf("Expected %d but received %d", tt.expected, actual) + } + }) + } +} diff --git a/09_dynamic_programming/javascript/examples/base.js b/09_dynamic_programming/javascript/examples/base.js index ae44163..934d056 100644 --- a/09_dynamic_programming/javascript/examples/base.js +++ b/09_dynamic_programming/javascript/examples/base.js @@ -1,7 +1,7 @@ -export default function initialize_matrix(rows, cols){ - let matrix = []; - for (let i = 0; i < rows.length; i++){ - matrix.push(Array(cols.length).fill(0)); - } - return matrix; -} \ No newline at end of file +module.exports = function initialize_matrix(rows, cols) { + let matrix = []; + for (let i = 0; i < rows.length; i++) { + matrix.push(Array(cols.length).fill(0)); + } + return matrix; +}; diff --git a/09_dynamic_programming/javascript/examples/diff_two_words.js b/09_dynamic_programming/javascript/examples/diff_two_words.js index 8911423..318878a 100644 --- a/09_dynamic_programming/javascript/examples/diff_two_words.js +++ b/09_dynamic_programming/javascript/examples/diff_two_words.js @@ -1,25 +1,25 @@ -import initialize_matrix as base from "./base.js"; +const initialize_matrix = require("./base.js"); -export default function diff( firstWord, secondWord ){ - let arr1 = firstWord.split(''); - let arr2 = secondWord.split(''); - let matrix = initialize_matrix(arr1, arr2); - for (let i = 0; i < arr1.length; i++){ - for (let j = 0; j < arr2.length; j++){ - 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; - } - } +function diff(firstWord, secondWord) { + let arr1 = firstWord.split(""); + let arr2 = secondWord.split(""); + let matrix = initialize_matrix(arr1, arr2); + for (let i = 0; i < arr1.length; i++) { + for (let j = 0; j < arr2.length; j++) { + 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]; -} \ No newline at end of file + } + return matrix[arr1.length - 1][arr2.length - 1]; +} diff --git a/README.md b/README.md index 9017b11..9246b14 100644 --- a/README.md +++ b/README.md @@ -14,5 +14,5 @@ This repo also contains every image in Grokking Algorithms, in hi-res. These ima ## 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! +- 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.