From 1a8fa2a92dc4b062f9e26081547453eaf735019e Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sun, 29 Oct 2017 16:33:05 -0400 Subject: [PATCH 001/488] added dynamic algorithm for binomial coeffecients --- dynamic-programming/binomial-coeffecient.go | 47 +++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 dynamic-programming/binomial-coeffecient.go diff --git a/dynamic-programming/binomial-coeffecient.go b/dynamic-programming/binomial-coeffecient.go new file mode 100644 index 000000000..d8a64d1fc --- /dev/null +++ b/dynamic-programming/binomial-coeffecient.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + myArrayOfK := [4]int{5, 6, 7, 8} + var x int + + fmt.Println("\nBinomial Coefficient Using Dynamic Programming:", bin2(50, 5)) + for _, element := range myArrayOfK { + start := time.Now() + x = bin2(50, element) + elapsed := time.Since(start) + fmt.Println("bin2 (50,", element, ") = ", x, " took ", elapsed) + + } + +} + +func bin2(n int, k int) int { + var i, j int + B := make([][]int, (n + 1)) + for i := range B { + B[i] = make([]int, k+1) + } + + for i = 0; i <= n; i++ { + for j = 0; j <= min(i, k); j++ { + if j == 0 || j == i { + B[i][j] = 1 + } else { + B[i][j] = B[i-1][j-1] + B[i-1][j] + } + } + } + return B[n][k] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} From b4080a9dc301b7c9043af7dfd16d5e2962e93590 Mon Sep 17 00:00:00 2001 From: Luiz Mai Date: Wed, 9 Oct 2019 13:52:10 -0300 Subject: [PATCH 002/488] levenshtein distance algorithm --- strings/levenshteinDistance.go | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 strings/levenshteinDistance.go diff --git a/strings/levenshteinDistance.go b/strings/levenshteinDistance.go new file mode 100644 index 000000000..ef9bc0f95 --- /dev/null +++ b/strings/levenshteinDistance.go @@ -0,0 +1,66 @@ +/* +This algorithm calculates the distance between two strings. +Parameters: two strings to compare +Output: distance between both strings +*/ + +package main + +import ( + "fmt" +) + +func levenshteinDistance(str1, str2 string, icost, dcost, scost int) int { + row1 := make([]int, len(str2)+1) + row2 := make([]int, len(str2)+1) + var tmp []int + + for i := 1; i <= len(str2); i++ { + row1[i] = i * icost + } + + for i := 1; i <= len(str1); i++ { + row2[0] = i * dcost + + for j := 1; j <= len(str2); j++ { + if str1[i-1] == str2[j-1] { + row2[j] = row1[j-1] + } else { + ins := row2[j-1] + icost + del := row1[j] + dcost + sub := row1[j-1] + scost + + if ins < del && ins < sub { + row2[j] = ins + } else if del < sub { + row2[j] = del + } else { + row2[j] = sub + } + } + } + + tmp = row1 + row1 = row2 + row2 = tmp + } + + return row1[len(row1)-1] +} + +func min(str1, str2 int) int { + if str1 < str2 { + return str1 + } + return str2 +} + +func main() { + str1 := "stingy" + str2 := "ring" + + strDistance := levenshteinDistance(str1, str2, 1, 1, 1) + fmt.Printf("Distance between %s and %s is: %d.", str1, str2, strDistance) + + return +} From d9174a8df7dae736639f20f24e9888d216f1c670 Mon Sep 17 00:00:00 2001 From: Luiz Mai Date: Wed, 9 Oct 2019 13:59:43 -0300 Subject: [PATCH 003/488] improvements on comments --- strings/levenshteinDistance.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/strings/levenshteinDistance.go b/strings/levenshteinDistance.go index ef9bc0f95..8b9262559 100644 --- a/strings/levenshteinDistance.go +++ b/strings/levenshteinDistance.go @@ -1,6 +1,6 @@ /* This algorithm calculates the distance between two strings. -Parameters: two strings to compare +Parameters: two strings to compare and weights of insertion, substitution and deletion. Output: distance between both strings */ @@ -59,8 +59,15 @@ func main() { str1 := "stingy" str2 := "ring" - strDistance := levenshteinDistance(str1, str2, 1, 1, 1) - fmt.Printf("Distance between %s and %s is: %d.", str1, str2, strDistance) + // Using weight 1 for insertion, substitution and deletion + strDistance1 := levenshteinDistance(str1, str2, 1, 1, 1) + fmt.Printf("Distance between \"%s\" and \"%s\" is: %d.\n", str1, str2, strDistance1) + // Output: Distance between "stingy" and "ring" is: 3. + + // Using weight 1 for insertion/substitution and weight 3 for deletion + strDistance2 := levenshteinDistance(str1, str2, 1, 1, 3) + fmt.Printf("Distance between \"%s\" and \"%s\" is: %d.\n", str1, str2, strDistance2) + // Output: Distance between "stingy" and "ring" is: 7. return } From 497ae1a733a44c0516e3bfabc83d99675a115211 Mon Sep 17 00:00:00 2001 From: Luiz Mai Date: Wed, 9 Oct 2019 13:59:58 -0300 Subject: [PATCH 004/488] fixing arguments order --- strings/levenshteinDistance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/levenshteinDistance.go b/strings/levenshteinDistance.go index 8b9262559..35cfec4d6 100644 --- a/strings/levenshteinDistance.go +++ b/strings/levenshteinDistance.go @@ -10,7 +10,7 @@ import ( "fmt" ) -func levenshteinDistance(str1, str2 string, icost, dcost, scost int) int { +func levenshteinDistance(str1, str2 string, icost, scost, dcost int) int { row1 := make([]int, len(str2)+1) row2 := make([]int, len(str2)+1) var tmp []int From 6b3e7801402298c1099f59877c61aeb0fd8a9f50 Mon Sep 17 00:00:00 2001 From: Anderson Queiroz Date: Sat, 12 Oct 2019 14:56:31 +0200 Subject: [PATCH 005/488] add Monte Carlo Pi algorithm --- other/monte_carlo_pi/monte_carlo_pi.go | 40 +++++++++++++++++++++ other/monte_carlo_pi/monte_carlo_pi_test.go | 16 +++++++++ 2 files changed, 56 insertions(+) create mode 100644 other/monte_carlo_pi/monte_carlo_pi.go create mode 100644 other/monte_carlo_pi/monte_carlo_pi_test.go diff --git a/other/monte_carlo_pi/monte_carlo_pi.go b/other/monte_carlo_pi/monte_carlo_pi.go new file mode 100644 index 000000000..0f5438d50 --- /dev/null +++ b/other/monte_carlo_pi/monte_carlo_pi.go @@ -0,0 +1,40 @@ +// Monte Carlo Pi +// [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method) to calculate Pi +// +// The basic idea of Monte Carlo is: +// 1. Define a domain of possible inputs +// 2. Generate inputs randomly from a probability distribution over the domain +// 3. Perform a deterministic computation on the inputs +// 4. Aggregate the results +// +// Thus the algorithm to calculate Pi is: +// +// 1. Given a circle inscribed in a square with side length 1. +// 2. randomly draw n points (x, y) | x,y in [0.0,1.0) +// 3. Count the amount of points inside the circle +// 4. pi = 4 * (points inside the circle) / n +// +// A point (x, y) is inside the circle if: +// +// x*x + y*y <= 1 +// + +package main + +import ( + "math" + "math/rand" +) + +// MonteCarloPi calculates Pi using the Monte Carlo method +func MonteCarloPi(iterations uint) float64 { + var inside, total uint + + for total = uint(0); total < iterations; total++ { + if in := math.Hypot(rand.Float64(), rand.Float64()) <= 1; in { + inside++ + } + } + + return float64(4) * (float64(inside) / float64(total)) +} diff --git a/other/monte_carlo_pi/monte_carlo_pi_test.go b/other/monte_carlo_pi/monte_carlo_pi_test.go new file mode 100644 index 000000000..e660f5eba --- /dev/null +++ b/other/monte_carlo_pi/monte_carlo_pi_test.go @@ -0,0 +1,16 @@ +package main + +import ( + "math" + "testing" +) + +func TestMonteCarloPi(t *testing.T) { + delta := 0.0001 + + pi := MonteCarloPi(100000000) + + if math.Abs(pi-math.Pi) > delta { + t.Errorf("Given: %.4f, expected: %.4f", pi, math.Pi) + } +} From d9a36e62ddc31aa1c335927575d46c79715b1678 Mon Sep 17 00:00:00 2001 From: babybug Date: Fri, 29 Nov 2019 23:40:14 +0800 Subject: [PATCH 006/488] fix #97 fix#97. --- data-structures/binary-tree/binary-tree.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data-structures/binary-tree/binary-tree.go b/data-structures/binary-tree/binary-tree.go index 80a88c6d4..f85563c8f 100644 --- a/data-structures/binary-tree/binary-tree.go +++ b/data-structures/binary-tree/binary-tree.go @@ -42,16 +42,16 @@ func preorder(n *node) { return } fmt.Print(n.val, " ") - inorder(n.left) - inorder(n.right) + preorder(n.left) + preorder(n.right) } func postorder(n *node) { if n == nil { return } - inorder(n.left) - inorder(n.right) + postorder(n.left) + postorder(n.right) fmt.Print(n.val, " ") } From 9896f573494d6d76b8e4b3217ff55a7c4d9dbc5f Mon Sep 17 00:00:00 2001 From: apple <1991585851@qq.com> Date: Thu, 26 Dec 2019 16:17:21 +0800 Subject: [PATCH 007/488] BinarySearchTree delete was wrong --- data-structures/binary-tree/binary-search-tree.go | 1 - 1 file changed, 1 deletion(-) diff --git a/data-structures/binary-tree/binary-search-tree.go b/data-structures/binary-tree/binary-search-tree.go index 1ce14349c..8d564e843 100644 --- a/data-structures/binary-tree/binary-search-tree.go +++ b/data-structures/binary-tree/binary-search-tree.go @@ -75,7 +75,6 @@ func bst_delete(root *node, val int) *node { } else { // node with two children d := inorderSuccessor(root) - root.val = d.val root.right = bst_delete(root.right, d.val) } } From 41954555923429368f81511f17b5c67e45e71f50 Mon Sep 17 00:00:00 2001 From: apple <1991585851@qq.com> Date: Thu, 26 Dec 2019 17:20:30 +0800 Subject: [PATCH 008/488] BinarySearchTree delete wrong --- .../binary-tree/binary-search-tree.go | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/data-structures/binary-tree/binary-search-tree.go b/data-structures/binary-tree/binary-search-tree.go index 8d564e843..7e1c691f3 100644 --- a/data-structures/binary-tree/binary-search-tree.go +++ b/data-structures/binary-tree/binary-search-tree.go @@ -66,16 +66,16 @@ func bst_delete(root *node, val int) *node { root.right = bst_delete(root.right, val) } else { // this is the node to delete - // node with one child if root.left == nil { - root = root.right + return root.right } else if root.right == nil { - root = root.left + return root.left } else { - // node with two children - d := inorderSuccessor(root) - root.right = bst_delete(root.right, d.val) + n := root.right + d := inorderSuccessor(n) + d.left = root.left + return root.right } } return root @@ -93,14 +93,19 @@ func (t *btree) depth() int { return _calculate_depth(t.root, 0) } -/* + func main() { t := &btree{nil} inorder(t.root) - t.root = insert(t.root, 10) + t.root = insert(t.root, 30) + t.root = insert(t.root, 20) t.root = insert(t.root, 15) - t.root = insert(t.root, 30) + t.root = insert(t.root, 10) + t.root = insert(t.root, 12) + t.root = insert(t.root, 9) + t.root = insert(t.root, 11) + t.root = insert(t.root, 17) fmt.Print(t.depth(), "\n") inorder(t.root) fmt.Print("\n") @@ -118,4 +123,4 @@ func main() { fmt.Print("\n") fmt.Print(t.depth(), "\n") } -*/ + From e6f2f4e938b6c6e74928e6bd8f7b57a926151a00 Mon Sep 17 00:00:00 2001 From: Wesllhey Holanda Date: Fri, 10 Apr 2020 14:09:36 -0300 Subject: [PATCH 009/488] hash map data structure --- data-structures/hash-map/hash_map.go | 141 +++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 data-structures/hash-map/hash_map.go diff --git a/data-structures/hash-map/hash_map.go b/data-structures/hash-map/hash_map.go new file mode 100644 index 000000000..ab9b0c2b1 --- /dev/null +++ b/data-structures/hash-map/hash_map.go @@ -0,0 +1,141 @@ +package data-structures + +import ( + "fmt" + "hash/fnv" +) + +var defaultCapacity uint64 = 1 << 10 + +type node struct { + key interface{} + value interface{} + next *node +} + +type hashMap struct { + capacity uint64 + size uint64 + table []*node +} + +func newHashMap() *hashMap { + return &hashMap{ + capacity: defaultCapacity, + table: make([]*node, defaultCapacity), + } +} + +func (hm *hashMap) get(key interface{}) interface{} { + node := hm.getNodeByHash(hm.hash(key)) + + if node != nil { + return node.value + } + + return nil +} + +func (hm *hashMap) put(key interface{}, value interface{}) interface{} { + return hm.putValue(hm.hash(key), key, value) +} + +func (hm *hashMap) putValue(hash uint64, key interface{}, value interface{}) interface{} { + if hm.capacity == 0 { + hm.capacity = defaultCapacity + hm.table = make([]*node, defaultCapacity) + } + + node := hm.getNodeByHash(hash) + + if node == nil { + hm.table[hash] = newNode(key, value) + + } else if node.key == key { + hm.table[hash] = newNodeWithNext(key, value, node) + return value + + } else { + hm.resize() + return hm.putValue(hash, key, value) + } + + hm.size++ + + return value + +} + +func (hm *hashMap) contains(key interface{}) bool { + node := hm.getNodeByHash(hm.hash(key)) + + if node != nil { + return true + } + + return false +} + +func (hm *hashMap) getNodeByHash(hash uint64) *node { + return hm.table[hash] +} + +func (hm *hashMap) resize() { + hm.capacity <<= 1 + + tempTable := hm.table + + hm.table = make([]*node, hm.capacity) + + for i := 0; i < len(tempTable); i++ { + node := tempTable[i] + if node == nil { + continue + } + + hm.table[hm.hash(node.key)] = node + } +} + +func newNode(key interface{}, value interface{}) *node { + return &node{ + key: key, + value: value, + } +} + +func newNodeWithNext(key interface{}, value interface{}, next *node) *node { + return &node{ + key: key, + value: value, + next: next, + } +} + +func (hm *hashMap) hash(key interface{}) uint64 { + h := fnv.New64a() + h.Write([]byte(fmt.Sprintf("%v", key))) + + hashValue := h.Sum64() + + return (hm.capacity - 1) & (hashValue ^ (hashValue >> 16)) +} + +// func main() { +// hashMap := newHashMap() + +// hashMap.put("test-1", 10) +// fmt.Println(hashMap.get("test-1")) + +// hashMap.put("test-1", 20) +// hashMap.put("test-2", 30) +// hashMap.put(1, 40) + +// fmt.Println(hashMap.get("test-1")) +// fmt.Println(hashMap.get("test-2")) +// fmt.Println(hashMap.get(1)) + +// fmt.Println(hashMap.contains(2)) +// fmt.Println(hashMap.contains(1)) +// fmt.Println(hashMap.contains("test-1")) +// } From 44e0f61c112e1b98bae8fd27008f843769eab1f9 Mon Sep 17 00:00:00 2001 From: wdy <2664683329@qq.com> Date: Mon, 4 May 2020 10:35:43 +0800 Subject: [PATCH 010/488] added counting sort --- sorts/counting_sort.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 sorts/counting_sort.go diff --git a/sorts/counting_sort.go b/sorts/counting_sort.go new file mode 100644 index 000000000..3175854f1 --- /dev/null +++ b/sorts/counting_sort.go @@ -0,0 +1,17 @@ +package sorts + +func CountingSort(arr []int, max int) []int { + //use the max value to create a slice of item counts + counts := make([]int, max+1) + result := make([]int, 0) + for _, item := range arr { + counts[item]++ + } + for i := 0; i < len(counts); i++ { + count := counts[i] + for j := 0; j < count; j++ { + result = append(result, i) + } + } + return result +} From eab0494da8b344b6a41347d6bcf90419243bc283 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sun, 10 May 2020 12:05:01 +0200 Subject: [PATCH 011/488] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 653ced575..2deff86bf 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ These algorithms are for demonstration purposes only. There are many sort implementations in the Go standard library that may have better performance. For a full list of all algorithms, please see: [DIRECTORY.md](https://github.com/TheAlgorithms/Go/blob/master/DIRECTORY.md) +Also see: https://algorithmswithgo.com ## Sort Algorithms From dc9501d242fa5f07a5f013921fcb8581f454c48d Mon Sep 17 00:00:00 2001 From: Brayo <62670517+brayo-pip@users.noreply.github.com> Date: Tue, 19 May 2020 22:52:18 +0300 Subject: [PATCH 012/488] Avoids Overflow Errors common in Binary search Adding two large integers then dividing the sum, (a+b)/2 ,might end up creating a sum that can't fit in memory. However this overflow can be avoided by never adding the numbers first instead, adding the difference of the two numbers to the least i.e (a+b)/2 == a+(b-a)/2 == b-(b-a)/2 ... Please comment or ask for further clarification instead of just rejecting the proposal. Thanks --- searches/binary_search.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/searches/binary_search.go b/searches/binary_search.go index 697b6704b..5d485ff9a 100644 --- a/searches/binary_search.go +++ b/searches/binary_search.go @@ -7,7 +7,7 @@ func binarySearch(array []int, target int, lowIndex int, highIndex int) int { if highIndex < lowIndex { return -1 } - mid := int((lowIndex + highIndex) / 2) + mid := int(lowIndex + (highIndex-lowIndex)/2) if array[mid] > target { return binarySearch(array, target, lowIndex, mid) } else if array[mid] < target { @@ -22,7 +22,7 @@ func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int endIndex := highIndex var mid int for startIndex < endIndex { - mid = int((startIndex + endIndex) / 2) + mid = int(startIndex + (endIndex-startIndex)) if array[mid] > target { endIndex = mid } else if array[mid] < target { From 89d49207f9d9d858e725fb2d5d1ff933fa7c2871 Mon Sep 17 00:00:00 2001 From: Brayo <62670517+brayo-pip@users.noreply.github.com> Date: Wed, 20 May 2020 15:11:57 +0300 Subject: [PATCH 013/488] Simplify the array looping Uses range to loop over the array enchancing code readibility --- other/maxSubarraySum.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/other/maxSubarraySum.go b/other/maxSubarraySum.go index a336dd378..f5592f0bf 100644 --- a/other/maxSubarraySum.go +++ b/other/maxSubarraySum.go @@ -17,8 +17,8 @@ func Max(x int, y int) int { func maxSubarraySum(array []int) int { var currentMax int = 0 var maxTillNow int = 0 - for i := 0; i < len(array); i++ { - currentMax = Max(array[i], currentMax + array[i]) + for _,v :=range array{ + currentMax = Max(v, currentMax + v) maxTillNow = Max(maxTillNow, currentMax) } return maxTillNow From 8cb19d7fbf3026cc155ce5697a0694a12c297e52 Mon Sep 17 00:00:00 2001 From: "Md. Muidul Alam" <2hin2222@gmail.com> Date: Sat, 23 May 2020 09:16:14 +0600 Subject: [PATCH 014/488] Fix grammatical and spelling mistakes in README.md --- README.md | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 2deff86bf..c8cd83a83 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ Also see: https://algorithmswithgo.com From [Wikipedia][bubble-wiki]: Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares each pair of adjacent items and swaps them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted. __Properties__ -* Worst case performance O(n^2) -* Best case performance O(n) -* Average case performance O(n^2) +* Worst case performance O(n^2) +* Best case performance O(n) +* Average case performance O(n^2) ###### View the algorithm in [action][bubble-toptal] @@ -30,9 +30,9 @@ __Properties__ From [Wikipedia][insertion-wiki]: Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. __Properties__ -* Worst case performance O(n^2) -* Best case performance O(n) -* Average case performance O(n^2) +* Worst case performance O(n^2) +* Best case performance O(n) +* Average case performance O(n^2) ###### View the algorithm in [action][insertion-toptal] @@ -43,9 +43,9 @@ __Properties__ From [Wikipedia][merge-wiki]: In computer science, merge sort (also commonly spelled mergesort) is an efficient, general-purpose, comparison-based sorting algorithm. Most implementations produce a stable sort, which means that the implementation preserves the input order of equal elements in the sorted output. Mergesort is a divide and conquer algorithm that was invented by John von Neumann in 1945. __Properties__ -* Worst case performance O(n log n) -* Best case performance O(n) -* Average case performance O(n) +* Worst case performance O(n log n) +* Best case performance O(n) +* Average case performance O(n) ###### View the algorithm in [action][merge-toptal] @@ -56,9 +56,9 @@ __Properties__ From [Wikipedia][quick-wiki]: Quicksort (sometimes called partition-exchange sort) is an efficient sorting algorithm, serving as a systematic method for placing the elements of an array in order. __Properties__ -* Worst case performance O(n^2) -* Best case performance O(n log n) or O(n) with three-way partition -* Average case performance O(n^2) +* Worst case performance O(n^2) +* Best case performance O(n log n) or O(n) with three-way partition +* Average case performance O(n^2) ###### View the algorithm in [action][quick-toptal] @@ -68,9 +68,9 @@ __Properties__ From [Wikipedia][selection-wiki]: The algorithm divides the input list into two parts: the sublist of items already sorted, which is built up from left to right at the front (left) of the list, and the sublist of items remaining to be sorted that occupy the rest of the list. Initially, the sorted sublist is empty and the unsorted sublist is the entire input list. The algorithm proceeds by finding the smallest (or largest, depending on sorting order) element in the unsorted sublist, exchanging (swapping) it with the leftmost unsorted element (putting it in sorted order), and moving the sublist boundaries one element to the right. __Properties__ -* Worst case performance O(n^2) -* Best case performance O(n^2) -* Average case performance O(n^2) +* Worst case performance O(n^2) +* Best case performance O(n^2) +* Average case performance O(n^2) ###### View the algorithm in [action][selection-toptal] @@ -86,7 +86,7 @@ __Properties__ ###### View the algorithm in [action][shell-toptal] -### Time-Compexity Graphs +### Time-Complexity Graphs Comparing the complexity of sorting algorithms (Bubble Sort, Insertion Sort, Selection Sort) @@ -100,13 +100,13 @@ Comparing the complexity of sorting algorithms (Bubble Sort, Insertion Sort, Sel ![alt text][linear-image] From [Wikipedia][linear-wiki]: linear search or sequential search is a method for finding a target value within a list. It sequentially checks each element of the list for the target value until a match is found or until all the elements have been searched. - Linear search runs in at worst linear time and makes at most n comparisons, where n is the length of the list. + Linear search runs in at the worst linear time and makes at most n comparisons, where n is the length of the list. __Properties__ -* Worst case performance O(n) -* Best case performance O(1) -* Average case performance O(n) -* Worst case space complexity O(1) iterative +* Worst case performance O(n) +* Best case performance O(1) +* Average case performance O(n) +* Worst case space complexity O(1) iterative ### Binary ![alt text][binary-image] @@ -114,10 +114,10 @@ __Properties__ From [Wikipedia][binary-wiki]: Binary search, also known as half-interval search or logarithmic search, is a search algorithm that finds the position of a target value within a sorted array. It compares the target value to the middle element of the array; if they are unequal, the half in which the target cannot lie is eliminated and the search continues on the remaining half until it is successful. __Properties__ -* Worst case performance O(log n) -* Best case performance O(1) -* Average case performance O(log n) -* Worst case space complexity O(1) +* Worst case performance O(log n) +* Best case performance O(1) +* Average case performance O(log n) +* Worst case space complexity O(1) ---------------------------------------------------------------------------------------------------------------------- @@ -128,7 +128,7 @@ __Properties__ In cryptography, a **Caesar cipher**, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift, is one of the simplest and most widely known encryption techniques.
It is **a type of substitution cipher** in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of 3, D would be replaced by A, E would become B, and so on.
The method is named after **Julius Caesar**, who used it in his private correspondence.
-The encryption step performed by a Caesar cipher is often incorporated as part of more complex schemes, such as the Vigenère cipher, and still has modern application in the ROT13 system. As with all single-alphabet substitution ciphers, the Caesar cipher is easily broken and in modern practice offers essentially no communication security. +The encryption step performed by a Caesar cipher is often incorporated as part of more complex schemes, such as the Vigenère cipher, and still has modern applications in the ROT13 system. As with all single-alphabet substitution ciphers, the Caesar cipher is easily broken and in modern practice offers essentially no communication security. ###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher) ### Transposition From 13e206ec18e18a9f5cc6b0650b561540f9e70ac9 Mon Sep 17 00:00:00 2001 From: q Date: Sat, 23 May 2020 20:24:55 +0800 Subject: [PATCH 015/488] update bubblesort swap --- sorts/bubble_sort.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sorts/bubble_sort.go b/sorts/bubble_sort.go index 77f73d6a9..c5591b254 100644 --- a/sorts/bubble_sort.go +++ b/sorts/bubble_sort.go @@ -2,23 +2,15 @@ package sorts func bubbleSort(arrayzor []int) []int { - - swapped := true for swapped { swapped = false for i := 0; i < len(arrayzor)-1; i++ { if arrayzor[i+1] < arrayzor[i] { - swap(arrayzor, i, i+1) + arrayzor[i+1], arrayzor[i] = arrayzor[i], arrayzor[i+1] swapped = true } } } return arrayzor } - -func swap(arrayzor []int, i, j int) { - tmp := arrayzor[j] - arrayzor[j] = arrayzor[i] - arrayzor[i] = tmp -} From 50597978e3ffbb5453ae0af8ab3e854463c24f14 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 23 May 2020 21:20:44 +0000 Subject: [PATCH 016/488] updating DIRECTORY.md --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 9572f98a4..f78b34281 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -8,6 +8,8 @@ * [Binary-Tree](https://github.com/TheAlgorithms/Go/blob/master/data-structures/binary-tree/binary-tree.go) * Dynamic-Array * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data-structures/dynamic-array/dynamic_array.go) + * Hash-Map + * [Hash Map](https://github.com/TheAlgorithms/Go/blob/master/data-structures/hash-map/hash_map.go) * Linked-List * [Double-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/double-linkedlist.go) * [Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/Linkedlist.go) From e4c9d7a4507a6813383974aa659c614f64d6fc3c Mon Sep 17 00:00:00 2001 From: Brayo Date: Sun, 24 May 2020 15:26:16 +0300 Subject: [PATCH 017/488] Update naiveStringSearch.go Properly implemented the algorithm. --- strings/naiveStringSearch.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/strings/naiveStringSearch.go b/strings/naiveStringSearch.go index 0dc2847cb..efb0c944c 100644 --- a/strings/naiveStringSearch.go +++ b/strings/naiveStringSearch.go @@ -16,14 +16,14 @@ import ( func naivePatternSearch(text string, pattern string) []int { var positions []int - for i := 0; i < len(text); i++ { + for i := 0; i < len(text)-len(pattern); i++ { var match bool = true - for j := 0; j < len(pattern); j++ { - if text[i+j] != pattern[j] { + j := i +(len(pattern)) + if text[i+j] != pattern[j] { match = false break } - } + if match { positions = append(positions, i) } From a4e5bfa14f675171419519d9ca7e50d1b0ffeb82 Mon Sep 17 00:00:00 2001 From: Brayo Date: Sun, 24 May 2020 16:31:29 +0300 Subject: [PATCH 018/488] Updated variable names to Go's naming conventions Updates to Go's naming conventions --- sorts/heap_sort.go | 12 ++++++------ sorts/quick_sort.go | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/sorts/heap_sort.go b/sorts/heap_sort.go index c5678893c..7140e7fe7 100644 --- a/sorts/heap_sort.go +++ b/sorts/heap_sort.go @@ -1,20 +1,20 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -type MaxHeap struct { +type maxHeap struct { slice []int heapSize int } -func BuildMaxHeap(slice []int) MaxHeap { - h := MaxHeap{slice: slice, heapSize: len(slice)} +func buildMaxHeap(slice []int) maxHeap { + h := maxHeap{slice: slice, heapSize: len(slice)} for i := len(slice) / 2; i >= 0; i-- { h.MaxHeapify(i) } return h } -func (h MaxHeap) MaxHeapify(i int) { +func (h maxHeap) MaxHeapify(i int) { l, r := 2*i+1, 2*i+2 max := i @@ -31,10 +31,10 @@ func (h MaxHeap) MaxHeapify(i int) { } } -func (h MaxHeap) size() int { return h.heapSize } // ??? +func (h maxHeap) size() int { return h.heapSize } // ??? func heapSort(slice []int) []int { - h := BuildMaxHeap(slice) + h := buildMaxHeap(slice) //log.Println(slice) for i := len(h.slice) - 1; i >= 1; i-- { h.slice[0], h.slice[i] = h.slice[i], h.slice[0] diff --git a/sorts/quick_sort.go b/sorts/quick_sort.go index 2d719a11e..f696d801d 100644 --- a/sorts/quick_sort.go +++ b/sorts/quick_sort.go @@ -13,26 +13,26 @@ func quickSort(arr []int) []int { median := arr[rand.Intn(len(arr))] - low_part := make([]int, 0, len(arr)) - high_part := make([]int, 0, len(arr)) - middle_part := make([]int, 0, len(arr)) + lowPart := make([]int, 0, len(arr)) + highPart := make([]int, 0, len(arr)) + middlePart := make([]int, 0, len(arr)) for _, item := range arr { switch { case item < median: - low_part = append(low_part, item) + lowPart = append(lowPart, item) case item == median: - middle_part = append(middle_part, item) + middlePart = append(middlePart, item) case item > median: - high_part = append(high_part, item) + highPart = append(highPart, item) } } - low_part = quickSort(low_part) - high_part = quickSort(high_part) + lowPart = quickSort(lowPart) + highPart = quickSort(highPart) - low_part = append(low_part, middle_part...) - low_part = append(low_part, high_part...) + lowPart = append(lowPart, middlePart...) + lowPart = append(lowPart, highPart...) - return low_part + return lowPart } From f3b9ecef8fa550dd5a2a083e260e0d042a6b9124 Mon Sep 17 00:00:00 2001 From: Brayo Date: Sun, 24 May 2020 16:33:27 +0300 Subject: [PATCH 019/488] Update bubble_sort.go A simplier more intuitive implementation --- sorts/bubble_sort.go | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/sorts/bubble_sort.go b/sorts/bubble_sort.go index 77f73d6a9..9618ba262 100644 --- a/sorts/bubble_sort.go +++ b/sorts/bubble_sort.go @@ -1,24 +1,21 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -func bubbleSort(arrayzor []int) []int { - - - swapped := true - for swapped { - swapped = false - for i := 0; i < len(arrayzor)-1; i++ { - if arrayzor[i+1] < arrayzor[i] { - swap(arrayzor, i, i+1) - swapped = true - } +func bubbleSort(array []int)[]int{ + for a:=0; aarray[j]{ + array[i],array[j] =array[j],array[i] + } + return array + +} \ No newline at end of file From dde9a7719454dcfec95c3c8d66464909fcd1f76a Mon Sep 17 00:00:00 2001 From: Brayo Date: Sun, 24 May 2020 16:58:48 +0300 Subject: [PATCH 020/488] Revert "Update bubble_sort.go" This reverts commit f3b9ecef8fa550dd5a2a083e260e0d042a6b9124. --- sorts/bubble_sort.go | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/sorts/bubble_sort.go b/sorts/bubble_sort.go index 9618ba262..77f73d6a9 100644 --- a/sorts/bubble_sort.go +++ b/sorts/bubble_sort.go @@ -1,21 +1,24 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -func bubbleSort(array []int)[]int{ - for a:=0; aarray[j]{ - array[i],array[j] =array[j],array[i] + swapped := true + for swapped { + swapped = false + for i := 0; i < len(arrayzor)-1; i++ { + if arrayzor[i+1] < arrayzor[i] { + swap(arrayzor, i, i+1) + swapped = true + } + } } - return array + return arrayzor +} -} \ No newline at end of file +func swap(arrayzor []int, i, j int) { + tmp := arrayzor[j] + arrayzor[j] = arrayzor[i] + arrayzor[i] = tmp +} From a516ad13fe10ca0176216ae280a91ed71c229f76 Mon Sep 17 00:00:00 2001 From: Brayo Date: Mon, 25 May 2020 04:08:52 +0300 Subject: [PATCH 021/488] Create xorCipher.go A simple implementation of the Xor Cipher --- ciphers/xorCipher.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 ciphers/xorCipher.go diff --git a/ciphers/xorCipher.go b/ciphers/xorCipher.go new file mode 100644 index 000000000..945211a47 --- /dev/null +++ b/ciphers/xorCipher.go @@ -0,0 +1,37 @@ +package main + +import "fmt" +func encrypt(key int, plaintext []int)(ciphertext []int){ + for _,char:= range plaintext { + ciphertext = append(ciphertext,xor(char,key)) + } + return +} +func xor(char int,key int)int{ + return (char^key) +} + +func decrypt(key int, ciphertext []int)(plaintext []int){ + for _,char:= range ciphertext { + plaintext = append(plaintext , xor(char,key)) + } + return +} + +func decodeToString(slice []int)(str string){ + for _,v:= range slice{ + str+=string(v) + } + return +} + +func main(){ + //string = hello world + key :=97 + message:=[]int{72,101,108,108,111,32,119,111,114,108,100} + encrypted:=encrypt(key,message) + decrypted:=decrypt(key,encrypted) + plaintext:=decodeToString(decrypted) + fmt.Println(plaintext) +} + From a2559202316ee8345fab7bde60294717d7b236fa Mon Sep 17 00:00:00 2001 From: Brayo Date: Sat, 30 May 2020 14:36:41 +0300 Subject: [PATCH 022/488] Create RSAcipher.go --- cachefile.dbm.dat | 0 cachefile.dbm.dir | 0 ciphers/RSAcipher.go | 172 +++++++++++++++++++++++++++++++++++++++++++ ciphers/xorCipher.go | 13 +++- 4 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 cachefile.dbm.dat create mode 100644 cachefile.dbm.dir create mode 100644 ciphers/RSAcipher.go diff --git a/cachefile.dbm.dat b/cachefile.dbm.dat new file mode 100644 index 000000000..e69de29bb diff --git a/cachefile.dbm.dir b/cachefile.dbm.dir new file mode 100644 index 000000000..e69de29bb diff --git a/ciphers/RSAcipher.go b/ciphers/RSAcipher.go new file mode 100644 index 000000000..39620898c --- /dev/null +++ b/ciphers/RSAcipher.go @@ -0,0 +1,172 @@ +package main + +import ( + //"math/big" + "math/rand" + "math" + "time" + "fmt" +) +func generatePrimes(limit int)int{ + /* + generate primes by factoring + relies on the 30k+i, though better formulae exist + where k >=0 and i = (1,7,11,13,17,13,19,23,29) + */ + primes:= prime(limit) + var choice []int + choice = append(choice, 1,7,11,13,17,19,23,29) + for{ + k:=rand.Intn(int(limit/30)) + i:=choice[rand.Intn(len(choice))] + c:=30*k+i + found := true + for _,v:= range primes{ + if c%v==0{ + found = false + break + } + } + if found{ + return c + } + } +} +func prime(limit int)(primes []int){ + sqrtLimit:=int(math.Ceil(math.Sqrt(float64(limit)))) + exit:= false + primes = append(primes,2,3,5) + lastIndex :=2 + for ;primes[lastIndex]=sqrtLimit{ + exit = true + break + } + } + + } + } + return +} +func lcm (a int, b int)int{ + //complexity depende + return int((a*b)/gcd(a,b)) + +} +func gcd (a int, b int) int{ + //complexity not clear + for b != 0{ + t:=b + b = a % b + a = t + } + return a +} +func modularMultiplicativeInverse(e int, delta int)int{ + //runs in O(n) where n = delta + e= e % delta + for i:=1;i0;{ + if e%2==1{ + r=(r*b)%mod + } + e =e>>1 + b = (b*b)%mod + } + return r +} + +func encryptRSA(message []int,e int,n int)[]int{ + //runs in O(k*log(n)) where k = len(message) and n = e + var ciphertext []int + for _,v := range message{ + ciphertext = append(ciphertext, modularExponentiation(v,e,n)) + } + return ciphertext +} +func decryptRSA(ciphertext []int, d int, n int )[]int{ + //runs in O(k*log(n)) where k = len(ciphertext) and n = d + var message []int + for _,v := range ciphertext { + message = append(message, modularExponentiation(v,d,n)) + } + return message +} +func toASCII(slice []rune)[]int{ + //runs in O(n) where n = len(slice) + var converted []int + for _,v:= range slice{ + converted = append(converted, int(v)) + } + return converted +} + +func toRune(slice []int)string{ + //runs in O(n) where n = len(slice) + var str string + for _,v:= range slice{ + str += string(v) + } + return str +} + + +func main(){ + rand.Seed(time.Now().UTC().UnixNano()) + bits:=15 + + p:= generatePrimes(1< Date: Sat, 30 May 2020 22:55:01 +0300 Subject: [PATCH 023/488] Delete cachefile.dbm.dir --- cachefile.dbm.dir | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cachefile.dbm.dir diff --git a/cachefile.dbm.dir b/cachefile.dbm.dir deleted file mode 100644 index e69de29bb..000000000 From c462d05380aa3d11cb7eff9f9b6d35777adf39ee Mon Sep 17 00:00:00 2001 From: Brayo <62670517+brayo-pip@users.noreply.github.com> Date: Sat, 30 May 2020 22:55:36 +0300 Subject: [PATCH 024/488] Delete cachefile.dbm.dat --- cachefile.dbm.dat | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cachefile.dbm.dat diff --git a/cachefile.dbm.dat b/cachefile.dbm.dat deleted file mode 100644 index e69de29bb..000000000 From f86861f16fa38814975efe24164ff2684b5ef49e Mon Sep 17 00:00:00 2001 From: Brayo Date: Tue, 2 Jun 2020 14:32:58 +0300 Subject: [PATCH 025/488] Update RSAcipher.go --- ciphers/RSAcipher.go | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/ciphers/RSAcipher.go b/ciphers/RSAcipher.go index 39620898c..d26302ae7 100644 --- a/ciphers/RSAcipher.go +++ b/ciphers/RSAcipher.go @@ -16,7 +16,7 @@ func generatePrimes(limit int)int{ primes:= prime(limit) var choice []int choice = append(choice, 1,7,11,13,17,19,23,29) - for{ + for{ k:=rand.Intn(int(limit/30)) i:=choice[rand.Intn(len(choice))] c:=30*k+i @@ -137,36 +137,38 @@ func toRune(slice []int)string{ } return str } - + func main(){ rand.Seed(time.Now().UTC().UnixNano()) - bits:=15 - + bits:=17 + p:= generatePrimes(1< Date: Tue, 2 Jun 2020 14:37:10 +0300 Subject: [PATCH 026/488] Create diffieHellmanKeyExchange.go --- ciphers/diffieHellmanKeyExchange.go | 74 +++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 ciphers/diffieHellmanKeyExchange.go diff --git a/ciphers/diffieHellmanKeyExchange.go b/ciphers/diffieHellmanKeyExchange.go new file mode 100644 index 000000000..bf72564b6 --- /dev/null +++ b/ciphers/diffieHellmanKeyExchange.go @@ -0,0 +1,74 @@ +package main + +import ( + "fmt" + "math/rand" +) +func main(){ + bit:=30 + /* + p and g are pre-agreed constants + that can be communicated over an insecure channel + p should ideally be a large prime number but any integer works + g should be a small integer, 2,3 works fine + + PS: Note that the secret keys are never send over + the network + */ + + p:=2+rand.Intn(1<0;{ + if e%2==1{ + r=(r*b)%mod + } + e =e>>1 + b = (b*b)%mod + } + return r +} From 702eacca4d7695c3cacf5714500294a2814337e5 Mon Sep 17 00:00:00 2001 From: Brayo Date: Wed, 3 Jun 2020 17:09:57 +0300 Subject: [PATCH 027/488] Added Diffie Key exchange --- ciphers/diffieHellmanKeyExchange.go | 32 ++++++------- other/NestedBrackets.go | 5 ++- searches/binary_search.go | 70 ++++++++++++++--------------- 3 files changed, 55 insertions(+), 52 deletions(-) diff --git a/ciphers/diffieHellmanKeyExchange.go b/ciphers/diffieHellmanKeyExchange.go index bf72564b6..c7cc06980 100644 --- a/ciphers/diffieHellmanKeyExchange.go +++ b/ciphers/diffieHellmanKeyExchange.go @@ -18,23 +18,23 @@ func main(){ p:=2+rand.Intn(1< 0 { var stack []byte for i := 0; i < len(input); i++ { diff --git a/searches/binary_search.go b/searches/binary_search.go index 697b6704b..ada801e67 100644 --- a/searches/binary_search.go +++ b/searches/binary_search.go @@ -1,35 +1,35 @@ -/* - Binary search implementation in Go -*/ -package main - -func binarySearch(array []int, target int, lowIndex int, highIndex int) int { - if highIndex < lowIndex { - return -1 - } - mid := int((lowIndex + highIndex) / 2) - if array[mid] > target { - return binarySearch(array, target, lowIndex, mid) - } else if array[mid] < target { - return binarySearch(array, target, mid+1, highIndex) - } else { - return mid - } -} - -func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { - startIndex := lowIndex - endIndex := highIndex - var mid int - for startIndex < endIndex { - mid = int((startIndex + endIndex) / 2) - if array[mid] > target { - endIndex = mid - } else if array[mid] < target { - startIndex = mid - } else { - return mid - } - } - return -1 -} +/* + Binary search implementation in Go +*/ +package main + +func binarySearch(array []int, target int, lowIndex int, highIndex int) int { + if highIndex < lowIndex { + return -1 + } + mid := int((lowIndex + (highIndex-lowindex)/2)) + if array[mid] > target { + return binarySearch(array, target, lowIndex, mid) + } else if array[mid] < target { + return binarySearch(array, target, mid+1, highIndex) + } else { + return mid + } +} + +func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { + startIndex := lowIndex + endIndex := highIndex + var mid int + for startIndex < endIndex { + mid = int((startIndex + (endIndex-startIndex)/2)) + if array[mid] > target { + endIndex = mid + } else if array[mid] < target { + startIndex = mid + } else { + return mid + } + } + return -1 +} From 1e503ca70f8fd126ac7cfd5fa366044c8ab07ffe Mon Sep 17 00:00:00 2001 From: Brayo Date: Wed, 3 Jun 2020 17:10:21 +0300 Subject: [PATCH 028/488] minor fixes --- ciphers/RSAcipher.go | 2 +- ciphers/diffieHellmanKeyExchange.go | 72 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 ciphers/diffieHellmanKeyExchange.go diff --git a/ciphers/RSAcipher.go b/ciphers/RSAcipher.go index 39620898c..ce106038b 100644 --- a/ciphers/RSAcipher.go +++ b/ciphers/RSAcipher.go @@ -63,7 +63,7 @@ func prime(limit int)(primes []int){ return } func lcm (a int, b int)int{ - //complexity depende + //complexity depends on gcd return int((a*b)/gcd(a,b)) } diff --git a/ciphers/diffieHellmanKeyExchange.go b/ciphers/diffieHellmanKeyExchange.go new file mode 100644 index 000000000..ea6e42490 --- /dev/null +++ b/ciphers/diffieHellmanKeyExchange.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "math/rand" +) + +func main() { + bit := 30 + /* + p and g are pre-agreed constants + that can be communicated over an insecure channel + p should ideally be a large prime number but any integer works + g should be a small integer, 2,3 works fine + + PS: Note that the secret keys are never send over + the network + */ + + p := 2 + rand.Intn(1< 0 { + if e%2 == 1 { + r = (r * b) % mod + } + e = e >> 1 + b = (b * b) % mod + } + return r +} From 0d28a325b02da5754e022dd5c2e79480aa9bebba Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 4 Jun 2020 04:41:27 +0000 Subject: [PATCH 029/488] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index f78b34281..5ee4aa9f9 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,6 +1,9 @@ ## Ciphers * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/CaesarCipher.go) + * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) + * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher.go) + * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xorCipher.go) ## Data-Structures * Binary-Tree From 8e01f3d134dcddea9e8ab08b08e45ae06a476ede Mon Sep 17 00:00:00 2001 From: Brayo Date: Fri, 5 Jun 2020 21:32:51 +0300 Subject: [PATCH 030/488] minor edits --- other/NestedBrackets.go | 3 +-- searches/binary_search.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/other/NestedBrackets.go b/other/NestedBrackets.go index 4582bf04d..e82f647d9 100644 --- a/other/NestedBrackets.go +++ b/other/NestedBrackets.go @@ -19,9 +19,8 @@ import ( ) func isBalanced(input string) string { -/* if len(input)%2 == 0{ + if len(input)%2 == 0{ return input + "is not balanced." - }*/ if len(input) > 0 { var stack []byte for i := 0; i < len(input); i++ { diff --git a/searches/binary_search.go b/searches/binary_search.go index ada801e67..544c56314 100644 --- a/searches/binary_search.go +++ b/searches/binary_search.go @@ -7,7 +7,7 @@ func binarySearch(array []int, target int, lowIndex int, highIndex int) int { if highIndex < lowIndex { return -1 } - mid := int((lowIndex + (highIndex-lowindex)/2)) + mid := int((lowIndex + (highIndex-lowIndex)/2)) if array[mid] > target { return binarySearch(array, target, lowIndex, mid) } else if array[mid] < target { From bdc2f27ef4f0c71f5a73b867f79a5dc313c999c4 Mon Sep 17 00:00:00 2001 From: Brayo Date: Sun, 7 Jun 2020 22:54:27 +0300 Subject: [PATCH 031/488] Minor updates Fixed a bug I had introduced in NaiveStringSearch.go, cleaned up the unnecessary comments in diffieHellmanKeyExchange.go... --- ciphers/diffieHellmanKeyExchange.go | 11 +++-------- ciphers/xorCipher.go | 1 + sorts/sorts_case_test.go | 2 +- strings/naiveStringSearch.go | 18 +++++++++--------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/ciphers/diffieHellmanKeyExchange.go b/ciphers/diffieHellmanKeyExchange.go index c7cc06980..1a6532abd 100644 --- a/ciphers/diffieHellmanKeyExchange.go +++ b/ciphers/diffieHellmanKeyExchange.go @@ -12,8 +12,7 @@ func main(){ p should ideally be a large prime number but any integer works g should be a small integer, 2,3 works fine - PS: Note that the secret keys are never send over - the network + PS: Note that the secret keys are never send over the network */ p:=2+rand.Intn(1< Date: Mon, 8 Jun 2020 12:37:34 +0800 Subject: [PATCH 032/488] fix(naivestringsearch): was not working at all --- strings/naiveStringSearch.go | 59 ++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/strings/naiveStringSearch.go b/strings/naiveStringSearch.go index efb0c944c..c93b1f134 100644 --- a/strings/naiveStringSearch.go +++ b/strings/naiveStringSearch.go @@ -1,44 +1,45 @@ /* This algorithm tries to search the given pattern in the given text. -If pattern is found from index position i in the text, +If pattern is found from index position i in the text, it is added to positions. Time Complexity : O(n*m) n = length of text - m = length of pattern + m = length of pattern */ package main -import ( - "fmt" +import ( + "fmt" ) -func naivePatternSearch(text string, pattern string) []int { - var positions []int - for i := 0; i < len(text)-len(pattern); i++ { - var match bool = true - j := i +(len(pattern)) - if text[i+j] != pattern[j] { - match = false - break - } - - if match { - positions = append(positions, i) - } - } - return positions +func naivePatternSearch(text string, pattern string) []int { + var positions []int + for i := 0; i < len(text)-len(pattern); i++ { + var match bool = true + for j := 0; j < len(pattern); j++ { + if text[i+j] != pattern[j] { + match = false + break + } + + } + if match { + positions = append(positions, i) + } + } + return positions } -func main() { - text := "ABAAABCDBBABCDDEBCABC" - pattern := "ABC" - var positions []int = naivePatternSearch(text, pattern) - if len(positions) == 0 { - fmt.Printf("Pattern not found in given text!") - } else { - fmt.Printf("Pattern found in following position:\n") - fmt.Printf("%v", positions) - } +func main() { + text := "ABAAABCDBBABCDDEBCABC" + pattern := "ABC" + var positions []int = naivePatternSearch(text, pattern) + if len(positions) == 0 { + fmt.Printf("Pattern not found in given text!") + } else { + fmt.Printf("Pattern found in following position:\n") + fmt.Printf("%v", positions) + } } From 318c44db8cf7f6a9202bba6ce85497f641195dee Mon Sep 17 00:00:00 2001 From: halafi Date: Mon, 8 Jun 2020 12:37:58 +0800 Subject: [PATCH 033/488] feat(strings): add algorithm implementations --- strings/multiple string matching/ac.go | 295 ++++++++++++++++ strings/multiple string matching/adac.go | 307 +++++++++++++++++ strings/multiple string matching/patterns.txt | 1 + strings/multiple string matching/sbom.go | 315 ++++++++++++++++++ strings/multiple string matching/text.txt | 1 + strings/single string matching/bom.go | 236 +++++++++++++ strings/single string matching/horspool.go | 102 ++++++ strings/single string matching/kmp.go | 104 ++++++ strings/single string matching/pattern.txt | 1 + strings/single string matching/text.txt | 1 + 10 files changed, 1363 insertions(+) create mode 100644 strings/multiple string matching/ac.go create mode 100644 strings/multiple string matching/adac.go create mode 100644 strings/multiple string matching/patterns.txt create mode 100644 strings/multiple string matching/sbom.go create mode 100644 strings/multiple string matching/text.txt create mode 100644 strings/single string matching/bom.go create mode 100644 strings/single string matching/horspool.go create mode 100644 strings/single string matching/kmp.go create mode 100644 strings/single string matching/pattern.txt create mode 100644 strings/single string matching/text.txt diff --git a/strings/multiple string matching/ac.go b/strings/multiple string matching/ac.go new file mode 100644 index 000000000..efecc9df1 --- /dev/null +++ b/strings/multiple string matching/ac.go @@ -0,0 +1,295 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "strings" + "time" +) + +// User defined. +// Set to true to print various extra stuff out (slows down the execution) +// Set to false for quick and quiet execution. +const debugMode bool = true + +// Implementation of Basic Aho-Corasick algorithm (Prefix based). +// Searches for a set of strings (patterns.txt) in text.txt. +func main() { + patFile, err := ioutil.ReadFile("patterns.txt") + if err != nil { + log.Fatal(err) + } + textFile, err := ioutil.ReadFile("text.txt") + if err != nil { + log.Fatal(err) + } + patterns := strings.Split(string(patFile), " ") + fmt.Printf("\nRunning: Basic Aho-Corasick algorithm.\n\n") + if debugMode == true { + fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) + } + for i := 0; i < len(patterns); i++ { + if len(patterns[i]) > len(textFile) { + log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) + } + if debugMode == true { + fmt.Printf("%q ", patterns[i]) + } + } + if debugMode == true { + fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) + } + ahoCorasick(string(textFile), patterns) +} + +// Function performing the Basic Aho-Corasick alghoritm. +// Finds and prints occurences of each pattern. +func ahoCorasick(t string, p []string) { + startTime := time.Now() + occurences := make(map[int][]int) + ac, f, s := buildAc(p) + if debugMode == true { + fmt.Printf("\n\nAC:\n\n") + } + current := 0 + for pos := 0; pos < len(t); pos++ { + if debugMode == true { + fmt.Printf("Position: %d, we read: %c", pos, t[pos]) + } + for getTransition(current, t[pos], ac) == -1 && s[current] != -1 { + current = s[current] + } + if getTransition(current, t[pos], ac) != -1 { + current = getTransition(current, t[pos], ac) + fmt.Printf(" (Continue) \n") + } else { + current = 0 + if debugMode == true { + fmt.Printf(" (FAIL) \n") + } + } + _, ok := f[current] + if ok { + for i := range f[current] { + if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match + if debugMode == true { + fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) + } + newOccurences := intArrayCapUp(occurences[f[current][i]]) + occurences[f[current][i]] = newOccurences + occurences[f[current][i]][len(newOccurences)-1] = pos - len(p[f[current][i]]) + 1 + } + } + } + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + for key, value := range occurences { //prints all occurences of each pattern (if there was at least one) + fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), p[key]) + for i := range value { + fmt.Printf("%d", value[i]) + if i != len(value)-1 { + fmt.Printf(", ") + } + } + fmt.Printf(".") + } + return +} + +// Functions that builds Aho Corasick automaton. +func buildAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int, s []int) { + acTrie, stateIsTerminal, f := constructTrie(p) + s = make([]int, len(stateIsTerminal)) //supply function + i := 0 //root of acTrie + acToReturn = acTrie + s[i] = -1 + if debugMode == true { + fmt.Printf("\n\nAC construction: \n") + } + for current := 1; current < len(stateIsTerminal); current++ { + o, parent := getParent(current, acTrie) + down := s[parent] + for stateExists(down, acToReturn) && getTransition(down, o, acToReturn) == -1 { + down = s[down] + } + if stateExists(down, acToReturn) { + s[current] = getTransition(down, o, acToReturn) + if stateIsTerminal[s[current]] == true { + stateIsTerminal[current] = true + f[current] = arrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) + if debugMode == true { + fmt.Printf(" f[%d] set to: ", current) + for i := range f[current] { + fmt.Printf("%d\n", f[current][i]) + } + } + } + } else { + s[current] = i //initial state? + } + } + if debugMode == true { + fmt.Printf("\nsupply function: \n") + for i := range s { + fmt.Printf("\ns[%d]=%d", i, s[i]) + } + fmt.Printf("\n\n") + for i, j := range f { + fmt.Printf("f[%d]=", i) + for k := range j { + fmt.Printf("%d\n", j[k]) + } + } + } + return acToReturn, f, s +} + +// Function that constructs Trie as an automaton for a set of reversed & trimmed strings. +func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { + trie = make(map[int]map[uint8]int) + stateIsTerminal = make([]bool, 1) + f = make(map[int][]int) + state := 1 + if debugMode == true { + fmt.Printf("\n\nTrie construction: \n") + } + createNewState(0, trie) + for i := 0; i < len(p); i++ { + current := 0 + j := 0 + for j < len(p[i]) && getTransition(current, p[i][j], trie) != -1 { + current = getTransition(current, p[i][j], trie) + j++ + } + for j < len(p[i]) { + stateIsTerminal = boolArrayCapUp(stateIsTerminal) + createNewState(state, trie) + stateIsTerminal[state] = false + createTransition(current, p[i][j], state, trie) + current = state + j++ + state++ + } + if stateIsTerminal[current] { + newArray := intArrayCapUp(f[current]) + newArray[len(newArray)-1] = i + f[current] = newArray //F(Current) <- F(Current) union {i} + if debugMode == true { + fmt.Printf(" and %d", i) + } + } else { + stateIsTerminal[current] = true + f[current] = []int{i} //F(Current) <- {i} + if debugMode == true { + fmt.Printf("\n%d is terminal for word number %d", current, i) + } + } + } + return trie, stateIsTerminal, f +} + +/** +Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. + +@author Mostafa http://stackoverflow.com/a/10485970 +*/ +func contains(s []int, e int) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} + +// Function that returns word found in text 't' at position range 'begin' to 'end'. +func getWord(begin, end int, t string) string { + for end >= len(t) { + return "" + } + d := make([]uint8, end-begin+1) + for j, i := 0, begin; i <= end; i, j = i+1, j+1 { + d[j] = t[i] + } + return string(d) +} + +// Dynamically increases an array size of int's by 1. +func intArrayCapUp(old []int) (new []int) { + new = make([]int, cap(old)+1) + copy(new, old) //copy(dst,src) + old = new + return new +} + +// Dynamically increases an array size of bool's by 1. +func boolArrayCapUp(old []bool) (new []bool) { + new = make([]bool, cap(old)+1) + copy(new, old) + old = new + return new +} + +// Concats two arrays of int's into one. +func arrayUnion(to, from []int) (concat []int) { + concat = to + for i := range from { + if !contains(concat, from[i]) { + concat = intArrayCapUp(concat) + concat[len(concat)-1] = from[i] + } + } + return concat +} + +// Function that finds the first previous state of a state and returns it. +// Used for trie where there is only one parent. +func getParent(state int, at map[int]map[uint8]int) (uint8, int) { + for beginState, transitions := range at { + for c, endState := range transitions { + if endState == state { + return c, beginState + } + } + } + return 0, 0 //unreachable +} + +// Automaton function for creating a new state 'state'. +func createNewState(state int, at map[int]map[uint8]int) { + at[state] = make(map[uint8]int) + if debugMode == true { + fmt.Printf("\ncreated state %d", state) + } +} + +// Creates a transition for function σ(state,letter) = end. +func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { + at[fromState][overChar] = toState + if debugMode == true { + fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) + } +} + +// Returns ending state for transition σ(fromState,overChar), '-1' if there is none. +func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { + if !stateExists(fromState, at) { + return -1 + } + toState, ok := at[fromState][overChar] + if ok == false { + return -1 + } + return toState +} + +// Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. +func stateExists(state int, at map[int]map[uint8]int) bool { + _, ok := at[state] + if !ok || state == -1 || at[state] == nil { + return false + } + return true +} diff --git a/strings/multiple string matching/adac.go b/strings/multiple string matching/adac.go new file mode 100644 index 000000000..14cedeb3b --- /dev/null +++ b/strings/multiple string matching/adac.go @@ -0,0 +1,307 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "strings" + "time" +) + +// User defined. +// Set to true to print various extra stuff out (slows down the execution) +// Set to false for quick and quiet execution. +const debugMode bool = true + +// Implementation of Advanced Aho-Corasick algorithm (Prefix based). +// Searches for a set of strings (patterns.txt) in text.txt. +func main() { + patFile, err := ioutil.ReadFile("patterns.txt") + if err != nil { + log.Fatal(err) + } + textFile, err := ioutil.ReadFile("text.txt") + if err != nil { + log.Fatal(err) + } + patterns := strings.Split(string(patFile), " ") + fmt.Printf("\nRunning: Advanced Aho-Corasick algorithm.\n\n") + if debugMode == true { + fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) + } + for i := 0; i < len(patterns); i++ { + if len(patterns[i]) > len(textFile) { + log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) + } + if debugMode == true { + fmt.Printf("%q ", patterns[i]) + } + } + if debugMode == true { + fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) + } + ahoCorasick(string(textFile), patterns) +} + +// Function performing the Advanced Aho-Corasick alghoritm. +// Finds and prints occurences of each pattern. +func ahoCorasick(t string, p []string) { + startTime := time.Now() + occurences := make(map[int][]int) + ac, f := buildExtendedAc(p) + if debugMode == true { + fmt.Printf("\n\nAC:\n\n") + } + current := 0 + for pos := 0; pos < len(t); pos++ { + if getTransition(current, t[pos], ac) != -1 { + current = getTransition(current, t[pos], ac) + } else { + current = 0 + } + _, ok := f[current] + if ok { + for i := range f[current] { + if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match + if debugMode == true { + fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) + } + newOccurences := intArrayCapUp(occurences[f[current][i]]) + occurences[f[current][i]] = newOccurences + occurences[f[current][i]][len(newOccurences)-1] = pos - len(p[f[current][i]]) + 1 + } + } + } + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + for key, value := range occurences { //prints all occurences of each pattern (if there was at least one) + fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), p[key]) + for i := range value { + fmt.Printf("%d", value[i]) + if i != len(value)-1 { + fmt.Printf(", ") + } + } + fmt.Printf(".") + } + return +} + +// Functions that builds extended Aho Corasick automaton. +func buildExtendedAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int) { + acTrie, stateIsTerminal, f := constructTrie(p) + s := make([]int, len(stateIsTerminal)) //supply function + i := 0 //root of acTrie + acToReturn = acTrie + s[i] = -1 + if debugMode == true { + fmt.Printf("\n\nAC construction: \n") + } + for current := 1; current < len(stateIsTerminal); current++ { + o, parent := getParent(current, acTrie) + down := s[parent] + for stateExists(down, acToReturn) && getTransition(down, o, acToReturn) == -1 { + down = s[down] + } + if stateExists(down, acToReturn) { + s[current] = getTransition(down, o, acToReturn) + if stateIsTerminal[s[current]] == true { + stateIsTerminal[current] = true + f[current] = arrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) + if debugMode == true { + fmt.Printf(" f[%d] set to: ", current) + for i := range f[current] { + fmt.Printf("%d\n", f[current][i]) + } + } + } + } else { + s[current] = i //initial state? + } + } + if debugMode == true { + fmt.Printf("\nsupply function: \n") + for i := range s { + fmt.Printf("\ns[%d]=%d", i, s[i]) + } + fmt.Printf("\n\n") + for i, j := range f { + fmt.Printf("f[%d]=", i) + for k := range j { + fmt.Printf("%d\n", j[k]) + } + } + } + if debugMode == true { + fmt.Printf("\n\nAdAC completion: \n") + } + // advanced Aho-Corasick part + a := computeAlphabet(p) // concat of all patterns in p + for j := range a { + if getTransition(i, a[j], acToReturn) == -1 { + createTransition(i, a[j], i, acToReturn) + } + } + for current := 1; current < len(stateIsTerminal); current++ { + for j := range a { + if getTransition(current, a[j], acToReturn) == -1 { + createTransition(current, a[j], getTransition(s[current], a[j], acToReturn), acToReturn) + } + } + } + return acToReturn, f +} + +// Function that constructs Trie as an automaton for a set of reversed & trimmed strings. +func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { + trie = make(map[int]map[uint8]int) + stateIsTerminal = make([]bool, 1) + f = make(map[int][]int) + state := 1 + if debugMode == true { + fmt.Printf("\n\nTrie construction: \n") + } + createNewState(0, trie) + for i := 0; i < len(p); i++ { + current := 0 + j := 0 + for j < len(p[i]) && getTransition(current, p[i][j], trie) != -1 { + current = getTransition(current, p[i][j], trie) + j++ + } + for j < len(p[i]) { + stateIsTerminal = boolArrayCapUp(stateIsTerminal) + createNewState(state, trie) + stateIsTerminal[state] = false + createTransition(current, p[i][j], state, trie) + current = state + j++ + state++ + } + if stateIsTerminal[current] { + newArray := intArrayCapUp(f[current]) + newArray[len(newArray)-1] = i + f[current] = newArray // F(Current) <- F(Current) union {i} + if debugMode == true { + fmt.Printf(" and %d", i) + } + } else { + stateIsTerminal[current] = true + f[current] = []int{i} // F(Current) <- {i} + if debugMode == true { + fmt.Printf("\n%d is terminal for word number %d", current, i) + } + } + } + return trie, stateIsTerminal, f +} + +// Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. +func contains(s []int, e int) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} + +// Function that returns word found in text 't' at position range 'begin' to 'end'. +func getWord(begin, end int, t string) string { + for end >= len(t) { + return "" + } + d := make([]uint8, end-begin+1) + for j, i := 0, begin; i <= end; i, j = i+1, j+1 { + d[j] = t[i] + } + return string(d) +} + +// Function that returns string of all the possible characters in given patterns. +func computeAlphabet(p []string) (s string) { + s = p[0] + for i := 1; i < len(p); i++ { + s = s + p[i] + } + return s +} + +// Dynamically increases an array size of int's by 1. +func intArrayCapUp(old []int) (new []int) { + new = make([]int, cap(old)+1) + copy(new, old) //copy(dst,src) + old = new + return new +} + +// Dynamically increases an array size of bool's by 1. +func boolArrayCapUp(old []bool) (new []bool) { + new = make([]bool, cap(old)+1) + copy(new, old) + old = new + return new +} + +// Concats two arrays of int's into one. +func arrayUnion(to, from []int) (concat []int) { + concat = to + for i := range from { + if !contains(concat, from[i]) { + concat = intArrayCapUp(concat) + concat[len(concat)-1] = from[i] + } + } + return concat +} + +// Function that finds the first previous state of a state and returns it. +// Used for trie where there is only one parent. +func getParent(state int, at map[int]map[uint8]int) (uint8, int) { + for beginState, transitions := range at { + for c, endState := range transitions { + if endState == state { + return c, beginState + } + } + } + return 0, 0 //unreachable +} + +// Automaton function for creating a new state 'state'. +func createNewState(state int, at map[int]map[uint8]int) { + at[state] = make(map[uint8]int) + if debugMode == true { + fmt.Printf("\ncreated state %d", state) + } +} + +// Creates a transition for function σ(state,letter) = end. +func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { + at[fromState][overChar] = toState + if debugMode == true { + fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) + } +} + +// Returns ending state for transition σ(fromState,overChar), '-1' if there is none. +func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { + if !stateExists(fromState, at) { + return -1 + } + toState, ok := at[fromState][overChar] + if ok == false { + return -1 + } + return toState +} + +// Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. +func stateExists(state int, at map[int]map[uint8]int) bool { + _, ok := at[state] + if !ok || state == -1 || at[state] == nil { + return false + } + return true +} diff --git a/strings/multiple string matching/patterns.txt b/strings/multiple string matching/patterns.txt new file mode 100644 index 000000000..2fedb65dc --- /dev/null +++ b/strings/multiple string matching/patterns.txt @@ -0,0 +1 @@ +announce annual annually \ No newline at end of file diff --git a/strings/multiple string matching/sbom.go b/strings/multiple string matching/sbom.go new file mode 100644 index 000000000..08ba904c5 --- /dev/null +++ b/strings/multiple string matching/sbom.go @@ -0,0 +1,315 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "strings" + "time" +) + +// User defined. +// Set to true to print various extra stuff out (slows down the execution) +// Set to false for quick and quiet execution. +const debugMode bool = true + +// Implementation of Set Backward Oracle Matching algorithm (Factor based). +// Searches for a set of strings (in 'patterns.txt') in text.txt. +func main() { + patFile, err := ioutil.ReadFile("patterns.txt") + if err != nil { + log.Fatal(err) + } + textFile, err := ioutil.ReadFile("text.txt") + if err != nil { + log.Fatal(err) + } + patterns := strings.Split(string(patFile), " ") + fmt.Printf("\nRunning: Set Backward Oracle Matching algorithm.\n\n") + if debugMode == true { + fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) + } + for i := 0; i < len(patterns); i++ { + if len(patterns[i]) > len(textFile) { + log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) + } + if debugMode == true { + fmt.Printf("%q ", patterns[i]) + } + } + if debugMode == true { + fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) + } + sbom(string(textFile), patterns) +} + +// Function sbom performing the Set Backward Oracle Matching alghoritm. +// Finds and prints occurences of each pattern. +func sbom(t string, p []string) { + startTime := time.Now() + occurences := make(map[int][]int) + lmin := computeMinLength(p) + or, f := buildOracleMultiple(reverseAll(trimToLength(p, lmin))) + if debugMode == true { + fmt.Printf("\n\nSBOM:\n\n") + } + pos := 0 + for pos <= len(t)-lmin { + current := 0 + j := lmin + if debugMode == true { + fmt.Printf("Position: %d, we read: ", pos) + } + for j >= 1 && stateExists(current, or) { + if debugMode == true { + fmt.Printf("%c", t[pos+j-1]) + } + current = getTransition(current, t[pos+j-1], or) + if debugMode == true { + if current == -1 { + fmt.Printf(" (FAIL) ") + } else { + fmt.Printf(", ") + } + } + j-- + } + if debugMode == true { + fmt.Printf("in the factor oracle. \n") + } + word := getWord(pos, pos+lmin-1, t) + if stateExists(current, or) && j == 0 && strings.HasPrefix(word, getCommonPrefix(p, f[current], lmin)) { //check for prefix match + for i := range f[current] { + if p[f[current][i]] == getWord(pos, pos-1+len(p[f[current][i]]), t) { //check for word match + if debugMode == true { + fmt.Printf("- Occurence, %q = %q\n", p[f[current][i]], word) + } + newOccurences := intArrayCapUp(occurences[f[current][i]]) + occurences[f[current][i]] = newOccurences + occurences[f[current][i]][len(newOccurences)-1] = pos + } + } + j = 0 + } + pos = pos + j + 1 + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + for key, value := range occurences { //prints all occurences of each pattern (if there was at least one) + fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), p[key]) + for i := range value { + fmt.Printf("%d", value[i]) + if i != len(value)-1 { + fmt.Printf(", ") + } + } + fmt.Printf(".") + } + return +} + +// Function that builds factor oracle. +func buildOracleMultiple(p []string) (orToReturn map[int]map[uint8]int, f map[int][]int) { + orTrie, stateIsTerminal, f := constructTrie(p) + s := make([]int, len(stateIsTerminal)) //supply function + i := 0 //root of trie + orToReturn = orTrie + s[i] = -1 + if debugMode == true { + fmt.Printf("\n\nOracle construction: \n") + } + for current := 1; current < len(stateIsTerminal); current++ { + o, parent := getParent(current, orTrie) + down := s[parent] + for stateExists(down, orToReturn) && getTransition(down, o, orToReturn) == -1 { + createTransition(down, o, current, orToReturn) + down = s[down] + } + if stateExists(down, orToReturn) { + s[current] = getTransition(down, o, orToReturn) + } else { + s[current] = i + } + } + return orToReturn, f +} + +// Function that constructs Trie as an automaton for a set of reversed & trimmed strings. +func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { + trie = make(map[int]map[uint8]int) + stateIsTerminal = make([]bool, 1) + f = make(map[int][]int) + state := 1 + if debugMode == true { + fmt.Printf("\n\nTrie construction: \n") + } + createNewState(0, trie) + for i := 0; i < len(p); i++ { + current := 0 + j := 0 + for j < len(p[i]) && getTransition(current, p[i][j], trie) != -1 { + current = getTransition(current, p[i][j], trie) + j++ + } + for j < len(p[i]) { + stateIsTerminal = boolArrayCapUp(stateIsTerminal) + createNewState(state, trie) + stateIsTerminal[state] = false + createTransition(current, p[i][j], state, trie) + current = state + j++ + state++ + } + if stateIsTerminal[current] { + newArray := intArrayCapUp(f[current]) + newArray[len(newArray)-1] = i + f[current] = newArray //F(Current) <- F(Current) union {i} + if debugMode == true { + fmt.Printf(" and %d", i) + } + } else { + stateIsTerminal[current] = true + f[current] = []int{i} //F(Current) <- {i} + if debugMode == true { + fmt.Printf("\n%d is terminal for word number %d", current, i) + } + } + } + return trie, stateIsTerminal, f +} + +// Dynamically increases an array size of int's by 1. +func intArrayCapUp(old []int) (new []int) { + new = make([]int, cap(old)+1) + copy(new, old) //copy(dst,src) + old = new + return new +} + +// Dynamically increases an array size of bool's by 1. +func boolArrayCapUp(old []bool) (new []bool) { + new = make([]bool, cap(old)+1) + copy(new, old) + old = new + return new +} + +// Function that takes an array of strings and reverses it. +func reverseAll(s []string) (reversed []string) { + reversed = make([]string, len(s)) + for i := 0; i < len(s); i++ { + reversed[i] = reverse(s[i]) + } + return reversed +} + +// Function that takes a single string and reverses it. +func reverse(s string) string { + l := len(s) + m := make([]rune, l) + for _, c := range s { + l-- + m[l] = c + } + return string(m) +} + +// Returns a prefix size 'lmin' for one string 'p' of first index found in 'f'. +// It is not needed to compare all the strings from 'p' indexed in 'f', +// thanks to the konwledge of 'lmin'. +func getCommonPrefix(p []string, f []int, lmin int) string { + r := []rune(p[f[0]]) + newR := make([]rune, lmin) + for j := 0; j < lmin; j++ { + newR[j] = r[j] + } + return string(newR) +} + +// Function that takes a set of strings 'p' and their wanted 'length' +// and then trims each string in that set to have desired 'length'. +func trimToLength(p []string, length int) (trimmedP []string) { + trimmedP = make([]string, len(p)) + for i := range p { + r := []rune(p[i]) + newR := make([]rune, length) + for j := 0; j < length; j++ { + newR[j] = r[j] + } + trimmedP[i] = string(newR) + } + return trimmedP +} + +// Function that returns word found in text 't' at position range 'begin' to 'end'. +func getWord(begin, end int, t string) string { + for end >= len(t) { + return "" + } + d := make([]uint8, end-begin+1) + for j, i := 0, begin; i <= end; i, j = i+1, j+1 { + d[j] = t[i] + } + return string(d) +} + +// Function that computes minimal length string in a set of strings. +func computeMinLength(p []string) (lmin int) { + lmin = len(p[0]) + for i := 1; i < len(p); i++ { + if len(p[i]) < lmin { + lmin = len(p[i]) + } + } + return lmin +} + +// Function that finds the first previous state of a state and returns it. +// Used for trie where there is only one parent. +func getParent(state int, at map[int]map[uint8]int) (uint8, int) { + for beginState, transitions := range at { + for c, endState := range transitions { + if endState == state { + return c, beginState + } + } + } + return 0, 0 //unreachable +} + +// Automaton function for creating a new state 'state'. +func createNewState(state int, at map[int]map[uint8]int) { + at[state] = make(map[uint8]int) + if debugMode == true { + fmt.Printf("\ncreated state %d", state) + } +} + +// Creates a transition for function σ(state,letter) = end. +func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { + at[fromState][overChar] = toState + if debugMode == true { + fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) + } +} + +// Returns ending state for transition σ(fromState,overChar), '-1' if there is none. +func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { + if !stateExists(fromState, at) { + return -1 + } + toState, ok := at[fromState][overChar] + if ok == false { + return -1 + } + return toState +} + +// Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. +func stateExists(state int, at map[int]map[uint8]int) bool { + _, ok := at[state] + if !ok || state == -1 || at[state] == nil { + return false + } + return true +} diff --git a/strings/multiple string matching/text.txt b/strings/multiple string matching/text.txt new file mode 100644 index 000000000..e98cf5c73 --- /dev/null +++ b/strings/multiple string matching/text.txt @@ -0,0 +1 @@ +CPM_annual_conference_announce \ No newline at end of file diff --git a/strings/single string matching/bom.go b/strings/single string matching/bom.go new file mode 100644 index 000000000..46d1f8359 --- /dev/null +++ b/strings/single string matching/bom.go @@ -0,0 +1,236 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "time" +) + +// User defined. +// Set to true to print various extra stuff out (slows down the execution) +// Set to false for quick and quiet execution. +const debugMode bool = false + +// User defined. +// Set to true to read input from two command line arguments +// Set to false to read input from two files "pattern.txt" and "text.txt" +const commandLineInput bool = false + +// Implementation of Backward Oracle Matching algorithm (Factor based approach). +// Requires either a two command line arguments separated by a single space, +// or two files in the same folder: "pattern.txt" containing the string to +// be searched for, "text.txt" containing the text to be searched in. +func main() { + if commandLineInput == true { // case of command line input + args := os.Args + if len(args) <= 2 { + log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") + } + pattern := args[1] + s := args[2] + for i := 3; i < len(args); i++ { + s = s + " " + args[i] + } + if len(args[1]) > len(s) { + log.Fatal("Pattern is longer than text!") + } + if debugMode == true { + fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") + fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) + fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) + } else { + fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") + } + bom(s, pattern) + } else if commandLineInput == false { // case of file line input + patFile, err := ioutil.ReadFile("pattern.txt") + if err != nil { + log.Fatal(err) + } + textFile, err := ioutil.ReadFile("text.txt") + if err != nil { + log.Fatal(err) + } + if len(patFile) > len(textFile) { + log.Fatal("Pattern is longer than text!") + } + if debugMode == true { + fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") + fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) + fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) + } else { + fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") + } + bom(string(textFile), string(patFile)) + } +} + +// Function bom performing the Backward Oracle Matching algorithm. +// Prints whether the word/pattern was found + positions of possible multiple occurrences +// or that the word was not found. +func bom(t, p string) { + startTime := time.Now() + n, m := len(t), len(p) + var current, j, pos int + oracle := oracleOnLine(reverse(p)) + occurences := make([]int, len(t)) + currentOcc := 0 + pos = 0 + if debugMode == true { + fmt.Printf("\n\nWe are reading backwards in %q, searching for %q\n\nat position %d:\n", t, p, pos+m-1) + } + for pos <= n-m { + current = 0 //initial state of the oracle + j = m + for j > 0 && stateExists(current, oracle) { + if debugMode == true { + prettyPrint(current, j, n, pos, t, oracle) + } + current = getTransition(current, t[pos+j-1], oracle) + j-- + } + if stateExists(current, oracle) { + if debugMode == true { + fmt.Printf(" We got an occurence!") + } + occurences[currentOcc] = pos + currentOcc++ + } + pos = pos + j + 1 + if pos+m-1 < len(t) { + if debugMode == true { + fmt.Printf("\n\nposition %d:\n", pos+m-1) + } + } + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + fmt.Printf("\n\n") + if currentOcc > 0 { + fmt.Printf("Word %q was found %d times at positions: ", p, currentOcc) + for k := 0; k < currentOcc-1; k++ { + fmt.Printf("%d, ", occurences[k]) + } + fmt.Printf("%d", occurences[currentOcc-1]) + fmt.Printf(".\n") + } + if currentOcc == 0 { + fmt.Printf("\nWord was not found.\n") + } + return +} + +// Construction of the factor oracle automaton for a word p. +func oracleOnLine(p string) (oracle map[int]map[uint8]int) { + if debugMode == true { + fmt.Printf("Oracle construction: \n") + } + oracle = make(map[int]map[uint8]int) + supply := make([]int, len(p)+2) // supply function + createNewState(0, oracle) + supply[0] = -1 + var orP string + for j := 0; j < len(p); j++ { + oracle, orP = oracleAddLetter(oracle, supply, orP, p[j]) + } + return oracle +} + +// Adds one letter to the oracle. +func oracleAddLetter(oracle map[int]map[uint8]int, supply []int, orP string, o uint8) (oracleToReturn map[int]map[uint8]int, orPToReturn string) { + m := len(orP) + var s int + createNewState(m+1, oracle) + createTransition(m, o, m+1, oracle) + k := supply[m] + for k > -1 && getTransition(k, o, oracle) == -1 { + createTransition(k, o, m+1, oracle) + k = supply[k] + } + if k == -1 { + s = 0 + } else { + s = getTransition(k, o, oracle) + } + supply[m+1] = s + return oracle, orP + string(o) +} + +// Function that takes a single string and reverses it. +// @author 'Walter' http://stackoverflow.com/a/10043083 +func reverse(s string) string { + l := len(s) + m := make([]rune, l) + for _, c := range s { + l-- + m[l] = c + } + return string(m) +} + +// Automaton function for creating a new state. +func createNewState(state int, at map[int]map[uint8]int) { + at[state] = make(map[uint8]int) + if debugMode == true { + fmt.Printf("\ncreated state %d", state) + } +} + +// Creates a transition for function σ(state,letter) = end. +func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { + at[fromState][overChar] = toState + if debugMode == true { + fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) + } +} + +// Returns ending state for transition σ(fromState,overChar), -1 if there is none. +func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { + if !stateExists(fromState, at) { + return -1 + } + toState, ok := at[fromState][overChar] + if ok == false { + return -1 + } + return toState +} + +// Checks if state exists. Returns true if it does, false otherwise. +func stateExists(state int, at map[int]map[uint8]int) bool { + _, ok := at[state] + if !ok || state == -1 || at[state] == nil { + return false + } + return true +} + +// Just some printing of extra information about what the algorithm does. +func prettyPrint(current int, j int, n int, pos int, t string, oracle map[int]map[uint8]int) { + if current == 0 && !(getTransition(current, t[pos+j-1], oracle) == -1) { + fmt.Printf("\n -->(%d)---(%c)--->(%d)", current, t[pos+j-1], getTransition(current, t[pos+j-1], oracle)) + } else if getTransition(current, t[pos+j-1], oracle) == -1 && current != 0 { + fmt.Printf("\n (%d)---(%c) ", current, t[pos+j-1]) + } else if getTransition(current, t[pos+j-1], oracle) == -1 && current == 0 { + fmt.Printf("\n -->(%d)---(%c) ", current, t[pos+j-1]) + } else { + fmt.Printf("\n (%d)---(%c)--->(%d)", current, t[pos+j-1], getTransition(current, t[pos+j-1], oracle)) + } + fmt.Printf(" ") + for a := 0; a < pos+j-1; a++ { + fmt.Printf("%c", t[a]) + } + if getTransition(current, t[pos+j-1], oracle) == -1 { + fmt.Printf("[%c]", t[pos+j-1]) + } else { + fmt.Printf("[%c]", t[pos+j-1]) + } + for a := pos + j; a < n; a++ { + fmt.Printf("%c", t[a]) + } + if getTransition(current, t[pos+j-1], oracle) == -1 { + fmt.Printf(" FAIL on the character[%c]", t[pos+j-1]) + } +} diff --git a/strings/single string matching/horspool.go b/strings/single string matching/horspool.go new file mode 100644 index 000000000..7d659a5de --- /dev/null +++ b/strings/single string matching/horspool.go @@ -0,0 +1,102 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" +) + +// User defined. +// Set to true to read input from two command line arguments +// Set to false to read input from two files "pattern.txt" and "text.txt" +const commandLineInput bool = false + +// Implementation of Boyer-Moore-Horspool algorithm (Suffix based approach). +// Requires either a two command line arguments separated by a single space, +// or two files in the same folder: "pattern.txt" containing the string to +// be searched for, "text.txt" containing the text to be searched in. +func main() { + if commandLineInput == true { // case of command line input + args := os.Args + if len(args) <= 2 { + log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") + } + pattern := args[1] + s := args[2] + for i := 3; i < len(args); i++ { + s = s + " " + args[i] + } + if len(args[1]) > len(s) { + log.Fatal("Pattern is longer than text!") + } + fmt.Printf("\nRunning: Horspool algorithm.\n\n") + fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) + fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) + horspool(s, pattern) + } else if commandLineInput == false { // case of file line input + patFile, err := ioutil.ReadFile("pattern.txt") + if err != nil { + log.Fatal(err) + } + textFile, err := ioutil.ReadFile("text.txt") + if err != nil { + log.Fatal(err) + } + if len(patFile) > len(textFile) { + log.Fatal("Pattern is longer than text!") + } + fmt.Printf("\nRunning: Horspool algorithm.\n\n") + fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) + fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) + horspool(string(textFile), string(patFile)) + } +} + +// Function horspool performing the Horspool algorithm. +// Prints whether the word/pattern was found and on what position in the text or not. +func horspool(t, p string) { + m, n, c, pos := len(p), len(t), 0, 0 + //Perprocessing + d := preprocess(t, p) + //Map output + fmt.Printf("Precomputed shifts per symbol: ") + for key, value := range d { + fmt.Printf("%c:%d; ", key, value) + } + fmt.Println() + //Searching + for pos <= n-m { + j := m + if t[pos+j-1] != p[j-1] { + fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) + c++ + } + for j > 0 && t[pos+j-1] == p[j-1] { + fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) + c++ + fmt.Printf(" - match") + j-- + } + if j == 0 { + fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", p, pos, t, c) + return + } + pos = pos + d[t[pos+m]] + } + fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", c) + return +} + +// Function that pre-computes map with Key: uint8 (char) Value: int. +// Values determine safe shifting of search window. +func preprocess(t, p string) (d map[uint8]int) { + d = make(map[uint8]int) + for i := 0; i < len(t); i++ { + d[t[i]] = len(p) + } + for i := 0; i < len(p); i++ { + d[p[i]] = len(p) - i + } + return d +} diff --git a/strings/single string matching/kmp.go b/strings/single string matching/kmp.go new file mode 100644 index 000000000..181be53a2 --- /dev/null +++ b/strings/single string matching/kmp.go @@ -0,0 +1,104 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" +) + +// User defined. +// Set to true to read input from two command line arguments +// Set to false to read input from two files "pattern.txt" and "text.txt" +const commandLineInput bool = false + +// Implementation of Knuth-Morris-Pratt algorithm (Prefix based approach). +// Requires either a two command line arguments separated by a single space, +// or two files in the same folder: "pattern.txt" containing the string to +// be searched for, "text.txt" containing the text to be searched in. +func main() { + if commandLineInput == true { // case of command line input + args := os.Args + if len(args) <= 2 { + log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") + } + pattern := args[1] + s := args[2] + for i := 3; i < len(args); i++ { + s = s + " " + args[i] + } + if len(args[1]) > len(s) { + log.Fatal("Pattern is longer than text!") + } + fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") + fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) + fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) + knp(s, pattern) + } else if commandLineInput == false { // case of file input + patFile, err := ioutil.ReadFile("pattern.txt") + if err != nil { + log.Fatal(err) + } + textFile, err := ioutil.ReadFile("text.txt") + if err != nil { + log.Fatal(err) + } + if len(patFile) > len(textFile) { + log.Fatal("Pattern is longer than text!") + } + fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") + fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) + fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) + knp(string(textFile), string(patFile)) + } +} + +// Function knp performing the Knuth-Morris-Pratt algorithm. +// Prints whether the word/pattern was found and on what position in the text or not. +// m - current match in text, i - current character in w, c - amount of comparisons. +func knp(text, word string) { + m, i, c := 0, 0, 0 + t := kmp_table(word) + for m+i < len(text) { + fmt.Printf("\n comparing characters %c %c at positions %d %d", text[m+i], word[i], m+i, i) + c++ + if word[i] == text[m+i] { + fmt.Printf(" - match") + if i == len(word)-1 { + fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word, m, text, c) + return + } + i++ + } else { + m = m + i - t[i] + if t[i] > -1 { + i = t[i] + } else { + i = 0 + } + } + } + fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", c) + return +} + +// Table building alghoritm. +// Takes word to be analyzed and table to be filled. +func kmp_table(word string) (t []int) { + t = make([]int, len(word)) + pos, cnd := 2, 0 + t[0], t[1] = -1, 0 + for pos < len(word) { + if word[pos-1] == word[cnd] { + cnd++ + t[pos] = cnd + pos++ + } else if cnd > 0 { + cnd = t[cnd] + } else { + t[pos] = 0 + pos++ + } + } + return t +} diff --git a/strings/single string matching/pattern.txt b/strings/single string matching/pattern.txt new file mode 100644 index 000000000..487161401 --- /dev/null +++ b/strings/single string matching/pattern.txt @@ -0,0 +1 @@ +announce \ No newline at end of file diff --git a/strings/single string matching/text.txt b/strings/single string matching/text.txt new file mode 100644 index 000000000..e98cf5c73 --- /dev/null +++ b/strings/single string matching/text.txt @@ -0,0 +1 @@ +CPM_annual_conference_announce \ No newline at end of file From 8ee19d2792208bd7312a9df9425067558bbcba04 Mon Sep 17 00:00:00 2001 From: rxaru Date: Wed, 10 Jun 2020 15:03:48 +0900 Subject: [PATCH 034/488] add solution of napsack problem with dp --- dynamic-programming/napsack.go | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 dynamic-programming/napsack.go diff --git a/dynamic-programming/napsack.go b/dynamic-programming/napsack.go new file mode 100644 index 000000000..4810fe978 --- /dev/null +++ b/dynamic-programming/napsack.go @@ -0,0 +1,77 @@ +// napsack Problem +// https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ +package napsack + +// package main + +import ( + "fmt" + "math" +) + +type item struct { + weight int + value int +} + +func max(a, b int) int { + return int(math.Max(float64(a), float64(b))) +} + +// display result of dp data structure +func dist(dp [][]int) { + for i := 0; i < len(dp); i++ { + str := "" + for j := 0; j < len(dp[i]); j++ { + str = str + " " + fmt.Sprintf("%d", dp[i][j]) + } + fmt.Println(str) + } +} + +// solve napsack problem +func solve(maxWeight int, items []item) [][]int { + n := len(items) + 1 + m := maxWeight + 1 + // create dp data structure + dp := make([][]int, n) + for i := range dp { + dp[i] = make([]int, m) + } + for i := 0; i < len(items); i++ { + for j := 0; j <= maxWeight; j++ { + if items[i].weight > j { + dp[i+1][j] = dp[i][j] + } else { + dp[i+1][j] = max(dp[i][j-items[i].weight]+items[i].value, dp[i][j]) + } + } + } + return dp +} + +// convert int slice into item slice +func baseConv(base [][]int) []item { + var items []item + for i := 0; i < len(base); i++ { + var tmp item + tmp.weight = base[i][0] + tmp.value = base[i][1] + items = append(items, tmp) + } + return items +} + +/* +func main() { + maxWeight := 50 + base := [][]int{ + {10, 60}, + {20, 100}, + {30, 120}, + } + items := baseConv(base) + dp := solve(maxWeight, items) + dist(dp) +} +*/ From 4bc5b24b78b12786fb49858f4c49350d2d038df9 Mon Sep 17 00:00:00 2001 From: Brayo Date: Wed, 10 Jun 2020 16:34:05 +0300 Subject: [PATCH 035/488] Create fastExponent.go --- math/fastExponent.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 math/fastExponent.go diff --git a/math/fastExponent.go b/math/fastExponent.go new file mode 100644 index 000000000..57a8d7b71 --- /dev/null +++ b/math/fastExponent.go @@ -0,0 +1,31 @@ +package main + +//based on square and multiply algorithm + +func fastExponentiation(b int, e int)float64{ + //runs in O(log(n)) where n = e + if e == 0{ + return 1.0 + } + if e == 1{ + return float64(b) + } + if e<0{ + e*=-1 + println("executed") + return 1/fastExponentiation(b,e) + } + r:=1 + for ;e>0;{ + if e%2==1{ + r=r*b + } + e =e>>1 + b = b*b + } + return float64(r) +} + +func main(){ + print(fastExponentiation(2,0)) +} \ No newline at end of file From 3535f2c7ec7bf4b2b1424a7fad44f0a751ab509f Mon Sep 17 00:00:00 2001 From: Brayo Date: Wed, 10 Jun 2020 16:34:18 +0300 Subject: [PATCH 036/488] Update NestedBrackets.go --- other/NestedBrackets.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/NestedBrackets.go b/other/NestedBrackets.go index e82f647d9..d3e0b19d9 100644 --- a/other/NestedBrackets.go +++ b/other/NestedBrackets.go @@ -19,7 +19,7 @@ import ( ) func isBalanced(input string) string { - if len(input)%2 == 0{ + if len(input)%2 != 0{ return input + "is not balanced." if len(input) > 0 { var stack []byte From fbf6eb0325a697f236f655f3475706bbd07dfbd6 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 11 Jun 2020 04:35:56 +0000 Subject: [PATCH 037/488] updating DIRECTORY.md --- DIRECTORY.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 5ee4aa9f9..ecff3fa0a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -51,4 +51,12 @@ * [Topological Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/topological_sort.go) ## Strings + * Multiple String Matching + * [Ac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/ac.go) + * [Adac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/adac.go) + * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/sbom.go) * [Naivestringsearch](https://github.com/TheAlgorithms/Go/blob/master/strings/naiveStringSearch.go) + * Single String Matching + * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/bom.go) + * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/horspool.go) + * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/kmp.go) From fba8a5b4e2ed192430563b5d41a2e9c7ee01eb4c Mon Sep 17 00:00:00 2001 From: rajneesh44 Date: Sun, 14 Jun 2020 14:12:30 +0530 Subject: [PATCH 038/488] DP-4 LCS --- .../longestCommonSubsequence.go | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 dynamic-programming/longestCommonSubsequence.go diff --git a/dynamic-programming/longestCommonSubsequence.go b/dynamic-programming/longestCommonSubsequence.go new file mode 100644 index 000000000..cf9ea030d --- /dev/null +++ b/dynamic-programming/longestCommonSubsequence.go @@ -0,0 +1,49 @@ +// LONGEST COMMON SUBSEQUENCE +// DP - 4 +// https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/ + +package longestcommonsubsequence +// package main + +// import "fmt" + +func max(a,b int) int{ + if a>b{ + return a + } + return b +} + +func longestCommonSubsequence(a string, b string, m int, n int) int{ + // m is the length of string a and n is the length of string b + + // here we are making a 2d slice of size (m+1)*(n+1) + lcs:= make([][] int, m+1) + for i:=0;i<=m;i++{ + lcs[i] = make([]int, n+1) + } + + // block that implements LCS + for i:=0;i<=m;i++{ + for j:=0;j<=n;j++{ + if i==0 || j==0{ + lcs[i][j] = 0; + }else if a[i-1] == b[j-1]{ + lcs[i][j] = lcs[i-1][j-1]+1 + }else{ + lcs[i][j] = max(lcs[i-1][j], lcs[i][j-1]) + } + } + } + // returning the length of longest common subsequence + return lcs[m][n] +} + +// func main(){ +// // declaring two strings and asking for input + +// var a,b string +// fmt.Scan(&a, &b) +// // calling the LCS function +// fmt.Println("The length of longest common subsequence is:", longestCommonSubsequence(a,b, len(a), len(b))) +// } From dd65dd3a1dd41f0d402008a63535682d90275d3e Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 14 Jun 2020 08:53:22 +0000 Subject: [PATCH 039/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index ecff3fa0a..ed3592d25 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -23,6 +23,7 @@ ## Dynamic-Programming * [Longest-Palindromic-Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longest-palindromic-subsequence.go) + * [Longestcommonsubsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longestCommonSubsequence.go) * [Matrix-Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/matrix-multiplication.go) * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/rod-cutting.go) From 86842bee8117082496df634ff3fca9f02ca7ed04 Mon Sep 17 00:00:00 2001 From: bakurits Date: Sun, 14 Jun 2020 15:09:13 +0400 Subject: [PATCH 040/488] Made Hashmap exportable --- data-structures/hash-map/hash_map.go | 71 +++++++++++++++------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/data-structures/hash-map/hash_map.go b/data-structures/hash-map/hash_map.go index ab9b0c2b1..f629f59b2 100644 --- a/data-structures/hash-map/hash_map.go +++ b/data-structures/hash-map/hash_map.go @@ -1,4 +1,4 @@ -package data-structures +package hash_map import ( "fmt" @@ -13,20 +13,23 @@ type node struct { next *node } -type hashMap struct { +// HashMap is golang implementation of hashmap +type HashMap struct { capacity uint64 size uint64 table []*node } -func newHashMap() *hashMap { - return &hashMap{ +// New return new HashMap instance +func New() *HashMap { + return &HashMap{ capacity: defaultCapacity, table: make([]*node, defaultCapacity), } } -func (hm *hashMap) get(key interface{}) interface{} { +// Get returns value associated with given key +func (hm *HashMap) Get(key interface{}) interface{} { node := hm.getNodeByHash(hm.hash(key)) if node != nil { @@ -36,11 +39,23 @@ func (hm *hashMap) get(key interface{}) interface{} { return nil } -func (hm *hashMap) put(key interface{}, value interface{}) interface{} { +// Put puts new key value in hashmap +func (hm *HashMap) Put(key interface{}, value interface{}) interface{} { return hm.putValue(hm.hash(key), key, value) } -func (hm *hashMap) putValue(hash uint64, key interface{}, value interface{}) interface{} { +// Contains checks if given key is stored in hashmap +func (hm *HashMap) Contains(key interface{}) bool { + node := hm.getNodeByHash(hm.hash(key)) + + if node != nil { + return true + } + + return false +} + +func (hm *HashMap) putValue(hash uint64, key interface{}, value interface{}) interface{} { if hm.capacity == 0 { hm.capacity = defaultCapacity hm.table = make([]*node, defaultCapacity) @@ -66,21 +81,11 @@ func (hm *hashMap) putValue(hash uint64, key interface{}, value interface{}) int } -func (hm *hashMap) contains(key interface{}) bool { - node := hm.getNodeByHash(hm.hash(key)) - - if node != nil { - return true - } - - return false -} - -func (hm *hashMap) getNodeByHash(hash uint64) *node { +func (hm *HashMap) getNodeByHash(hash uint64) *node { return hm.table[hash] } -func (hm *hashMap) resize() { +func (hm *HashMap) resize() { hm.capacity <<= 1 tempTable := hm.table @@ -112,9 +117,9 @@ func newNodeWithNext(key interface{}, value interface{}, next *node) *node { } } -func (hm *hashMap) hash(key interface{}) uint64 { +func (hm *HashMap) hash(key interface{}) uint64 { h := fnv.New64a() - h.Write([]byte(fmt.Sprintf("%v", key))) + _, _ = h.Write([]byte(fmt.Sprintf("%v", key))) hashValue := h.Sum64() @@ -122,20 +127,20 @@ func (hm *hashMap) hash(key interface{}) uint64 { } // func main() { -// hashMap := newHashMap() +// HashMap := New() -// hashMap.put("test-1", 10) -// fmt.Println(hashMap.get("test-1")) +// HashMap.Put("test-1", 10) +// fmt.Println(HashMap.Get("test-1")) -// hashMap.put("test-1", 20) -// hashMap.put("test-2", 30) -// hashMap.put(1, 40) +// HashMap.Put("test-1", 20) +// HashMap.Put("test-2", 30) +// HashMap.Put(1, 40) -// fmt.Println(hashMap.get("test-1")) -// fmt.Println(hashMap.get("test-2")) -// fmt.Println(hashMap.get(1)) +// fmt.Println(HashMap.Get("test-1")) +// fmt.Println(HashMap.Get("test-2")) +// fmt.Println(HashMap.Get(1)) -// fmt.Println(hashMap.contains(2)) -// fmt.Println(hashMap.contains(1)) -// fmt.Println(hashMap.contains("test-1")) +// fmt.Println(HashMap.Contains(2)) +// fmt.Println(HashMap.Contains(1)) +// fmt.Println(HashMap.Contains("test-1")) // } From 5fcb9e46b7494d833b09a9c0b9b56d7678ff8378 Mon Sep 17 00:00:00 2001 From: bakurits Date: Sun, 14 Jun 2020 15:34:53 +0400 Subject: [PATCH 041/488] added go modules integration --- go.mod | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..4f30be98d --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module TheAlgorithms/Go + +go 1.14 From 0f34f657fd57bdc2078787c70d3cbdb6634879f5 Mon Sep 17 00:00:00 2001 From: bakurits Date: Sun, 14 Jun 2020 15:36:57 +0400 Subject: [PATCH 042/488] move commented code to test file --- data-structures/hash-map/hash_map.go | 21 +---------------- data-structures/hash-map/hash_map_test.go | 28 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 data-structures/hash-map/hash_map_test.go diff --git a/data-structures/hash-map/hash_map.go b/data-structures/hash-map/hash_map.go index f629f59b2..cc3263c8d 100644 --- a/data-structures/hash-map/hash_map.go +++ b/data-structures/hash-map/hash_map.go @@ -1,4 +1,4 @@ -package hash_map +package hashmap import ( "fmt" @@ -125,22 +125,3 @@ func (hm *HashMap) hash(key interface{}) uint64 { return (hm.capacity - 1) & (hashValue ^ (hashValue >> 16)) } - -// func main() { -// HashMap := New() - -// HashMap.Put("test-1", 10) -// fmt.Println(HashMap.Get("test-1")) - -// HashMap.Put("test-1", 20) -// HashMap.Put("test-2", 30) -// HashMap.Put(1, 40) - -// fmt.Println(HashMap.Get("test-1")) -// fmt.Println(HashMap.Get("test-2")) -// fmt.Println(HashMap.Get(1)) - -// fmt.Println(HashMap.Contains(2)) -// fmt.Println(HashMap.Contains(1)) -// fmt.Println(HashMap.Contains("test-1")) -// } diff --git a/data-structures/hash-map/hash_map_test.go b/data-structures/hash-map/hash_map_test.go new file mode 100644 index 000000000..4c3124eee --- /dev/null +++ b/data-structures/hash-map/hash_map_test.go @@ -0,0 +1,28 @@ +package hashmap_test + +import ( + hashmap "TheAlgorithms/Go/data-structures/hash-map" + "fmt" + "testing" +) + +func TestHashMap_Contains(t *testing.T) { + + mp := hashmap.New() + + mp.Put("test-1", 10) + fmt.Println(mp.Get("test-1")) + + mp.Put("test-1", 20) + mp.Put("test-2", 30) + mp.Put(1, 40) + + fmt.Println(mp.Get("test-1")) + fmt.Println(mp.Get("test-2")) + fmt.Println(mp.Get(1)) + + fmt.Println(mp.Contains(2)) + fmt.Println(mp.Contains(1)) + fmt.Println(mp.Contains("test-1")) + +} From 48bb15492908ade2a963554308f0c83d47ee5ec8 Mon Sep 17 00:00:00 2001 From: ioane margiani Date: Sun, 14 Jun 2020 16:33:34 +0400 Subject: [PATCH 043/488] Added implementation of Floyd-Warshall algorithm --- DIRECTORY.md | 3 ++ graphs/floyd_warshall.go | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 graphs/floyd_warshall.go diff --git a/DIRECTORY.md b/DIRECTORY.md index ed3592d25..afde4a818 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -27,6 +27,9 @@ * [Matrix-Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/matrix-multiplication.go) * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/rod-cutting.go) +## Graphs + * [Floyd-Warshall algorithm](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall.go) + ## Other * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxSubarraySum.go) * [Nestedbrackets](https://github.com/TheAlgorithms/Go/blob/master/other/NestedBrackets.go) diff --git a/graphs/floyd_warshall.go b/graphs/floyd_warshall.go new file mode 100644 index 000000000..3bf9a6896 --- /dev/null +++ b/graphs/floyd_warshall.go @@ -0,0 +1,63 @@ +// Floyd-Warshall algorithm +// https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm + +package graph + +import ( + "math" +) + +// Defining matrix to use 2d array easier +type Matrix [][]float64 + +// Defining maximum value. If two vertices share this value, it means they are not connected +var maxValue = math.Inf(1) + +// Returns all pair's shortest path using Floyd Warshall algorithm +func FloydWarshall(graph Matrix) Matrix { + // If graph is empty or width != height, returns nil + if len(graph) == 0 || len(graph) != len(graph[0]) { + return nil + } + + numVertecies := len(graph) + + // Initializing result matrix and filling it up with same values as given graph + result := make(Matrix, numVertecies) + + for i := 0; i < numVertecies; i++ { + result[i] = make([]float64, numVertecies) + for j := 0; j < numVertecies; j++ { + result[i][j] = graph[i][j] + } + } + + // Running over the result matrix and following the algorithm + for k := 0; k < numVertecies; k++ { + for i := 0; i < numVertecies; i++ { + for j := 0; j < numVertecies; j++ { + // If there is a less costly path from i to j node, remembering it + if result[i][j] > result[i][k]+result[k][j] { + result[i][j] = result[i][k] + result[k][j] + } + } + } + } + + return result +} + +// func main() { +// var graph Matrix +// graph = Matrix{{0, maxValue, -2, maxValue}, +// {4, 0, 3, maxValue}, +// {maxValue, maxValue, 0, 2}, +// {maxValue, -1, maxValue, 0}} + +// result := FloydWarshall(graph) + +// // Print result +// for i := 0; i < len(result); i++ { +// fmt.Printf("%4g\n", result[i]) +// } +// } From c25bdc4e8ffebabefee7779f62abb4c82c82b522 Mon Sep 17 00:00:00 2001 From: brayo Date: Sun, 14 Jun 2020 21:36:12 +0300 Subject: [PATCH 044/488] Create RSAcipher(Big).go An alternate implementation of RSA using the math/rand library. Uses 1024 bit encryption --- ciphers/RSAcipher(Big).go | 128 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 ciphers/RSAcipher(Big).go diff --git a/ciphers/RSAcipher(Big).go b/ciphers/RSAcipher(Big).go new file mode 100644 index 000000000..e5a9ab094 --- /dev/null +++ b/ciphers/RSAcipher(Big).go @@ -0,0 +1,128 @@ +package main + +import ( + "math/big" + crypto"crypto/rand" + "strconv" + "fmt" +) +/* +Care has been taken to uses cryptographic secure functions +The primes numbers are 1024 bits which is as secure as u can get really +crypto/rand library has been imported as crypto and not rand +This import style will make it easier to spot all the cryptographic secure functions +*/ +func main(){ + p,_:= crypto.Prime(crypto.Reader,1024) + q,_:= crypto.Prime(crypto.Reader,1024) + if !(primeCheck(p)||primeCheck(q)){ + //they are always prime, no worries + fmt.Println("These numbers ain't prime") + } + n := new(big.Int).Mul(p,q) + + one := big.NewInt(1) + + delta := lcmBig(p.Sub(p,one),q.Sub(q,one)) + + e,_:= crypto.Prime(crypto.Reader,delta.BitLen()) + d := big.NewInt(0) + d.ModInverse(e,delta) + + cleartext := "Black Lives Matter, all lives can't matter until Black lives matter" + runes :=[]rune(cleartext) + ASCIIs :=toASCII(runes) + stringEncoded := stringEncode(ASCIIs) + bigNum, _ := new(big.Int).SetString(stringEncoded,0) + /* + TODO: check that bigNum is not larger than N if larger break + into two or more strings and encrypt separately + */ + fmt.Printf("Message to be encrypted: %v \n",cleartext) + fmt.Printf("ASCII encoded: %v\n",bigNum) + encrypted := encryptBig(bigNum,e,n) + fmt.Printf("ciphertext: %v \n",encrypted) + decrypted := decryptBig(encrypted,d,n) + fmt.Printf("Decrypted but still ASCII encoded: %v \n",decrypted) + decryptASCIIs := stringDecode(decrypted) + fmt.Printf("Plaintext (original message) :%v",toRune(decryptASCIIs)) +} + +func encryptBig(num *big.Int, privateExponent *big.Int, modulus *big.Int)*big.Int{ + //encrypts by modular exponentiation + encrypted := new(big.Int).Exp(num,privateExponent,modulus) + return encrypted +} + +func decryptBig(num *big.Int, publicExponent *big.Int, modulus *big.Int)*big.Int{ + //decrypts by modular exponentiation + decrypted := new(big.Int).Exp(num,publicExponent,modulus) + return decrypted +} + +func lcmBig(x *big.Int, y *big.Int)*big.Int{ + //an lcm implementation for big.Int numbers + gcd := new(big.Int).GCD(nil,nil,x,y) + temp := new(big.Int).Mul(x,y) + lcm := new(big.Int).Div(temp,gcd) + return lcm +} + +func primeCheck(prime *big.Int)bool{ + //primality test + return prime.ProbablyPrime(256) +} + +func toASCII(slice []rune)[]int{ + //runs in O(n) where n = len(slice) + var converted []int + for _,v:= range slice{ + converted = append(converted, int(v)) + } + return converted +} + +func toRune(slice []int)string{ + //runs in O(n) where n = len(slice) + var str string + for _,v:= range slice{ + str += string(v) + } + return str +} + +func stringEncode(slice []int)string{ + //encodes the ASCII to a string + var out []string + for _,v := range slice{ + if v<100 { + out =append(out,"0"+strconv.Itoa(v)) + continue + } + out = append(out, strconv.Itoa(v)) + } + var str string + for _,v := range out{ + str += v + } + /*strips leading 0 if present to avoid conversion errors + */ + if str[0]== '0'{ + str = str[1:] + } + return str +} + +func stringDecode(decryptedBig *big.Int)[]int{ + //decodes the number to string then ASCII values + str := decryptedBig.String() + if len(str)%3!=0{ + str ="0"+str + } + var ASCII []int + for i:=0; i Date: Wed, 17 Jun 2020 04:37:21 +0000 Subject: [PATCH 045/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index ed3592d25..3fbf0af46 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -2,6 +2,7 @@ ## Ciphers * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/CaesarCipher.go) * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) + * [Rsacipher(Big)](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher(Big).go) * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher.go) * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xorCipher.go) From 9634690473b38e19aa230e96b61db31d1131406b Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 11:52:58 +0200 Subject: [PATCH 046/488] golangci-lint.yml: Upgrade go and Actions --- .github/workflows/golangci-lint.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 851c8d40e..537dfa857 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -5,17 +5,17 @@ jobs: golangci-lint: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v1 - with: - go-version: 1.13 - - uses: actions/checkout@v1 - - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0 - - run: | - go version ; ./bin/golangci-lint --version - ./bin/golangci-lint run --no-config || true - - run: ./bin/golangci-lint run --no-config ciphers strings - - run: ./bin/golangci-lint run --no-config data-structures || true - - run: ./bin/golangci-lint run --no-config dynamic-programming || true - - run: ./bin/golangci-lint run --no-config other || true - - run: ./bin/golangci-lint run --no-config searches || true - - run: ./bin/golangci-lint run --no-config sorts + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: 1.14 + - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0 + - run: | + go version ; ./bin/golangci-lint --version + ./bin/golangci-lint run --no-config || true + - run: ./bin/golangci-lint run --no-config ciphers strings + - run: ./bin/golangci-lint run --no-config data-structures || true + - run: ./bin/golangci-lint run --no-config dynamic-programming || true + - run: ./bin/golangci-lint run --no-config other || true + - run: ./bin/golangci-lint run --no-config searches || true + - run: ./bin/golangci-lint run --no-config sorts From 414c246fc2dec71aa4e83774d99b1af349a76f63 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 12:02:57 +0200 Subject: [PATCH 047/488] uses: golangci/golangci-lint-action@v1 --- .github/workflows/golangci-lint.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 537dfa857..e25dd08dc 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -6,16 +6,17 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v1 with: - go-version: 1.14 - - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0 + # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. + version: v1.27 - run: | go version ; ./bin/golangci-lint --version - ./bin/golangci-lint run --no-config || true - - run: ./bin/golangci-lint run --no-config ciphers strings - - run: ./bin/golangci-lint run --no-config data-structures || true - - run: ./bin/golangci-lint run --no-config dynamic-programming || true - - run: ./bin/golangci-lint run --no-config other || true - - run: ./bin/golangci-lint run --no-config searches || true - - run: ./bin/golangci-lint run --no-config sorts + golangci-lint run --no-config || true + - run: golangci-lint run --no-config ciphers strings + - run: golangci-lint run --no-config data-structures || true + - run: golangci-lint run --no-config dynamic-programming || true + - run: golangci-lint run --no-config other || true + - run: golangci-lint run --no-config searches || true + - run: golangci-lint run --no-config sorts From 325b65b171d75501e035afb5244500e14562d67d Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 12:07:09 +0200 Subject: [PATCH 048/488] args: --issues-exit-code=0 --- .github/workflows/golangci-lint.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e25dd08dc..eda969056 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -11,8 +11,9 @@ jobs: with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. version: v1.27 + args: --issues-exit-code=0 # Someday we can remove this... - run: | - go version ; ./bin/golangci-lint --version + go version ; golangci-lint --version golangci-lint run --no-config || true - run: golangci-lint run --no-config ciphers strings - run: golangci-lint run --no-config data-structures || true From c3d04b6e3682b7d490b2daa87ae9c8e9e608675c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 12:19:01 +0200 Subject: [PATCH 049/488] Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index eda969056..3cca2d109 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -14,7 +14,7 @@ jobs: args: --issues-exit-code=0 # Someday we can remove this... - run: | go version ; golangci-lint --version - golangci-lint run --no-config || true + # golangci-lint run --no-config || true - run: golangci-lint run --no-config ciphers strings - run: golangci-lint run --no-config data-structures || true - run: golangci-lint run --no-config dynamic-programming || true From c37c7eac20da3c22df2ae186681915ef7f7a3bde Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 12:27:49 +0200 Subject: [PATCH 050/488] Revert "golangci-lint.yml: Upgrade go and Actions" (#147) --- .github/workflows/golangci-lint.yml | 30 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 3cca2d109..851c8d40e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -5,19 +5,17 @@ jobs: golangci-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v1 - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.27 - args: --issues-exit-code=0 # Someday we can remove this... - - run: | - go version ; golangci-lint --version - # golangci-lint run --no-config || true - - run: golangci-lint run --no-config ciphers strings - - run: golangci-lint run --no-config data-structures || true - - run: golangci-lint run --no-config dynamic-programming || true - - run: golangci-lint run --no-config other || true - - run: golangci-lint run --no-config searches || true - - run: golangci-lint run --no-config sorts + - uses: actions/setup-go@v1 + with: + go-version: 1.13 + - uses: actions/checkout@v1 + - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0 + - run: | + go version ; ./bin/golangci-lint --version + ./bin/golangci-lint run --no-config || true + - run: ./bin/golangci-lint run --no-config ciphers strings + - run: ./bin/golangci-lint run --no-config data-structures || true + - run: ./bin/golangci-lint run --no-config dynamic-programming || true + - run: ./bin/golangci-lint run --no-config other || true + - run: ./bin/golangci-lint run --no-config searches || true + - run: ./bin/golangci-lint run --no-config sorts From ee0b062e92b628a028aad071d04a87c7474a9d9e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 12:30:58 +0200 Subject: [PATCH 051/488] Recreate #146 #146 Do not merge if tests are failing. --- .github/workflows/golangci-lint.yml | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 851c8d40e..3f39d16f6 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -5,17 +5,19 @@ jobs: golangci-lint: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v1 - with: - go-version: 1.13 - - uses: actions/checkout@v1 - - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0 - - run: | - go version ; ./bin/golangci-lint --version - ./bin/golangci-lint run --no-config || true - - run: ./bin/golangci-lint run --no-config ciphers strings - - run: ./bin/golangci-lint run --no-config data-structures || true - - run: ./bin/golangci-lint run --no-config dynamic-programming || true - - run: ./bin/golangci-lint run --no-config other || true - - run: ./bin/golangci-lint run --no-config searches || true - - run: ./bin/golangci-lint run --no-config sorts + - uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v1 + with: + # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. + version: v1.27 + args: --issues-exit-code=0 # Someday we can remove this... + - run: | + go version ; golangci-lint --version + # golangci-lint run --no-config || true + - run: golangci-lint run --no-config ciphers strings + - run: golangci-lint run --no-config data-structures || true + - run: golangci-lint run --no-config dynamic-programming || true + - run: golangci-lint run --no-config other || true + - run: golangci-lint run --no-config searches || true + - run: golangci-lint run --no-config sorts From 0c4309e603851d62ae3848278dbe1db551517c59 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 12:34:32 +0200 Subject: [PATCH 052/488] Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 30 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 3f39d16f6..851c8d40e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -5,19 +5,17 @@ jobs: golangci-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v1 - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.27 - args: --issues-exit-code=0 # Someday we can remove this... - - run: | - go version ; golangci-lint --version - # golangci-lint run --no-config || true - - run: golangci-lint run --no-config ciphers strings - - run: golangci-lint run --no-config data-structures || true - - run: golangci-lint run --no-config dynamic-programming || true - - run: golangci-lint run --no-config other || true - - run: golangci-lint run --no-config searches || true - - run: golangci-lint run --no-config sorts + - uses: actions/setup-go@v1 + with: + go-version: 1.13 + - uses: actions/checkout@v1 + - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0 + - run: | + go version ; ./bin/golangci-lint --version + ./bin/golangci-lint run --no-config || true + - run: ./bin/golangci-lint run --no-config ciphers strings + - run: ./bin/golangci-lint run --no-config data-structures || true + - run: ./bin/golangci-lint run --no-config dynamic-programming || true + - run: ./bin/golangci-lint run --no-config other || true + - run: ./bin/golangci-lint run --no-config searches || true + - run: ./bin/golangci-lint run --no-config sorts From 40fd3d22975b431c4fd4c7b1e46aa852a72100a8 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Jun 2020 13:53:48 +0200 Subject: [PATCH 053/488] Re-recreate #146 (#148) * Re-recreate #146 #146 Do not merge if tests are failing. * working-directory: sorts * Set $PATH * run: set-env PATH= * run: echo ::set-env name=PATH:: * Update golangci-lint.yml * Update golangci-lint.yml * Update golangci-lint.yml * Subdirectories * Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 41 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 851c8d40e..22c5c485d 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -4,18 +4,31 @@ on: [push, pull_request] jobs: golangci-lint: runs-on: ubuntu-latest + strategy: + fail-fast: false steps: - - uses: actions/setup-go@v1 - with: - go-version: 1.13 - - uses: actions/checkout@v1 - - run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0 - - run: | - go version ; ./bin/golangci-lint --version - ./bin/golangci-lint run --no-config || true - - run: ./bin/golangci-lint run --no-config ciphers strings - - run: ./bin/golangci-lint run --no-config data-structures || true - - run: ./bin/golangci-lint run --no-config dynamic-programming || true - - run: ./bin/golangci-lint run --no-config other || true - - run: ./bin/golangci-lint run --no-config searches || true - - run: ./bin/golangci-lint run --no-config sorts + - uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v1 + with: + # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. + version: v1.27 + working-directory: sorts + args: --issues-exit-code=0 # Hopefully someday we can remove this... + # Only show new issues if this is a pull request... + # only-new-issues: true + - run: echo "::set-env name=PATH::/home/runner/golangci-lint-1.27.0-linux-amd64:$PATH" + - run: go version ; golangci-lint --version # Fix the following and remove || true + - run: golangci-lint run --no-config ciphers || true + - run: golangci-lint run --no-config data-structures/binary-tree || true + - run: golangci-lint run --no-config data-structures/dynamic-array || true + - run: golangci-lint run --no-config data-structures/hash-map || true + - run: golangci-lint run --no-config data-structures/linked-list || true + - run: golangci-lint run --no-config data-structures/trie || true + - run: golangci-lint run --no-config dynamic-programming || true + - run: golangci-lint run --no-config other || true + - run: golangci-lint run --no-config searches || true + - run: golangci-lint run --no-config sorts + - run: golangci-lint run --no-config strings + - run: golangci-lint run --no-config "strings/multiple string matching" || true + # - run: golangci-lint run --no-config "strings/single string matching" || true From 33f933f8c0c2086173593a5a48f4908849fd2021 Mon Sep 17 00:00:00 2001 From: Sridhar Shrey Date: Sun, 21 Jun 2020 18:29:02 +0530 Subject: [PATCH 054/488] add search tests --- searches/search_test.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 searches/search_test.go diff --git a/searches/search_test.go b/searches/search_test.go new file mode 100644 index 000000000..91d1125bd --- /dev/null +++ b/searches/search_test.go @@ -0,0 +1,37 @@ +package main + +import "testing" + +type searchTest struct { + data []int + key int + expected int + name string +} + +var searchTests = []searchTest{ + //Sanity + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, + //Absent + {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, + //Empty slice + {[]int{}, 2, -1, "Empty"}, +} + +func TestBinarySearch(t *testing.T) { + for _, test := range searchTests { + actual := binarySearch(test.data, test.key, 0, len(test.data)-1) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} + +func TestLinearSearch(t *testing.T) { + for _, test := range searchTests { + actual := linearSearch(test.data, test.key) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} From 2cb5f1e3dd107b3e58f41a123d84b89b193209b9 Mon Sep 17 00:00:00 2001 From: rxaru Date: Mon, 22 Jun 2020 17:13:54 +0900 Subject: [PATCH 055/488] renamed napsack.go to Knapsack.go, changed using struct to using weight, value slice, changed printing all to printing max profit. --- dynamic-programming/knapsack.go | 49 +++++++++++++++++++++ dynamic-programming/napsack.go | 77 --------------------------------- 2 files changed, 49 insertions(+), 77 deletions(-) create mode 100644 dynamic-programming/knapsack.go delete mode 100644 dynamic-programming/napsack.go diff --git a/dynamic-programming/knapsack.go b/dynamic-programming/knapsack.go new file mode 100644 index 000000000..3a920e5dd --- /dev/null +++ b/dynamic-programming/knapsack.go @@ -0,0 +1,49 @@ +// Knapsack Problem +// https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ +package Knapsack + +// package main + +import ( + "math" +) + +func max(a, b int) int { + return int(math.Max(float64(a), float64(b))) +} + +// solve knapsack problem +// return maxProfit +func solve(maxWeight int, weights, values []int) int { + n := len(weights) + m := maxWeight + // create dp data structure + dp := make([][]int, n+1) + for i := range dp { + dp[i] = make([]int, m+1) + } + for i := 0; i < len(weights); i++ { + for j := 0; j <= maxWeight; j++ { + if weights[i] > j { + dp[i+1][j] = dp[i][j] + } else { + dp[i+1][j] = max(dp[i][j-weights[i]]+values[i], dp[i][j]) + } + } + } + return dp[n][m] +} + +/* +func main() { + maxWeight := 50 + values := []int{ + 60, 100, 120, + } + weights := []int{ + 10, 20, 30, + } + maxProfit := solve(maxWeight, weights, values) + fmt.Println(maxProfit) +} +*/ diff --git a/dynamic-programming/napsack.go b/dynamic-programming/napsack.go deleted file mode 100644 index 4810fe978..000000000 --- a/dynamic-programming/napsack.go +++ /dev/null @@ -1,77 +0,0 @@ -// napsack Problem -// https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ -package napsack - -// package main - -import ( - "fmt" - "math" -) - -type item struct { - weight int - value int -} - -func max(a, b int) int { - return int(math.Max(float64(a), float64(b))) -} - -// display result of dp data structure -func dist(dp [][]int) { - for i := 0; i < len(dp); i++ { - str := "" - for j := 0; j < len(dp[i]); j++ { - str = str + " " + fmt.Sprintf("%d", dp[i][j]) - } - fmt.Println(str) - } -} - -// solve napsack problem -func solve(maxWeight int, items []item) [][]int { - n := len(items) + 1 - m := maxWeight + 1 - // create dp data structure - dp := make([][]int, n) - for i := range dp { - dp[i] = make([]int, m) - } - for i := 0; i < len(items); i++ { - for j := 0; j <= maxWeight; j++ { - if items[i].weight > j { - dp[i+1][j] = dp[i][j] - } else { - dp[i+1][j] = max(dp[i][j-items[i].weight]+items[i].value, dp[i][j]) - } - } - } - return dp -} - -// convert int slice into item slice -func baseConv(base [][]int) []item { - var items []item - for i := 0; i < len(base); i++ { - var tmp item - tmp.weight = base[i][0] - tmp.value = base[i][1] - items = append(items, tmp) - } - return items -} - -/* -func main() { - maxWeight := 50 - base := [][]int{ - {10, 60}, - {20, 100}, - {30, 120}, - } - items := baseConv(base) - dp := solve(maxWeight, items) - dist(dp) -} -*/ From 4c7a731221d601f8ddff00637d03aef17f37cabf Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 22 Jun 2020 12:20:00 +0000 Subject: [PATCH 056/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 3fbf0af46..0aca41fbf 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -23,6 +23,7 @@ * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/trie/trie_test.go) ## Dynamic-Programming + * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/knapsack.go) * [Longest-Palindromic-Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longest-palindromic-subsequence.go) * [Longestcommonsubsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longestCommonSubsequence.go) * [Matrix-Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/matrix-multiplication.go) From 6585799ea86d455d96bd0b9455bdcffb04fb594b Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 22 Jun 2020 12:25:54 +0000 Subject: [PATCH 057/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 0aca41fbf..342da0134 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -40,6 +40,7 @@ ## Searches * [Binary Search](https://github.com/TheAlgorithms/Go/blob/master/searches/binary_search.go) * [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search.go) + * [Search Test](https://github.com/TheAlgorithms/Go/blob/master/searches/search_test.go) ## Sorts * [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubble_sort.go) From c5bb51e9cd0ac1f6ea6650e117bfcc341a0df8a8 Mon Sep 17 00:00:00 2001 From: rxaru Date: Tue, 23 Jun 2020 14:58:00 +0900 Subject: [PATCH 058/488] implemented dfs, bfs --- searches/breadth_first_search.go | 76 +++++++++++++++++++++++++++++++ searches/depth_first_search.go | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 searches/breadth_first_search.go create mode 100644 searches/depth_first_search.go diff --git a/searches/breadth_first_search.go b/searches/breadth_first_search.go new file mode 100644 index 000000000..c4ccbc59f --- /dev/null +++ b/searches/breadth_first_search.go @@ -0,0 +1,76 @@ +package main + +import "fmt" + +// getIdx return target node index +func getIdx(target int, nodes []int) int { + for i := 0; i < len(nodes); i++ { + if nodes[i] == target { + return i + } + } + return -1 +} + +func notExist(target int, slice []int) bool { + for i := 0; i < len(slice); i++ { + if slice[i] == target { + return false + } + } + return true +} + +// bfs return whether start reach end or not. +func bfs(start, end int, nodes []int, edges [][]bool) bool { + var route []int + var queue []int + startIdx := getIdx(start, nodes) + queue = append(queue, startIdx) + for len(queue) > 0 { + now := queue[0] + route = append(route, nodes[now]) + // update queue + if len(queue) > 1 { + queue = queue[1:] + } else { + queue = queue[0:] + } + for i := 0; i < len(edges[now]); i++ { + if edges[now][i] && notExist(i, queue) { + queue = append(queue, i) + } + edges[now][i] = false + edges[i][now] = false + } + if route[len(route)-1] == end { + return true + } + } + return false +} + +func main() { + // show graph as node 1-demensional matrix, edge 2-demensional matrix + nodes := []int{ + 1, 2, 3, 4, 5, 6, + } + /* + sample graph + ①-② + | | + ③-④-⑤-⑥ + */ + edges := [][]bool{ + {false, true, true, false, false, false}, + {true, false, false, true, false, false}, + {true, false, false, true, false, false}, + {false, true, true, false, true, false}, + {false, false, false, true, false, true}, + {false, false, false, false, true, false}, + } + start := 1 + end := 6 + result := bfs(start, end, nodes, edges) + fmt.Println(result) +} diff --git a/searches/depth_first_search.go b/searches/depth_first_search.go new file mode 100644 index 000000000..07eb3364d --- /dev/null +++ b/searches/depth_first_search.go @@ -0,0 +1,77 @@ +package main + +import "fmt" + +// getIdx return target node index +func getIdx(target int, nodes []int) int { + for i := 0; i < len(nodes); i++ { + if nodes[i] == target { + return i + } + } + return -1 +} + +func notExist(target int, slice []int) bool { + for i := 0; i < len(slice); i++ { + if slice[i] == target { + return false + } + } + return true +} + +// dfs return route, whether reach end or not +func dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { + var route []int + var stack []int + startIdx := getIdx(start, nodes) + stack = append(stack, startIdx) + for len(stack) > 0 { + now := stack[len(stack)-1] + route = append(route, nodes[now]) + // update stack + if len(stack) > 1 { + stack = stack[:len(stack)-1] + } else { + stack = stack[:len(stack)-1] + } + for i := 0; i < len(edges[now]); i++ { + // exist edge + if edges[now][i] && notExist(i, stack) { + stack = append(stack, i) + } + edges[now][i] = false + edges[i][now] = false + } + if route[len(route)-1] == end { + return route, true + } + } + return nil, false +} + +func main() { + // show graph as node 1-demensional matrix, edge 2-demensional matrix + nodes := []int{ + 1, 2, 3, 4, 5, 6, + } + /* + sample graph + ①-② + | | + ③-④-⑤-⑥ + */ + edges := [][]bool{ + {false, true, true, false, false, false}, + {true, false, false, true, false, false}, + {true, false, false, true, false, false}, + {false, true, true, false, true, false}, + {false, false, false, true, false, true}, + {false, false, false, false, true, false}, + } + start := 1 + end := 6 + route, _ := dfs(start, end, nodes, edges) + fmt.Println(route) +} From 5ff916acf1914c702d8192bd73ec7bf3a497b5d8 Mon Sep 17 00:00:00 2001 From: rxaru Date: Fri, 26 Jun 2020 15:40:16 +0900 Subject: [PATCH 059/488] removed necessary comments --- searches/breadth_first_search.go | 4 ---- searches/depth_first_search.go | 5 ----- 2 files changed, 9 deletions(-) diff --git a/searches/breadth_first_search.go b/searches/breadth_first_search.go index c4ccbc59f..59d745272 100644 --- a/searches/breadth_first_search.go +++ b/searches/breadth_first_search.go @@ -2,7 +2,6 @@ package main import "fmt" -// getIdx return target node index func getIdx(target int, nodes []int) int { for i := 0; i < len(nodes); i++ { if nodes[i] == target { @@ -21,7 +20,6 @@ func notExist(target int, slice []int) bool { return true } -// bfs return whether start reach end or not. func bfs(start, end int, nodes []int, edges [][]bool) bool { var route []int var queue []int @@ -30,7 +28,6 @@ func bfs(start, end int, nodes []int, edges [][]bool) bool { for len(queue) > 0 { now := queue[0] route = append(route, nodes[now]) - // update queue if len(queue) > 1 { queue = queue[1:] } else { @@ -51,7 +48,6 @@ func bfs(start, end int, nodes []int, edges [][]bool) bool { } func main() { - // show graph as node 1-demensional matrix, edge 2-demensional matrix nodes := []int{ 1, 2, 3, 4, 5, 6, } diff --git a/searches/depth_first_search.go b/searches/depth_first_search.go index 07eb3364d..502ffd724 100644 --- a/searches/depth_first_search.go +++ b/searches/depth_first_search.go @@ -2,7 +2,6 @@ package main import "fmt" -// getIdx return target node index func getIdx(target int, nodes []int) int { for i := 0; i < len(nodes); i++ { if nodes[i] == target { @@ -21,7 +20,6 @@ func notExist(target int, slice []int) bool { return true } -// dfs return route, whether reach end or not func dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { var route []int var stack []int @@ -30,14 +28,12 @@ func dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { for len(stack) > 0 { now := stack[len(stack)-1] route = append(route, nodes[now]) - // update stack if len(stack) > 1 { stack = stack[:len(stack)-1] } else { stack = stack[:len(stack)-1] } for i := 0; i < len(edges[now]); i++ { - // exist edge if edges[now][i] && notExist(i, stack) { stack = append(stack, i) } @@ -52,7 +48,6 @@ func dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { } func main() { - // show graph as node 1-demensional matrix, edge 2-demensional matrix nodes := []int{ 1, 2, 3, 4, 5, 6, } From 51744debde58962d88277a05dde87ee5453c1226 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 26 Jun 2020 09:11:02 +0000 Subject: [PATCH 060/488] updating DIRECTORY.md --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 342da0134..9fab5026b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -39,6 +39,8 @@ ## Searches * [Binary Search](https://github.com/TheAlgorithms/Go/blob/master/searches/binary_search.go) + * [Breadth First Search](https://github.com/TheAlgorithms/Go/blob/master/searches/breadth_first_search.go) + * [Depth First Search](https://github.com/TheAlgorithms/Go/blob/master/searches/depth_first_search.go) * [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search.go) * [Search Test](https://github.com/TheAlgorithms/Go/blob/master/searches/search_test.go) From 6fcebd13c8beb583fcb8a82c3543a43bcd8d0954 Mon Sep 17 00:00:00 2001 From: vinayak Date: Tue, 30 Jun 2020 23:16:53 +0530 Subject: [PATCH 061/488] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c8cd83a83..b81858417 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # The Algorithms - Go +![golangci-lint](https://github.com/TheAlgorithms/Go/workflows/golangci-lint/badge.svg) +![Go](https://github.com/TheAlgorithms/Go/workflows/Go/badge.svg) +![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) + ### Algorithms implemented in Go (for education) These algorithms are for demonstration purposes only. There are many sort implementations in the Go standard library that may have better performance. From 86024c571fb9c685b2a924753bdd9a3951af74d8 Mon Sep 17 00:00:00 2001 From: Brayo Date: Wed, 1 Jul 2020 21:29:58 +0300 Subject: [PATCH 062/488] Standard formatting I ran go fmt for every single go file in the repo. Maybe this can be automated via Github Actions --- ciphers/RSAcipher.go | 157 +++++++++++----------- ciphers/xorCipher.go | 42 +++--- data-structures/linked-list/Linkedlist.go | 24 ++-- math/fastExponent.go | 30 ++--- searches/linear_search.go | 2 +- 5 files changed, 127 insertions(+), 128 deletions(-) diff --git a/ciphers/RSAcipher.go b/ciphers/RSAcipher.go index 62676054d..920978e5f 100644 --- a/ciphers/RSAcipher.go +++ b/ciphers/RSAcipher.go @@ -2,57 +2,58 @@ package main import ( //"math/big" - "math/rand" + "fmt" "math" + "math/rand" "time" - "fmt" ) -func generatePrimes(limit int)int{ + +func generatePrimes(limit int) int { /* - generate primes by factoring - relies on the 30k+i, though better formulae exist - where k >=0 and i = (1,7,11,13,17,13,19,23,29) + generate primes by factoring + relies on the 30k+i, though better formulae exist + where k >=0 and i = (1,7,11,13,17,13,19,23,29) */ - primes:= prime(limit) + primes := prime(limit) var choice []int - choice = append(choice, 1,7,11,13,17,19,23,29) - for{ - k:=rand.Intn(int(limit/30)) - i:=choice[rand.Intn(len(choice))] - c:=30*k+i + choice = append(choice, 1, 7, 11, 13, 17, 19, 23, 29) + for { + k := rand.Intn(int(limit / 30)) + i := choice[rand.Intn(len(choice))] + c := 30*k + i found := true - for _,v:= range primes{ - if c%v==0{ + for _, v := range primes { + if c%v == 0 { found = false break } } - if found{ + if found { return c } } } -func prime(limit int)(primes []int){ - sqrtLimit:=int(math.Ceil(math.Sqrt(float64(limit)))) - exit:= false - primes = append(primes,2,3,5) - lastIndex :=2 - for ;primes[lastIndex]=sqrtLimit{ + if i >= sqrtLimit { exit = true break } @@ -62,113 +63,111 @@ func prime(limit int)(primes []int){ } return } -func lcm (a int, b int)int{ +func lcm(a int, b int) int { //complexity depends on gcd - return int((a*b)/gcd(a,b)) + return int((a * b) / gcd(a, b)) } -func gcd (a int, b int) int{ +func gcd(a int, b int) int { //complexity not clear - for b != 0{ - t:=b + for b != 0 { + t := b b = a % b a = t } return a } -func modularMultiplicativeInverse(e int, delta int)int{ +func modularMultiplicativeInverse(e int, delta int) int { //runs in O(n) where n = delta - e= e % delta - for i:=1;i0;{ - if e%2==1{ - r=(r*b)%mod + for e > 0 { + if e%2 == 1 { + r = (r * b) % mod } - e =e>>1 - b = (b*b)%mod + e = e >> 1 + b = (b * b) % mod } return r } -func encryptRSA(message []int,e int,n int)[]int{ +func encryptRSA(message []int, e int, n int) []int { //runs in O(k*log(n)) where k = len(message) and n = e var ciphertext []int - for _,v := range message{ - ciphertext = append(ciphertext, modularExponentiation(v,e,n)) + for _, v := range message { + ciphertext = append(ciphertext, modularExponentiation(v, e, n)) } return ciphertext } -func decryptRSA(ciphertext []int, d int, n int )[]int{ +func decryptRSA(ciphertext []int, d int, n int) []int { //runs in O(k*log(n)) where k = len(ciphertext) and n = d var message []int - for _,v := range ciphertext { - message = append(message, modularExponentiation(v,d,n)) + for _, v := range ciphertext { + message = append(message, modularExponentiation(v, d, n)) } return message } -func toASCII(slice []rune)[]int{ +func toASCII(slice []rune) []int { //runs in O(n) where n = len(slice) var converted []int - for _,v:= range slice{ + for _, v := range slice { converted = append(converted, int(v)) } return converted } -func toRune(slice []int)string{ +func toRune(slice []int) string { //runs in O(n) where n = len(slice) var str string - for _,v:= range slice{ + for _, v := range slice { str += string(v) } return str } - -func main(){ +func main() { rand.Seed(time.Now().UTC().UnixNano()) - bits:=17 + bits := 17 - p:= generatePrimes(1< nnode` * is this way, nnode2 is before nnode - */ - nnode2 := &node { - v: val, + */ + nnode2 := &node{ + v: val, next: nnode, } /* now head is equals nnode2 */ @@ -62,7 +62,7 @@ func (l *node) popFront() *node { /* create a new node equals to first node pointed by head */ cpnode := new(node) cpnode = head.next - + /* now head is equals cpnode (second node) */ head = cpnode @@ -76,7 +76,7 @@ func (l *node) popBack() *node { /* create a new node equals to head */ cpnode := new(node) cpnode = head - + /* read list to the penultimate node */ for cpnode.next.next != nil { cpnode = cpnode.next @@ -89,14 +89,14 @@ func (l *node) popBack() *node { func main() { lista := new(node) lista.pushBack(25).pushBack(24).pushBack(32) /* lista: 25 24 32 */ - lista.pushBack(56) /* lista: 25 24 32 56 */ - lista.pushFront(36) /* lista: 36 25 24 32 56 */ - lista.popFront() /* lista: 25 24 32 56 */ - lista.popBack() /* lista: 25 24 32 */ - + lista.pushBack(56) /* lista: 25 24 32 56 */ + lista.pushFront(36) /* lista: 36 25 24 32 56 */ + lista.popFront() /* lista: 25 24 32 56 */ + lista.popBack() /* lista: 25 24 32 */ + /* read the list until head is not nil */ for head != nil { - fmt.Printf("%d ",head.v) + fmt.Printf("%d ", head.v) head = head.next /*head points to next node */ } } diff --git a/math/fastExponent.go b/math/fastExponent.go index 57a8d7b71..98b68ca62 100644 --- a/math/fastExponent.go +++ b/math/fastExponent.go @@ -2,30 +2,30 @@ package main //based on square and multiply algorithm -func fastExponentiation(b int, e int)float64{ +func fastExponentiation(b int, e int) float64 { //runs in O(log(n)) where n = e - if e == 0{ + if e == 0 { return 1.0 } - if e == 1{ + if e == 1 { return float64(b) } - if e<0{ - e*=-1 + if e < 0 { + e *= -1 println("executed") - return 1/fastExponentiation(b,e) + return 1 / fastExponentiation(b, e) } - r:=1 - for ;e>0;{ - if e%2==1{ - r=r*b + r := 1 + for e > 0 { + if e%2 == 1 { + r = r * b } - e =e>>1 - b = b*b + e = e >> 1 + b = b * b } return float64(r) } -func main(){ - print(fastExponentiation(2,0)) -} \ No newline at end of file +func main() { + print(fastExponentiation(2, 0)) +} diff --git a/searches/linear_search.go b/searches/linear_search.go index d21e79f06..ef997a874 100644 --- a/searches/linear_search.go +++ b/searches/linear_search.go @@ -12,7 +12,7 @@ func linearSearch(array []int, query int) int { } func main() { - + fmt.Println("Linear search:") array := []int{0, 2, 4, 6, 8, 10, 12, 14, 16, 18} index := linearSearch(array, 10) From 39788aad29192eeb9052b1fe27582691e59f3c8d Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 6 Jul 2020 12:38:55 +0000 Subject: [PATCH 063/488] updating DIRECTORY.md --- DIRECTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 8c35a3c13..21cdb1e54 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -30,7 +30,7 @@ * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/rod-cutting.go) ## Graphs - * [Floyd-Warshall algorithm](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall.go) + * [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall.go) ## Other * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxSubarraySum.go) From e04399c723c5a38b3ee663bbfc8692fc80606f9e Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 6 Jul 2020 14:59:35 +0000 Subject: [PATCH 064/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 21cdb1e54..40028a61a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -49,6 +49,7 @@ ## Sorts * [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubble_sort.go) + * [Counting Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/counting_sort.go) * [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heap_sort.go) * [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertion_sort.go) * [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/merge_sort.go) From 8662301547cb6b66fa1336e70155cd3e348c6889 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 6 Jul 2020 15:08:43 +0000 Subject: [PATCH 065/488] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 40028a61a..702a64604 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -34,6 +34,9 @@ ## Other * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxSubarraySum.go) + * Monte Carlo Pi + * [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi.go) + * [Monte Carlo Pi Test](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi_test.go) * [Nestedbrackets](https://github.com/TheAlgorithms/Go/blob/master/other/NestedBrackets.go) * [Passwordgenerator](https://github.com/TheAlgorithms/Go/blob/master/other/PasswordGenerator.go) * [Prime Numbers](https://github.com/TheAlgorithms/Go/blob/master/other/prime_numbers.go) From 0a4be73e53873f9b9cd892f448c2e4d7469a6555 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 6 Jul 2020 15:21:23 +0000 Subject: [PATCH 066/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 702a64604..3faad33f1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -23,6 +23,7 @@ * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/trie/trie_test.go) ## Dynamic-Programming + * [Binomial-Coeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/binomial-coeffecient.go) * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/knapsack.go) * [Longest-Palindromic-Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longest-palindromic-subsequence.go) * [Longestcommonsubsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longestCommonSubsequence.go) From 7a06c93657f75c0ef29d9c1dc0fa934d865c6e02 Mon Sep 17 00:00:00 2001 From: brayo Date: Sat, 27 Jun 2020 15:52:10 +0300 Subject: [PATCH 067/488] Standard formatted the Repo I manually ran go fmt for each file on the repo,tried writting a python script but it backfire on me. I think you guys should set this to run automatically on Github actions. --- ciphers/RSAcipher(Big).go | 256 +++++++++--------- ciphers/RSAcipher.go | 159 ++++++----- ciphers/diffieHellmanKeyExchange.go | 80 +++--- ciphers/xorCipher.go | 42 +-- .../longestCommonSubsequence.go | 41 +-- searches/binary_search.go | 70 ++--- searches/linear_search.go | 2 +- sorts/bubble_sort.go | 1 - sorts/sorts_case_test.go | 3 +- 9 files changed, 325 insertions(+), 329 deletions(-) diff --git a/ciphers/RSAcipher(Big).go b/ciphers/RSAcipher(Big).go index e5a9ab094..3dfb3446f 100644 --- a/ciphers/RSAcipher(Big).go +++ b/ciphers/RSAcipher(Big).go @@ -1,128 +1,128 @@ -package main - -import ( - "math/big" - crypto"crypto/rand" - "strconv" - "fmt" -) -/* -Care has been taken to uses cryptographic secure functions -The primes numbers are 1024 bits which is as secure as u can get really -crypto/rand library has been imported as crypto and not rand -This import style will make it easier to spot all the cryptographic secure functions -*/ -func main(){ - p,_:= crypto.Prime(crypto.Reader,1024) - q,_:= crypto.Prime(crypto.Reader,1024) - if !(primeCheck(p)||primeCheck(q)){ - //they are always prime, no worries - fmt.Println("These numbers ain't prime") - } - n := new(big.Int).Mul(p,q) - - one := big.NewInt(1) - - delta := lcmBig(p.Sub(p,one),q.Sub(q,one)) - - e,_:= crypto.Prime(crypto.Reader,delta.BitLen()) - d := big.NewInt(0) - d.ModInverse(e,delta) - - cleartext := "Black Lives Matter, all lives can't matter until Black lives matter" - runes :=[]rune(cleartext) - ASCIIs :=toASCII(runes) - stringEncoded := stringEncode(ASCIIs) - bigNum, _ := new(big.Int).SetString(stringEncoded,0) - /* - TODO: check that bigNum is not larger than N if larger break - into two or more strings and encrypt separately - */ - fmt.Printf("Message to be encrypted: %v \n",cleartext) - fmt.Printf("ASCII encoded: %v\n",bigNum) - encrypted := encryptBig(bigNum,e,n) - fmt.Printf("ciphertext: %v \n",encrypted) - decrypted := decryptBig(encrypted,d,n) - fmt.Printf("Decrypted but still ASCII encoded: %v \n",decrypted) - decryptASCIIs := stringDecode(decrypted) - fmt.Printf("Plaintext (original message) :%v",toRune(decryptASCIIs)) -} - -func encryptBig(num *big.Int, privateExponent *big.Int, modulus *big.Int)*big.Int{ - //encrypts by modular exponentiation - encrypted := new(big.Int).Exp(num,privateExponent,modulus) - return encrypted -} - -func decryptBig(num *big.Int, publicExponent *big.Int, modulus *big.Int)*big.Int{ - //decrypts by modular exponentiation - decrypted := new(big.Int).Exp(num,publicExponent,modulus) - return decrypted -} - -func lcmBig(x *big.Int, y *big.Int)*big.Int{ - //an lcm implementation for big.Int numbers - gcd := new(big.Int).GCD(nil,nil,x,y) - temp := new(big.Int).Mul(x,y) - lcm := new(big.Int).Div(temp,gcd) - return lcm -} - -func primeCheck(prime *big.Int)bool{ - //primality test - return prime.ProbablyPrime(256) -} - -func toASCII(slice []rune)[]int{ - //runs in O(n) where n = len(slice) - var converted []int - for _,v:= range slice{ - converted = append(converted, int(v)) - } - return converted -} - -func toRune(slice []int)string{ - //runs in O(n) where n = len(slice) - var str string - for _,v:= range slice{ - str += string(v) - } - return str -} - -func stringEncode(slice []int)string{ - //encodes the ASCII to a string - var out []string - for _,v := range slice{ - if v<100 { - out =append(out,"0"+strconv.Itoa(v)) - continue - } - out = append(out, strconv.Itoa(v)) - } - var str string - for _,v := range out{ - str += v - } - /*strips leading 0 if present to avoid conversion errors - */ - if str[0]== '0'{ - str = str[1:] - } - return str -} - -func stringDecode(decryptedBig *big.Int)[]int{ - //decodes the number to string then ASCII values - str := decryptedBig.String() - if len(str)%3!=0{ - str ="0"+str - } - var ASCII []int - for i:=0; i=0 and i = (1,7,11,13,17,13,19,23,29) + generate primes by factoring + relies on the 30k+i, though better formulae exist + where k >=0 and i = (1,7,11,13,17,13,19,23,29) */ - primes:= prime(limit) + primes := prime(limit) var choice []int - choice = append(choice, 1,7,11,13,17,19,23,29) - for{ - k:=rand.Intn(int(limit/30)) - i:=choice[rand.Intn(len(choice))] - c:=30*k+i + choice = append(choice, 1, 7, 11, 13, 17, 19, 23, 29) + for { + k := rand.Intn(int(limit / 30)) + i := choice[rand.Intn(len(choice))] + c := 30*k + i found := true - for _,v:= range primes{ - if c%v==0{ + for _, v := range primes { + if c%v == 0 { found = false break } } - if found{ + if found { return c } } } -func prime(limit int)(primes []int){ - sqrtLimit:=int(math.Ceil(math.Sqrt(float64(limit)))) - exit:= false - primes = append(primes,2,3,5) - lastIndex :=2 - for ;primes[lastIndex]=sqrtLimit{ + if i >= sqrtLimit { exit = true break } @@ -62,113 +63,111 @@ func prime(limit int)(primes []int){ } return } -func lcm (a int, b int)int{ - //complexity depende - return int((a*b)/gcd(a,b)) +func lcm(a int, b int) int { + //complexity depends on gcd + return int((a * b) / gcd(a, b)) } -func gcd (a int, b int) int{ +func gcd(a int, b int) int { //complexity not clear - for b != 0{ - t:=b + for b != 0 { + t := b b = a % b a = t } return a } -func modularMultiplicativeInverse(e int, delta int)int{ +func modularMultiplicativeInverse(e int, delta int) int { //runs in O(n) where n = delta - e= e % delta - for i:=1;i0;{ - if e%2==1{ - r=(r*b)%mod + for e > 0 { + if e%2 == 1 { + r = (r * b) % mod } - e =e>>1 - b = (b*b)%mod + e = e >> 1 + b = (b * b) % mod } return r } -func encryptRSA(message []int,e int,n int)[]int{ +func encryptRSA(message []int, e int, n int) []int { //runs in O(k*log(n)) where k = len(message) and n = e var ciphertext []int - for _,v := range message{ - ciphertext = append(ciphertext, modularExponentiation(v,e,n)) + for _, v := range message { + ciphertext = append(ciphertext, modularExponentiation(v, e, n)) } return ciphertext } -func decryptRSA(ciphertext []int, d int, n int )[]int{ +func decryptRSA(ciphertext []int, d int, n int) []int { //runs in O(k*log(n)) where k = len(ciphertext) and n = d var message []int - for _,v := range ciphertext { - message = append(message, modularExponentiation(v,d,n)) + for _, v := range ciphertext { + message = append(message, modularExponentiation(v, d, n)) } return message } -func toASCII(slice []rune)[]int{ +func toASCII(slice []rune) []int { //runs in O(n) where n = len(slice) var converted []int - for _,v:= range slice{ + for _, v := range slice { converted = append(converted, int(v)) } return converted } -func toRune(slice []int)string{ +func toRune(slice []int) string { //runs in O(n) where n = len(slice) var str string - for _,v:= range slice{ + for _, v := range slice { str += string(v) } return str } - -func main(){ +func main() { rand.Seed(time.Now().UTC().UnixNano()) - bits:=17 + bits := 17 - p:= generatePrimes(1<0;{ - if e%2==1{ - r=(r*b)%mod + for e > 0 { + if e%2 == 1 { + r = (r * b) % mod } - e =e>>1 - b = (b*b)%mod + e = e >> 1 + b = (b * b) % mod } return r } diff --git a/ciphers/xorCipher.go b/ciphers/xorCipher.go index 58433a710..c280ccd0e 100644 --- a/ciphers/xorCipher.go +++ b/ciphers/xorCipher.go @@ -1,44 +1,44 @@ package main import "fmt" -func encrypt(key int, plaintext []int)(ciphertext []int){ - for _,char:= range plaintext { - ciphertext = append(ciphertext,xor(char,key)) + +func encrypt(key int, plaintext []int) (ciphertext []int) { + for _, char := range plaintext { + ciphertext = append(ciphertext, xor(char, key)) } return } -func xor(char int,key int)int{ - return (char^key) +func xor(char int, key int) int { + return (char ^ key) } -func decrypt(key int, ciphertext []int)(plaintext []int){ - for _,char:= range ciphertext { - plaintext = append(plaintext , xor(char,key)) +func decrypt(key int, ciphertext []int) (plaintext []int) { + for _, char := range ciphertext { + plaintext = append(plaintext, xor(char, key)) } return } -func decodeToString(slice []int)(str string){ - for _,v:= range slice{ - str+=string(v) +func decodeToString(slice []int) (str string) { + for _, v := range slice { + str += string(v) } return } -func toASCII(slice []rune)[]int{ +func toASCII(slice []rune) []int { var converted []int - for _,v:= range slice{ + for _, v := range slice { converted = append(converted, int(v)) } return converted } -func main(){ +func main() { str := "hello world" - key :=97 - temp:= []rune(str) - message:=toASCII(temp) - encrypted:=encrypt(key,message) - decrypted:=decrypt(key,encrypted) - plaintext:=decodeToString(decrypted) + key := 97 + temp := []rune(str) + message := toASCII(temp) + encrypted := encrypt(key, message) + decrypted := decrypt(key, encrypted) + plaintext := decodeToString(decrypted) fmt.Println(plaintext) } - diff --git a/dynamic-programming/longestCommonSubsequence.go b/dynamic-programming/longestCommonSubsequence.go index cf9ea030d..0d09111a8 100644 --- a/dynamic-programming/longestCommonSubsequence.go +++ b/dynamic-programming/longestCommonSubsequence.go @@ -1,36 +1,37 @@ -// LONGEST COMMON SUBSEQUENCE +// LONGEST COMMON SUBSEQUENCE // DP - 4 // https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/ package longestcommonsubsequence -// package main + +// package main // import "fmt" -func max(a,b int) int{ - if a>b{ +func max(a, b int) int { + if a > b { return a } return b } -func longestCommonSubsequence(a string, b string, m int, n int) int{ - // m is the length of string a and n is the length of string b - +func longestCommonSubsequence(a string, b string, m int, n int) int { + // m is the length of string a and n is the length of string b + // here we are making a 2d slice of size (m+1)*(n+1) - lcs:= make([][] int, m+1) - for i:=0;i<=m;i++{ + lcs := make([][]int, m+1) + for i := 0; i <= m; i++ { lcs[i] = make([]int, n+1) } // block that implements LCS - for i:=0;i<=m;i++{ - for j:=0;j<=n;j++{ - if i==0 || j==0{ - lcs[i][j] = 0; - }else if a[i-1] == b[j-1]{ - lcs[i][j] = lcs[i-1][j-1]+1 - }else{ + for i := 0; i <= m; i++ { + for j := 0; j <= n; j++ { + if i == 0 || j == 0 { + lcs[i][j] = 0 + } else if a[i-1] == b[j-1] { + lcs[i][j] = lcs[i-1][j-1] + 1 + } else { lcs[i][j] = max(lcs[i-1][j], lcs[i][j-1]) } } @@ -40,10 +41,10 @@ func longestCommonSubsequence(a string, b string, m int, n int) int{ } // func main(){ -// // declaring two strings and asking for input - -// var a,b string +// // declaring two strings and asking for input + +// var a,b string // fmt.Scan(&a, &b) -// // calling the LCS function +// // calling the LCS function // fmt.Println("The length of longest common subsequence is:", longestCommonSubsequence(a,b, len(a), len(b))) // } diff --git a/searches/binary_search.go b/searches/binary_search.go index 5d485ff9a..4496948a8 100644 --- a/searches/binary_search.go +++ b/searches/binary_search.go @@ -1,35 +1,35 @@ -/* - Binary search implementation in Go -*/ -package main - -func binarySearch(array []int, target int, lowIndex int, highIndex int) int { - if highIndex < lowIndex { - return -1 - } - mid := int(lowIndex + (highIndex-lowIndex)/2) - if array[mid] > target { - return binarySearch(array, target, lowIndex, mid) - } else if array[mid] < target { - return binarySearch(array, target, mid+1, highIndex) - } else { - return mid - } -} - -func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { - startIndex := lowIndex - endIndex := highIndex - var mid int - for startIndex < endIndex { - mid = int(startIndex + (endIndex-startIndex)) - if array[mid] > target { - endIndex = mid - } else if array[mid] < target { - startIndex = mid - } else { - return mid - } - } - return -1 -} +/* + Binary search implementation in Go +*/ +package main + +func binarySearch(array []int, target int, lowIndex int, highIndex int) int { + if highIndex < lowIndex { + return -1 + } + mid := int(lowIndex + (highIndex-lowIndex)/2) + if array[mid] > target { + return binarySearch(array, target, lowIndex, mid) + } else if array[mid] < target { + return binarySearch(array, target, mid+1, highIndex) + } else { + return mid + } +} + +func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { + startIndex := lowIndex + endIndex := highIndex + var mid int + for startIndex < endIndex { + mid = int(startIndex + (endIndex - startIndex)) + if array[mid] > target { + endIndex = mid + } else if array[mid] < target { + startIndex = mid + } else { + return mid + } + } + return -1 +} diff --git a/searches/linear_search.go b/searches/linear_search.go index d21e79f06..ef997a874 100644 --- a/searches/linear_search.go +++ b/searches/linear_search.go @@ -12,7 +12,7 @@ func linearSearch(array []int, query int) int { } func main() { - + fmt.Println("Linear search:") array := []int{0, 2, 4, 6, 8, 10, 12, 14, 16, 18} index := linearSearch(array, 10) diff --git a/sorts/bubble_sort.go b/sorts/bubble_sort.go index 77f73d6a9..52387f0a6 100644 --- a/sorts/bubble_sort.go +++ b/sorts/bubble_sort.go @@ -3,7 +3,6 @@ package sorts func bubbleSort(arrayzor []int) []int { - swapped := true for swapped { swapped = false diff --git a/sorts/sorts_case_test.go b/sorts/sorts_case_test.go index 093abef3a..ef384fccd 100644 --- a/sorts/sorts_case_test.go +++ b/sorts/sorts_case_test.go @@ -15,7 +15,6 @@ type sortTest struct { var arr []int = makeRandArray(500_000) - var sortTests = []sortTest{ //Sorted slice {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, @@ -27,7 +26,7 @@ var sortTests = []sortTest{ {[]int{}, []int{}, "Empty"}, //Single-entry slice {[]int{1}, []int{1}, "Singleton"}, - + //500k values sort {arr, getSortedVersion(arr), "Large Random"}, } From ca23fb25ca1481c3e6235a2c4a7d3b58975cabde Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 6 Jul 2020 17:17:44 +0000 Subject: [PATCH 068/488] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 3faad33f1..cae0ee2cb 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -33,6 +33,9 @@ ## Graphs * [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall.go) +## Math + * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/fastExponent.go) + ## Other * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxSubarraySum.go) * Monte Carlo Pi From fe9bb1beece53f7bac5500563ca458a8e5bae8c9 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 6 Jul 2020 20:18:41 +0000 Subject: [PATCH 069/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index cae0ee2cb..59583ee3d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -68,6 +68,7 @@ * [Topological Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/topological_sort.go) ## Strings + * [Levenshteindistance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteinDistance.go) * Multiple String Matching * [Ac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/ac.go) * [Adac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/adac.go) From bba6aba829769fc034419db5349ffe4c3e99fad2 Mon Sep 17 00:00:00 2001 From: D4rkia Date: Sat, 11 Jul 2020 15:30:48 +0200 Subject: [PATCH 070/488] Add basic string genetic algorithm --- genetic-algorithm/genetic_algo.go | 103 ++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 genetic-algorithm/genetic_algo.go diff --git a/genetic-algorithm/genetic_algo.go b/genetic-algorithm/genetic_algo.go new file mode 100644 index 000000000..d6f8b7cc8 --- /dev/null +++ b/genetic-algorithm/genetic_algo.go @@ -0,0 +1,103 @@ +package main + +import ( + "errors" + "fmt" + "math/rand" + "os" + "sort" + "strconv" + "time" + "unicode/utf8" +) + +type populationItem struct { + Key string + Value float64 +} + +func main() { + // Define a random seed + rand.Seed(time.Now().UnixNano()) + + // Define parameters + sentence := string("This is a genetic algorithm to evaluate, combine, evolve mutate a string!") + charmap := []rune(" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,;!?+-*#@^'èéòà€ù=)(&%$£/\\") + populationNum := 200 + selectionNum := 50 + mutationProb := .1 + + // Verify the presence of all char in sentence + for position, r := range []rune(sentence) { + find := func() bool { + for _, n := range charmap { + if n == r { + return true + } + } + return false + } + if !find() { + fmt.Println(errors.New("Character not aviable in charmap"), position, "\"", string(r), "\"") + os.Exit(1) + } + } + + // Generate random population + pop := make([]populationItem, populationNum, populationNum) + for i := 0; i < populationNum; i++ { + key := "" + for x := 0; x < utf8.RuneCountInString(sentence); x++ { + choice := rand.Intn(len(charmap)) + key += string(charmap[choice]) + } + pop[i] = populationItem{key, 0} + } + + for gen, generatedPop := 1, 0; ; gen++ { + generatedPop += len(pop) + + // Random population created now it's time to evaluate + for i, item := range pop { + itemKey, sentenceRune := []rune(item.Key), []rune(sentence) + for x := 0; x < len(sentence); x++ { + if itemKey[x] == sentenceRune[x] { + pop[i].Value++ + } + } + pop[i].Value = pop[i].Value / float64(len(sentenceRune)) + } + // Check if there is a right evolution + sort.SliceStable(pop, func(i, j int) bool { return pop[i].Value > pop[j].Value }) + if pop[0].Key == sentence { + fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", pop[0]) + break + } + // Print the best result + if gen%1000 == 0 { + fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", pop[0]) + } + // Combine, Evolve and Mutate + var popChildren []populationItem + for i := 0; i < int(selectionNum); i++ { + parent1 := pop[i] + parent2 := pop[i+1] + split := rand.Intn(utf8.RuneCountInString(sentence)) + + // Save Children 1 + child := append([]rune(parent1.Key)[:split], []rune(parent2.Key)[split:]...) + if rand.Float64() > mutationProb { + child[rand.Intn(len(child))] = charmap[rand.Intn(len(charmap))] + } + popChildren = append(popChildren, populationItem{string(child), 0}) + + // Save Children 2 + child = append([]rune(parent2.Key)[:split], []rune(parent1.Key)[split:]...) + if rand.Float64() > mutationProb { + child[rand.Intn(len(child))] = charmap[rand.Intn(len(charmap))] + } + popChildren = append(popChildren, populationItem{string(child), 0}) + } + pop = popChildren + } +} From af323c9d0b4d2b6b1c708809f9862f5ee9ba5dda Mon Sep 17 00:00:00 2001 From: D4rkia <49065066+D4rkia@users.noreply.github.com> Date: Sat, 11 Jul 2020 17:14:47 +0200 Subject: [PATCH 071/488] Improve comments --- genetic-algorithm/genetic_algo.go | 124 +++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 35 deletions(-) diff --git a/genetic-algorithm/genetic_algo.go b/genetic-algorithm/genetic_algo.go index d6f8b7cc8..7120c1823 100644 --- a/genetic-algorithm/genetic_algo.go +++ b/genetic-algorithm/genetic_algo.go @@ -1,3 +1,14 @@ +/* +Simple multithreaded algorithm to show how the 4 phases of a genetic +algorithm works (Evaluation, Selection, Crossover and Mutation) +https://en.wikipedia.org/wiki/Genetic_algorithm + +Link to the same algorithm implemented in python: +https://github.com/TheAlgorithms/Python/blob/master/genetic_algorithm/basic_string.py + +Author: D4rkia +*/ + package main import ( @@ -16,19 +27,26 @@ type populationItem struct { Value float64 } -func main() { - // Define a random seed - rand.Seed(time.Now().UnixNano()) - +func genetic_string(target string, charmap []rune) (int, int, string) { // Define parameters - sentence := string("This is a genetic algorithm to evaluate, combine, evolve mutate a string!") - charmap := []rune(" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,;!?+-*#@^'èéòà€ù=)(&%$£/\\") + // Maximum size of the population. bigger could be faster but is more memory expensive populationNum := 200 + // Number of elements selected in every generation for evolution the selection takes + // place from the best to the worst of that generation must be smaller than N_POPULATION selectionNum := 50 - mutationProb := .1 + // Probability that an element of a generation can mutate changing one of its genes this + // guarantees that all genes will be used during evolution + mutationProb := .4 + // Just a seed to improve randomness required by the algorithm + rand.Seed(time.Now().UnixNano()) - // Verify the presence of all char in sentence - for position, r := range []rune(sentence) { + // Verify if 'populationNum' s bigger than 'selectionNum' + if populationNum < selectionNum { + fmt.Println(errors.New("PopulationNum must be bigger tha selectionNum ")) + os.Exit(1) + } + // Verify that the target contains no genes besides the ones inside genes variable. + for position, r := range []rune(target) { find := func() bool { for _, n := range charmap { if n == r { @@ -43,61 +61,97 @@ func main() { } } - // Generate random population + // Generate random starting population pop := make([]populationItem, populationNum, populationNum) for i := 0; i < populationNum; i++ { key := "" - for x := 0; x < utf8.RuneCountInString(sentence); x++ { + for x := 0; x < utf8.RuneCountInString(target); x++ { choice := rand.Intn(len(charmap)) key += string(charmap[choice]) } pop[i] = populationItem{key, 0} } - for gen, generatedPop := 1, 0; ; gen++ { + // Just some logs to know what the algorithms is doing + gen, generatedPop := 0, 0 + + // This loop will end when we will find a perfect match for our target + for { + gen += 1 generatedPop += len(pop) // Random population created now it's time to evaluate for i, item := range pop { - itemKey, sentenceRune := []rune(item.Key), []rune(sentence) - for x := 0; x < len(sentence); x++ { - if itemKey[x] == sentenceRune[x] { + pop[i].Value = 0 + itemKey, targetRune := []rune(item.Key), []rune(target) + for x := 0; x < len(target); x++ { + if itemKey[x] == targetRune[x] { pop[i].Value++ } } - pop[i].Value = pop[i].Value / float64(len(sentenceRune)) + pop[i].Value = pop[i].Value / float64(len(targetRune)) } - // Check if there is a right evolution sort.SliceStable(pop, func(i, j int) bool { return pop[i].Value > pop[j].Value }) - if pop[0].Key == sentence { - fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", pop[0]) + + // Check if there is a matching evolution + if pop[0].Key == target { break } - // Print the best result - if gen%1000 == 0 { + // Print the best resultPrint the Best result every 10 generations + // just to know that the algorithm is working + if gen%10 == 0 { fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", pop[0]) } - // Combine, Evolve and Mutate + + // Generate a new population vector keeping some of the best evolutions + // Keeping this avoid regression of evolution var popChildren []populationItem + popChildren = append(popChildren, pop[0:int(selectionNum/3)]...) + + // This is Selection for i := 0; i < int(selectionNum); i++ { parent1 := pop[i] - parent2 := pop[i+1] - split := rand.Intn(utf8.RuneCountInString(sentence)) - - // Save Children 1 - child := append([]rune(parent1.Key)[:split], []rune(parent2.Key)[split:]...) - if rand.Float64() > mutationProb { - child[rand.Intn(len(child))] = charmap[rand.Intn(len(charmap))] + // Generate more child proportionally to the fitness score + child_n := (parent1.Value * 100) + 1 + if child_n >= 10 { + child_n = 10 } - popChildren = append(popChildren, populationItem{string(child), 0}) + for x := 0.0; x < child_n; x++ { + parent2 := pop[rand.Intn(selectionNum)] + // Crossover + split := rand.Intn(utf8.RuneCountInString(target)) + child1 := append([]rune(parent1.Key)[:split], []rune(parent2.Key)[split:]...) + child2 := append([]rune(parent2.Key)[:split], []rune(parent1.Key)[split:]...) + //Clean fitness value + // Mutate + if rand.Float64() < mutationProb { + child1[rand.Intn(len(child1))] = charmap[rand.Intn(len(charmap))] + } + if rand.Float64() < mutationProb { + child2[rand.Intn(len(child2))] = charmap[rand.Intn(len(charmap))] + } + // Push into 'popChildren' + popChildren = append(popChildren, populationItem{string(child1), 0}) + popChildren = append(popChildren, populationItem{string(child2), 0}) - // Save Children 2 - child = append([]rune(parent2.Key)[:split], []rune(parent1.Key)[split:]...) - if rand.Float64() > mutationProb { - child[rand.Intn(len(child))] = charmap[rand.Intn(len(charmap))] + // Check if the population has already reached the maximum value and if so, + // break the cycle. If this check is disabled the algorithm will take + // forever to compute large strings but will also calculate small string in + // a lot fewer generationsù + if len(popChildren) >= selectionNum { + break + } } - popChildren = append(popChildren, populationItem{string(child), 0}) } pop = popChildren } + return gen, generatedPop, pop[0].Key +} + +func main() { + // Define parameters + target := string("This is a genetic algorithm to evaluate, combine, evolve and mutate a string!") + charmap := []rune(" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,;!?+-*#@^'èéòà€ù=)(&%$£/\\") + gen, generatedPop, best := genetic_string(target, charmap) + fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", best) } From 2059c601b21e60b5aa04882fb64849bfc40921c6 Mon Sep 17 00:00:00 2001 From: brayo Date: Sat, 11 Jul 2020 20:45:15 +0300 Subject: [PATCH 072/488] whoa mind in awe --- graphs/floyd_warshall.go | 27 ++++++++--------- other/monte_carlo_pi/monte_carlo_pi.go | 40 -------------------------- 2 files changed, 14 insertions(+), 53 deletions(-) delete mode 100644 other/monte_carlo_pi/monte_carlo_pi.go diff --git a/graphs/floyd_warshall.go b/graphs/floyd_warshall.go index 3bf9a6896..75303eeca 100644 --- a/graphs/floyd_warshall.go +++ b/graphs/floyd_warshall.go @@ -1,10 +1,11 @@ // Floyd-Warshall algorithm // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm -package graph +package main import ( "math" + "fmt" ) // Defining matrix to use 2d array easier @@ -47,17 +48,17 @@ func FloydWarshall(graph Matrix) Matrix { return result } -// func main() { -// var graph Matrix -// graph = Matrix{{0, maxValue, -2, maxValue}, -// {4, 0, 3, maxValue}, -// {maxValue, maxValue, 0, 2}, -// {maxValue, -1, maxValue, 0}} +func main() { + var graph Matrix + graph = Matrix{{0, maxValue, -2, maxValue}, + {4, 0, 3, maxValue}, + {maxValue, maxValue, 0, 2}, + {maxValue, -1, maxValue, 0}} -// result := FloydWarshall(graph) + result := FloydWarshall(graph) -// // Print result -// for i := 0; i < len(result); i++ { -// fmt.Printf("%4g\n", result[i]) -// } -// } + //Print result + for i := 0; i < len(result); i++ { + fmt.Printf("%4g\n", result[i]) + } + } diff --git a/other/monte_carlo_pi/monte_carlo_pi.go b/other/monte_carlo_pi/monte_carlo_pi.go deleted file mode 100644 index 0f5438d50..000000000 --- a/other/monte_carlo_pi/monte_carlo_pi.go +++ /dev/null @@ -1,40 +0,0 @@ -// Monte Carlo Pi -// [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method) to calculate Pi -// -// The basic idea of Monte Carlo is: -// 1. Define a domain of possible inputs -// 2. Generate inputs randomly from a probability distribution over the domain -// 3. Perform a deterministic computation on the inputs -// 4. Aggregate the results -// -// Thus the algorithm to calculate Pi is: -// -// 1. Given a circle inscribed in a square with side length 1. -// 2. randomly draw n points (x, y) | x,y in [0.0,1.0) -// 3. Count the amount of points inside the circle -// 4. pi = 4 * (points inside the circle) / n -// -// A point (x, y) is inside the circle if: -// -// x*x + y*y <= 1 -// - -package main - -import ( - "math" - "math/rand" -) - -// MonteCarloPi calculates Pi using the Monte Carlo method -func MonteCarloPi(iterations uint) float64 { - var inside, total uint - - for total = uint(0); total < iterations; total++ { - if in := math.Hypot(rand.Float64(), rand.Float64()) <= 1; in { - inside++ - } - } - - return float64(4) * (float64(inside) / float64(total)) -} From 6d09e8353e560dddfe1ceee62a376a43fc2b2700 Mon Sep 17 00:00:00 2001 From: D4rkia Date: Mon, 13 Jul 2020 13:26:42 +0200 Subject: [PATCH 073/488] Fix golint --- genetic-algorithm/genetic_algo.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/genetic-algorithm/genetic_algo.go b/genetic-algorithm/genetic_algo.go index 7120c1823..a4648dcbd 100644 --- a/genetic-algorithm/genetic_algo.go +++ b/genetic-algorithm/genetic_algo.go @@ -27,7 +27,7 @@ type populationItem struct { Value float64 } -func genetic_string(target string, charmap []rune) (int, int, string) { +func geneticString(target string, charmap []rune) (int, int, string) { // Define parameters // Maximum size of the population. bigger could be faster but is more memory expensive populationNum := 200 @@ -77,7 +77,7 @@ func genetic_string(target string, charmap []rune) (int, int, string) { // This loop will end when we will find a perfect match for our target for { - gen += 1 + gen++ generatedPop += len(pop) // Random population created now it's time to evaluate @@ -112,11 +112,11 @@ func genetic_string(target string, charmap []rune) (int, int, string) { for i := 0; i < int(selectionNum); i++ { parent1 := pop[i] // Generate more child proportionally to the fitness score - child_n := (parent1.Value * 100) + 1 - if child_n >= 10 { - child_n = 10 + nChild := (parent1.Value * 100) + 1 + if nChild >= 10 { + nChild = 10 } - for x := 0.0; x < child_n; x++ { + for x := 0.0; x < nChild; x++ { parent2 := pop[rand.Intn(selectionNum)] // Crossover split := rand.Intn(utf8.RuneCountInString(target)) @@ -152,6 +152,6 @@ func main() { // Define parameters target := string("This is a genetic algorithm to evaluate, combine, evolve and mutate a string!") charmap := []rune(" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,;!?+-*#@^'èéòà€ù=)(&%$£/\\") - gen, generatedPop, best := genetic_string(target, charmap) + gen, generatedPop, best := geneticString(target, charmap) fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", best) } From f1bd08bd7487d70b545b9c6dd990359652f5d17e Mon Sep 17 00:00:00 2001 From: yicheng wang Date: Wed, 22 Jul 2020 16:37:38 +0800 Subject: [PATCH 074/488] chore: delete git lines --- ciphers/diffieHellmanKeyExchange.go | 40 ++++++++++++----------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/ciphers/diffieHellmanKeyExchange.go b/ciphers/diffieHellmanKeyExchange.go index be255f19a..d3a985ec9 100644 --- a/ciphers/diffieHellmanKeyExchange.go +++ b/ciphers/diffieHellmanKeyExchange.go @@ -12,7 +12,6 @@ func main() { that can be communicated over an insecure channel p should ideally be a large prime number but any integer works g should be a small integer, 2,3 works fine - PS: Note that the secret keys are never send over the network */ @@ -24,40 +23,33 @@ func main() { AliceSecret := 1 + rand.Intn(1<>1 - b = (b*b)%mod + e = e >> 1 + b = (b * b) % mod } return r } From 2765275b1687bda84aaaa5d4c7072b48c7814ac2 Mon Sep 17 00:00:00 2001 From: brayo Date: Thu, 30 Jul 2020 00:42:02 +0300 Subject: [PATCH 075/488] Create Rot13 and minor updates --- ciphers/RSAcipher.go | 12 +++---- ciphers/Rot13.go | 34 ++++++++++++++++++ ciphers/diffieHellmanKeyExchange.go | 39 +++++++++----------- ciphers/xorCipher.go | 12 +++---- math/Sieve.go | 50 ++++++++++++++++++++++++++ other/PrimeNumbers.go | 3 +- other/maxSubarraySum.go | 22 ++++++------ other/monte_carlo_pi/monte_carlo_pi.go | 50 ++++++++++++++++++++++++++ other/prime_numbers.go | 3 +- searches/binary_search.go | 6 ---- searches/breadth_first_search.go | 4 +-- 11 files changed, 177 insertions(+), 58 deletions(-) create mode 100644 ciphers/Rot13.go create mode 100644 math/Sieve.go create mode 100644 other/monte_carlo_pi/monte_carlo_pi.go diff --git a/ciphers/RSAcipher.go b/ciphers/RSAcipher.go index 920978e5f..e458a8c7c 100644 --- a/ciphers/RSAcipher.go +++ b/ciphers/RSAcipher.go @@ -63,12 +63,12 @@ func prime(limit int) (primes []int) { } return } -func lcm(a int, b int) int { +func lcm(a, b int) int { //complexity depends on gcd return int((a * b) / gcd(a, b)) } -func gcd(a int, b int) int { +func gcd(a, b int) int { //complexity not clear for b != 0 { t := b @@ -77,7 +77,7 @@ func gcd(a int, b int) int { } return a } -func modularMultiplicativeInverse(e int, delta int) int { +func modularMultiplicativeInverse(e, delta int) int { //runs in O(n) where n = delta e = e % delta for i := 1; i < delta; i++ { @@ -88,7 +88,7 @@ func modularMultiplicativeInverse(e int, delta int) int { return 0 } -func modularExponentiation(b int, e int, mod int) int { +func modularExponentiation(b, e, mod int) int { //runs in O(log(n)) where n = e if mod == 1 { return 0 @@ -105,7 +105,7 @@ func modularExponentiation(b int, e int, mod int) int { return r } -func encryptRSA(message []int, e int, n int) []int { +func encryptRSA(message []int, e, n int) []int { //runs in O(k*log(n)) where k = len(message) and n = e var ciphertext []int for _, v := range message { @@ -113,7 +113,7 @@ func encryptRSA(message []int, e int, n int) []int { } return ciphertext } -func decryptRSA(ciphertext []int, d int, n int) []int { +func decryptRSA(ciphertext []int, d, n int) []int { //runs in O(k*log(n)) where k = len(ciphertext) and n = d var message []int for _, v := range ciphertext { diff --git a/ciphers/Rot13.go b/ciphers/Rot13.go new file mode 100644 index 000000000..adc29cb38 --- /dev/null +++ b/ciphers/Rot13.go @@ -0,0 +1,34 @@ +package main + +import ( + "bytes" + "fmt" + "strings" +) + +func rot13(input string) string { + var outputBuffer bytes.Buffer + for _, r := range strings.ToLower(input) { + newByte := int(r) + + if newByte >= 'a' && newByte <= 'z' { + newByte += 13 + + if newByte > 'z' { + newByte -= 26 + } else if newByte < 'a' { + newByte += 26 + } + } + + outputBuffer.WriteString(string(newByte)) + } + return outputBuffer.String() + +} +func main() { + cleartext := "We'll just make him an offer he can't refuse... tell me you get the pop culture reference" + encrypted := rot13(cleartext) + decrypted := rot13(encrypted) + fmt.Printf("Cleartext: %v\nencrypted: %v\ndecrypted: %v\n", cleartext, encrypted, decrypted) +} diff --git a/ciphers/diffieHellmanKeyExchange.go b/ciphers/diffieHellmanKeyExchange.go index be255f19a..d2a08a12d 100644 --- a/ciphers/diffieHellmanKeyExchange.go +++ b/ciphers/diffieHellmanKeyExchange.go @@ -24,40 +24,33 @@ func main() { AliceSecret := 1 + rand.Intn(1<>1 - b = (b*b)%mod + e = e >> 1 + b = (b * b) % mod } return r } diff --git a/ciphers/xorCipher.go b/ciphers/xorCipher.go index 4206f0a14..c280ccd0e 100644 --- a/ciphers/xorCipher.go +++ b/ciphers/xorCipher.go @@ -34,11 +34,11 @@ func toASCII(slice []rune) []int { } func main() { str := "hello world" - key :=97 - temp:= []rune(str) - message:=toASCII(temp) - encrypted:=encrypt(key,message) - decrypted:=decrypt(key,encrypted) - plaintext:=decodeToString(decrypted) + key := 97 + temp := []rune(str) + message := toASCII(temp) + encrypted := encrypt(key, message) + decrypted := decrypt(key, encrypted) + plaintext := decodeToString(decrypted) fmt.Println(plaintext) } diff --git a/math/Sieve.go b/math/Sieve.go new file mode 100644 index 000000000..80a81cf13 --- /dev/null +++ b/math/Sieve.go @@ -0,0 +1,50 @@ +package main + +import ( + _ "fmt" +) + +func main() { + var l, f int + l = 100 + channel := make(chan int, l) + channelTwo := make(chan int, l) + var nums []bool + + for i := 0; i < l; i++ { + nums = append(nums, true) + } + f = 2 + + go crossOff(channel, channelTwo, f, l) + go nextF(f, channelTwo, nums) + //blocks and sieves out non-primes + for { + select { + case index := <-channel: + nums[index-1] = false + } + } +} +func crossOff(c chan int, r chan int, f int, l int) { + for f != -1 { + for f <= l { + c <- f + f += f + } + f = <-r + r <- 1 + } + +} + +func nextF(f int, r chan int, nums []bool) { + for { + <-r + for i, v := range nums[f:] { + if v == true { + r <- i + f + } + } + } +} diff --git a/other/PrimeNumbers.go b/other/PrimeNumbers.go index 4fb7364c7..fa2fc81a2 100644 --- a/other/PrimeNumbers.go +++ b/other/PrimeNumbers.go @@ -2,10 +2,10 @@ package main import ( "fmt" + "github.com/douglasmakey/golang-algorithms-/utils" "math" "os" "strconv" - "github.com/douglasmakey/golang-algorithms-/utils" "time" ) @@ -32,7 +32,6 @@ func isPrime(n int64) bool { return false } - limit = int64(math.Ceil(math.Sqrt(float64(n)))) for i = 3; i <= limit; i += 2 { if math.Mod(float64(n), float64(i)) == 0 { diff --git a/other/maxSubarraySum.go b/other/maxSubarraySum.go index f5592f0bf..78e1b8db3 100644 --- a/other/maxSubarraySum.go +++ b/other/maxSubarraySum.go @@ -1,4 +1,4 @@ -/* O(n) solution, for calculating +/* O(n) solution, for calculating maximum contiguous sum in the given array. */ package main @@ -8,23 +8,23 @@ import ( ) func Max(x int, y int) int { - if x < y { - return y - } - return x + if x < y { + return y + } + return x } func maxSubarraySum(array []int) int { - var currentMax int = 0 - var maxTillNow int = 0 - for _,v :=range array{ - currentMax = Max(v, currentMax + v) - maxTillNow = Max(maxTillNow, currentMax) + var currentMax int = 0 + var maxTillNow int = 0 + for _, v := range array { + currentMax = Max(v, currentMax+v) + maxTillNow = Max(maxTillNow, currentMax) } return maxTillNow } func main() { array := []int{-2, -5, 6, 0, -2, 0, -3, 1, 0, 5, -6} - fmt.Println("Maximum contiguous sum: ", maxSubarraySum(array)) + fmt.Println("Maximum contiguous sum: ", maxSubarraySum(array)) } diff --git a/other/monte_carlo_pi/monte_carlo_pi.go b/other/monte_carlo_pi/monte_carlo_pi.go new file mode 100644 index 000000000..d427dfe1f --- /dev/null +++ b/other/monte_carlo_pi/monte_carlo_pi.go @@ -0,0 +1,50 @@ +package main + +import ( + "fmt" + "math" + "math/rand" + "runtime" + "sync" + "time" +) + +func main() { + cpus := runtime.NumCPU() + monteCarlo := func(iterations, cpus int) float64{ + start := time.Now() + flow := make(chan int, int(math.Floor(float64(cpus)/2))) + var wg sync.WaitGroup + var total int + miniFunc := func(iters int, flow chan int) { + defer wg.Done() + var inside int + for i := 0; i < iters; i++ { + x := rand.Float64() + y := rand.Float64() + if math.Hypot(x, y) <= 1 { + inside++ + } + } + flow <- inside + } //end of minifunc + fuxc := func(flow chan int) { + defer wg.Done() + for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { + total += <-flow + } + } //end of fuxc + wg.Add(int(math.Floor(float64(cpus) / 2))) + //spawn goroutines for half the logical processors + // This leaves free cpus for swapping + for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { + go miniFunc(int(math.Ceil(float64(iterations/int(math.Floor(float64(cpus)/2))))), flow) + } + wg.Add(1) + go fuxc(flow) + wg.Wait() + fmt.Printf("took %v \n",time.Since(start)) + return 4 * float64(total) / float64(iterations) + }//end of monteCarlo + fmt.Println(monteCarlo(2<<18, cpus)) +} diff --git a/other/prime_numbers.go b/other/prime_numbers.go index 4fb7364c7..fa2fc81a2 100644 --- a/other/prime_numbers.go +++ b/other/prime_numbers.go @@ -2,10 +2,10 @@ package main import ( "fmt" + "github.com/douglasmakey/golang-algorithms-/utils" "math" "os" "strconv" - "github.com/douglasmakey/golang-algorithms-/utils" "time" ) @@ -32,7 +32,6 @@ func isPrime(n int64) bool { return false } - limit = int64(math.Ceil(math.Sqrt(float64(n)))) for i = 3; i <= limit; i += 2 { if math.Mod(float64(n), float64(i)) == 0 { diff --git a/searches/binary_search.go b/searches/binary_search.go index 46c32bd6c..d37b70955 100644 --- a/searches/binary_search.go +++ b/searches/binary_search.go @@ -1,7 +1,3 @@ -<<<<<<< HEAD -/* - Binary search implementation in Go -*/ package main func binarySearch(array []int, target int, lowIndex int, highIndex int) int { @@ -34,5 +30,3 @@ func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int } return -1 } -======= ->>>>>>> master diff --git a/searches/breadth_first_search.go b/searches/breadth_first_search.go index 59d745272..b67c61a06 100644 --- a/searches/breadth_first_search.go +++ b/searches/breadth_first_search.go @@ -20,7 +20,7 @@ func notExist(target int, slice []int) bool { return true } -func bfs(start, end int, nodes []int, edges [][]bool) bool { +func breadthFirstSearch(start, end int, nodes []int, edges [][]bool) bool { var route []int var queue []int startIdx := getIdx(start, nodes) @@ -67,6 +67,6 @@ func main() { } start := 1 end := 6 - result := bfs(start, end, nodes, edges) + result := breadthFirstSearch(start, end, nodes, edges) fmt.Println(result) } From 69dc53293c1d782d217e6b55a562b83007e106ed Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 20 Sep 2020 11:59:15 +0000 Subject: [PATCH 076/488] updating DIRECTORY.md --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 59583ee3d..116cd359d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -2,6 +2,7 @@ ## Ciphers * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/CaesarCipher.go) * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) + * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/Rot13.go) * [Rsacipher(Big)](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher(Big).go) * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher.go) * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xorCipher.go) @@ -35,6 +36,7 @@ ## Math * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/fastExponent.go) + * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/Sieve.go) ## Other * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxSubarraySum.go) From 8f33af5c640162eeb73bf5d1df58072d89519106 Mon Sep 17 00:00:00 2001 From: Anup Kumar Panwar <1anuppanwar@gmail.com> Date: Sun, 27 Sep 2020 13:10:38 +0530 Subject: [PATCH 077/488] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b81858417..70f817aa1 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ These algorithms are for demonstration purposes only. There are many sort implementations in the Go standard library that may have better performance. For a full list of all algorithms, please see: [DIRECTORY.md](https://github.com/TheAlgorithms/Go/blob/master/DIRECTORY.md) -Also see: https://algorithmswithgo.com ## Sort Algorithms From 9b0f822742c37a28fe06c04126ba9a2b8145f822 Mon Sep 17 00:00:00 2001 From: nomisrevol Date: Tue, 29 Sep 2020 12:25:35 +0700 Subject: [PATCH 078/488] Fix lint code of sorts_case_test effect other code --- sorts/sorts_case_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorts/sorts_case_test.go b/sorts/sorts_case_test.go index 841e15060..ef384fccd 100644 --- a/sorts/sorts_case_test.go +++ b/sorts/sorts_case_test.go @@ -13,7 +13,7 @@ type sortTest struct { name string } -var arr []= makeRandArray(500_000) +var arr []int = makeRandArray(500_000) var sortTests = []sortTest{ //Sorted slice From 3576bdaed19b3ed07f6a8716acb8e67931d72d08 Mon Sep 17 00:00:00 2001 From: nomisrevol Date: Tue, 29 Sep 2020 12:30:23 +0700 Subject: [PATCH 079/488] Refactor bubble_sort.go --- sorts/bubble_sort.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sorts/bubble_sort.go b/sorts/bubble_sort.go index d5311b153..13311f3eb 100644 --- a/sorts/bubble_sort.go +++ b/sorts/bubble_sort.go @@ -1,14 +1,19 @@ -//Package sorts a package for demonstrating sorting algorithms in Go +// Package sorts a package for demonstrating sorting algorithms in Go +// Implementation of basic bubble sort algorithm +// Reference: https://en.wikipedia.org/wiki/Bubble_sort + package sorts + +func bubbleSort(arr []int) []int { swapped := true for swapped { swapped = false - for i := 0; i < len(arrayzor)-1; i++ { - if arrayzor[i+1] < arrayzor[i] { - arrayzor[i+1], arrayzor[i] = arrayzor[i], arrayzor[i+1] + for i := 0; i < len(arr)-1; i++ { + if arr[i+1] < arr[i] { + arr[i+1], arr[i] = arr[i], arr[i+1] swapped = true } } } - return arrayzor + return arr } From d67be9f7f925bf6da2053c3ea70050bd933199cf Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Tue, 15 Sep 2020 10:35:29 +0530 Subject: [PATCH 080/488] Create greatest_common_divisor.go Create greatest_common_divisor.go Update greatest_common_divisor.go Update greatest_common_divisor.go Update greatest_common_divisor.go Fixed the indentation. Update greatest_common_divisor.go Update greatest_common_divisor.go Update greatest_common_divisor.go Fixed the indentation. Changes --- math/greatest_common_divisor.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 math/greatest_common_divisor.go diff --git a/math/greatest_common_divisor.go b/math/greatest_common_divisor.go new file mode 100644 index 000000000..ea5fe8a29 --- /dev/null +++ b/math/greatest_common_divisor.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" +) + +func gcd(a, b int) int { + if b == 0 { + return a + } + return gcd(b, a%b) + +} + +func main() { + fmt.Println(gcd(3, 99)) +} From 222127ba35cee864d3688b7ec16132d194ead362 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 29 Sep 2020 05:35:36 +0000 Subject: [PATCH 081/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 116cd359d..c090cbc28 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -36,6 +36,7 @@ ## Math * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/fastExponent.go) + * [Greatest Common Divisor](https://github.com/TheAlgorithms/Go/blob/master/math/greatest_common_divisor.go) * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/Sieve.go) ## Other From 95872dca19c71bfbfdc62bffbe0b1ea212917d91 Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Thu, 1 Oct 2020 12:35:51 +0530 Subject: [PATCH 082/488] Update fastExponent.go --- math/fastExponent.go | 62 ++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/math/fastExponent.go b/math/fastExponent.go index 98b68ca62..0b8b0c882 100644 --- a/math/fastExponent.go +++ b/math/fastExponent.go @@ -1,31 +1,49 @@ package main -//based on square and multiply algorithm +//iterative O(logn) function for pow(x, y) +func IterativePower(n uint, power uint) uint { + var res uint = 1 + for power > 0 { -func fastExponentiation(b int, e int) float64 { - //runs in O(log(n)) where n = e - if e == 0 { - return 1.0 + if (power & 1) != 0 { + res = res * n + } + + power = power >> 1 + n = n * n } - if e == 1 { - return float64(b) + return res +} + +//recursive O(logn) function for pow(x, y) +func RecursivePower(n uint, power uint) uint { + if power == 0 { + return 1 } - if e < 0 { - e *= -1 - println("executed") - return 1 / fastExponentiation(b, e) + var temp = RecursivePower(n, power/2) + if power%2 == 0 { + return temp * temp + } else { + return n * temp * temp } - r := 1 - for e > 0 { - if e%2 == 1 { - r = r * b - } - e = e >> 1 - b = b * b - } - return float64(r) } -func main() { - print(fastExponentiation(2, 0)) + +//recursive O(n) function for pow(x, y) +func RecursivePower1( n uint, power uint) uint{ + if power == 0 { + return 1 + } else if power % 2 == 0 { + return RecursivePower1(n, power/2) * RecursivePower1(n, power/2) + } else + { + return n * RecursivePower1(n, power/2) * RecursivePower1(n, power/2) + } } + +//Benchmarking Results +//goos: windows +//goarch: amd64 +//BenchmarkIterativePower-12 330048070 3.62 ns/op +//BenchmarkRecursivePower-12 124427038 9.63 ns/op +//BenchmarkRecursivePower1-12 20380434 58.5 ns/op From d9069e9de99a78aba0acee364aa2871bfe9fcd39 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 2 Oct 2020 07:55:10 +0000 Subject: [PATCH 083/488] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index c090cbc28..e75093959 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -15,6 +15,7 @@ * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data-structures/dynamic-array/dynamic_array.go) * Hash-Map * [Hash Map](https://github.com/TheAlgorithms/Go/blob/master/data-structures/hash-map/hash_map.go) + * [Hash Map Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/hash-map/hash_map_test.go) * Linked-List * [Double-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/double-linkedlist.go) * [Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/Linkedlist.go) From a30f367ceb37bbb5dc35bdbbf632bc473c49cd1e Mon Sep 17 00:00:00 2001 From: CFV Date: Sat, 3 Oct 2020 17:04:50 +0200 Subject: [PATCH 084/488] Add polybius cipher --- ciphers/polybius.go | 59 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 ciphers/polybius.go diff --git a/ciphers/polybius.go b/ciphers/polybius.go new file mode 100644 index 000000000..534b87fd7 --- /dev/null +++ b/ciphers/polybius.go @@ -0,0 +1,59 @@ +package main + +import ( + "errors" + "strings" +) + +type polybius struct { + size int + characters string + key string +} + +func newPolybius(key string, size int, chars string) (*polybius, error) { + key = strings.ToUpper(key) + chars = strings.ToUpper(chars)[:size] + if len(chars) != size { + return nil, errors.New("chars must be as long as size") + } + if len(key) != size*size { + return nil, errors.New("key must be as long as the size squared") + } + return &polybius{size, chars, key}, nil +} + +func (p *polybius) encrypt(text string) string { + chars := []rune(strings.ToUpper(text)) + encryptedText := "" + for _, char := range chars { + encryptedText += p.encipher(char) + } + return encryptedText +} + +func (p *polybius) decrypt(text string) string { + chars := []rune(strings.ToUpper(text)) + decryptedText := "" + for i := 0; i < len(chars); i += 2 { + decryptedText += p.decipher(chars[i : i+2]) + } + return decryptedText +} + +func (p *polybius) encipher(char rune) string { + index := strings.IndexRune(p.key, char) + row := index / p.size + col := index % p.size + chars := []rune(p.characters) + return string([]rune{chars[row], chars[col]}) +} + +func (p *polybius) decipher(chars []rune) string { + if len(chars) != 2 { + panic("decipher takes two chars") + } + row := strings.IndexRune(p.characters, chars[0]) + col := strings.IndexRune(p.characters, chars[1]) + return string([]rune(p.key)[row*p.size+col]) +} From 34c3214ab60455a6f727072bb042c234b09703c5 Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Sun, 4 Oct 2020 19:42:24 +0530 Subject: [PATCH 085/488] Create primalityTest.go (#179) * Create the prime_check.go * Added test file --- math/prime_check/prime_check.go | 34 +++++++++++++++++++++ math/prime_check/prime_check_test.go | 44 ++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 math/prime_check/prime_check.go create mode 100644 math/prime_check/prime_check_test.go diff --git a/math/prime_check/prime_check.go b/math/prime_check/prime_check.go new file mode 100644 index 000000000..b1656342b --- /dev/null +++ b/math/prime_check/prime_check.go @@ -0,0 +1,34 @@ +//A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography. +//Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number is prime or not. +//Source - Wikipedia https://en.wikipedia.org/wiki/Primality_test +package main + +func NaiveApproach(n int) bool { + if n < 2 { + return false + } + for i := 2; i < n; i++ { + + if n%i == 0 { + return false + } + } + return true +} + +func PairApproach(n int) bool { + if n < 2 { + return false + } + for i := 2; i*i <= n; i++ { + if n%i == 0 { + return false + } + } + return true +} + +//goos: windows +//goarch: amd64 +//BenchmarkNaiveApproach-12 660980034 1.81 ns/op +//BenchmarkPairApproach-12 664641356 1.82 ns/op diff --git a/math/prime_check/prime_check_test.go b/math/prime_check/prime_check_test.go new file mode 100644 index 000000000..17f608ce1 --- /dev/null +++ b/math/prime_check/prime_check_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "testing" +) + +func TestTableNaiveApproach(t *testing.T) { + var tests = []struct { + input int + expected bool + }{ + {2, true}, + {3, true}, + {1, false}, + {10, false}, + {23, true}, + } + + for _, test := range tests { + if output := NaiveApproach(test.input); output != test.expected { + t.Error("Test Failed: {} inputted, {} expected, recieved: {}", test.input, test.expected, output) + } + } + +} +func TestTablePairApproach(t *testing.T) { + var tests = []struct { + input int + expected bool + }{ + {2, true}, + {3, true}, + {1, false}, + {10, false}, + {23, true}, + } + + for _, test := range tests { + if output := PairApproach(test.input); output != test.expected { + t.Error("Test Failed: {} inputted, {} expected, recieved: {}", test.input, test.expected, output) + } + } + +} From 6629aad20677e4dbd88a3e4ce26d8a46fb356aaa Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 4 Oct 2020 14:12:39 +0000 Subject: [PATCH 086/488] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index e75093959..76d5e5f30 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -38,6 +38,9 @@ ## Math * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/fastExponent.go) * [Greatest Common Divisor](https://github.com/TheAlgorithms/Go/blob/master/math/greatest_common_divisor.go) + * Prime Check + * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/prime_check/prime_check.go) + * [Prime Check Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime_check/prime_check_test.go) * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/Sieve.go) ## Other From 6f4c6359819994807a400d67903712cb22bb31b5 Mon Sep 17 00:00:00 2001 From: mattan Date: Wed, 7 Oct 2020 03:29:57 +0300 Subject: [PATCH 087/488] Initial Commit --- sorts/radix_sort.go | 73 +++++++++++++++++++++++++++++++++++++++++++++ sorts/sorts_test.go | 35 +++++++++++++++++----- 2 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 sorts/radix_sort.go diff --git a/sorts/radix_sort.go b/sorts/radix_sort.go new file mode 100644 index 000000000..bdb577e22 --- /dev/null +++ b/sorts/radix_sort.go @@ -0,0 +1,73 @@ +package sorts + +import ( + "math" +) + +func max(arr []int) int { + max := math.MinInt64 + for _, item := range arr { + if item > max { + max = item + } + } + return max +} + +func countSort(arr []int, exp int) []int { + var digits [10]int + var output = make([]int, len(arr)) + for _, item := range arr { + digits[(item/exp)%10]++ + } + + for i := 1; i < 10; i++ { + digits[i] += digits[i-1] + } + + for i := len(arr) - 1; i >= 0; i-- { + output[digits[(arr[i]/exp)%10]-1] = arr[i] + digits[(arr[i]/exp)%10]-- + } + + return output +} + +func RadixSort(arr []int) []int { + maxElement := max(arr) + for exp := 1; maxElement/exp > 0; exp *= 10 { + arr = countSort(arr, exp) + } + return arr +} + +// The following adds support for signed ints +/* + +func unsignedRadixSort(arr []int) []int { + maxElement := max(arr) + for exp := 1; maxElement/exp > 0; exp *= 10 { + arr = countSort(arr, exp) + } + return arr +} + +func RadixSort(arr []int) []int { + var negatives, nonNegatives []int + + for _, item := range arr { + if item < 0 { + negatives = append(negatives, -item) + } else { + nonNegatives = append(nonNegatives, item) + } + } + negatives = unsignedRadixSort(negatives) + + // Reverse the negative array and restore signs + for i, j := 0, len(negatives) -1; i < j; i,j = i + 1, j - 1 { + negatives[i], negatives[j] = -negatives[j], -negatives[i] + } + return append(negatives, unsignedRadixSort(nonNegatives)...) +} +*/ diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index 4769397b5..8ab66d095 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -95,6 +95,19 @@ func TestShell(t *testing.T) { } } +func TestRadix(t *testing.T) { + for _, test := range sortTests { + actual := RadixSort(test.input) + pos, sorted := compareSlices(actual, test.expected) + if !sorted { + if pos == -1 { + t.Errorf("test %s failed due to slice length changing", test.name) + } + t.Errorf("test %s failed at index %d", test.name, pos) + } + } +} + /*func TestTopological(t *testing.T) { for _, test := range sortTests { actual := topologicalSort(test.input) @@ -119,13 +132,13 @@ func BenchmarkBubble(b *testing.B) { } } -func BenchmarkSelection(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - selectionSort(test.input) - } - } -} +//func BenchmarkSelection(b *testing.B) { +// for i := 0; i < b.N; i++ { +// for _, test := range sortTests { +// selectionSort(test.input) +// } +// } +//} func BenchmarkInsertion(b *testing.B) { for i := 0; i < b.N; i++ { @@ -167,6 +180,14 @@ func BenchmarkShell(b *testing.B) { } } +func BenchmarkRadix(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range sortTests { + RadixSort(test.input) + } + } +} + /*func BenchmarkTopological(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { From efedf3afafb6a64ec3ada0fadfa0853153eb4551 Mon Sep 17 00:00:00 2001 From: mattan Date: Wed, 7 Oct 2020 03:44:24 +0300 Subject: [PATCH 088/488] Added Radix Sort --- sorts/sorts_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index 8ab66d095..bd3682944 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -132,13 +132,13 @@ func BenchmarkBubble(b *testing.B) { } } -//func BenchmarkSelection(b *testing.B) { -// for i := 0; i < b.N; i++ { -// for _, test := range sortTests { -// selectionSort(test.input) -// } -// } -//} +func BenchmarkSelection(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range sortTests { + selectionSort(test.input) + } + } +} func BenchmarkInsertion(b *testing.B) { for i := 0; i < b.N; i++ { From 93c51b47dd233a4f60f8edf4e6662ddc74bd19bc Mon Sep 17 00:00:00 2001 From: nomisrevol Date: Wed, 7 Oct 2020 14:07:21 +0700 Subject: [PATCH 089/488] Add .gitignore for IDEs --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..66f8fb502 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +.vscode/ From 543fa8d2795fb2b4e43e7354733f68c82387b093 Mon Sep 17 00:00:00 2001 From: nomisrevol Date: Wed, 7 Oct 2020 14:16:27 +0700 Subject: [PATCH 090/488] Refactor counting sort and add test --- sorts/{bubble_sort.go => bubblesort.go} | 1 - sorts/counting_sort.go | 17 ---------- sorts/countingsort.go | 27 ++++++++++++++++ sorts/sorts_test.go | 41 ++++++++----------------- 4 files changed, 40 insertions(+), 46 deletions(-) rename sorts/{bubble_sort.go => bubblesort.go} (83%) delete mode 100644 sorts/counting_sort.go create mode 100644 sorts/countingsort.go diff --git a/sorts/bubble_sort.go b/sorts/bubblesort.go similarity index 83% rename from sorts/bubble_sort.go rename to sorts/bubblesort.go index 13311f3eb..2a0244908 100644 --- a/sorts/bubble_sort.go +++ b/sorts/bubblesort.go @@ -1,4 +1,3 @@ -// Package sorts a package for demonstrating sorting algorithms in Go // Implementation of basic bubble sort algorithm // Reference: https://en.wikipedia.org/wiki/Bubble_sort diff --git a/sorts/counting_sort.go b/sorts/counting_sort.go deleted file mode 100644 index 3175854f1..000000000 --- a/sorts/counting_sort.go +++ /dev/null @@ -1,17 +0,0 @@ -package sorts - -func CountingSort(arr []int, max int) []int { - //use the max value to create a slice of item counts - counts := make([]int, max+1) - result := make([]int, 0) - for _, item := range arr { - counts[item]++ - } - for i := 0; i < len(counts); i++ { - count := counts[i] - for j := 0; j < count; j++ { - result = append(result, i) - } - } - return result -} diff --git a/sorts/countingsort.go b/sorts/countingsort.go new file mode 100644 index 000000000..930955cd7 --- /dev/null +++ b/sorts/countingsort.go @@ -0,0 +1,27 @@ +// Reference: https://en.wikipedia.org/wiki/Counting_sort + +package sorts + +func countingSort(arr []int) []int { + if len(arr) == 0 { + return make([]int, 0) + } + maxElement := arr[0] + for i := 1; i < len(arr); i++ { + if arr[i] > maxElement { + maxElement = arr[i] + } + } + + counts := make([]int, maxElement+1) + result := make([]int, 0) + for _, item := range arr { + counts[item]++ + } + for i := 0; i <= maxElement; i++ { + for j := 0; j < counts[i]; j++ { + result = append(result, i) + } + } + return result +} diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index 4769397b5..bd047d8a7 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -2,8 +2,6 @@ package sorts import "testing" -//BEGIN TESTS - func TestBubble(t *testing.T) { for _, test := range sortTests { actual := bubbleSort(test.input) @@ -17,6 +15,19 @@ func TestBubble(t *testing.T) { } } +func TestCountingSort(t *testing.T) { + for _, testcase := range sortTests { + actual := countingSort(testcase.input) + pos, sorted := compareSlices(actual, testcase.expected) + if !sorted { + if pos == -1 { + t.Errorf("test %s failed due to slice length changing", testcase.name) + } + t.Errorf("test %s failed at index %d", testcase.name, pos) + } + } +} + func TestSelection(t *testing.T) { for _, test := range sortTests { actual := selectionSort(test.input) @@ -95,22 +106,6 @@ func TestShell(t *testing.T) { } } -/*func TestTopological(t *testing.T) { - for _, test := range sortTests { - actual := topologicalSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } -}*/ - -//END TESTS - -//BEGIN BENCHMARKS func BenchmarkBubble(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { @@ -167,16 +162,6 @@ func BenchmarkShell(b *testing.B) { } } -/*func BenchmarkTopological(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - topologicalSort(test.input) - } - } -}*/ - -//END BENCHMARKS - func compareSlices(a []int, b []int) (int, bool) { if len(a) != len(b) { return -1, false From cc2521bff921bed94d3935b0182d1e5007ff653b Mon Sep 17 00:00:00 2001 From: nomisrevol Date: Wed, 7 Oct 2020 14:23:57 +0700 Subject: [PATCH 091/488] Refactor insertion sort --- sorts/insertion_sort.go | 15 --------------- sorts/insertionsort.go | 15 +++++++++++++++ sorts/sorts_test.go | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) delete mode 100644 sorts/insertion_sort.go create mode 100644 sorts/insertionsort.go diff --git a/sorts/insertion_sort.go b/sorts/insertion_sort.go deleted file mode 100644 index 9a95e0a6b..000000000 --- a/sorts/insertion_sort.go +++ /dev/null @@ -1,15 +0,0 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts - -func insertionSort(arr []int) []int { - for out := 1; out < len(arr); out++ { - temp := arr[out] - in := out - - for ; in > 0 && arr[in-1] >= temp; in-- { - arr[in] = arr[in-1] - } - arr[in] = temp - } - return arr -} diff --git a/sorts/insertionsort.go b/sorts/insertionsort.go new file mode 100644 index 000000000..ee76369cb --- /dev/null +++ b/sorts/insertionsort.go @@ -0,0 +1,15 @@ +// Reference: https://en.wikipedia.org/wiki/Insertion_sort + +package sorts + +func insertionSort(arr []int) []int { + for currentIndex := 1; currentIndex < len(arr); currentIndex++ { + temporary := arr[currentIndex] + iterator := currentIndex + for ; iterator > 0 && arr[iterator-1] >= temporary; iterator-- { + arr[iterator] = arr[iterator-1] + } + arr[iterator] = temporary + } + return arr +} diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index bd047d8a7..a27fe6e0b 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -2,7 +2,7 @@ package sorts import "testing" -func TestBubble(t *testing.T) { +func TestBubbleSort(t *testing.T) { for _, test := range sortTests { actual := bubbleSort(test.input) pos, sorted := compareSlices(actual, test.expected) @@ -28,7 +28,7 @@ func TestCountingSort(t *testing.T) { } } -func TestSelection(t *testing.T) { +func TestSelectionSort(t *testing.T) { for _, test := range sortTests { actual := selectionSort(test.input) pos, sorted := compareSlices(actual, test.expected) @@ -41,7 +41,7 @@ func TestSelection(t *testing.T) { } } -func TestInsertion(t *testing.T) { +func TestInsertionSort(t *testing.T) { for _, test := range sortTests { actual := insertionSort(test.input) pos, sorted := compareSlices(actual, test.expected) @@ -54,7 +54,7 @@ func TestInsertion(t *testing.T) { } } -func TestMerge(t *testing.T) { +func TestMergeSort(t *testing.T) { for _, test := range sortTests { actual := Mergesort(test.input) pos, sorted := compareSlices(actual, test.expected) @@ -67,7 +67,7 @@ func TestMerge(t *testing.T) { } } -func TestHeap(t *testing.T) { +func TestHeapSort(t *testing.T) { for _, test := range sortTests { actual := heapSort(test.input) pos, sorted := compareSlices(actual, test.expected) @@ -80,7 +80,7 @@ func TestHeap(t *testing.T) { } } -func TestQuick(t *testing.T) { +func TestQuickSort(t *testing.T) { for _, test := range sortTests { actual := quickSort(test.input) pos, sorted := compareSlices(actual, test.expected) @@ -93,7 +93,7 @@ func TestQuick(t *testing.T) { } } -func TestShell(t *testing.T) { +func TestShellSort(t *testing.T) { for _, test := range sortTests { actual := shellSort(test.input) pos, sorted := compareSlices(actual, test.expected) From d45c4b050b25ca745518d5456e3819888f07917b Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Wed, 7 Oct 2020 07:25:39 +0000 Subject: [PATCH 092/488] updating DIRECTORY.md --- DIRECTORY.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 76d5e5f30..243b71dd1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -62,10 +62,10 @@ * [Search Test](https://github.com/TheAlgorithms/Go/blob/master/searches/search_test.go) ## Sorts - * [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubble_sort.go) - * [Counting Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/counting_sort.go) + * [Bubblesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubblesort.go) + * [Countingsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/countingsort.go) * [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heap_sort.go) - * [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertion_sort.go) + * [Insertionsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertionsort.go) * [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/merge_sort.go) * [Quick Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quick_sort.go) * [Selection Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selection_sort.go) From 33066f414b62f1d07f28723631bffa1da02d05f9 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Wed, 7 Oct 2020 18:00:03 +0530 Subject: [PATCH 093/488] Changed linked list to make it extensible and accept any data type. Also added some unit tests. Signed-off-by: Jobin John --- .../linked-list/single-linkedlist.go | 123 ----------------- .../singlelinkedlist/single-linkedlist.go | 125 ++++++++++++++++++ .../single-linkedlist_test.go | 67 ++++++++++ 3 files changed, 192 insertions(+), 123 deletions(-) delete mode 100644 data-structures/linked-list/single-linkedlist.go create mode 100644 data-structures/linked-list/singlelinkedlist/single-linkedlist.go create mode 100644 data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go diff --git a/data-structures/linked-list/single-linkedlist.go b/data-structures/linked-list/single-linkedlist.go deleted file mode 100644 index bbcfb46ac..000000000 --- a/data-structures/linked-list/single-linkedlist.go +++ /dev/null @@ -1,123 +0,0 @@ -// demonstration of singly linked list in golang - -package singlelinkedlist - -// package main - -import "fmt" - -type node struct { - val int - next *node -} - -type singlelinkedlist struct { - head *node -} - -// to avoid mistakes when using pointer vs struct for new node creation -func newNode(val int) *node { - return &node{val, nil} -} - -func (ll *singlelinkedlist) addAtBeg(val int) { - n := newNode(val) - n.next = ll.head - ll.head = n -} - -func (ll *singlelinkedlist) addAtEnd(val int) { - n := newNode(val) - - if ll.head == nil { - ll.head = n - return - } - - cur := ll.head - for ; cur.next != nil; cur = cur.next { - } - cur.next = n -} - -func (ll *singlelinkedlist) delAtBeg() int { - if ll.head == nil { - return -1 - } - - cur := ll.head - ll.head = cur.next - - return cur.val -} - -func (ll *singlelinkedlist) delAtEnd() int { - if ll.head == nil { - return -1 - } - - if ll.head.next == nil { - return ll.delAtBeg() - } - - cur := ll.head - - for ; cur.next.next != nil; cur = cur.next { - } - - retval := cur.next.val - cur.next = nil - return retval - -} - -func (ll *singlelinkedlist) count() int { - var ctr int = 0 - - for cur := ll.head; cur != nil; cur = cur.next { - ctr += 1 - } - - return ctr -} - -func (ll *singlelinkedlist) reverse() { - var prev, next *node - cur := ll.head - - for cur != nil { - next = cur.next - cur.next = prev - prev = cur - cur = next - } - - ll.head = prev -} - -func (ll *singlelinkedlist) display() { - for cur := ll.head; cur != nil; cur = cur.next { - fmt.Print(cur.val, " ") - } - - fmt.Print("\n") -} - -// func main() { -// ll := singlelinkedlist{} - -// ll.addAtBeg(10) -// ll.addAtEnd(20) -// ll.display() -// ll.addAtBeg(30) -// ll.display() -// ll.reverse() -// ll.display() - -// fmt.Print(ll.delAtBeg(), "\n") -// ll.display() - -// fmt.Print(ll.delAtEnd(), "\n") -// ll.display() - -// } diff --git a/data-structures/linked-list/singlelinkedlist/single-linkedlist.go b/data-structures/linked-list/singlelinkedlist/single-linkedlist.go new file mode 100644 index 000000000..d2f2df9b2 --- /dev/null +++ b/data-structures/linked-list/singlelinkedlist/single-linkedlist.go @@ -0,0 +1,125 @@ +package singlelinkedlist + +// demonstration of singly linked list in golang +import "fmt" + +type node struct { + Val interface{} + Next *node +} + +type singlelinkedlist struct { + length int + Head *node +} + +// CreateList returns a new instance of a linked list +func CreateList() *singlelinkedlist { + return &singlelinkedlist{} +} + +// to avoid mistakes when using pointer vs struct for new node creation +func newNode(val interface{}) *node { + return &node{val, nil} +} + +func (ll *singlelinkedlist) AddAtBeg(val interface{}) { + n := newNode(val) + n.Next = ll.Head + ll.Head = n + ll.length++ +} + +func (ll *singlelinkedlist) AddAtEnd(val int) { + n := newNode(val) + + if ll.Head == nil { + ll.Head = n + ll.length++ + return + } + + cur := ll.Head + for ; cur.Next != nil; cur = cur.Next { + } + cur.Next = n + ll.length++ +} + +func (ll *singlelinkedlist) DelAtBeg() interface{} { + if ll.Head == nil { + return -1 + } + + cur := ll.Head + ll.Head = cur.Next + ll.length-- + + return cur.Val +} + +func (ll *singlelinkedlist) DelAtEnd() interface{} { + if ll.Head == nil { + return -1 + } + + if ll.Head.Next == nil { + return ll.DelAtBeg() + } + + cur := ll.Head + + for ; cur.Next.Next != nil; cur = cur.Next { + } + + retval := cur.Next.Val + cur.Next = nil + ll.length-- + return retval + +} + +func (ll *singlelinkedlist) Count() int { + return ll.length +} + +func (ll *singlelinkedlist) Reverse() { + var prev, Next *node + cur := ll.Head + + for cur != nil { + Next = cur.Next + cur.Next = prev + prev = cur + cur = Next + } + + ll.Head = prev +} + +func (ll *singlelinkedlist) Display() { + for cur := ll.Head; cur != nil; cur = cur.Next { + fmt.Print(cur.Val, " ") + } + + fmt.Print("\n") +} + +// func main() { +// ll := singlelinkedlist{} + +// ll.addAtBeg(10) +// ll.addAtEnd(20) +// ll.display() +// ll.addAtBeg(30) +// ll.display() +// ll.reverse() +// ll.display() + +// fmt.Print(ll.delAtBeg(), "\n") +// ll.display() + +// fmt.Print(ll.delAtEnd(), "\n") +// ll.display() + +// } diff --git a/data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go b/data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go new file mode 100644 index 000000000..c9eb951bb --- /dev/null +++ b/data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go @@ -0,0 +1,67 @@ +package singlelinkedlist + +import ( + "reflect" + "testing" +) + +func TestLinkedList(t *testing.T) { + list := CreateList() + list.AddAtBeg(1) + list.AddAtBeg(2) + list.AddAtBeg(3) + + t.Run("Test AddAtBeg()", func(t *testing.T) { + want := []interface{}{3, 2, 1} + got := []interface{}{} + current := list.Head + got = append(got, current.Val) + for current.Next != nil { + current = current.Next + got = append(got, current.Val) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + list.AddAtEnd(4) + + t.Run("Test AddAtEnd()", func(t *testing.T) { + want := []interface{}{3, 2, 1, 4} + got := []interface{}{} + current := list.Head + got = append(got, current.Val) + for current.Next != nil { + current = current.Next + got = append(got, current.Val) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + t.Run("Test DelAtBeg()", func(t *testing.T) { + want := interface{}(3) + got := list.DelAtBeg() + if got != want { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + t.Run("Test DelAtEnd()", func(t *testing.T) { + want := interface{}(4) + got := list.DelAtEnd() + if got != want { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + t.Run("Test Count()", func(t *testing.T) { + want := 2 + got := list.Count() + if got != want { + t.Errorf("got: %v, want: %v", got, want) + } + }) +} From e1302bd544216ac188e758b5093eba9d52965332 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Wed, 7 Oct 2020 18:25:56 +0530 Subject: [PATCH 094/488] Added some comments to exported functions to make it lint compliant. Signed-off-by: Jobin John --- .../singlelinkedlist/single-linkedlist.go | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/data-structures/linked-list/singlelinkedlist/single-linkedlist.go b/data-structures/linked-list/singlelinkedlist/single-linkedlist.go index d2f2df9b2..e280aa7b0 100644 --- a/data-structures/linked-list/singlelinkedlist/single-linkedlist.go +++ b/data-structures/linked-list/singlelinkedlist/single-linkedlist.go @@ -23,6 +23,7 @@ func newNode(val interface{}) *node { return &node{val, nil} } +// AddAtBeg adds a new node with given value at the beginning of the list. func (ll *singlelinkedlist) AddAtBeg(val interface{}) { n := newNode(val) n.Next = ll.Head @@ -30,6 +31,7 @@ func (ll *singlelinkedlist) AddAtBeg(val interface{}) { ll.length++ } +// AddAtEnd adds a new node with given value at the end of the list. func (ll *singlelinkedlist) AddAtEnd(val int) { n := newNode(val) @@ -46,6 +48,7 @@ func (ll *singlelinkedlist) AddAtEnd(val int) { ll.length++ } +// DelAtBeg deletes the node at the head(beginning) of the list and returns its value. Returns -1 if the list is empty. func (ll *singlelinkedlist) DelAtBeg() interface{} { if ll.Head == nil { return -1 @@ -58,6 +61,7 @@ func (ll *singlelinkedlist) DelAtBeg() interface{} { return cur.Val } +// DelAtEnd deletes the node at the tail(end) of the list and returns its value. Returns -1 if the list is empty. func (ll *singlelinkedlist) DelAtEnd() interface{} { if ll.Head == nil { return -1 @@ -79,10 +83,12 @@ func (ll *singlelinkedlist) DelAtEnd() interface{} { } +// Count returns the current size of the list. func (ll *singlelinkedlist) Count() int { return ll.length } +// Reverse reverses the list. func (ll *singlelinkedlist) Reverse() { var prev, Next *node cur := ll.Head @@ -97,6 +103,7 @@ func (ll *singlelinkedlist) Reverse() { ll.Head = prev } +// Display prints out the elements of the list. func (ll *singlelinkedlist) Display() { for cur := ll.Head; cur != nil; cur = cur.Next { fmt.Print(cur.Val, " ") @@ -104,22 +111,3 @@ func (ll *singlelinkedlist) Display() { fmt.Print("\n") } - -// func main() { -// ll := singlelinkedlist{} - -// ll.addAtBeg(10) -// ll.addAtEnd(20) -// ll.display() -// ll.addAtBeg(30) -// ll.display() -// ll.reverse() -// ll.display() - -// fmt.Print(ll.delAtBeg(), "\n") -// ll.display() - -// fmt.Print(ll.delAtEnd(), "\n") -// ll.display() - -// } From a24e2b8164c87eb76bfa57a4e0391c96dd585b62 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 11 Oct 2020 07:43:35 +0000 Subject: [PATCH 095/488] updating DIRECTORY.md --- DIRECTORY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 243b71dd1..b1d8f64c0 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -19,7 +19,9 @@ * Linked-List * [Double-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/double-linkedlist.go) * [Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/Linkedlist.go) - * [Single-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/single-linkedlist.go) + * Singlelinkedlist + * [Single-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/singlelinkedlist/single-linkedlist.go) + * [Single-Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go) * Trie * [Trie](https://github.com/TheAlgorithms/Go/blob/master/data-structures/trie/trie.go) * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/trie/trie_test.go) From 9fae2bb4ec3a1ebfc3965576337cd0eb35ecd4e6 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 11 Oct 2020 14:16:02 +0530 Subject: [PATCH 096/488] Update issue templates Added two templates to assist contributors when creating issues: - One for reporting issues, errors in existing implementations. - Second for proposing new implementations or enhancements to existing ones. --- .github/ISSUE_TEMPLATE/bug_report.md | 27 +++++++++++++++++++ .../new-optimize-implementation.md | 20 ++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/new-optimize-implementation.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..160740ee5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/new-optimize-implementation.md b/.github/ISSUE_TEMPLATE/new-optimize-implementation.md new file mode 100644 index 000000000..db6cb5224 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new-optimize-implementation.md @@ -0,0 +1,20 @@ +--- +name: New/Optimize implementation +about: Propose an enhancement or a new algorithm implementation. +title: '' +labels: enhancement +assignees: '' + +--- + +**Description** +Provide a clear and concise description of the issue. + +For new implementation: +- Name and problem statement for the algorithm. + +For enhancement: +- Specify what needs to be changed and why. For example: + - Adding tests. + - Optimizing logic. + - Refactoring file and folders for better structure. From 6c79983601e5e3271deb9a7edbf94d7f342061bd Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 11 Oct 2020 17:53:00 +0530 Subject: [PATCH 097/488] Added a basic pull request template. Signed-off-by: Jobin John --- .github/PULL_REQUEST_TEMPLATE/pull_request.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request.md diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request.md b/.github/PULL_REQUEST_TEMPLATE/pull_request.md new file mode 100644 index 000000000..5fd421062 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request.md @@ -0,0 +1,10 @@ + From 7baf3b5fc4379dec6468bcb44a0cdacb3d2cbe73 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Tue, 6 Oct 2020 23:46:41 +0200 Subject: [PATCH 098/488] add tests for Caesar cipher --- ciphers/{ => caesar}/CaesarCipher.go | 0 ciphers/caesar/caesar_test.go | 68 ++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) rename ciphers/{ => caesar}/CaesarCipher.go (100%) create mode 100644 ciphers/caesar/caesar_test.go diff --git a/ciphers/CaesarCipher.go b/ciphers/caesar/CaesarCipher.go similarity index 100% rename from ciphers/CaesarCipher.go rename to ciphers/caesar/CaesarCipher.go diff --git a/ciphers/caesar/caesar_test.go b/ciphers/caesar/caesar_test.go new file mode 100644 index 000000000..d3ccb8ad7 --- /dev/null +++ b/ciphers/caesar/caesar_test.go @@ -0,0 +1,68 @@ +package main + +import ( + "testing" +) + +var caesarTestData = []struct { + description string + input string + key int + expected string +}{ + { + "Basic caesar encryption with letter 'a'", + "a", + 3, + "d", + }, + { + "Basic caesar encryption wrap around alphabet on letter 'z'", + "z", + 3, + "c", + }, + { + "Encrypt a simple string with ceasar encryiption", + "hello", + 3, + "khoor", + }, + { + "Encrypt a simple string with key 13", + "hello", + 13, + "uryyb", + }, + { + "Encrypt a simple string with key -13", + "hello", + -13, + "uryyb", + }, + { + "With key of 26 output should be the same as the input", + "no change", + 26, + "no change", + }, + { + "Encrpyt sentence with key 10", + "the quick brown fox jumps over the lazy dog.", + 10, + "dro aesmu lbygx pyh tewzc yfob dro vkji nyq.", + }, +} + +func TestCeasarCipher(t *testing.T) { + for _, test := range caesarTestData { + t.Run(test.description, func(t *testing.T) { + actual := caesarCipher(test.input, test.key) + if actual != test.expected { + t.Logf("FAIL: %s", test.description) + t.Fatalf("With input string '%s' and key '%d' was expecting '%s' but actual was '%s'", + test.input, test.key, test.expected, actual) + } + }) + } +} From 1127456143526141c2f8116acf4fd6bcbcb8cd1b Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 11 Oct 2020 22:35:35 +0530 Subject: [PATCH 099/488] Refactored folder and package names, removed main func and added tests. Signed-off-by: Jobin John --- .../levenshteinDistance.go | 36 +------------ .../levenshteinDistance_test.go | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+), 34 deletions(-) rename strings/{ => levenshteindistance}/levenshteinDistance.go (51%) create mode 100644 strings/levenshteindistance/levenshteinDistance_test.go diff --git a/strings/levenshteinDistance.go b/strings/levenshteindistance/levenshteinDistance.go similarity index 51% rename from strings/levenshteinDistance.go rename to strings/levenshteindistance/levenshteinDistance.go index 35cfec4d6..143315536 100644 --- a/strings/levenshteinDistance.go +++ b/strings/levenshteindistance/levenshteinDistance.go @@ -4,16 +4,11 @@ Parameters: two strings to compare and weights of insertion, substitution and de Output: distance between both strings */ -package main - -import ( - "fmt" -) +package levenshteindistance func levenshteinDistance(str1, str2 string, icost, scost, dcost int) int { row1 := make([]int, len(str2)+1) row2 := make([]int, len(str2)+1) - var tmp []int for i := 1; i <= len(str2); i++ { row1[i] = i * icost @@ -39,35 +34,8 @@ func levenshteinDistance(str1, str2 string, icost, scost, dcost int) int { } } } - - tmp = row1 - row1 = row2 - row2 = tmp + row1, row2 = row2, row1 } return row1[len(row1)-1] } - -func min(str1, str2 int) int { - if str1 < str2 { - return str1 - } - return str2 -} - -func main() { - str1 := "stingy" - str2 := "ring" - - // Using weight 1 for insertion, substitution and deletion - strDistance1 := levenshteinDistance(str1, str2, 1, 1, 1) - fmt.Printf("Distance between \"%s\" and \"%s\" is: %d.\n", str1, str2, strDistance1) - // Output: Distance between "stingy" and "ring" is: 3. - - // Using weight 1 for insertion/substitution and weight 3 for deletion - strDistance2 := levenshteinDistance(str1, str2, 1, 1, 3) - fmt.Printf("Distance between \"%s\" and \"%s\" is: %d.\n", str1, str2, strDistance2) - // Output: Distance between "stingy" and "ring" is: 7. - - return -} diff --git a/strings/levenshteindistance/levenshteinDistance_test.go b/strings/levenshteindistance/levenshteinDistance_test.go new file mode 100644 index 000000000..9079d844a --- /dev/null +++ b/strings/levenshteindistance/levenshteinDistance_test.go @@ -0,0 +1,52 @@ +package levenshteindistance + +import "testing" + +var testCases = []struct { + name string + string1 string + string2 string + insertionCost int + substitutionCost int + deletionCost int + expected int +}{ + { + "strings with equal operation weights.", + "stingy", + "ring", + 1, + 1, + 1, + 3, + }, + { + "strings with different operation weights.", + "stingy", + "ring", + 1, + 1, + 3, + 7, + }, + { + "strings with different operation weights.", + "kitten", + "sitting", + 1, + 1, + 1, + 3, + }, +} + +func TestLevenshteinDistance(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := levenshteinDistance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost) + if actual != tc.expected { + t.Errorf("Expected Levenshtein distance between strings: '%s' and '%s' is %v, but got: %v", tc.string1, tc.string2, tc.expected, actual) + } + }) + } +} From 91b649428dec3be8abce5d4b6e65b40128bbfcc5 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 11 Oct 2020 22:56:12 +0530 Subject: [PATCH 100/488] Refactored files, removed main func, added tests. Signed-off-by: Jobin John --- .../{ => naivesearch}/naiveStringSearch.go | 20 +------- strings/naivesearch/naiveStringSearch_test.go | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+), 18 deletions(-) rename strings/{ => naivesearch}/naiveStringSearch.go (58%) create mode 100644 strings/naivesearch/naiveStringSearch_test.go diff --git a/strings/naiveStringSearch.go b/strings/naivesearch/naiveStringSearch.go similarity index 58% rename from strings/naiveStringSearch.go rename to strings/naivesearch/naiveStringSearch.go index c93b1f134..e6f942190 100644 --- a/strings/naiveStringSearch.go +++ b/strings/naivesearch/naiveStringSearch.go @@ -8,15 +8,11 @@ Time Complexity : O(n*m) m = length of pattern */ -package main - -import ( - "fmt" -) +package naivesearch func naivePatternSearch(text string, pattern string) []int { var positions []int - for i := 0; i < len(text)-len(pattern); i++ { + for i := 0; i <= len(text)-len(pattern); i++ { var match bool = true for j := 0; j < len(pattern); j++ { if text[i+j] != pattern[j] { @@ -31,15 +27,3 @@ func naivePatternSearch(text string, pattern string) []int { } return positions } - -func main() { - text := "ABAAABCDBBABCDDEBCABC" - pattern := "ABC" - var positions []int = naivePatternSearch(text, pattern) - if len(positions) == 0 { - fmt.Printf("Pattern not found in given text!") - } else { - fmt.Printf("Pattern found in following position:\n") - fmt.Printf("%v", positions) - } -} diff --git a/strings/naivesearch/naiveStringSearch_test.go b/strings/naivesearch/naiveStringSearch_test.go new file mode 100644 index 000000000..87943a679 --- /dev/null +++ b/strings/naivesearch/naiveStringSearch_test.go @@ -0,0 +1,49 @@ +package naivesearch + +import ( + "reflect" + "testing" +) + +var testCases = []struct { + name string + input string + pattern string + expected []int +}{ + { + "string with multiple pattern matches", + "ABAAABCDBBABCDDEBCABC", + "ABC", + []int{4, 10, 18}, + }, + { + "string with single pattern match", + "ABCDEFGHIJKLMN", + "CDE", + []int{2}, + }, + { + "string with no pattern match", + "ABCDEFGHIJKLMN", + "XYZ", + []int(nil), + }, + { + "empty string", + "", + "XYZ", + []int(nil), + }, +} + +func TestNaivePatternSearch(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := naivePatternSearch(tc.input, tc.pattern) + if !reflect.DeepEqual(actual, tc.expected) { + t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v, but actual matches are: %v", tc.pattern, tc.input, tc.expected, actual) + } + }) + } +} From f748d60c9866318b84dadfed483c8e34721994ef Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 11 Oct 2020 23:54:07 +0530 Subject: [PATCH 101/488] Updated ci lint configuration. Signed-off-by: Jobin John --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 22c5c485d..b641f287e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -29,6 +29,6 @@ jobs: - run: golangci-lint run --no-config other || true - run: golangci-lint run --no-config searches || true - run: golangci-lint run --no-config sorts - - run: golangci-lint run --no-config strings + - run: golangci-lint run --no-config strings/... - run: golangci-lint run --no-config "strings/multiple string matching" || true # - run: golangci-lint run --no-config "strings/single string matching" || true From baca44fd85a13ac8c96db29b8927b9a8116f8209 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 11 Oct 2020 23:57:39 +0530 Subject: [PATCH 102/488] Temporarily removed recursive search and added individual folders in ci lint config. Signed-off-by: Jobin John --- .github/workflows/golangci-lint.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index b641f287e..8a75691f4 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -29,6 +29,8 @@ jobs: - run: golangci-lint run --no-config other || true - run: golangci-lint run --no-config searches || true - run: golangci-lint run --no-config sorts - - run: golangci-lint run --no-config strings/... + # - run: golangci-lint run --no-config strings/... - run: golangci-lint run --no-config "strings/multiple string matching" || true # - run: golangci-lint run --no-config "strings/single string matching" || true + - run: golangci-lint run --no-config strings/levenshteindistance + - run: golangci-lint run --no-config strings/naivesearch From 6b860fc02a56aad5abe39469b3c581b2b348a6e7 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 12 Oct 2020 04:00:18 +0000 Subject: [PATCH 103/488] updating DIRECTORY.md --- DIRECTORY.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index b1d8f64c0..5d7ebb55e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -77,12 +77,16 @@ * [Topological Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/topological_sort.go) ## Strings - * [Levenshteindistance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteinDistance.go) + * Levenshteindistance + * [Levenshteindistance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteindistance/levenshteinDistance.go) + * [Levenshteindistance Test](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteindistance/levenshteinDistance_test.go) * Multiple String Matching * [Ac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/ac.go) * [Adac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/adac.go) * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/sbom.go) - * [Naivestringsearch](https://github.com/TheAlgorithms/Go/blob/master/strings/naiveStringSearch.go) + * Naivesearch + * [Naivestringsearch](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch.go) + * [Naivestringsearch Test](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch_test.go) * Single String Matching * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/bom.go) * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/horspool.go) From fd6a0655575b089347b233a434700ff5043e97df Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Mon, 12 Oct 2020 07:58:45 +0200 Subject: [PATCH 104/488] add tests for xor cipher (#218) Co-authored-by: Michele Caci --- ciphers/{ => xor}/xorCipher.go | 0 ciphers/xor/xor_cipher_test.go | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) rename ciphers/{ => xor}/xorCipher.go (100%) create mode 100644 ciphers/xor/xor_cipher_test.go diff --git a/ciphers/xorCipher.go b/ciphers/xor/xorCipher.go similarity index 100% rename from ciphers/xorCipher.go rename to ciphers/xor/xorCipher.go diff --git a/ciphers/xor/xor_cipher_test.go b/ciphers/xor/xor_cipher_test.go new file mode 100644 index 000000000..3e7c8e14e --- /dev/null +++ b/ciphers/xor/xor_cipher_test.go @@ -0,0 +1,86 @@ +package main + +import ( + "reflect" + "testing" +) + +var xorTestData = []struct { + description string + input string + key int + encrypted string +}{ + { + "Encrypt letter 'a' with key 0 makes no changes", + "a", + 0, + "a", + }, + { + "Encrypt letter 'a' with key 1", + "a", + 1, + "`", + }, + { + "Encrypt letter 'a' with key 10", + "a", + 10, + "k", + }, + { + "Encrypt 'hello world' with key 0 makes no changes", + "hello world", + 0, + "hello world", + }, + { + "Encrypt 'hello world' with key 1", + "hello world", + 1, + "idmmn!vnsme", + }, + { + "Encrypt 'hello world' with key 10", + "hello world", + 10, + "boffe*}exfn", + }, + { + "Encrypt full sentence with key 128", + "the quick brown fox jumps over the lazy dog.", + 64, + "4(%`15)#+`\"2/7.`&/8`*5-03`/6%2`4(%`,!:9`$/'n", + }, +} + +func TestXorCipherEncrypt(t *testing.T) { + for _, test := range xorTestData { + t.Run(test.description, func(t *testing.T) { + + message := toASCII([]rune(test.input)) + encrypted := encrypt(test.key, message) + + if actual := decodeToString(encrypted); !reflect.DeepEqual(actual, test.encrypted) { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expecting %s, actual %s", test.encrypted, actual) + } + }) + } +} + +func TestXorCipherDecrypt(t *testing.T) { + for _, test := range xorTestData { + t.Run(test.description, func(t *testing.T) { + + message := toASCII([]rune(test.encrypted)) + decrypted := decrypt(test.key, message) + + if actual := decodeToString(decrypted); !reflect.DeepEqual(actual, test.input) { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expecting %s, actual %s", test.input, actual) + } + }) + } +} From 659523b6e4e8c8cc1499d74051191f45b186781e Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 12 Oct 2020 05:59:01 +0000 Subject: [PATCH 105/488] updating DIRECTORY.md --- DIRECTORY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 5d7ebb55e..631df34bb 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -5,7 +5,9 @@ * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/Rot13.go) * [Rsacipher(Big)](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher(Big).go) * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher.go) - * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xorCipher.go) + * Xor + * [Xor Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xor_cipher_test.go) + * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xorCipher.go) ## Data-Structures * Binary-Tree From 8f09e1f2502476a0415c1fd48423f20569af4df5 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Mon, 12 Oct 2020 08:00:00 +0200 Subject: [PATCH 106/488] add tests for rsa cipher (#217) Co-authored-by: Michele Caci --- ciphers/{ => rsa}/RSAcipher.go | 0 ciphers/rsa/rsa_cipher_test.go | 63 ++++++++++++++++++++++++++ ciphers/{ => rsaBig}/RSAcipher(Big).go | 0 ciphers/rsaBig/rsa_cipher_big_test.go | 62 +++++++++++++++++++++++++ 4 files changed, 125 insertions(+) rename ciphers/{ => rsa}/RSAcipher.go (100%) create mode 100644 ciphers/rsa/rsa_cipher_test.go rename ciphers/{ => rsaBig}/RSAcipher(Big).go (100%) create mode 100644 ciphers/rsaBig/rsa_cipher_big_test.go diff --git a/ciphers/RSAcipher.go b/ciphers/rsa/RSAcipher.go similarity index 100% rename from ciphers/RSAcipher.go rename to ciphers/rsa/RSAcipher.go diff --git a/ciphers/rsa/rsa_cipher_test.go b/ciphers/rsa/rsa_cipher_test.go new file mode 100644 index 000000000..0bc7b64e1 --- /dev/null +++ b/ciphers/rsa/rsa_cipher_test.go @@ -0,0 +1,63 @@ +package main + +import ( + "math/rand" + "reflect" + "testing" + "time" +) + +var rsaTestData = []struct { + description string + input string +}{ + { + "Encrypt letter 'a'", + "a", + }, + { + "Encrypt 'hello world'", + "hello world", + }, + { + "Encrypt full sentence", + "the quick brown fox jumps over the lazy dog.", + }, + { + "Encrypt full sentence from RSAcipher.go main function", + "I think RSA is really great", + }, +} + +func TestRSACipher(t *testing.T) { + rand.Seed(time.Now().UTC().UnixNano()) + bits := 17 + + p := generatePrimes(1 << bits) + q := generatePrimes(1 << bits) + for p == q { + q = generatePrimes(1 << bits) + } + n := p * q + + delta := lcm(p-1, q-1) + + e := generatePrimes(delta) + d := modularMultiplicativeInverse(e, delta) + + for _, test := range rsaTestData { + t.Run(test.description, func(t *testing.T) { + + message := []rune(test.input) + expected := toASCII(message) + + encrypted := encryptRSA(expected, e, n) + decrypted := decryptRSA(encrypted, d, n) + + if actual := decrypted; !reflect.DeepEqual(actual, expected) { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expecting %v, actual %v", expected, actual) + } + }) + } +} diff --git a/ciphers/RSAcipher(Big).go b/ciphers/rsaBig/RSAcipher(Big).go similarity index 100% rename from ciphers/RSAcipher(Big).go rename to ciphers/rsaBig/RSAcipher(Big).go diff --git a/ciphers/rsaBig/rsa_cipher_big_test.go b/ciphers/rsaBig/rsa_cipher_big_test.go new file mode 100644 index 000000000..0625af846 --- /dev/null +++ b/ciphers/rsaBig/rsa_cipher_big_test.go @@ -0,0 +1,62 @@ +package main + +import ( + crypto "crypto/rand" + "math/big" + "testing" +) + +var rsaTestData = []struct { + description string + input string +}{ + { + "Encrypt letter 'a'", + "a", + }, + { + "Encrypt 'hello world'", + "hello world", + }, + { + "Encrypt full sentence", + "the quick brown fox jumps over the lazy dog.", + }, + { + "Encrypt full sentence from RSAcipher(Big).go main function", + "Black Lives Matter, all lives can't matter until Black lives matter", + }, +} + +func TestRSABigCipher(t *testing.T) { + p, _ := crypto.Prime(crypto.Reader, 1024) + q, _ := crypto.Prime(crypto.Reader, 1024) + n := new(big.Int).Mul(p, q) + + one := big.NewInt(1) + + delta := lcmBig(p.Sub(p, one), q.Sub(q, one)) + + e, _ := crypto.Prime(crypto.Reader, delta.BitLen()) + d := big.NewInt(0) + d.ModInverse(e, delta) + + for _, test := range rsaTestData { + t.Run(test.description, func(t *testing.T) { + + runes := []rune(test.input) + ASCIIs := toASCII(runes) + stringEncoded := stringEncode(ASCIIs) + bigNum, _ := new(big.Int).SetString(stringEncoded, 0) + + encrypted := encryptBig(bigNum, e, n) + decrypted := decryptBig(encrypted, d, n) + decryptASCIIs := stringDecode(decrypted) + + if actual := toRune(decryptASCIIs); actual != test.input { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expecting %s, actual %s", test.input, actual) + } + }) + } +} From e6864ff550dca54b5f43d58c2eac9dd4967180b3 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 12 Oct 2020 06:00:16 +0000 Subject: [PATCH 107/488] updating DIRECTORY.md --- DIRECTORY.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 631df34bb..217ba7798 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,8 +3,12 @@ * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/CaesarCipher.go) * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/Rot13.go) - * [Rsacipher(Big)](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher(Big).go) - * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/RSAcipher.go) + * Rsa + * [Rsa Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa/rsa_cipher_test.go) + * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa/RSAcipher.go) + * Rsabig + * [Rsa Cipher Big Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsaBig/rsa_cipher_big_test.go) + * [Rsacipher(Big)](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsaBig/RSAcipher(Big).go) * Xor * [Xor Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xor_cipher_test.go) * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xorCipher.go) From b1d27eb15610496bcf308e87c17d06c2770eae09 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 12 Oct 2020 06:22:02 +0000 Subject: [PATCH 108/488] updating DIRECTORY.md --- DIRECTORY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 217ba7798..15f7a2c7c 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,6 +1,8 @@ ## Ciphers - * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/CaesarCipher.go) + * Caesar + * [Caesar Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_test.go) + * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/CaesarCipher.go) * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/Rot13.go) * Rsa From b9e84b5ede43cbed077e23cb152e4c9abe80c2db Mon Sep 17 00:00:00 2001 From: Jobin John Date: Mon, 12 Oct 2020 21:11:50 +0530 Subject: [PATCH 109/488] Files refactored for lint compliance. Tests and benchmarks added. Signed-off-by: Jobin John --- .github/workflows/golangci-lint.yml | 4 ++ math/fastExponent.go | 49 -------------- math/gcd/greatest_common_divisor.go | 9 +++ math/gcd/greatest_common_divisor_test.go | 31 +++++++++ math/greatest_common_divisor.go | 17 ----- math/power/fastExponent.go | 39 +++++++++++ math/power/fastExponent_test.go | 67 +++++++++++++++++++ math/prime_check/prime_check_test.go | 44 ------------ .../prime_check.go | 12 ++-- math/primecheck/prime_check_test.go | 62 +++++++++++++++++ math/{ => sieve}/Sieve.go | 0 11 files changed, 217 insertions(+), 117 deletions(-) delete mode 100644 math/fastExponent.go create mode 100644 math/gcd/greatest_common_divisor.go create mode 100644 math/gcd/greatest_common_divisor_test.go delete mode 100644 math/greatest_common_divisor.go create mode 100644 math/power/fastExponent.go create mode 100644 math/power/fastExponent_test.go delete mode 100644 math/prime_check/prime_check_test.go rename math/{prime_check => primecheck}/prime_check.go (56%) create mode 100644 math/primecheck/prime_check_test.go rename math/{ => sieve}/Sieve.go (100%) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 8a75691f4..a2124cb87 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -34,3 +34,7 @@ jobs: # - run: golangci-lint run --no-config "strings/single string matching" || true - run: golangci-lint run --no-config strings/levenshteindistance - run: golangci-lint run --no-config strings/naivesearch + - run: golangci-lint run --no-config math/gcd + - run: golangci-lint run --no-config math/power + - run: golangci-lint run --no-config math/primecheck + - run: golangci-lint run --no-config math/sieve || true" diff --git a/math/fastExponent.go b/math/fastExponent.go deleted file mode 100644 index 0b8b0c882..000000000 --- a/math/fastExponent.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -//iterative O(logn) function for pow(x, y) -func IterativePower(n uint, power uint) uint { - var res uint = 1 - for power > 0 { - - if (power & 1) != 0 { - res = res * n - } - - power = power >> 1 - n = n * n - } - return res -} - -//recursive O(logn) function for pow(x, y) -func RecursivePower(n uint, power uint) uint { - if power == 0 { - return 1 - } - var temp = RecursivePower(n, power/2) - if power%2 == 0 { - return temp * temp - } else { - return n * temp * temp - } -} - - -//recursive O(n) function for pow(x, y) -func RecursivePower1( n uint, power uint) uint{ - if power == 0 { - return 1 - } else if power % 2 == 0 { - return RecursivePower1(n, power/2) * RecursivePower1(n, power/2) - } else - { - return n * RecursivePower1(n, power/2) * RecursivePower1(n, power/2) - } -} - -//Benchmarking Results -//goos: windows -//goarch: amd64 -//BenchmarkIterativePower-12 330048070 3.62 ns/op -//BenchmarkRecursivePower-12 124427038 9.63 ns/op -//BenchmarkRecursivePower1-12 20380434 58.5 ns/op diff --git a/math/gcd/greatest_common_divisor.go b/math/gcd/greatest_common_divisor.go new file mode 100644 index 000000000..ef22b1589 --- /dev/null +++ b/math/gcd/greatest_common_divisor.go @@ -0,0 +1,9 @@ +package gcd + +// Gcd finds and returns the greatest common divisor of a given integer. +func Gcd(a, b int) int { + if b == 0 { + return a + } + return Gcd(b, a%b) +} diff --git a/math/gcd/greatest_common_divisor_test.go b/math/gcd/greatest_common_divisor_test.go new file mode 100644 index 000000000..ef589fabe --- /dev/null +++ b/math/gcd/greatest_common_divisor_test.go @@ -0,0 +1,31 @@ +package gcd + +import "testing" + +var testCases = []struct { + name string + a int + b int + output int +}{ + {"gcd of 10 and 0", 10, 0, 10}, + {"gcd of 98 and 56", 98, 56, 14}, + {"gcd of 0 and 10", 0, 10, 10}, +} + +func TestGCD(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := Gcd(tc.a, tc.b) + if actual != tc.output { + t.Errorf("Expected GCD of %d and %d to be: %v, but got: %d", tc.a, tc.b, tc.output, actual) + } + }) + } +} + +func BenchmarkGCD(b *testing.B) { + for i := 0; i < b.N; i++ { + Gcd(98, 56) + } +} diff --git a/math/greatest_common_divisor.go b/math/greatest_common_divisor.go deleted file mode 100644 index ea5fe8a29..000000000 --- a/math/greatest_common_divisor.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "fmt" -) - -func gcd(a, b int) int { - if b == 0 { - return a - } - return gcd(b, a%b) - -} - -func main() { - fmt.Println(gcd(3, 99)) -} diff --git a/math/power/fastExponent.go b/math/power/fastExponent.go new file mode 100644 index 000000000..61e4660b4 --- /dev/null +++ b/math/power/fastExponent.go @@ -0,0 +1,39 @@ +package power + +// IterativePower is iterative O(logn) function for pow(x, y) +func IterativePower(n uint, power uint) uint { + var res uint = 1 + for power > 0 { + + if (power & 1) != 0 { + res = res * n + } + + power = power >> 1 + n = n * n + } + return res +} + +// RecursivePower is recursive O(logn) function for pow(x, y) +func RecursivePower(n uint, power uint) uint { + if power == 0 { + return 1 + } + var temp = RecursivePower(n, power/2) + if power%2 == 0 { + return temp * temp + } + return n * temp * temp +} + +// RecursivePower1 is recursive O(n) function for pow(x, y) +func RecursivePower1(n uint, power uint) uint { + if power == 0 { + return 1 + } else if power%2 == 0 { + return RecursivePower1(n, power/2) * RecursivePower1(n, power/2) + } else { + return n * RecursivePower1(n, power/2) * RecursivePower1(n, power/2) + } +} diff --git a/math/power/fastExponent_test.go b/math/power/fastExponent_test.go new file mode 100644 index 000000000..6a2f671eb --- /dev/null +++ b/math/power/fastExponent_test.go @@ -0,0 +1,67 @@ +package power + +import "testing" + +var testCases = []struct { + name string + base uint + power uint + expected uint +}{ + {"0^2", 0, 2, 0}, + {"2^0", 2, 0, 1}, + {"2^3", 2, 3, 8}, + {"8^3", 8, 3, 512}, + {"10^5", 10, 5, 100000}, +} + +func TestIterativePower(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := IterativePower(tc.base, tc.power) + if actual != tc.expected { + t.Errorf("Expected %d to the power of %d to be: %d, but got: %d", tc.base, tc.power, tc.expected, actual) + } + }) + } +} + +func TestRecursivePower(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := RecursivePower(tc.base, tc.power) + if actual != tc.expected { + t.Errorf("Expected %d to the power of %d to be: %d, but got: %d", tc.base, tc.power, tc.expected, actual) + } + }) + } +} + +func TestRecursivePower1(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := RecursivePower1(tc.base, tc.power) + if actual != tc.expected { + t.Errorf("Expected %d to the power of %d to be: %d, but got: %d", tc.base, tc.power, tc.expected, actual) + } + }) + } +} + +func BenchmarkIterativePower(b *testing.B) { + for i := 0; i < b.N; i++ { + IterativePower(10, 5) + } +} + +func BenchmarkRecursivePower(b *testing.B) { + for i := 0; i < b.N; i++ { + RecursivePower(10, 5) + } +} + +func BenchmarkRecursivePower1(b *testing.B) { + for i := 0; i < b.N; i++ { + RecursivePower1(10, 5) + } +} diff --git a/math/prime_check/prime_check_test.go b/math/prime_check/prime_check_test.go deleted file mode 100644 index 17f608ce1..000000000 --- a/math/prime_check/prime_check_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "testing" -) - -func TestTableNaiveApproach(t *testing.T) { - var tests = []struct { - input int - expected bool - }{ - {2, true}, - {3, true}, - {1, false}, - {10, false}, - {23, true}, - } - - for _, test := range tests { - if output := NaiveApproach(test.input); output != test.expected { - t.Error("Test Failed: {} inputted, {} expected, recieved: {}", test.input, test.expected, output) - } - } - -} -func TestTablePairApproach(t *testing.T) { - var tests = []struct { - input int - expected bool - }{ - {2, true}, - {3, true}, - {1, false}, - {10, false}, - {23, true}, - } - - for _, test := range tests { - if output := PairApproach(test.input); output != test.expected { - t.Error("Test Failed: {} inputted, {} expected, recieved: {}", test.input, test.expected, output) - } - } - -} diff --git a/math/prime_check/prime_check.go b/math/primecheck/prime_check.go similarity index 56% rename from math/prime_check/prime_check.go rename to math/primecheck/prime_check.go index b1656342b..6f03a5918 100644 --- a/math/prime_check/prime_check.go +++ b/math/primecheck/prime_check.go @@ -1,8 +1,10 @@ -//A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography. +package primecheck + +// A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography. //Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number is prime or not. //Source - Wikipedia https://en.wikipedia.org/wiki/Primality_test -package main +// NaiveApproach checks if an integer is prime or not. Returns a bool. func NaiveApproach(n int) bool { if n < 2 { return false @@ -16,6 +18,7 @@ func NaiveApproach(n int) bool { return true } +// PairApproach checks primality of an integer and returns a bool. More efficient than the naive approach as number of iterations are less. func PairApproach(n int) bool { if n < 2 { return false @@ -27,8 +30,3 @@ func PairApproach(n int) bool { } return true } - -//goos: windows -//goarch: amd64 -//BenchmarkNaiveApproach-12 660980034 1.81 ns/op -//BenchmarkPairApproach-12 664641356 1.82 ns/op diff --git a/math/primecheck/prime_check_test.go b/math/primecheck/prime_check_test.go new file mode 100644 index 000000000..62c8105e0 --- /dev/null +++ b/math/primecheck/prime_check_test.go @@ -0,0 +1,62 @@ +package primecheck + +import ( + "testing" +) + +func TestTableNaiveApproach(t *testing.T) { + var tests = []struct { + name string + input int + expected bool + }{ + {"smallest prime", 2, true}, + {"random prime", 3, true}, + {"neither prime nor composite", 1, false}, + {"random non-prime", 10, false}, + {"another random prime", 23, true}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if output := NaiveApproach(test.input); output != test.expected { + t.Errorf("For input: %d, expected: %v, but got: %v", test.input, test.expected, output) + } + }) + } + +} +func TestTablePairApproach(t *testing.T) { + var tests = []struct { + name string + input int + expected bool + }{ + {"smallest prime", 2, true}, + {"random prime", 3, true}, + {"neither prime nor composite", 1, false}, + {"random non-prime", 10, false}, + {"another random prime", 23, true}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if output := NaiveApproach(test.input); output != test.expected { + t.Errorf("For input: %d, expected: %v, but got: %v", test.input, test.expected, output) + } + }) + } + +} + +func BenchmarkNaiveApproach(b *testing.B) { + for i := 0; i < b.N; i++ { + NaiveApproach(23) + } +} + +func BenchmarkPairApproach(b *testing.B) { + for i := 0; i < b.N; i++ { + PairApproach(23) + } +} diff --git a/math/Sieve.go b/math/sieve/Sieve.go similarity index 100% rename from math/Sieve.go rename to math/sieve/Sieve.go From 9e6a93c106bb05c7599efa976fc41e1de45d0814 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Mon, 12 Oct 2020 21:19:24 +0530 Subject: [PATCH 110/488] Removed a stray quote. Signed-off-by: Jobin John --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index a2124cb87..73e35bfe2 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -37,4 +37,4 @@ jobs: - run: golangci-lint run --no-config math/gcd - run: golangci-lint run --no-config math/power - run: golangci-lint run --no-config math/primecheck - - run: golangci-lint run --no-config math/sieve || true" + - run: golangci-lint run --no-config math/sieve || true From 4c3473da661290218bb3d3bddc0b1b6f12a7c911 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Mon, 12 Oct 2020 21:48:06 +0530 Subject: [PATCH 111/488] Files refactored for lint compliance. Tests and benchmarks added. (#221) * Files refactored for lint compliance. Tests and benchmarks added. Signed-off-by: Jobin John * Removed a stray quote. Signed-off-by: Jobin John --- .github/workflows/golangci-lint.yml | 4 ++ math/fastExponent.go | 49 -------------- math/gcd/greatest_common_divisor.go | 9 +++ math/gcd/greatest_common_divisor_test.go | 31 +++++++++ math/greatest_common_divisor.go | 17 ----- math/power/fastExponent.go | 39 +++++++++++ math/power/fastExponent_test.go | 67 +++++++++++++++++++ math/prime_check/prime_check_test.go | 44 ------------ .../prime_check.go | 12 ++-- math/primecheck/prime_check_test.go | 62 +++++++++++++++++ math/{ => sieve}/Sieve.go | 0 11 files changed, 217 insertions(+), 117 deletions(-) delete mode 100644 math/fastExponent.go create mode 100644 math/gcd/greatest_common_divisor.go create mode 100644 math/gcd/greatest_common_divisor_test.go delete mode 100644 math/greatest_common_divisor.go create mode 100644 math/power/fastExponent.go create mode 100644 math/power/fastExponent_test.go delete mode 100644 math/prime_check/prime_check_test.go rename math/{prime_check => primecheck}/prime_check.go (56%) create mode 100644 math/primecheck/prime_check_test.go rename math/{ => sieve}/Sieve.go (100%) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 8a75691f4..73e35bfe2 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -34,3 +34,7 @@ jobs: # - run: golangci-lint run --no-config "strings/single string matching" || true - run: golangci-lint run --no-config strings/levenshteindistance - run: golangci-lint run --no-config strings/naivesearch + - run: golangci-lint run --no-config math/gcd + - run: golangci-lint run --no-config math/power + - run: golangci-lint run --no-config math/primecheck + - run: golangci-lint run --no-config math/sieve || true diff --git a/math/fastExponent.go b/math/fastExponent.go deleted file mode 100644 index 0b8b0c882..000000000 --- a/math/fastExponent.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -//iterative O(logn) function for pow(x, y) -func IterativePower(n uint, power uint) uint { - var res uint = 1 - for power > 0 { - - if (power & 1) != 0 { - res = res * n - } - - power = power >> 1 - n = n * n - } - return res -} - -//recursive O(logn) function for pow(x, y) -func RecursivePower(n uint, power uint) uint { - if power == 0 { - return 1 - } - var temp = RecursivePower(n, power/2) - if power%2 == 0 { - return temp * temp - } else { - return n * temp * temp - } -} - - -//recursive O(n) function for pow(x, y) -func RecursivePower1( n uint, power uint) uint{ - if power == 0 { - return 1 - } else if power % 2 == 0 { - return RecursivePower1(n, power/2) * RecursivePower1(n, power/2) - } else - { - return n * RecursivePower1(n, power/2) * RecursivePower1(n, power/2) - } -} - -//Benchmarking Results -//goos: windows -//goarch: amd64 -//BenchmarkIterativePower-12 330048070 3.62 ns/op -//BenchmarkRecursivePower-12 124427038 9.63 ns/op -//BenchmarkRecursivePower1-12 20380434 58.5 ns/op diff --git a/math/gcd/greatest_common_divisor.go b/math/gcd/greatest_common_divisor.go new file mode 100644 index 000000000..ef22b1589 --- /dev/null +++ b/math/gcd/greatest_common_divisor.go @@ -0,0 +1,9 @@ +package gcd + +// Gcd finds and returns the greatest common divisor of a given integer. +func Gcd(a, b int) int { + if b == 0 { + return a + } + return Gcd(b, a%b) +} diff --git a/math/gcd/greatest_common_divisor_test.go b/math/gcd/greatest_common_divisor_test.go new file mode 100644 index 000000000..ef589fabe --- /dev/null +++ b/math/gcd/greatest_common_divisor_test.go @@ -0,0 +1,31 @@ +package gcd + +import "testing" + +var testCases = []struct { + name string + a int + b int + output int +}{ + {"gcd of 10 and 0", 10, 0, 10}, + {"gcd of 98 and 56", 98, 56, 14}, + {"gcd of 0 and 10", 0, 10, 10}, +} + +func TestGCD(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := Gcd(tc.a, tc.b) + if actual != tc.output { + t.Errorf("Expected GCD of %d and %d to be: %v, but got: %d", tc.a, tc.b, tc.output, actual) + } + }) + } +} + +func BenchmarkGCD(b *testing.B) { + for i := 0; i < b.N; i++ { + Gcd(98, 56) + } +} diff --git a/math/greatest_common_divisor.go b/math/greatest_common_divisor.go deleted file mode 100644 index ea5fe8a29..000000000 --- a/math/greatest_common_divisor.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "fmt" -) - -func gcd(a, b int) int { - if b == 0 { - return a - } - return gcd(b, a%b) - -} - -func main() { - fmt.Println(gcd(3, 99)) -} diff --git a/math/power/fastExponent.go b/math/power/fastExponent.go new file mode 100644 index 000000000..61e4660b4 --- /dev/null +++ b/math/power/fastExponent.go @@ -0,0 +1,39 @@ +package power + +// IterativePower is iterative O(logn) function for pow(x, y) +func IterativePower(n uint, power uint) uint { + var res uint = 1 + for power > 0 { + + if (power & 1) != 0 { + res = res * n + } + + power = power >> 1 + n = n * n + } + return res +} + +// RecursivePower is recursive O(logn) function for pow(x, y) +func RecursivePower(n uint, power uint) uint { + if power == 0 { + return 1 + } + var temp = RecursivePower(n, power/2) + if power%2 == 0 { + return temp * temp + } + return n * temp * temp +} + +// RecursivePower1 is recursive O(n) function for pow(x, y) +func RecursivePower1(n uint, power uint) uint { + if power == 0 { + return 1 + } else if power%2 == 0 { + return RecursivePower1(n, power/2) * RecursivePower1(n, power/2) + } else { + return n * RecursivePower1(n, power/2) * RecursivePower1(n, power/2) + } +} diff --git a/math/power/fastExponent_test.go b/math/power/fastExponent_test.go new file mode 100644 index 000000000..6a2f671eb --- /dev/null +++ b/math/power/fastExponent_test.go @@ -0,0 +1,67 @@ +package power + +import "testing" + +var testCases = []struct { + name string + base uint + power uint + expected uint +}{ + {"0^2", 0, 2, 0}, + {"2^0", 2, 0, 1}, + {"2^3", 2, 3, 8}, + {"8^3", 8, 3, 512}, + {"10^5", 10, 5, 100000}, +} + +func TestIterativePower(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := IterativePower(tc.base, tc.power) + if actual != tc.expected { + t.Errorf("Expected %d to the power of %d to be: %d, but got: %d", tc.base, tc.power, tc.expected, actual) + } + }) + } +} + +func TestRecursivePower(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := RecursivePower(tc.base, tc.power) + if actual != tc.expected { + t.Errorf("Expected %d to the power of %d to be: %d, but got: %d", tc.base, tc.power, tc.expected, actual) + } + }) + } +} + +func TestRecursivePower1(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := RecursivePower1(tc.base, tc.power) + if actual != tc.expected { + t.Errorf("Expected %d to the power of %d to be: %d, but got: %d", tc.base, tc.power, tc.expected, actual) + } + }) + } +} + +func BenchmarkIterativePower(b *testing.B) { + for i := 0; i < b.N; i++ { + IterativePower(10, 5) + } +} + +func BenchmarkRecursivePower(b *testing.B) { + for i := 0; i < b.N; i++ { + RecursivePower(10, 5) + } +} + +func BenchmarkRecursivePower1(b *testing.B) { + for i := 0; i < b.N; i++ { + RecursivePower1(10, 5) + } +} diff --git a/math/prime_check/prime_check_test.go b/math/prime_check/prime_check_test.go deleted file mode 100644 index 17f608ce1..000000000 --- a/math/prime_check/prime_check_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "testing" -) - -func TestTableNaiveApproach(t *testing.T) { - var tests = []struct { - input int - expected bool - }{ - {2, true}, - {3, true}, - {1, false}, - {10, false}, - {23, true}, - } - - for _, test := range tests { - if output := NaiveApproach(test.input); output != test.expected { - t.Error("Test Failed: {} inputted, {} expected, recieved: {}", test.input, test.expected, output) - } - } - -} -func TestTablePairApproach(t *testing.T) { - var tests = []struct { - input int - expected bool - }{ - {2, true}, - {3, true}, - {1, false}, - {10, false}, - {23, true}, - } - - for _, test := range tests { - if output := PairApproach(test.input); output != test.expected { - t.Error("Test Failed: {} inputted, {} expected, recieved: {}", test.input, test.expected, output) - } - } - -} diff --git a/math/prime_check/prime_check.go b/math/primecheck/prime_check.go similarity index 56% rename from math/prime_check/prime_check.go rename to math/primecheck/prime_check.go index b1656342b..6f03a5918 100644 --- a/math/prime_check/prime_check.go +++ b/math/primecheck/prime_check.go @@ -1,8 +1,10 @@ -//A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography. +package primecheck + +// A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography. //Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number is prime or not. //Source - Wikipedia https://en.wikipedia.org/wiki/Primality_test -package main +// NaiveApproach checks if an integer is prime or not. Returns a bool. func NaiveApproach(n int) bool { if n < 2 { return false @@ -16,6 +18,7 @@ func NaiveApproach(n int) bool { return true } +// PairApproach checks primality of an integer and returns a bool. More efficient than the naive approach as number of iterations are less. func PairApproach(n int) bool { if n < 2 { return false @@ -27,8 +30,3 @@ func PairApproach(n int) bool { } return true } - -//goos: windows -//goarch: amd64 -//BenchmarkNaiveApproach-12 660980034 1.81 ns/op -//BenchmarkPairApproach-12 664641356 1.82 ns/op diff --git a/math/primecheck/prime_check_test.go b/math/primecheck/prime_check_test.go new file mode 100644 index 000000000..62c8105e0 --- /dev/null +++ b/math/primecheck/prime_check_test.go @@ -0,0 +1,62 @@ +package primecheck + +import ( + "testing" +) + +func TestTableNaiveApproach(t *testing.T) { + var tests = []struct { + name string + input int + expected bool + }{ + {"smallest prime", 2, true}, + {"random prime", 3, true}, + {"neither prime nor composite", 1, false}, + {"random non-prime", 10, false}, + {"another random prime", 23, true}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if output := NaiveApproach(test.input); output != test.expected { + t.Errorf("For input: %d, expected: %v, but got: %v", test.input, test.expected, output) + } + }) + } + +} +func TestTablePairApproach(t *testing.T) { + var tests = []struct { + name string + input int + expected bool + }{ + {"smallest prime", 2, true}, + {"random prime", 3, true}, + {"neither prime nor composite", 1, false}, + {"random non-prime", 10, false}, + {"another random prime", 23, true}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if output := NaiveApproach(test.input); output != test.expected { + t.Errorf("For input: %d, expected: %v, but got: %v", test.input, test.expected, output) + } + }) + } + +} + +func BenchmarkNaiveApproach(b *testing.B) { + for i := 0; i < b.N; i++ { + NaiveApproach(23) + } +} + +func BenchmarkPairApproach(b *testing.B) { + for i := 0; i < b.N; i++ { + PairApproach(23) + } +} diff --git a/math/Sieve.go b/math/sieve/Sieve.go similarity index 100% rename from math/Sieve.go rename to math/sieve/Sieve.go From 54b22a07f3658aae4e05b3085227b45e71fc936a Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 12 Oct 2020 16:18:22 +0000 Subject: [PATCH 112/488] updating DIRECTORY.md --- DIRECTORY.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 15f7a2c7c..d73fe5054 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -46,12 +46,17 @@ * [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall.go) ## Math - * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/fastExponent.go) - * [Greatest Common Divisor](https://github.com/TheAlgorithms/Go/blob/master/math/greatest_common_divisor.go) - * Prime Check - * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/prime_check/prime_check.go) - * [Prime Check Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime_check/prime_check_test.go) - * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/Sieve.go) + * Gcd + * [Greatest Common Divisor](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/greatest_common_divisor.go) + * [Greatest Common Divisor Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/greatest_common_divisor_test.go) + * Power + * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastExponent.go) + * [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastExponent_test.go) + * Primecheck + * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/prime_check.go) + * [Prime Check Test](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/prime_check_test.go) + * Sieve + * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/Sieve.go) ## Other * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxSubarraySum.go) From 979c4693e3d47b3601acaa24696d711fe55b23c4 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Sun, 11 Oct 2020 15:46:16 +0200 Subject: [PATCH 113/488] tests for rot13 algorithm --- ciphers/{Rot13.go => rot13/rot13.go} | 10 +--- ciphers/rot13/rot13_test.go | 70 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 9 deletions(-) rename ciphers/{Rot13.go => rot13/rot13.go} (57%) create mode 100644 ciphers/rot13/rot13_test.go diff --git a/ciphers/Rot13.go b/ciphers/rot13/rot13.go similarity index 57% rename from ciphers/Rot13.go rename to ciphers/rot13/rot13.go index adc29cb38..30ac8a875 100644 --- a/ciphers/Rot13.go +++ b/ciphers/rot13/rot13.go @@ -1,8 +1,7 @@ -package main +package rot13 import ( "bytes" - "fmt" "strings" ) @@ -24,11 +23,4 @@ func rot13(input string) string { outputBuffer.WriteString(string(newByte)) } return outputBuffer.String() - -} -func main() { - cleartext := "We'll just make him an offer he can't refuse... tell me you get the pop culture reference" - encrypted := rot13(cleartext) - decrypted := rot13(encrypted) - fmt.Printf("Cleartext: %v\nencrypted: %v\ndecrypted: %v\n", cleartext, encrypted, decrypted) } diff --git a/ciphers/rot13/rot13_test.go b/ciphers/rot13/rot13_test.go new file mode 100644 index 000000000..1e5716357 --- /dev/null +++ b/ciphers/rot13/rot13_test.go @@ -0,0 +1,70 @@ +package rot13 + +import ( + "testing" +) + +var rot13TestData = []struct { + description string + input string + expected string +}{ + { + "Basic rotation with letter 'a' gives 'n", + "a", + "n", + }, + { + "Rotation with wrapping around alphabet on letter 'z' gives 'm'", + "z", + "m", + }, + { + "Rotation on 'hello world'", + "hello world", + "uryyb jbeyq", + }, + { + "Rotation on the rotation of 'hello world' gives 'hello world' back", + "uryyb jbeyq", + "hello world", + }, + { + "Full sentence rotation", + "the quick brown fox jumps over the lazy dog.", + "gur dhvpx oebja sbk whzcf bire gur ynml qbt.", + }, + { + "Sentence from Rot13.go main function", + "we'll just make him an offer he can't refuse... tell me you get the pop culture reference", + "jr'yy whfg znxr uvz na bssre ur pna'g ershfr... gryy zr lbh trg gur cbc phygher ersrerapr", + }, +} + +func TestRot13Encrypt(t *testing.T) { + for _, test := range rot13TestData { + t.Run(test.description, func(t *testing.T) { + input := test.input + expected := test.expected + assertRot13Output(t, input, expected) + }) + } +} + +func TestRot13Decrypt(t *testing.T) { + for _, test := range rot13TestData { + t.Run(test.description, func(t *testing.T) { + input := test.expected + expected := test.input + assertRot13Output(t, input, expected) + }) + } +} + +func assertRot13Output(t *testing.T, input, expected string) { + actual := rot13(input) + if actual != expected { + t.Fatalf("With input string '%s' was expecting '%s' but actual was '%s'", + input, expected, actual) + } +} From e43e5324cadecfd8b1e6bb0c07d6ef719a7c2498 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 13 Oct 2020 07:20:58 +0000 Subject: [PATCH 114/488] updating DIRECTORY.md --- DIRECTORY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index d73fe5054..c805389d7 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -4,7 +4,9 @@ * [Caesar Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_test.go) * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/CaesarCipher.go) * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) - * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/Rot13.go) + * Rot13 + * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13.go) + * [Rot13 Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13_test.go) * Rsa * [Rsa Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa/rsa_cipher_test.go) * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa/RSAcipher.go) From bc8315f6b55419b3b96401d5e3b0ce0636cc0727 Mon Sep 17 00:00:00 2001 From: localleon Date: Wed, 14 Oct 2020 19:27:00 +0200 Subject: [PATCH 115/488] Added Pythagoras Theorem (#205) * Added Pythagoras Theorem * Removed Main, changed package name * Exported Vector Struct for external use * TableDriven Test, better float64 handling * Parallel Testing, fixed leftover math.Abs function --- math/pythagoras/pythagoras.go | 18 +++++++++++++++ math/pythagoras/pythagoras_test.go | 37 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 math/pythagoras/pythagoras.go create mode 100644 math/pythagoras/pythagoras_test.go diff --git a/math/pythagoras/pythagoras.go b/math/pythagoras/pythagoras.go new file mode 100644 index 000000000..fb3c51c4c --- /dev/null +++ b/math/pythagoras/pythagoras.go @@ -0,0 +1,18 @@ +package pythagoras + +import ( + "math" +) + +//Vector defines a tuple with 3 values in 3d-space +type Vector struct { + x float64 + y float64 + z float64 +} + +//Distance calculates the distance between to vectors with the Pythagoras theorem +func Distance(a, b Vector) float64 { + res := math.Pow(b.x-a.x, 2.0) + math.Pow(b.y-a.y, 2.0) + math.Pow(b.z-a.z, 2.0) + return math.Sqrt(res) +} diff --git a/math/pythagoras/pythagoras_test.go b/math/pythagoras/pythagoras_test.go new file mode 100644 index 000000000..1ae7e1185 --- /dev/null +++ b/math/pythagoras/pythagoras_test.go @@ -0,0 +1,37 @@ +package pythagoras + +import ( + "math" + "testing" +) + +// TableDrivenTest for checking multiple values against our Test Function +var distanceTest = []struct { + name string + v1 Vector + v2 Vector + res float64 +}{ + {"random negative vector", Vector{2, -1, 7}, Vector{1, -3, 5}, 3.0}, + {"random wide vectors", Vector{4, 10, 9}, Vector{4, 3, 5}, 8.06}, + {"random wide vectors", Vector{8, 5, 5}, Vector{1, 1, 12}, 10.67}, + {"random short vectors", Vector{1, 1, 1}, Vector{2, 2, 2}, 1.73}, +} + +//TestDistance tests the Function Distance with 2 vectors +func TestDistance(t *testing.T) { + t.Parallel() // marks TestDistance as capable of running in parallel with other tests + for _, tt := range distanceTest { + tt := tt // NOTE: https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := Distance(tt.v1, tt.v2) // Calculate result for + roundRes := (math.Floor(res*100) / 100) // Round to 2 decimal places because we can't compare an infinite number of places + // Check result + if roundRes != tt.res { + t.Errorf("Distance(%v, %v) = %f, expected %f", + tt.v1, tt.v2, roundRes, tt.res) + } + }) + } +} From 0519b414ef4c3bbc5bdaccd7159957108336943d Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Wed, 14 Oct 2020 17:27:18 +0000 Subject: [PATCH 116/488] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index c805389d7..9f04752e2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -57,6 +57,9 @@ * Primecheck * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/prime_check.go) * [Prime Check Test](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/prime_check_test.go) + * Pythagoras + * [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras.go) + * [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go) * Sieve * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/Sieve.go) From 76a97f5ba0de65d18d6f5f153c9d353a080aa1b9 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 14 Oct 2020 20:21:24 +0200 Subject: [PATCH 117/488] golangci/golangci-lint-action@v2 --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 73e35bfe2..9afcf3160 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: golangci-lint - uses: golangci/golangci-lint-action@v1 + uses: golangci/golangci-lint-action@v2 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. version: v1.27 From f7a53973af0d263fe0c2397783d04a45e749ae43 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 14 Oct 2020 20:26:38 +0200 Subject: [PATCH 118/488] Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 9afcf3160..ffac64633 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -12,7 +12,7 @@ jobs: uses: golangci/golangci-lint-action@v2 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.27 + version: v1.31.0 working-directory: sorts args: --issues-exit-code=0 # Hopefully someday we can remove this... # Only show new issues if this is a pull request... From 14d7ed8c17f70127d987705000fc424ee7e0a5dc Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 14 Oct 2020 20:27:44 +0200 Subject: [PATCH 119/488] Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index ffac64633..444a608b3 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -12,7 +12,7 @@ jobs: uses: golangci/golangci-lint-action@v2 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.31.0 + version: v1.31 working-directory: sorts args: --issues-exit-code=0 # Hopefully someday we can remove this... # Only show new issues if this is a pull request... From 89d3288025630df860d67478c5779f1e7fb885f3 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 14 Oct 2020 20:30:32 +0200 Subject: [PATCH 120/488] Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 444a608b3..40fff4c40 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -17,7 +17,6 @@ jobs: args: --issues-exit-code=0 # Hopefully someday we can remove this... # Only show new issues if this is a pull request... # only-new-issues: true - - run: echo "::set-env name=PATH::/home/runner/golangci-lint-1.27.0-linux-amd64:$PATH" - run: go version ; golangci-lint --version # Fix the following and remove || true - run: golangci-lint run --no-config ciphers || true - run: golangci-lint run --no-config data-structures/binary-tree || true From 28bdc6c17b824bbbff3092f92a50d43c2a904c1c Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 14 Oct 2020 20:33:10 +0200 Subject: [PATCH 121/488] Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 40fff4c40..6d70c40e3 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -9,15 +9,16 @@ jobs: steps: - uses: actions/checkout@v2 - name: golangci-lint - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v1 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.31 + version: v1.27 working-directory: sorts args: --issues-exit-code=0 # Hopefully someday we can remove this... - # Only show new issues if this is a pull request... + # Only show new issues if this is a pull request... # only-new-issues: true - - run: go version ; golangci-lint --version # Fix the following and remove || true + - run: echo "::set-env name=PATH::/home/runner/golangci-lint-1.27.0-linux-amd64:$PATH" + - run: go version ; golangci-lint --version # Fix the following and remove || true - run: golangci-lint run --no-config ciphers || true - run: golangci-lint run --no-config data-structures/binary-tree || true - run: golangci-lint run --no-config data-structures/dynamic-array || true @@ -30,7 +31,7 @@ jobs: - run: golangci-lint run --no-config sorts # - run: golangci-lint run --no-config strings/... - run: golangci-lint run --no-config "strings/multiple string matching" || true - # - run: golangci-lint run --no-config "strings/single string matching" || true + # - run: golangci-lint run --no-config "strings/single string matching" || true - run: golangci-lint run --no-config strings/levenshteindistance - run: golangci-lint run --no-config strings/naivesearch - run: golangci-lint run --no-config math/gcd From 4925b41651db2f4b7edecda99f0c0b67ee066598 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 14 Oct 2020 22:08:30 +0200 Subject: [PATCH 122/488] Upgrade golangci/golangci-lint-action@v2 (#222) * Upgrade golangci/golangci-lint-action@v2 * actions/setup-go@v2 * Update golangci-lint.yml * Update golangci-lint.yml * Update golangci-lint.yml * Update golangci-lint.yml * Update golangci-lint.yml * gosimple change * gosimple change * Update golangci-lint.yml --- .github/workflows/golangci-lint.yml | 17 ++++++++--------- data-structures/hash-map/hash_map.go | 7 +------ math/sieve/Sieve.go | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 6d70c40e3..ece101928 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -8,21 +8,20 @@ jobs: fail-fast: false steps: - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v1 + - uses: actions/setup-go@v2 + - uses: golangci/golangci-lint-action@v2 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.27 - working-directory: sorts + version: v1.31 args: --issues-exit-code=0 # Hopefully someday we can remove this... - # Only show new issues if this is a pull request... - # only-new-issues: true - - run: echo "::set-env name=PATH::/home/runner/golangci-lint-1.27.0-linux-amd64:$PATH" + working-directory: sorts # Hopefully someday we can remove this... and enable only-new-issues + # only-new-issues: true # Let's focus on this PR first + - run: echo "/home/runner/golangci-lint-1.31.0-linux-amd64" >> $GITHUB_PATH - run: go version ; golangci-lint --version # Fix the following and remove || true - - run: golangci-lint run --no-config ciphers || true + - run: golangci-lint run --no-config ciphers - run: golangci-lint run --no-config data-structures/binary-tree || true - run: golangci-lint run --no-config data-structures/dynamic-array || true - - run: golangci-lint run --no-config data-structures/hash-map || true + - run: golangci-lint run --no-config data-structures/hash-map - run: golangci-lint run --no-config data-structures/linked-list || true - run: golangci-lint run --no-config data-structures/trie || true - run: golangci-lint run --no-config dynamic-programming || true diff --git a/data-structures/hash-map/hash_map.go b/data-structures/hash-map/hash_map.go index cc3263c8d..bd03e641f 100644 --- a/data-structures/hash-map/hash_map.go +++ b/data-structures/hash-map/hash_map.go @@ -47,12 +47,7 @@ func (hm *HashMap) Put(key interface{}, value interface{}) interface{} { // Contains checks if given key is stored in hashmap func (hm *HashMap) Contains(key interface{}) bool { node := hm.getNodeByHash(hm.hash(key)) - - if node != nil { - return true - } - - return false + return node != nil } func (hm *HashMap) putValue(hash uint64, key interface{}, value interface{}) interface{} { diff --git a/math/sieve/Sieve.go b/math/sieve/Sieve.go index 80a81cf13..0162c3a4d 100644 --- a/math/sieve/Sieve.go +++ b/math/sieve/Sieve.go @@ -42,7 +42,7 @@ func nextF(f int, r chan int, nums []bool) { for { <-r for i, v := range nums[f:] { - if v == true { + if v { r <- i + f } } From ac4b511a147fc84b4f0256b7c0fcb9933cf88bad Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 15 Oct 2020 11:08:09 +0200 Subject: [PATCH 123/488] Enable .github/CODEOWNERS @TheAlgorithms/go_maintainers The Go repo is now using [CODEOWNERS](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/about-code-owners) which will automatically request a review when someone opens a (non-draft) pull request in a directory that you own. So if you are interested in a particular directory then please @mention yourself after that directory. This is voluntary but it should help us to do a divide-and-conquer on all these Hacktoberfest pull requests. --- .github/CODEOWNERS | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..6cbcd7048 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,19 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# More details are here: https://help.github.com/articles/about-codeowners/ + +# The '*' pattern is global owners. + +# Order is important. The last matching pattern has the most precedence. + +/.* @cclauss +/ciphers/ +/data-structures/ +/dynamic-programming/ +/graphs/ +/math/ +/other/ +/searches/ +/sorts/ +/strings/ @Mystigan From 249abe54a859510d3a069b9dec3d8891f2ed8af7 Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Thu, 15 Oct 2020 19:44:16 +0530 Subject: [PATCH 124/488] Update CODEOWNERS (#223) --- .github/CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6cbcd7048..bb3ca85d0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,9 +10,9 @@ /.* @cclauss /ciphers/ /data-structures/ -/dynamic-programming/ -/graphs/ -/math/ +/dynamic-programming/ @vedantmamgain +/graphs/ @vedantmamgain +/math/ @vedantmamgain /other/ /searches/ /sorts/ From 3d00230d606348a3c084ae172abb68152e43abce Mon Sep 17 00:00:00 2001 From: Jobin John Date: Thu, 15 Oct 2020 20:21:35 +0530 Subject: [PATCH 125/488] Update CODEOWNERS (#224) I am still in the process of learning DS and algorithms myself. Currently, attached myself to topics that I can comment on directly or with some research. Will add more as I expand my knowledge. --- .github/CODEOWNERS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bb3ca85d0..0755f7541 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,11 +9,11 @@ /.* @cclauss /ciphers/ -/data-structures/ +/data-structures/ @Mystigan /dynamic-programming/ @vedantmamgain /graphs/ @vedantmamgain -/math/ @vedantmamgain +/math/ @vedantmamgain @Mystigan /other/ -/searches/ -/sorts/ -/strings/ @Mystigan +/searches/ @Mystigan +/sorts/ @Mystigan +/strings/ From dad2ef2dba781b25e3094351d406750f11c5fb87 Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Sat, 17 Oct 2020 12:57:37 +0530 Subject: [PATCH 126/488] Update CODEOWNERS (#230) --- .github/CODEOWNERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0755f7541..baf4f9bf5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,12 +8,12 @@ # Order is important. The last matching pattern has the most precedence. /.* @cclauss -/ciphers/ -/data-structures/ @Mystigan +/ciphers/ @vedantmamgain +/data-structures/ @Mystigan @vedantmamgain /dynamic-programming/ @vedantmamgain /graphs/ @vedantmamgain /math/ @vedantmamgain @Mystigan -/other/ +/other/ @vedantmamgain /searches/ @Mystigan /sorts/ @Mystigan -/strings/ +/strings/ @vedantmamgain From b65657ee21817ecfdbfa34d5b0c0f9d7c24ab057 Mon Sep 17 00:00:00 2001 From: WilliamChang80 Date: Fri, 16 Oct 2020 23:40:06 +0700 Subject: [PATCH 127/488] Added test case for kmp algorithm --- .../bom.go | 0 .../horspool.go | 0 .../kmp}/kmp.go | 72 +++++++++++-------- .../single-string-matching/kmp/kmp_test.go | 53 ++++++++++++++ .../pattern.txt | 0 .../text.txt | 0 6 files changed, 96 insertions(+), 29 deletions(-) rename strings/{single string matching => single-string-matching}/bom.go (100%) rename strings/{single string matching => single-string-matching}/horspool.go (100%) rename strings/{single string matching => single-string-matching/kmp}/kmp.go (56%) create mode 100644 strings/single-string-matching/kmp/kmp_test.go rename strings/{single string matching => single-string-matching}/pattern.txt (100%) rename strings/{single string matching => single-string-matching}/text.txt (100%) diff --git a/strings/single string matching/bom.go b/strings/single-string-matching/bom.go similarity index 100% rename from strings/single string matching/bom.go rename to strings/single-string-matching/bom.go diff --git a/strings/single string matching/horspool.go b/strings/single-string-matching/horspool.go similarity index 100% rename from strings/single string matching/horspool.go rename to strings/single-string-matching/horspool.go diff --git a/strings/single string matching/kmp.go b/strings/single-string-matching/kmp/kmp.go similarity index 56% rename from strings/single string matching/kmp.go rename to strings/single-string-matching/kmp/kmp.go index 181be53a2..0ce14a8dc 100644 --- a/strings/single string matching/kmp.go +++ b/strings/single-string-matching/kmp/kmp.go @@ -1,4 +1,4 @@ -package main +package kmp import ( "fmt" @@ -10,53 +10,65 @@ import ( // User defined. // Set to true to read input from two command line arguments // Set to false to read input from two files "pattern.txt" and "text.txt" -const commandLineInput bool = false +const isTakingInputFromCommandLine bool = true +const notFoundPosition int = -1 + +type result struct { + resultPosition int + numberOfComparison int +} // Implementation of Knuth-Morris-Pratt algorithm (Prefix based approach). // Requires either a two command line arguments separated by a single space, // or two files in the same folder: "pattern.txt" containing the string to // be searched for, "text.txt" containing the text to be searched in. func main() { - if commandLineInput == true { // case of command line input + var text string + var word string + + if isTakingInputFromCommandLine { // case of command line input args := os.Args if len(args) <= 2 { log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") } - pattern := args[1] - s := args[2] + word = args[1] + text = args[2] for i := 3; i < len(args); i++ { - s = s + " " + args[i] + text = text + " " + args[i] } - if len(args[1]) > len(s) { - log.Fatal("Pattern is longer than text!") - } - fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") - fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) - fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) - knp(s, pattern) - } else if commandLineInput == false { // case of file input - patFile, err := ioutil.ReadFile("pattern.txt") + } else { // case of file input + patFile, err := ioutil.ReadFile("../pattern.txt") if err != nil { log.Fatal(err) } - textFile, err := ioutil.ReadFile("text.txt") + textFile, err := ioutil.ReadFile("../text.txt") if err != nil { log.Fatal(err) } - if len(patFile) > len(textFile) { - log.Fatal("Pattern is longer than text!") - } - fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") - fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) - fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) - knp(string(textFile), string(patFile)) + text = string(textFile) + word = string(patFile) + } + + if len(word) > len(text) { + log.Fatal("Pattern is longer than text!") + } + fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") + fmt.Printf("Search word (%d chars long): %q.\n", len(word), word) + fmt.Printf("Text (%d chars long): %q.\n\n", len(text), text) + + r := kmp(text, word) + if r.resultPosition == notFoundPosition { + fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", r.numberOfComparison) + } else { + fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word, + r.resultPosition, text, r.numberOfComparison) } } -// Function knp performing the Knuth-Morris-Pratt algorithm. +// Function kmp performing the Knuth-Morris-Pratt algorithm. // Prints whether the word/pattern was found and on what position in the text or not. // m - current match in text, i - current character in w, c - amount of comparisons. -func knp(text, word string) { +func kmp(text string, word string) result { m, i, c := 0, 0, 0 t := kmp_table(word) for m+i < len(text) { @@ -65,8 +77,9 @@ func knp(text, word string) { if word[i] == text[m+i] { fmt.Printf(" - match") if i == len(word)-1 { - fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word, m, text, c) - return + return result{ + m, c, + } } i++ } else { @@ -78,8 +91,9 @@ func knp(text, word string) { } } } - fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", c) - return + return result{notFoundPosition, + c, + } } // Table building alghoritm. diff --git a/strings/single-string-matching/kmp/kmp_test.go b/strings/single-string-matching/kmp/kmp_test.go new file mode 100644 index 000000000..6233053ac --- /dev/null +++ b/strings/single-string-matching/kmp/kmp_test.go @@ -0,0 +1,53 @@ +package kmp + +import ( + "reflect" + "testing" +) + +var testCases = []struct { + name string + word string + text string + expected result +}{ + { + "String comparison on single pattern match", + "announce", + "CPM_annual_conference_announce", + result{ + 22, + 32, + }, + }, + { + "String comparison on multiple pattern match", + "AABA", + "AABAACAADAABAABA", + result{ + 0, + 4, + }, + }, + { + "String comparison with not found pattern", + "AABC", + "AABAACAADAABAABA", + result{ + -1, + 23, + }, + }, +} + +func TestKMP(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := kmp(tc.text, tc.word) + if !reflect.DeepEqual(actual, tc.expected) { + t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v steps at position %v, but actual matches are: %v steps at position %v", + tc.word, tc.text, tc.expected.numberOfComparison, tc.expected.resultPosition, actual.numberOfComparison, actual.resultPosition) + } + }) + } +} diff --git a/strings/single string matching/pattern.txt b/strings/single-string-matching/pattern.txt similarity index 100% rename from strings/single string matching/pattern.txt rename to strings/single-string-matching/pattern.txt diff --git a/strings/single string matching/text.txt b/strings/single-string-matching/text.txt similarity index 100% rename from strings/single string matching/text.txt rename to strings/single-string-matching/text.txt From d9ca0e854fee20bfbdc2d4e744a966ae7b36fe96 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 17 Oct 2020 09:32:16 +0000 Subject: [PATCH 128/488] updating DIRECTORY.md --- DIRECTORY.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 9f04752e2..29f3eeb2a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -105,7 +105,9 @@ * Naivesearch * [Naivestringsearch](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch.go) * [Naivestringsearch Test](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch_test.go) - * Single String Matching - * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/bom.go) - * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/horspool.go) - * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single%20string%20matching/kmp.go) + * Single-String-Matching + * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/bom.go) + * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/horspool.go) + * Kmp + * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/kmp/kmp.go) + * [Kmp Test](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/kmp/kmp_test.go) From 3341f6fb3a146c157387f918479b61cbbbbf5db8 Mon Sep 17 00:00:00 2001 From: William Chang <48861800+WilliamChang80@users.noreply.github.com> Date: Sat, 17 Oct 2020 19:21:55 +0700 Subject: [PATCH 129/488] Added test on multiple string matching algorithm (#232) --- .github/workflows/golangci-lint.yml | 2 +- .../advanced-aho-corasick}/adac.go | 53 ++++++++----- .../advanced-aho-corasick/adac_test.go | 79 +++++++++++++++++++ .../aho-corasick}/ac.go | 55 +++++++------ .../aho-corasick/ac_test.go | 79 +++++++++++++++++++ .../patterns.txt | 0 .../sbom}/sbom.go | 54 ++++++++----- .../sbom/sbom_test.go | 79 +++++++++++++++++++ .../text.txt | 0 9 files changed, 337 insertions(+), 64 deletions(-) rename strings/{multiple string matching => multiple-string-matching/advanced-aho-corasick}/adac.go (90%) create mode 100644 strings/multiple-string-matching/advanced-aho-corasick/adac_test.go rename strings/{multiple string matching => multiple-string-matching/aho-corasick}/ac.go (88%) create mode 100644 strings/multiple-string-matching/aho-corasick/ac_test.go rename strings/{multiple string matching => multiple-string-matching}/patterns.txt (100%) rename strings/{multiple string matching => multiple-string-matching/sbom}/sbom.go (90%) create mode 100644 strings/multiple-string-matching/sbom/sbom_test.go rename strings/{multiple string matching => multiple-string-matching}/text.txt (100%) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index ece101928..88d7ac2f9 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -29,7 +29,7 @@ jobs: - run: golangci-lint run --no-config searches || true - run: golangci-lint run --no-config sorts # - run: golangci-lint run --no-config strings/... - - run: golangci-lint run --no-config "strings/multiple string matching" || true + - run: golangci-lint run --no-config "strings/multiple-string-matching" || true # - run: golangci-lint run --no-config "strings/single string matching" || true - run: golangci-lint run --no-config strings/levenshteindistance - run: golangci-lint run --no-config strings/naivesearch diff --git a/strings/multiple string matching/adac.go b/strings/multiple-string-matching/advanced-aho-corasick/adac.go similarity index 90% rename from strings/multiple string matching/adac.go rename to strings/multiple-string-matching/advanced-aho-corasick/adac.go index 14cedeb3b..2a4f452aa 100644 --- a/strings/multiple string matching/adac.go +++ b/strings/multiple-string-matching/advanced-aho-corasick/adac.go @@ -1,4 +1,4 @@ -package main +package advancedahocorasick import ( "fmt" @@ -13,14 +13,18 @@ import ( // Set to false for quick and quiet execution. const debugMode bool = true +type result struct { + occurrences map[string][]int +} + // Implementation of Advanced Aho-Corasick algorithm (Prefix based). // Searches for a set of strings (patterns.txt) in text.txt. func main() { - patFile, err := ioutil.ReadFile("patterns.txt") + patFile, err := ioutil.ReadFile("../patterns.txt") if err != nil { log.Fatal(err) } - textFile, err := ioutil.ReadFile("text.txt") + textFile, err := ioutil.ReadFile("../text.txt") if err != nil { log.Fatal(err) } @@ -40,14 +44,25 @@ func main() { if debugMode == true { fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) } - ahoCorasick(string(textFile), patterns) + r := ahoCorasick(string(textFile), patterns) + for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) + fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) + for i := range value { + fmt.Printf("%d", value[i]) + if i != len(value)-1 { + fmt.Printf(", ") + } + } + fmt.Printf(".") + } + return } // Function performing the Advanced Aho-Corasick alghoritm. -// Finds and prints occurences of each pattern. -func ahoCorasick(t string, p []string) { +// Finds and prints occurrences of each pattern. +func ahoCorasick(t string, p []string) result { startTime := time.Now() - occurences := make(map[int][]int) + occurrences := make(map[int][]int) ac, f := buildExtendedAc(p) if debugMode == true { fmt.Printf("\n\nAC:\n\n") @@ -66,26 +81,24 @@ func ahoCorasick(t string, p []string) { if debugMode == true { fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) } - newOccurences := intArrayCapUp(occurences[f[current][i]]) - occurences[f[current][i]] = newOccurences - occurences[f[current][i]][len(newOccurences)-1] = pos - len(p[f[current][i]]) + 1 + newOccurrences := intArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurrences + occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 } } } } elapsed := time.Since(startTime) fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - for key, value := range occurences { //prints all occurences of each pattern (if there was at least one) - fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), p[key]) - for i := range value { - fmt.Printf("%d", value[i]) - if i != len(value)-1 { - fmt.Printf(", ") - } - } - fmt.Printf(".") + + var resultOccurrences = make(map[string][]int) + for key, value := range occurrences { + resultOccurrences[p[key]] = value + } + + return result{ + resultOccurrences, } - return } // Functions that builds extended Aho Corasick automaton. diff --git a/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go b/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go new file mode 100644 index 000000000..d05047231 --- /dev/null +++ b/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go @@ -0,0 +1,79 @@ +package advancedahocorasick + +import ( + "fmt" + "reflect" + "testing" +) + +var testCases = []struct { + name string + words []string + text string + expected result +}{ + + { + "String comparison on all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conferenceannounce_announce_annually_announce", + result{ + map[string][]int{ + "annual": {4, 39}, + "announce": {21, 30, 48}, + "annually": {39}, + }, + }, + }, + { + "String comparison on not all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conference_announce", + result{ + map[string][]int{ + "annual": {4}, + "announce": {22}, + }, + }, + }, + { + "String comparison on not all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conference_announce", + result{ + map[string][]int{ + "annual": {4}, + "announce": {22}, + }, + }, + }, +} + +func TestAhoCorasick(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := ahoCorasick(tc.text, tc.words) + if !reflect.DeepEqual(actual, tc.expected) { + actualString := convertToString(actual) + expectedString := convertToString(tc.expected) + t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", + tc.words, tc.text, actualString, expectedString) + } + }) + } +} + +func convertToString(res result) string { + var r string + for key, val := range res.occurrences { + r = r + fmt.Sprintf("Word: '%s' at positions: ", key) + for i := range val { + r = r + fmt.Sprintf("%d", val[i]) + if i != len(val)-1 { + r = r + fmt.Sprintf(", ") + } + } + r = r + fmt.Sprintf(". ") + } + return r +} diff --git a/strings/multiple string matching/ac.go b/strings/multiple-string-matching/aho-corasick/ac.go similarity index 88% rename from strings/multiple string matching/ac.go rename to strings/multiple-string-matching/aho-corasick/ac.go index efecc9df1..2e68c7ac3 100644 --- a/strings/multiple string matching/ac.go +++ b/strings/multiple-string-matching/aho-corasick/ac.go @@ -1,4 +1,4 @@ -package main +package ahocorasick import ( "fmt" @@ -13,14 +13,18 @@ import ( // Set to false for quick and quiet execution. const debugMode bool = true +type result struct { + occurrences map[string][]int +} + // Implementation of Basic Aho-Corasick algorithm (Prefix based). // Searches for a set of strings (patterns.txt) in text.txt. func main() { - patFile, err := ioutil.ReadFile("patterns.txt") + patFile, err := ioutil.ReadFile("../patterns.txt") if err != nil { log.Fatal(err) } - textFile, err := ioutil.ReadFile("text.txt") + textFile, err := ioutil.ReadFile("../text.txt") if err != nil { log.Fatal(err) } @@ -40,14 +44,24 @@ func main() { if debugMode == true { fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) } - ahoCorasick(string(textFile), patterns) + r := ahoCorasick(string(textFile), patterns) + for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) + fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) + for i := range value { + fmt.Printf("%d", value[i]) + if i != len(value)-1 { + fmt.Printf(", ") + } + } + fmt.Printf(".") + } } -// Function performing the Basic Aho-Corasick alghoritm. -// Finds and prints occurences of each pattern. -func ahoCorasick(t string, p []string) { +// Function performing the Basic Aho-Corasick algorithm. +// Finds and prints occurrences of each pattern. +func ahoCorasick(t string, p []string) result { startTime := time.Now() - occurences := make(map[int][]int) + occurrences := make(map[int][]int) ac, f, s := buildAc(p) if debugMode == true { fmt.Printf("\n\nAC:\n\n") @@ -76,26 +90,23 @@ func ahoCorasick(t string, p []string) { if debugMode == true { fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) } - newOccurences := intArrayCapUp(occurences[f[current][i]]) - occurences[f[current][i]] = newOccurences - occurences[f[current][i]][len(newOccurences)-1] = pos - len(p[f[current][i]]) + 1 + newOccurrences := intArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurrences + occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 } } } } elapsed := time.Since(startTime) fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - for key, value := range occurences { //prints all occurences of each pattern (if there was at least one) - fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), p[key]) - for i := range value { - fmt.Printf("%d", value[i]) - if i != len(value)-1 { - fmt.Printf(", ") - } - } - fmt.Printf(".") + var resultOccurrences = make(map[string][]int) + for key, value := range occurrences { + resultOccurrences[p[key]] = value + } + + return result{ + resultOccurrences, } - return } // Functions that builds Aho Corasick automaton. @@ -191,7 +202,7 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo } /** -Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. +Returns 'true' if array of int's 's' contains int 'e', 'false' otherwise. @author Mostafa http://stackoverflow.com/a/10485970 */ diff --git a/strings/multiple-string-matching/aho-corasick/ac_test.go b/strings/multiple-string-matching/aho-corasick/ac_test.go new file mode 100644 index 000000000..d6638b77c --- /dev/null +++ b/strings/multiple-string-matching/aho-corasick/ac_test.go @@ -0,0 +1,79 @@ +package ahocorasick + +import ( + "fmt" + "reflect" + "testing" +) + +var testCases = []struct { + name string + words []string + text string + expected result +}{ + + { + "String comparison on all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conferenceannounce_announce_annually_announce", + result{ + map[string][]int{ + "annual": {4, 39}, + "announce": {21,30,48}, + "annually": {39}, + }, + }, + }, + { + "String comparison on not all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conference_announce", + result{ + map[string][]int{ + "annual": {4}, + "announce": {22}, + }, + }, + }, + { + "String comparison on not all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conference_announce", + result{ + map[string][]int{ + "annual": {4}, + "announce": {22}, + }, + }, + }, +} + +func TestAhoCorasick(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := ahoCorasick(tc.text, tc.words) + if !reflect.DeepEqual(actual, tc.expected) { + actualString := convertToString(actual) + expectedString := convertToString(tc.expected) + t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", + tc.words, tc.text, actualString, expectedString) + } + }) + } +} + +func convertToString(res result) string { + var r string + for key, val := range res.occurrences { + r = r + fmt.Sprintf("Word: '%s' at positions: ", key) + for i := range val { + r = r + fmt.Sprintf("%d", val[i]) + if i != len(val)-1 { + r = r + fmt.Sprintf(", ") + } + } + r = r + fmt.Sprintf(". ") + } + return r +} diff --git a/strings/multiple string matching/patterns.txt b/strings/multiple-string-matching/patterns.txt similarity index 100% rename from strings/multiple string matching/patterns.txt rename to strings/multiple-string-matching/patterns.txt diff --git a/strings/multiple string matching/sbom.go b/strings/multiple-string-matching/sbom/sbom.go similarity index 90% rename from strings/multiple string matching/sbom.go rename to strings/multiple-string-matching/sbom/sbom.go index 08ba904c5..b0cd2a7b4 100644 --- a/strings/multiple string matching/sbom.go +++ b/strings/multiple-string-matching/sbom/sbom.go @@ -1,4 +1,4 @@ -package main +package sbom import ( "fmt" @@ -13,14 +13,18 @@ import ( // Set to false for quick and quiet execution. const debugMode bool = true +type result struct { + occurrences map[string][]int +} + // Implementation of Set Backward Oracle Matching algorithm (Factor based). // Searches for a set of strings (in 'patterns.txt') in text.txt. func main() { - patFile, err := ioutil.ReadFile("patterns.txt") + patFile, err := ioutil.ReadFile("../patterns.txt") if err != nil { log.Fatal(err) } - textFile, err := ioutil.ReadFile("text.txt") + textFile, err := ioutil.ReadFile("../text.txt") if err != nil { log.Fatal(err) } @@ -40,14 +44,25 @@ func main() { if debugMode == true { fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) } - sbom(string(textFile), patterns) + r := sbom(string(textFile), patterns) + for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) + fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) + for i := range value { + fmt.Printf("%d", value[i]) + if i != len(value)-1 { + fmt.Printf(", ") + } + } + fmt.Printf(".") + } + } -// Function sbom performing the Set Backward Oracle Matching alghoritm. -// Finds and prints occurences of each pattern. -func sbom(t string, p []string) { +// Function sbom performing the Set Backward Oracle Matching algorithm. +// Finds and prints occurrences of each pattern. +func sbom(t string, p []string) result { startTime := time.Now() - occurences := make(map[int][]int) + occurrences := make(map[int][]int) lmin := computeMinLength(p) or, f := buildOracleMultiple(reverseAll(trimToLength(p, lmin))) if debugMode == true { @@ -84,9 +99,9 @@ func sbom(t string, p []string) { if debugMode == true { fmt.Printf("- Occurence, %q = %q\n", p[f[current][i]], word) } - newOccurences := intArrayCapUp(occurences[f[current][i]]) - occurences[f[current][i]] = newOccurences - occurences[f[current][i]][len(newOccurences)-1] = pos + newOccurences := intArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurences + occurrences[f[current][i]][len(newOccurences)-1] = pos } } j = 0 @@ -95,17 +110,14 @@ func sbom(t string, p []string) { } elapsed := time.Since(startTime) fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - for key, value := range occurences { //prints all occurences of each pattern (if there was at least one) - fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), p[key]) - for i := range value { - fmt.Printf("%d", value[i]) - if i != len(value)-1 { - fmt.Printf(", ") - } - } - fmt.Printf(".") + var resultOccurrences = make(map[string][]int) + for key, value := range occurrences { + resultOccurrences[p[key]] = value + } + + return result{ + resultOccurrences, } - return } // Function that builds factor oracle. diff --git a/strings/multiple-string-matching/sbom/sbom_test.go b/strings/multiple-string-matching/sbom/sbom_test.go new file mode 100644 index 000000000..aa9d1e140 --- /dev/null +++ b/strings/multiple-string-matching/sbom/sbom_test.go @@ -0,0 +1,79 @@ +package sbom + +import ( + "fmt" + "reflect" + "testing" +) + +var testCases = []struct { + name string + words []string + text string + expected result +}{ + + { + "String comparison on all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conferenceannounce_announce_annually_announce", + result{ + map[string][]int{ + "annual": {4, 39}, + "announce": {21, 30, 48}, + "annually": {39}, + }, + }, + }, + { + "String comparison on not all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conference_announce", + result{ + map[string][]int{ + "annual": {4}, + "announce": {22}, + }, + }, + }, + { + "String comparison on not all patterns found", + []string{"announce", "annual", "annually"}, + "CPM_annual_conference_announce", + result{ + map[string][]int{ + "annual": {4}, + "announce": {22}, + }, + }, + }, +} + +func TestAhoCorasick(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := sbom(tc.text, tc.words) + if !reflect.DeepEqual(actual, tc.expected) { + actualString := convertToString(actual) + expectedString := convertToString(tc.expected) + t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", + tc.words, tc.text, actualString, expectedString) + } + }) + } +} + +func convertToString(res result) string { + var r string + for key, val := range res.occurrences { + r = r + fmt.Sprintf("Word: '%s' at positions: ", key) + for i := range val { + r = r + fmt.Sprintf("%d", val[i]) + if i != len(val)-1 { + r = r + fmt.Sprintf(", ") + } + } + r = r + fmt.Sprintf(". ") + } + return r +} diff --git a/strings/multiple string matching/text.txt b/strings/multiple-string-matching/text.txt similarity index 100% rename from strings/multiple string matching/text.txt rename to strings/multiple-string-matching/text.txt From 3ed92dcb47042396f72d1d403ad4b681265aa105 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 17 Oct 2020 12:22:09 +0000 Subject: [PATCH 130/488] updating DIRECTORY.md --- DIRECTORY.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 29f3eeb2a..e328d7ad9 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -98,10 +98,16 @@ * Levenshteindistance * [Levenshteindistance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteindistance/levenshteinDistance.go) * [Levenshteindistance Test](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteindistance/levenshteinDistance_test.go) - * Multiple String Matching - * [Ac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/ac.go) - * [Adac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/adac.go) - * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple%20string%20matching/sbom.go) + * Multiple-String-Matching + * Advanced-Aho-Corasick + * [Adac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/advanced-aho-corasick/adac.go) + * [Adac Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go) + * Aho-Corasick + * [Ac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/aho-corasick/ac.go) + * [Ac Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/aho-corasick/ac_test.go) + * Sbom + * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/sbom/sbom.go) + * [Sbom Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/sbom/sbom_test.go) * Naivesearch * [Naivestringsearch](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch.go) * [Naivestringsearch Test](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch_test.go) From 72a682ab88bd3153c146b0759933cd7acf568c7d Mon Sep 17 00:00:00 2001 From: mattan Date: Sat, 17 Oct 2020 19:58:07 +0300 Subject: [PATCH 131/488] - Added new test cases for sort, with negative integers - Changed sort function names to uppercase where they were lowercase - Enclosed each iteration in t.Run() to ensure all tests are executed - Added a unified test framework to avoid code duplication - Fixed Radix sort to deal with negative numbers --- sorts/heap_sort.go | 2 +- sorts/insertion_sort.go | 2 +- sorts/quick_sort.go | 6 +- sorts/radix_sort.go | 25 ++------ sorts/shell_sort.go | 2 +- sorts/sorts_case_test.go | 37 +++++++++-- sorts/sorts_test.go | 134 +++++++++++---------------------------- 7 files changed, 78 insertions(+), 130 deletions(-) diff --git a/sorts/heap_sort.go b/sorts/heap_sort.go index 7140e7fe7..e5ccadbca 100644 --- a/sorts/heap_sort.go +++ b/sorts/heap_sort.go @@ -33,7 +33,7 @@ func (h maxHeap) MaxHeapify(i int) { func (h maxHeap) size() int { return h.heapSize } // ??? -func heapSort(slice []int) []int { +func HeapSort(slice []int) []int { h := buildMaxHeap(slice) //log.Println(slice) for i := len(h.slice) - 1; i >= 1; i-- { diff --git a/sorts/insertion_sort.go b/sorts/insertion_sort.go index 9a95e0a6b..ca11fa2d2 100644 --- a/sorts/insertion_sort.go +++ b/sorts/insertion_sort.go @@ -1,7 +1,7 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -func insertionSort(arr []int) []int { +func InsertionSort(arr []int) []int { for out := 1; out < len(arr); out++ { temp := arr[out] in := out diff --git a/sorts/quick_sort.go b/sorts/quick_sort.go index f696d801d..52274e98c 100644 --- a/sorts/quick_sort.go +++ b/sorts/quick_sort.go @@ -5,7 +5,7 @@ import ( "math/rand" ) -func quickSort(arr []int) []int { +func QuickSort(arr []int) []int { if len(arr) <= 1 { return arr @@ -28,8 +28,8 @@ func quickSort(arr []int) []int { } } - lowPart = quickSort(lowPart) - highPart = quickSort(highPart) + lowPart = QuickSort(lowPart) + highPart = QuickSort(highPart) lowPart = append(lowPart, middlePart...) lowPart = append(lowPart, highPart...) diff --git a/sorts/radix_sort.go b/sorts/radix_sort.go index bdb577e22..163678218 100644 --- a/sorts/radix_sort.go +++ b/sorts/radix_sort.go @@ -1,11 +1,7 @@ package sorts -import ( - "math" -) - func max(arr []int) int { - max := math.MinInt64 + max := arr[0] for _, item := range arr { if item > max { max = item @@ -17,10 +13,10 @@ func max(arr []int) int { func countSort(arr []int, exp int) []int { var digits [10]int var output = make([]int, len(arr)) + for _, item := range arr { digits[(item/exp)%10]++ } - for i := 1; i < 10; i++ { digits[i] += digits[i-1] } @@ -33,18 +29,10 @@ func countSort(arr []int, exp int) []int { return output } -func RadixSort(arr []int) []int { - maxElement := max(arr) - for exp := 1; maxElement/exp > 0; exp *= 10 { - arr = countSort(arr, exp) - } - return arr -} - -// The following adds support for signed ints -/* - func unsignedRadixSort(arr []int) []int { + if len(arr) == 0 { + return arr + } maxElement := max(arr) for exp := 1; maxElement/exp > 0; exp *= 10 { arr = countSort(arr, exp) @@ -65,9 +53,8 @@ func RadixSort(arr []int) []int { negatives = unsignedRadixSort(negatives) // Reverse the negative array and restore signs - for i, j := 0, len(negatives) -1; i < j; i,j = i + 1, j - 1 { + for i, j := 0, len(negatives)-1; i <= j; i, j = i+1, j-1 { negatives[i], negatives[j] = -negatives[j], -negatives[i] } return append(negatives, unsignedRadixSort(nonNegatives)...) } -*/ diff --git a/sorts/shell_sort.go b/sorts/shell_sort.go index b1a4702aa..81e16b911 100644 --- a/sorts/shell_sort.go +++ b/sorts/shell_sort.go @@ -1,7 +1,7 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -func shellSort(arr []int) []int { +func ShellSort(arr []int) []int { for d := int(len(arr) / 2); d > 0; d /= 2 { for i := d; i < len(arr); i++ { for j := i; j >= d && arr[j-d] > arr[j]; j -= d { diff --git a/sorts/sorts_case_test.go b/sorts/sorts_case_test.go index ef384fccd..90947f41c 100644 --- a/sorts/sorts_case_test.go +++ b/sorts/sorts_case_test.go @@ -13,25 +13,39 @@ type sortTest struct { name string } +var uarr []int = makeRandNonNegativeArray(500_000) var arr []int = makeRandArray(500_000) var sortTests = []sortTest{ //Sorted slice - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted"}, + {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted"}, + //Reversed slice - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed"}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed"}, + + //Reversed slice, even length + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Even"}, + + //Random order with repetitions + {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order with repetitions"}, + //Empty slice {[]int{}, []int{}, "Empty"}, //Single-entry slice {[]int{1}, []int{1}, "Singleton"}, - //500k values sort - {arr, getSortedVersion(arr), "Large Random"}, + //500k non negative int values sort + {uarr, getSortedVersion(uarr), "Large Random"}, + + //500k int values sort + {arr, getSortedVersion(arr), "Large Random2"}, } -func makeRandArray(size int) []int { +func makeRandNonNegativeArray(size int) []int { vals := make([]int, size) for i := 0; i < size; i++ { temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size))) @@ -40,6 +54,15 @@ func makeRandArray(size int) []int { return vals } +func makeRandArray(size int) []int { + vals := make([]int, size) + for i := 0; i < size; i++ { + temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size))) + vals[i] = int(temp.Int64()) - 250_000 + } + return vals +} + func getSortedVersion(a []int) []int { sort.Slice(a, func(i, j int) bool { return a[i] < a[j] }) return a diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index bd3682944..8f5a744c9 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -1,125 +1,63 @@ package sorts -import "testing" +import ( + "fmt" + "testing" +) -//BEGIN TESTS - -func TestBubble(t *testing.T) { +func testFramework(t *testing.T, sortingFunction func([]int) []int) { for _, test := range sortTests { - actual := bubbleSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) + t.Run(test.name, func(t *testing.T) { + actual := sortingFunction(test.input) + pos, sorted := compareSlices(actual, test.expected) + if !sorted { + if pos == -1 { + t.Errorf("test %s failed due to slice length changing", test.name) + } + + for i := pos - 10; i < pos+10; i++ { + fmt.Print(actual[i], " ") + } + t.Errorf("test %s failed at index %d", test.name, pos) + } - t.Errorf("test %s failed at index %d", test.name, pos) - } + }) } } -func TestSelection(t *testing.T) { - for _, test := range sortTests { - actual := selectionSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } +//BEGIN TESTS + +func TestBubble(t *testing.T) { + testFramework(t, bubbleSort) } func TestInsertion(t *testing.T) { - for _, test := range sortTests { - actual := insertionSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } + testFramework(t, InsertionSort) } func TestMerge(t *testing.T) { - for _, test := range sortTests { - actual := Mergesort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } + testFramework(t, Mergesort) } func TestHeap(t *testing.T) { - for _, test := range sortTests { - actual := heapSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } + testFramework(t, HeapSort) } func TestQuick(t *testing.T) { - for _, test := range sortTests { - actual := quickSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } + testFramework(t, QuickSort) } func TestShell(t *testing.T) { - for _, test := range sortTests { - actual := shellSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } + testFramework(t, ShellSort) } func TestRadix(t *testing.T) { - for _, test := range sortTests { - actual := RadixSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } + testFramework(t, RadixSort) } -/*func TestTopological(t *testing.T) { - for _, test := range sortTests { - actual := topologicalSort(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - } -}*/ +/* func TestTopological(t *testing.T) { + testFramework(t, topologicalSort) +} */ //END TESTS @@ -143,7 +81,7 @@ func BenchmarkSelection(b *testing.B) { func BenchmarkInsertion(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { - insertionSort(test.input) + InsertionSort(test.input) } } } @@ -159,7 +97,7 @@ func BenchmarkMerge(b *testing.B) { func BenchmarkHeap(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { - heapSort(test.input) + HeapSort(test.input) } } } @@ -167,7 +105,7 @@ func BenchmarkHeap(b *testing.B) { func BenchmarkQuick(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { - quickSort(test.input) + QuickSort(test.input) } } } @@ -175,7 +113,7 @@ func BenchmarkQuick(b *testing.B) { func BenchmarkShell(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { - shellSort(test.input) + ShellSort(test.input) } } } From 82ff0c00685ac13a6deef46ac3ef02ca019014a0 Mon Sep 17 00:00:00 2001 From: mattan Date: Sun, 18 Oct 2020 02:42:24 +0300 Subject: [PATCH 132/488] -updated test cases to include unsigned -renamed random slice maker functions --- sorts/sorts_case_test.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/sorts/sorts_case_test.go b/sorts/sorts_case_test.go index 90947f41c..df97f3be4 100644 --- a/sorts/sorts_case_test.go +++ b/sorts/sorts_case_test.go @@ -13,25 +13,35 @@ type sortTest struct { name string } -var uarr []int = makeRandNonNegativeArray(500_000) -var arr []int = makeRandArray(500_000) +var uarr []int = makeRandomUnsignedSlice(500_000) +var arr []int = makeRandomSignedSlice(500_000) var sortTests = []sortTest{ + //Sorted slice + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, + //Reversed slice + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, + + //500k int values sort + {arr, getSortedVersion(arr), "Large Random Signed"}, + //Sorted slice {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, //Reversed slice {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, //Reversed slice, even length {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Even"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned #2"}, //Random order with repetitions {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order with repetitions"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order"}, //Empty slice {[]int{}, []int{}, "Empty"}, @@ -39,13 +49,10 @@ var sortTests = []sortTest{ {[]int{1}, []int{1}, "Singleton"}, //500k non negative int values sort - {uarr, getSortedVersion(uarr), "Large Random"}, - - //500k int values sort - {arr, getSortedVersion(arr), "Large Random2"}, + {uarr, getSortedVersion(uarr), "Large Random unsigned"}, } -func makeRandNonNegativeArray(size int) []int { +func makeRandomUnsignedSlice(size int) []int { vals := make([]int, size) for i := 0; i < size; i++ { temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size))) @@ -54,7 +61,7 @@ func makeRandNonNegativeArray(size int) []int { return vals } -func makeRandArray(size int) []int { +func makeRandomSignedSlice(size int) []int { vals := make([]int, size) for i := 0; i < size; i++ { temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size))) From d504855437b2167aa0743da49956b57cdf6a910f Mon Sep 17 00:00:00 2001 From: mattan Date: Sun, 18 Oct 2020 02:42:24 +0300 Subject: [PATCH 133/488] - fixed test names - moved selection sort test and benchmark to the end because it takes very long to finish. --- sorts/selection_sort.go | 2 +- sorts/sorts_case_test.go | 23 +++++++++++------------ sorts/sorts_test.go | 28 ++++++++++++++-------------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/sorts/selection_sort.go b/sorts/selection_sort.go index a142f1a45..7923a8fae 100644 --- a/sorts/selection_sort.go +++ b/sorts/selection_sort.go @@ -1,7 +1,7 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -func selectionSort(arr []int) []int { +func SelectionSort(arr []int) []int { for i := 0; i < len(arr); i++ { min := i diff --git a/sorts/sorts_case_test.go b/sorts/sorts_case_test.go index df97f3be4..56550cee9 100644 --- a/sorts/sorts_case_test.go +++ b/sorts/sorts_case_test.go @@ -19,37 +19,36 @@ var arr []int = makeRandomSignedSlice(500_000) var sortTests = []sortTest{ //Sorted slice {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, //Reversed slice {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, - - //500k int values sort - {arr, getSortedVersion(arr), "Large Random Signed"}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, + //500k unsigned int values sort + {uarr, getSortedVersion(uarr), "Large Random Unsigned"}, //Sorted slice {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, //Reversed slice {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, //Reversed slice, even length {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned #2"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, //Random order with repetitions {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order"}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, + + //500k int values sort + {arr, getSortedVersion(arr), "Large Random Signed"}, //Empty slice {[]int{}, []int{}, "Empty"}, //Single-entry slice {[]int{1}, []int{1}, "Singleton"}, - - //500k non negative int values sort - {uarr, getSortedVersion(uarr), "Large Random unsigned"}, } func makeRandomUnsignedSlice(size int) []int { diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index 8f5a744c9..b3b04fa4b 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -1,7 +1,6 @@ package sorts import ( - "fmt" "testing" ) @@ -14,12 +13,7 @@ func testFramework(t *testing.T, sortingFunction func([]int) []int) { if pos == -1 { t.Errorf("test %s failed due to slice length changing", test.name) } - - for i := pos - 10; i < pos+10; i++ { - fmt.Print(actual[i], " ") - } t.Errorf("test %s failed at index %d", test.name, pos) - } }) } @@ -55,6 +49,11 @@ func TestRadix(t *testing.T) { testFramework(t, RadixSort) } +// Very slow, consider commenting +func TestSelection(t *testing.T) { + testFramework(t, SelectionSort) +} + /* func TestTopological(t *testing.T) { testFramework(t, topologicalSort) } */ @@ -70,14 +69,6 @@ func BenchmarkBubble(b *testing.B) { } } -func BenchmarkSelection(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - selectionSort(test.input) - } - } -} - func BenchmarkInsertion(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { @@ -126,6 +117,15 @@ func BenchmarkRadix(b *testing.B) { } } +// Very Slow, consider commenting +func BenchmarkSelection(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range sortTests { + SelectionSort(test.input) + } + } +} + /*func BenchmarkTopological(b *testing.B) { for i := 0; i < b.N; i++ { for _, test := range sortTests { From faff37740c91e875b508867e1d3c8e6313243f18 Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 18 Oct 2020 18:17:42 +0530 Subject: [PATCH 134/488] modify insertion sort. Signed-off-by: Jobin John --- sorts/insertion_sort.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sorts/insertion_sort.go b/sorts/insertion_sort.go index ca11fa2d2..b036fc751 100644 --- a/sorts/insertion_sort.go +++ b/sorts/insertion_sort.go @@ -2,14 +2,13 @@ package sorts func InsertionSort(arr []int) []int { - for out := 1; out < len(arr); out++ { - temp := arr[out] - in := out - - for ; in > 0 && arr[in-1] >= temp; in-- { - arr[in] = arr[in-1] + for currentIndex := 1; currentIndex < len(arr); currentIndex++ { + temporary := arr[currentIndex] + iterator := currentIndex + for ; iterator > 0 && arr[iterator-1] >= temporary; iterator-- { + arr[iterator] = arr[iterator-1] } - arr[in] = temp + arr[iterator] = temporary } return arr } From 2ee1d702f59129bd0d62bc1f933f54b95be8cf2a Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 18 Oct 2020 18:18:25 +0530 Subject: [PATCH 135/488] delete old insertionsort. --- sorts/insertionsort.go | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 sorts/insertionsort.go diff --git a/sorts/insertionsort.go b/sorts/insertionsort.go deleted file mode 100644 index ee76369cb..000000000 --- a/sorts/insertionsort.go +++ /dev/null @@ -1,15 +0,0 @@ -// Reference: https://en.wikipedia.org/wiki/Insertion_sort - -package sorts - -func insertionSort(arr []int) []int { - for currentIndex := 1; currentIndex < len(arr); currentIndex++ { - temporary := arr[currentIndex] - iterator := currentIndex - for ; iterator > 0 && arr[iterator-1] >= temporary; iterator-- { - arr[iterator] = arr[iterator-1] - } - arr[iterator] = temporary - } - return arr -} From 39eebae9addeb40d5841b9270b328f60c515eea8 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 18 Oct 2020 12:52:18 +0000 Subject: [PATCH 136/488] updating DIRECTORY.md --- DIRECTORY.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index e328d7ad9..0de8fdc74 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -85,9 +85,10 @@ * [Bubblesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubblesort.go) * [Countingsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/countingsort.go) * [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heap_sort.go) - * [Insertionsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertionsort.go) + * [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertion_sort.go) * [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/merge_sort.go) * [Quick Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quick_sort.go) + * [Radix Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radix_sort.go) * [Selection Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selection_sort.go) * [Shell Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shell_sort.go) * [Sorts Case Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_case_test.go) From 9087f6789c78caeb1eea7e9fcfa604d106aaa19c Mon Sep 17 00:00:00 2001 From: FuXiang Shu <6470547+Crazy3lf@users.noreply.github.com> Date: Sun, 25 Oct 2020 21:20:14 +0800 Subject: [PATCH 137/488] Update iterBinarySearch (#245) * added test for iterBinarySearch and 2 more test cases * Update iterBinarySearch * Updated test failure output to be clearer * Update iterBinarySearch - highIndex should not subtract by 1 --- searches/binary_search.go | 8 ++++---- searches/search_test.go | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/searches/binary_search.go b/searches/binary_search.go index d37b70955..4a5b78fa5 100644 --- a/searches/binary_search.go +++ b/searches/binary_search.go @@ -18,12 +18,12 @@ func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int startIndex := lowIndex endIndex := highIndex var mid int - for startIndex < endIndex { - mid = int(startIndex + (endIndex - startIndex)) + for startIndex <= endIndex { + mid = int(startIndex + (endIndex)/2) if array[mid] > target { - endIndex = mid + endIndex = mid - 1 } else if array[mid] < target { - startIndex = mid + startIndex = mid + 1 } else { return mid } diff --git a/searches/search_test.go b/searches/search_test.go index 91d1125bd..4390aba5c 100644 --- a/searches/search_test.go +++ b/searches/search_test.go @@ -12,6 +12,10 @@ type searchTest struct { var searchTests = []searchTest{ //Sanity {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, + //First + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "First"}, + //Last + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Last"}, //Absent {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, //Empty slice @@ -22,7 +26,16 @@ func TestBinarySearch(t *testing.T) { for _, test := range searchTests { actual := binarySearch(test.data, test.key, 0, len(test.data)-1) if actual != test.expected { - t.Errorf("test %s failed", test.name) + t.Errorf("test %s failed: expected '%d', get '%d'", test.name, test.expected, actual) + } + } +} + +func TestIterBinarySearch(t *testing.T) { + for _, test := range searchTests { + actual := iterBinarySearch(test.data, test.key, 0, len(test.data)-1) + if actual != test.expected { + t.Errorf("test %s failed: expected '%d', get '%d'", test.name, test.expected, actual) } } } @@ -31,7 +44,7 @@ func TestLinearSearch(t *testing.T) { for _, test := range searchTests { actual := linearSearch(test.data, test.key) if actual != test.expected { - t.Errorf("test %s failed", test.name) + t.Errorf("test %s failed: expected '%d', get '%d'", test.name, test.expected, actual) } } } From f5c0813c551d0af4fb34227315cb0cd80940e28a Mon Sep 17 00:00:00 2001 From: Jobin John Date: Sun, 25 Oct 2020 19:46:11 +0530 Subject: [PATCH 138/488] Revert "Update iterBinarySearch (#245)" This reverts commit 9087f6789c78caeb1eea7e9fcfa604d106aaa19c. --- searches/binary_search.go | 8 ++++---- searches/search_test.go | 17 ++--------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/searches/binary_search.go b/searches/binary_search.go index 4a5b78fa5..d37b70955 100644 --- a/searches/binary_search.go +++ b/searches/binary_search.go @@ -18,12 +18,12 @@ func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int startIndex := lowIndex endIndex := highIndex var mid int - for startIndex <= endIndex { - mid = int(startIndex + (endIndex)/2) + for startIndex < endIndex { + mid = int(startIndex + (endIndex - startIndex)) if array[mid] > target { - endIndex = mid - 1 + endIndex = mid } else if array[mid] < target { - startIndex = mid + 1 + startIndex = mid } else { return mid } diff --git a/searches/search_test.go b/searches/search_test.go index 4390aba5c..91d1125bd 100644 --- a/searches/search_test.go +++ b/searches/search_test.go @@ -12,10 +12,6 @@ type searchTest struct { var searchTests = []searchTest{ //Sanity {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, - //First - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "First"}, - //Last - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Last"}, //Absent {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, //Empty slice @@ -26,16 +22,7 @@ func TestBinarySearch(t *testing.T) { for _, test := range searchTests { actual := binarySearch(test.data, test.key, 0, len(test.data)-1) if actual != test.expected { - t.Errorf("test %s failed: expected '%d', get '%d'", test.name, test.expected, actual) - } - } -} - -func TestIterBinarySearch(t *testing.T) { - for _, test := range searchTests { - actual := iterBinarySearch(test.data, test.key, 0, len(test.data)-1) - if actual != test.expected { - t.Errorf("test %s failed: expected '%d', get '%d'", test.name, test.expected, actual) + t.Errorf("test %s failed", test.name) } } } @@ -44,7 +31,7 @@ func TestLinearSearch(t *testing.T) { for _, test := range searchTests { actual := linearSearch(test.data, test.key) if actual != test.expected { - t.Errorf("test %s failed: expected '%d', get '%d'", test.name, test.expected, actual) + t.Errorf("test %s failed", test.name) } } } From 2137c997401501e03bae95aa1cd9eacbb1e02937 Mon Sep 17 00:00:00 2001 From: nomisrevol Date: Tue, 27 Oct 2020 22:53:18 +0700 Subject: [PATCH 139/488] Refactor repo with filename convention and folder convention --- .github/workflows/golangci-lint.yml | 12 ++++++------ .../binary-tree/binarysearchtree.go | 0 .../binary-tree/binarytree.go | 0 .../dynamic-array/dynamicarray.go | 0 .../hash_map.go => datastructures/hashmap/hashmap.go | 0 .../hashmap/hashmap_test.go | 2 +- .../linkedlist/doublylinkedlist.go | 2 +- .../singlelinkedlist/single-linkedlist.go | 0 .../singlelinkedlist/single-linkedlist_test.go | 0 .../linkedlist/singlylinkedlist.go | 2 +- {data-structures => datastructures}/trie/trie.go | 0 .../trie/trie_test.go | 0 .../binomialcoeffecient.go | 0 .../knapsack.go | 0 .../longest-palindromic-subsequence.go | 0 .../longestCommonSubsequence.go | 0 .../matrix-multiplication.go | 2 +- .../rod-cutting.go | 0 .../breathfirstsearch.go | 2 +- .../depthfirstsearch.go | 2 +- graphs/{floyd_warshall.go => floydwarshall.go} | 2 +- math/gcd/{greatest_common_divisor.go => gcd.go} | 0 .../{greatest_common_divisor_test.go => gcd_test.go} | 0 math/power/{fastExponent.go => fastexponent.go} | 0 .../{fastExponent_test.go => fastexponent_test.go} | 0 math/primecheck/{prime_check.go => primecheck.go} | 0 .../{prime_check_test.go => primecheck_test.go} | 0 other/{maxSubarraySum.go => maxsubarraysum.go} | 0 other/{NestedBrackets.go => nestedbrackets.go} | 0 other/{PasswordGenerator.go => passwordgenerator.go} | 0 ...{string_combinations.go => stringcombinations.go} | 0 searches/{binary_search.go => binarysearch.go} | 2 +- searches/{linear_search.go => linearsearch.go} | 2 +- searches/search_test.go | 2 +- sorts/{heap_sort.go => heapsort.go} | 0 sorts/{insertion_sort.go => insertionsort.go} | 0 sorts/{merge_sort.go => mergesort.go} | 0 sorts/{quick_sort.go => quicksort.go} | 0 sorts/{radix_sort.go => radixsort.go} | 0 sorts/{selection_sort.go => selectionsort.go} | 0 sorts/{shell_sort.go => shellsort.go} | 0 sorts/{sorts_case_test.go => sorts_testcases.go} | 0 sorts/{topological_sort.go => topologicalsort.go} | 4 ++-- 43 files changed, 18 insertions(+), 18 deletions(-) rename data-structures/binary-tree/binary-search-tree.go => datastructures/binary-tree/binarysearchtree.go (100%) rename data-structures/binary-tree/binary-tree.go => datastructures/binary-tree/binarytree.go (100%) rename data-structures/dynamic-array/dynamic_array.go => datastructures/dynamic-array/dynamicarray.go (100%) rename data-structures/hash-map/hash_map.go => datastructures/hashmap/hashmap.go (100%) rename data-structures/hash-map/hash_map_test.go => datastructures/hashmap/hashmap_test.go (88%) rename data-structures/linked-list/double-linkedlist.go => datastructures/linkedlist/doublylinkedlist.go (98%) rename {data-structures/linked-list => datastructures/linkedlist}/singlelinkedlist/single-linkedlist.go (100%) rename {data-structures/linked-list => datastructures/linkedlist}/singlelinkedlist/single-linkedlist_test.go (100%) rename data-structures/linked-list/Linkedlist.go => datastructures/linkedlist/singlylinkedlist.go (99%) rename {data-structures => datastructures}/trie/trie.go (100%) rename {data-structures => datastructures}/trie/trie_test.go (100%) rename dynamic-programming/binomial-coeffecient.go => dynamicprogramming/binomialcoeffecient.go (100%) rename {dynamic-programming => dynamicprogramming}/knapsack.go (100%) rename {dynamic-programming => dynamicprogramming}/longest-palindromic-subsequence.go (100%) rename {dynamic-programming => dynamicprogramming}/longestCommonSubsequence.go (100%) rename {dynamic-programming => dynamicprogramming}/matrix-multiplication.go (93%) rename {dynamic-programming => dynamicprogramming}/rod-cutting.go (100%) rename searches/breadth_first_search.go => graphs/breathfirstsearch.go (98%) rename searches/depth_first_search.go => graphs/depthfirstsearch.go (98%) rename graphs/{floyd_warshall.go => floydwarshall.go} (99%) rename math/gcd/{greatest_common_divisor.go => gcd.go} (100%) rename math/gcd/{greatest_common_divisor_test.go => gcd_test.go} (100%) rename math/power/{fastExponent.go => fastexponent.go} (100%) rename math/power/{fastExponent_test.go => fastexponent_test.go} (100%) rename math/primecheck/{prime_check.go => primecheck.go} (100%) rename math/primecheck/{prime_check_test.go => primecheck_test.go} (100%) rename other/{maxSubarraySum.go => maxsubarraysum.go} (100%) rename other/{NestedBrackets.go => nestedbrackets.go} (100%) rename other/{PasswordGenerator.go => passwordgenerator.go} (100%) rename other/{string_combinations.go => stringcombinations.go} (100%) rename searches/{binary_search.go => binarysearch.go} (97%) rename searches/{linear_search.go => linearsearch.go} (96%) rename sorts/{heap_sort.go => heapsort.go} (100%) rename sorts/{insertion_sort.go => insertionsort.go} (100%) rename sorts/{merge_sort.go => mergesort.go} (100%) rename sorts/{quick_sort.go => quicksort.go} (100%) rename sorts/{radix_sort.go => radixsort.go} (100%) rename sorts/{selection_sort.go => selectionsort.go} (100%) rename sorts/{shell_sort.go => shellsort.go} (100%) rename sorts/{sorts_case_test.go => sorts_testcases.go} (100%) rename sorts/{topological_sort.go => topologicalsort.go} (98%) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 88d7ac2f9..e58ca3adc 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -19,12 +19,12 @@ jobs: - run: echo "/home/runner/golangci-lint-1.31.0-linux-amd64" >> $GITHUB_PATH - run: go version ; golangci-lint --version # Fix the following and remove || true - run: golangci-lint run --no-config ciphers - - run: golangci-lint run --no-config data-structures/binary-tree || true - - run: golangci-lint run --no-config data-structures/dynamic-array || true - - run: golangci-lint run --no-config data-structures/hash-map - - run: golangci-lint run --no-config data-structures/linked-list || true - - run: golangci-lint run --no-config data-structures/trie || true - - run: golangci-lint run --no-config dynamic-programming || true + - run: golangci-lint run --no-config datastructures/binary-tree || true + - run: golangci-lint run --no-config datastructures/dynamic-array || true + - run: golangci-lint run --no-config datastructures/hashmap + - run: golangci-lint run --no-config datastructures/linkedlist || true + - run: golangci-lint run --no-config datastructures/trie || true + - run: golangci-lint run --no-config dynamicprogramming || true - run: golangci-lint run --no-config other || true - run: golangci-lint run --no-config searches || true - run: golangci-lint run --no-config sorts diff --git a/data-structures/binary-tree/binary-search-tree.go b/datastructures/binary-tree/binarysearchtree.go similarity index 100% rename from data-structures/binary-tree/binary-search-tree.go rename to datastructures/binary-tree/binarysearchtree.go diff --git a/data-structures/binary-tree/binary-tree.go b/datastructures/binary-tree/binarytree.go similarity index 100% rename from data-structures/binary-tree/binary-tree.go rename to datastructures/binary-tree/binarytree.go diff --git a/data-structures/dynamic-array/dynamic_array.go b/datastructures/dynamic-array/dynamicarray.go similarity index 100% rename from data-structures/dynamic-array/dynamic_array.go rename to datastructures/dynamic-array/dynamicarray.go diff --git a/data-structures/hash-map/hash_map.go b/datastructures/hashmap/hashmap.go similarity index 100% rename from data-structures/hash-map/hash_map.go rename to datastructures/hashmap/hashmap.go diff --git a/data-structures/hash-map/hash_map_test.go b/datastructures/hashmap/hashmap_test.go similarity index 88% rename from data-structures/hash-map/hash_map_test.go rename to datastructures/hashmap/hashmap_test.go index 4c3124eee..8b65fc70f 100644 --- a/data-structures/hash-map/hash_map_test.go +++ b/datastructures/hashmap/hashmap_test.go @@ -1,7 +1,7 @@ package hashmap_test import ( - hashmap "TheAlgorithms/Go/data-structures/hash-map" + "TheAlgorithms/Go/datastructures/hashmap" "fmt" "testing" ) diff --git a/data-structures/linked-list/double-linkedlist.go b/datastructures/linkedlist/doublylinkedlist.go similarity index 98% rename from data-structures/linked-list/double-linkedlist.go rename to datastructures/linkedlist/doublylinkedlist.go index c87f9003b..9b05130ed 100644 --- a/data-structures/linked-list/double-linkedlist.go +++ b/datastructures/linkedlist/doublylinkedlist.go @@ -1,6 +1,6 @@ // demonstration of doubly linked list in golang -package doublelinkedlist +package linkedlist // package main diff --git a/data-structures/linked-list/singlelinkedlist/single-linkedlist.go b/datastructures/linkedlist/singlelinkedlist/single-linkedlist.go similarity index 100% rename from data-structures/linked-list/singlelinkedlist/single-linkedlist.go rename to datastructures/linkedlist/singlelinkedlist/single-linkedlist.go diff --git a/data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go b/datastructures/linkedlist/singlelinkedlist/single-linkedlist_test.go similarity index 100% rename from data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go rename to datastructures/linkedlist/singlelinkedlist/single-linkedlist_test.go diff --git a/data-structures/linked-list/Linkedlist.go b/datastructures/linkedlist/singlylinkedlist.go similarity index 99% rename from data-structures/linked-list/Linkedlist.go rename to datastructures/linkedlist/singlylinkedlist.go index bacfcb88c..be23eb7a7 100644 --- a/data-structures/linked-list/Linkedlist.go +++ b/datastructures/linkedlist/singlylinkedlist.go @@ -1,4 +1,4 @@ -package main +package linkedlist import "fmt" diff --git a/data-structures/trie/trie.go b/datastructures/trie/trie.go similarity index 100% rename from data-structures/trie/trie.go rename to datastructures/trie/trie.go diff --git a/data-structures/trie/trie_test.go b/datastructures/trie/trie_test.go similarity index 100% rename from data-structures/trie/trie_test.go rename to datastructures/trie/trie_test.go diff --git a/dynamic-programming/binomial-coeffecient.go b/dynamicprogramming/binomialcoeffecient.go similarity index 100% rename from dynamic-programming/binomial-coeffecient.go rename to dynamicprogramming/binomialcoeffecient.go diff --git a/dynamic-programming/knapsack.go b/dynamicprogramming/knapsack.go similarity index 100% rename from dynamic-programming/knapsack.go rename to dynamicprogramming/knapsack.go diff --git a/dynamic-programming/longest-palindromic-subsequence.go b/dynamicprogramming/longest-palindromic-subsequence.go similarity index 100% rename from dynamic-programming/longest-palindromic-subsequence.go rename to dynamicprogramming/longest-palindromic-subsequence.go diff --git a/dynamic-programming/longestCommonSubsequence.go b/dynamicprogramming/longestCommonSubsequence.go similarity index 100% rename from dynamic-programming/longestCommonSubsequence.go rename to dynamicprogramming/longestCommonSubsequence.go diff --git a/dynamic-programming/matrix-multiplication.go b/dynamicprogramming/matrix-multiplication.go similarity index 93% rename from dynamic-programming/matrix-multiplication.go rename to dynamicprogramming/matrix-multiplication.go index dc77ee0a6..e02d98b20 100644 --- a/dynamic-programming/matrix-multiplication.go +++ b/dynamicprogramming/matrix-multiplication.go @@ -1,6 +1,6 @@ // matrix chain multiplication problem // https://en.wikipedia.org/wiki/Matrix_chain_multiplication -// www.geeksforgeeks.org/dynamic-programming-set-8-matrix-chain-multiplication/ +// www.geeksforgeeks.org/dynamicprogramming-set-8-matrix-chain-multiplication/ // package main package matrixChainMultiplication diff --git a/dynamic-programming/rod-cutting.go b/dynamicprogramming/rod-cutting.go similarity index 100% rename from dynamic-programming/rod-cutting.go rename to dynamicprogramming/rod-cutting.go diff --git a/searches/breadth_first_search.go b/graphs/breathfirstsearch.go similarity index 98% rename from searches/breadth_first_search.go rename to graphs/breathfirstsearch.go index b67c61a06..66e8c7e29 100644 --- a/searches/breadth_first_search.go +++ b/graphs/breathfirstsearch.go @@ -1,4 +1,4 @@ -package main +package graphs import "fmt" diff --git a/searches/depth_first_search.go b/graphs/depthfirstsearch.go similarity index 98% rename from searches/depth_first_search.go rename to graphs/depthfirstsearch.go index 502ffd724..6f0003c46 100644 --- a/searches/depth_first_search.go +++ b/graphs/depthfirstsearch.go @@ -1,4 +1,4 @@ -package main +package graphs import "fmt" diff --git a/graphs/floyd_warshall.go b/graphs/floydwarshall.go similarity index 99% rename from graphs/floyd_warshall.go rename to graphs/floydwarshall.go index 75303eeca..4fe0807ce 100644 --- a/graphs/floyd_warshall.go +++ b/graphs/floydwarshall.go @@ -1,7 +1,7 @@ // Floyd-Warshall algorithm // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm -package main +package graphs import ( "math" diff --git a/math/gcd/greatest_common_divisor.go b/math/gcd/gcd.go similarity index 100% rename from math/gcd/greatest_common_divisor.go rename to math/gcd/gcd.go diff --git a/math/gcd/greatest_common_divisor_test.go b/math/gcd/gcd_test.go similarity index 100% rename from math/gcd/greatest_common_divisor_test.go rename to math/gcd/gcd_test.go diff --git a/math/power/fastExponent.go b/math/power/fastexponent.go similarity index 100% rename from math/power/fastExponent.go rename to math/power/fastexponent.go diff --git a/math/power/fastExponent_test.go b/math/power/fastexponent_test.go similarity index 100% rename from math/power/fastExponent_test.go rename to math/power/fastexponent_test.go diff --git a/math/primecheck/prime_check.go b/math/primecheck/primecheck.go similarity index 100% rename from math/primecheck/prime_check.go rename to math/primecheck/primecheck.go diff --git a/math/primecheck/prime_check_test.go b/math/primecheck/primecheck_test.go similarity index 100% rename from math/primecheck/prime_check_test.go rename to math/primecheck/primecheck_test.go diff --git a/other/maxSubarraySum.go b/other/maxsubarraysum.go similarity index 100% rename from other/maxSubarraySum.go rename to other/maxsubarraysum.go diff --git a/other/NestedBrackets.go b/other/nestedbrackets.go similarity index 100% rename from other/NestedBrackets.go rename to other/nestedbrackets.go diff --git a/other/PasswordGenerator.go b/other/passwordgenerator.go similarity index 100% rename from other/PasswordGenerator.go rename to other/passwordgenerator.go diff --git a/other/string_combinations.go b/other/stringcombinations.go similarity index 100% rename from other/string_combinations.go rename to other/stringcombinations.go diff --git a/searches/binary_search.go b/searches/binarysearch.go similarity index 97% rename from searches/binary_search.go rename to searches/binarysearch.go index d37b70955..48592d67f 100644 --- a/searches/binary_search.go +++ b/searches/binarysearch.go @@ -1,4 +1,4 @@ -package main +package searches func binarySearch(array []int, target int, lowIndex int, highIndex int) int { if highIndex < lowIndex { diff --git a/searches/linear_search.go b/searches/linearsearch.go similarity index 96% rename from searches/linear_search.go rename to searches/linearsearch.go index ef997a874..23baec9e9 100644 --- a/searches/linear_search.go +++ b/searches/linearsearch.go @@ -1,4 +1,4 @@ -package main +package searches import "fmt" diff --git a/searches/search_test.go b/searches/search_test.go index 91d1125bd..d4a3f2c78 100644 --- a/searches/search_test.go +++ b/searches/search_test.go @@ -1,4 +1,4 @@ -package main +package searches import "testing" diff --git a/sorts/heap_sort.go b/sorts/heapsort.go similarity index 100% rename from sorts/heap_sort.go rename to sorts/heapsort.go diff --git a/sorts/insertion_sort.go b/sorts/insertionsort.go similarity index 100% rename from sorts/insertion_sort.go rename to sorts/insertionsort.go diff --git a/sorts/merge_sort.go b/sorts/mergesort.go similarity index 100% rename from sorts/merge_sort.go rename to sorts/mergesort.go diff --git a/sorts/quick_sort.go b/sorts/quicksort.go similarity index 100% rename from sorts/quick_sort.go rename to sorts/quicksort.go diff --git a/sorts/radix_sort.go b/sorts/radixsort.go similarity index 100% rename from sorts/radix_sort.go rename to sorts/radixsort.go diff --git a/sorts/selection_sort.go b/sorts/selectionsort.go similarity index 100% rename from sorts/selection_sort.go rename to sorts/selectionsort.go diff --git a/sorts/shell_sort.go b/sorts/shellsort.go similarity index 100% rename from sorts/shell_sort.go rename to sorts/shellsort.go diff --git a/sorts/sorts_case_test.go b/sorts/sorts_testcases.go similarity index 100% rename from sorts/sorts_case_test.go rename to sorts/sorts_testcases.go diff --git a/sorts/topological_sort.go b/sorts/topologicalsort.go similarity index 98% rename from sorts/topological_sort.go rename to sorts/topologicalsort.go index 91ff40d51..a725f9d0a 100644 --- a/sorts/topological_sort.go +++ b/sorts/topologicalsort.go @@ -1,7 +1,7 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -/*type Dependency struct { +type Dependency struct { nodeId int children []int } @@ -81,7 +81,7 @@ func topologicalSort(input []Edge) ([]int, [][]int) { levels = append(levels, level) } return res, levels -}*/ +} /*func main() { var edges []Edge From 5110300309b16e9d000d9fada4785cd6a1a2fe39 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 27 Oct 2020 15:54:24 +0000 Subject: [PATCH 140/488] updating DIRECTORY.md --- DIRECTORY.md | 90 ++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 0de8fdc74..3aaae2e7d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -17,46 +17,48 @@ * [Xor Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xor_cipher_test.go) * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xorCipher.go) -## Data-Structures +## Datastructures * Binary-Tree - * [Binary-Search-Tree](https://github.com/TheAlgorithms/Go/blob/master/data-structures/binary-tree/binary-search-tree.go) - * [Binary-Tree](https://github.com/TheAlgorithms/Go/blob/master/data-structures/binary-tree/binary-tree.go) + * [Binarysearchtree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/binarysearchtree.go) + * [Binarytree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/binarytree.go) * Dynamic-Array - * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data-structures/dynamic-array/dynamic_array.go) - * Hash-Map - * [Hash Map](https://github.com/TheAlgorithms/Go/blob/master/data-structures/hash-map/hash_map.go) - * [Hash Map Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/hash-map/hash_map_test.go) - * Linked-List - * [Double-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/double-linkedlist.go) - * [Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/Linkedlist.go) + * [Dynamicarray](https://github.com/TheAlgorithms/Go/blob/master/datastructures/dynamic-array/dynamicarray.go) + * Hashmap + * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/datastructures/hashmap/hashmap.go) + * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/hashmap/hashmap_test.go) + * Linkedlist + * [Doublylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/doublylinkedlist.go) * Singlelinkedlist - * [Single-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/singlelinkedlist/single-linkedlist.go) - * [Single-Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/linked-list/singlelinkedlist/single-linkedlist_test.go) + * [Single-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlelinkedlist/single-linkedlist.go) + * [Single-Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlelinkedlist/single-linkedlist_test.go) + * [Singlylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist.go) * Trie - * [Trie](https://github.com/TheAlgorithms/Go/blob/master/data-structures/trie/trie.go) - * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/data-structures/trie/trie_test.go) + * [Trie](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie.go) + * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie_test.go) -## Dynamic-Programming - * [Binomial-Coeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/binomial-coeffecient.go) - * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/knapsack.go) - * [Longest-Palindromic-Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longest-palindromic-subsequence.go) - * [Longestcommonsubsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/longestCommonSubsequence.go) - * [Matrix-Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/matrix-multiplication.go) - * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamic-programming/rod-cutting.go) +## Dynamicprogramming + * [Binomialcoeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/binomialcoeffecient.go) + * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/knapsack.go) + * [Longest-Palindromic-Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/longest-palindromic-subsequence.go) + * [Longestcommonsubsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/longestCommonSubsequence.go) + * [Matrix-Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/matrix-multiplication.go) + * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/rod-cutting.go) ## Graphs - * [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall.go) + * [Breathfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/breathfirstsearch.go) + * [Depthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/depthfirstsearch.go) + * [Floydwarshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floydwarshall.go) ## Math * Gcd - * [Greatest Common Divisor](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/greatest_common_divisor.go) - * [Greatest Common Divisor Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/greatest_common_divisor_test.go) + * [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go) + * [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go) * Power - * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastExponent.go) - * [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastExponent_test.go) + * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent.go) + * [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent_test.go) * Primecheck - * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/prime_check.go) - * [Prime Check Test](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/prime_check_test.go) + * [Primecheck](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/primecheck.go) + * [Primecheck Test](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/primecheck_test.go) * Pythagoras * [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras.go) * [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go) @@ -64,36 +66,34 @@ * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/Sieve.go) ## Other - * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxSubarraySum.go) + * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxsubarraysum.go) * Monte Carlo Pi * [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi.go) * [Monte Carlo Pi Test](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi_test.go) - * [Nestedbrackets](https://github.com/TheAlgorithms/Go/blob/master/other/NestedBrackets.go) - * [Passwordgenerator](https://github.com/TheAlgorithms/Go/blob/master/other/PasswordGenerator.go) + * [Nestedbrackets](https://github.com/TheAlgorithms/Go/blob/master/other/nestedbrackets.go) + * [Passwordgenerator](https://github.com/TheAlgorithms/Go/blob/master/other/passwordgenerator.go) * [Prime Numbers](https://github.com/TheAlgorithms/Go/blob/master/other/prime_numbers.go) * [Primenumbers](https://github.com/TheAlgorithms/Go/blob/master/other/PrimeNumbers.go) - * [String Combinations](https://github.com/TheAlgorithms/Go/blob/master/other/string_combinations.go) + * [Stringcombinations](https://github.com/TheAlgorithms/Go/blob/master/other/stringcombinations.go) ## Searches - * [Binary Search](https://github.com/TheAlgorithms/Go/blob/master/searches/binary_search.go) - * [Breadth First Search](https://github.com/TheAlgorithms/Go/blob/master/searches/breadth_first_search.go) - * [Depth First Search](https://github.com/TheAlgorithms/Go/blob/master/searches/depth_first_search.go) - * [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search.go) + * [Binarysearch](https://github.com/TheAlgorithms/Go/blob/master/searches/binarysearch.go) + * [Linearsearch](https://github.com/TheAlgorithms/Go/blob/master/searches/linearsearch.go) * [Search Test](https://github.com/TheAlgorithms/Go/blob/master/searches/search_test.go) ## Sorts * [Bubblesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubblesort.go) * [Countingsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/countingsort.go) - * [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heap_sort.go) - * [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertion_sort.go) - * [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/merge_sort.go) - * [Quick Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quick_sort.go) - * [Radix Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radix_sort.go) - * [Selection Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selection_sort.go) - * [Shell Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shell_sort.go) - * [Sorts Case Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_case_test.go) + * [Heapsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heapsort.go) + * [Insertionsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertionsort.go) + * [Mergesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/mergesort.go) + * [Quicksort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quicksort.go) + * [Radixsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radixsort.go) + * [Selectionsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selectionsort.go) + * [Shellsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shellsort.go) * [Sorts Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_test.go) - * [Topological Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/topological_sort.go) + * [Sorts Testcases](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_testcases.go) + * [Topologicalsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/topologicalsort.go) ## Strings * Levenshteindistance From 920b018573ff6f0219afc706c6dec40d4399c980 Mon Sep 17 00:00:00 2001 From: Navid Zarepak Date: Tue, 27 Oct 2020 20:22:30 +0330 Subject: [PATCH 141/488] Added roman to integer conversion (#240) * Create roman_to_integer.go * test for roman to integer conversion * Delete countingsort.go Co-authored-by: Christian Clauss --- .../roman-to-integer/roman_to_integer.go | 25 ++++++++++++++++ .../roman-to-integer/roman_to_integer_test.go | 29 +++++++++++++++++++ sorts/countingsort.go | 27 ----------------- 3 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 conversions/roman-to-integer/roman_to_integer.go create mode 100644 conversions/roman-to-integer/roman_to_integer_test.go delete mode 100644 sorts/countingsort.go diff --git a/conversions/roman-to-integer/roman_to_integer.go b/conversions/roman-to-integer/roman_to_integer.go new file mode 100644 index 000000000..b9601e7db --- /dev/null +++ b/conversions/roman-to-integer/roman_to_integer.go @@ -0,0 +1,25 @@ +/* +This algorithm will convert a standard roman number to an integer +https://en.wikipedia.org/wiki/Roman_numerals +Function receives a string as a roman number and outputs an integer +Maximum output will be 3999 +Only standard form is supported +*/ +package conversions + +var romans = map[string]int{"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} + +func RomanToInteger(roman string) int { + total := 0 + holder := 0 + for holder < len(roman) { + if holder+1 < len(roman) && (romans[string(roman[holder])] < romans[string(roman[holder+1])]) { + total += romans[string(roman[holder+1])] - romans[string(roman[holder])] + holder += 2 + } else { + total += romans[string(roman[holder])] + holder++ + } + } + return total +} diff --git a/conversions/roman-to-integer/roman_to_integer_test.go b/conversions/roman-to-integer/roman_to_integer_test.go new file mode 100644 index 000000000..9923e596a --- /dev/null +++ b/conversions/roman-to-integer/roman_to_integer_test.go @@ -0,0 +1,29 @@ +package conversions + +import "testing" + +type romanToIntegerConversionTest struct { + input string + expected int + name string +} + +var romanToIntegerTests = []romanToIntegerConversionTest{ + {input: "DCCLXXXIX", expected: 789, name: "DCCLXXXIX-789"}, + {input: "MLXVI", expected: 1066, name: "MLXVI-1066"}, + {input: "MCMXVIII", expected: 1918, name: "MCMXVIII-1918"}, + {input: "V", expected: 5, name: "V-5"}, +} + +func TestRomanToInteger(t *testing.T) { + + for _, test := range romanToIntegerTests { + convertedValue := RomanToInteger(test.input) + if convertedValue != test.expected { + t.Errorf( + "roman to integer test %s failed. expected '%d' but got '%d'", + test.name, test.expected, convertedValue, + ) + } + } +} diff --git a/sorts/countingsort.go b/sorts/countingsort.go deleted file mode 100644 index 930955cd7..000000000 --- a/sorts/countingsort.go +++ /dev/null @@ -1,27 +0,0 @@ -// Reference: https://en.wikipedia.org/wiki/Counting_sort - -package sorts - -func countingSort(arr []int) []int { - if len(arr) == 0 { - return make([]int, 0) - } - maxElement := arr[0] - for i := 1; i < len(arr); i++ { - if arr[i] > maxElement { - maxElement = arr[i] - } - } - - counts := make([]int, maxElement+1) - result := make([]int, 0) - for _, item := range arr { - counts[item]++ - } - for i := 0; i <= maxElement; i++ { - for j := 0; j < counts[i]; j++ { - result = append(result, i) - } - } - return result -} From 602e3bb4d1684ace1587c0028544040b7558b91d Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Tue, 27 Oct 2020 16:52:46 +0000 Subject: [PATCH 142/488] updating DIRECTORY.md --- DIRECTORY.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 3aaae2e7d..7ad71d481 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -17,6 +17,11 @@ * [Xor Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xor_cipher_test.go) * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xorCipher.go) +## Conversions + * Roman-To-Integer + * [Roman To Integer](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman-to-integer/roman_to_integer.go) + * [Roman To Integer Test](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman-to-integer/roman_to_integer_test.go) + ## Datastructures * Binary-Tree * [Binarysearchtree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/binarysearchtree.go) @@ -83,7 +88,6 @@ ## Sorts * [Bubblesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubblesort.go) - * [Countingsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/countingsort.go) * [Heapsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heapsort.go) * [Insertionsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertionsort.go) * [Mergesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/mergesort.go) From e87997988fde54dbbf09afa0d493dca59a5ddeb1 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 27 Oct 2020 18:24:44 +0100 Subject: [PATCH 143/488] Delete topologicalsort.go (#250) * Delete topologicalsort.go * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 1 - sorts/topologicalsort.go | 112 --------------------------------------- 2 files changed, 113 deletions(-) delete mode 100644 sorts/topologicalsort.go diff --git a/DIRECTORY.md b/DIRECTORY.md index 7ad71d481..8a2d26991 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -97,7 +97,6 @@ * [Shellsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shellsort.go) * [Sorts Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_test.go) * [Sorts Testcases](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_testcases.go) - * [Topologicalsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/topologicalsort.go) ## Strings * Levenshteindistance diff --git a/sorts/topologicalsort.go b/sorts/topologicalsort.go deleted file mode 100644 index a725f9d0a..000000000 --- a/sorts/topologicalsort.go +++ /dev/null @@ -1,112 +0,0 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts - -type Dependency struct { - nodeId int - children []int -} - -// converts dependencies to edges -func dependenciesToEdges(dependencies []Dependency) []Edge { - edges := []Edge{} - for _, node := range dependencies { - for _, child := range node.children { - edges = append(edges, Edge{start: node.nodeId, end: child}) - } - } - return edges -} - -type Edge struct { - start int // start and end are node ids - end int -} - -type Node struct { - id int - children []int - selected bool - incoming int -} - -// takes a list of edges as input with start and end node_ids -// useful for cases like task ordering -func topologicalSort(input []Edge) ([]int, [][]int) { - - // generate a mapping for node_id and number of incoming edges - incoming := make(map[int]int) - for _, edge := range input { - if _, ok := incoming[edge.start]; !ok { - incoming[edge.start] = 0 - } - incoming[edge.end] += 1 - } - - nodes := make([]*Node, 0) - for k, v := range incoming { - chdn := []int{} - for _, edge := range input { - if edge.start == k { - chdn = append(chdn, edge.end) - } - } - nodes = append(nodes, &Node{id: k, children: chdn, selected: false, incoming: v}) - } - - res := []int{} - var levels [][]int - for len(res) < len(nodes) { - level := []int{} - queue := []int{} - for idx, node := range nodes { - // select a node with no incoming dependency - if !node.selected && node.incoming == 0 { - queue = append(queue, idx) - nodes[idx].selected = true - } - } - for _, idx := range queue { - node := nodes[idx] - level = append(level, node.id) - // decrement incoming values for all children - for _, childId := range node.children { - for _, child := range nodes { - if !child.selected && child.id == childId { - child.incoming-- - } - } - } - } - res = append(res, level...) - levels = append(levels, level) - } - return res, levels -} - -/*func main() { - var edges []Edge - edges = append(edges, Edge{1, 2}) - edges = append(edges, Edge{2, 3}) - edges = append(edges, Edge{4, 3}) - edges = append(edges, Edge{4, 5}) - edges = append(edges, Edge{3, 6}) - edges = append(edges, Edge{5, 6}) - - order, levels := topologicalSort(edges) - fmt.Println("result: ", order) - fmt.Println("levels: ", levels) - - // or you can specify dependencies - var deps []Dependency - deps = append(deps, Dependency{nodeId: 1, children: []int{2}}) - deps = append(deps, Dependency{nodeId: 2, children: []int{3}}) - deps = append(deps, Dependency{nodeId: 4, children: []int{3, 5}}) - deps = append(deps, Dependency{nodeId: 5, children: []int{6}}) - deps = append(deps, Dependency{nodeId: 3, children: []int{6}}) - - edges = dependenciesToEdges(deps) - order, levels = topologicalSort(edges) - fmt.Println("result: ", order) - fmt.Println("levels: ", levels) - -}*/ From f6b4606ebd833df06b8582e01e47ec9751d3dd00 Mon Sep 17 00:00:00 2001 From: OOP Date: Sat, 31 Oct 2020 17:00:45 +0700 Subject: [PATCH 144/488] add new testcase and fix typo --- ciphers/xor/xor_cipher_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ciphers/xor/xor_cipher_test.go b/ciphers/xor/xor_cipher_test.go index 3e7c8e14e..0b3a2aefc 100644 --- a/ciphers/xor/xor_cipher_test.go +++ b/ciphers/xor/xor_cipher_test.go @@ -48,11 +48,17 @@ var xorTestData = []struct { "boffe*}exfn", }, { - "Encrypt full sentence with key 128", + "Encrypt full sentence with key 64", "the quick brown fox jumps over the lazy dog.", 64, "4(%`15)#+`\"2/7.`&/8`*5-03`/6%2`4(%`,!:9`$/'n", }, + { + "Encrypt a word with key 32 make the case swap", + "abcdefghijklmNOPQRSTUVWXYZ", + 32, + "ABCDEFGHIJKLMnopqrstuvwxyz", + }, } func TestXorCipherEncrypt(t *testing.T) { From 98add674888591fadbf372acc161c46ef181bba6 Mon Sep 17 00:00:00 2001 From: Jason Jiang Date: Mon, 2 Nov 2020 19:01:22 +1300 Subject: [PATCH 145/488] Add fibonacci algorithm by dynamic programming (#252) * Add fibonacci algorithm by dynamic programming * Improve fibonacci.go implementation * Add test for NthFibonacci function * Put the test runs inside test cases loop --- dynamicprogramming/fibonacc_test.go | 42 +++++++++++++++++++++++++++++ dynamicprogramming/fibonacci.go | 21 +++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 dynamicprogramming/fibonacc_test.go create mode 100644 dynamicprogramming/fibonacci.go diff --git a/dynamicprogramming/fibonacc_test.go b/dynamicprogramming/fibonacc_test.go new file mode 100644 index 000000000..e14806107 --- /dev/null +++ b/dynamicprogramming/fibonacc_test.go @@ -0,0 +1,42 @@ +package dynamicprogramming + +import ( + "fmt" + "testing" +) + +func Test_NthFibonacci(t *testing.T) { + // source: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibtable.html + var fibonacciNumbers = []struct { + nth uint + fibonacci uint + }{ + {0, 0}, + {1, 1}, + {2, 1}, + {3, 2}, + {4, 3}, + {5, 5}, + {6, 8}, + {7, 13}, + {8, 21}, + {9, 34}, + {10, 55}, + {20, 6765}, + {30, 832040}, + {40, 102334155}, + {50, 12586269025}, + {60, 1548008755920}, + {70, 190392490709135}, + {80, 23416728348467685}, + {90, 2880067194370816120}, + } + for i := range fibonacciNumbers { + t.Run(fmt.Sprintf("the %dth Fibonacci number", fibonacciNumbers[i].nth), func(t *testing.T) { + result := NthFibonacci(fibonacciNumbers[i].nth) + if result != fibonacciNumbers[i].fibonacci { + t.Errorf("Expected the %dth Fibonacci number to be %d, got %d", fibonacciNumbers[i].nth, fibonacciNumbers[i].fibonacci, result) + } + }) + } +} diff --git a/dynamicprogramming/fibonacci.go b/dynamicprogramming/fibonacci.go new file mode 100644 index 000000000..2d6d3417c --- /dev/null +++ b/dynamicprogramming/fibonacci.go @@ -0,0 +1,21 @@ +package dynamicprogramming + +// https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/ + +// NthFibonacci returns the nth Fibonacci Number +func NthFibonacci(n uint) uint { + if n == 0 { + return 0 + } + + // n1 and n2 are the (i-1)th and ith Fibonacci numbers, respectively + var n1, n2 uint = 0, 1 + + for i := uint(1); i < n; i++ { + n3 := n1 + n2 + n1 = n2 + n2 = n3 + } + + return n2 +} From 70432933dfcf89c747bf72475bbe2a87be159820 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 2 Nov 2020 06:01:38 +0000 Subject: [PATCH 146/488] updating DIRECTORY.md --- DIRECTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 8a2d26991..d0596e056 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -43,6 +43,8 @@ ## Dynamicprogramming * [Binomialcoeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/binomialcoeffecient.go) + * [Fibonacc Test](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/fibonacc_test.go) + * [Fibonacci](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/fibonacci.go) * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/knapsack.go) * [Longest-Palindromic-Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/longest-palindromic-subsequence.go) * [Longestcommonsubsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/longestCommonSubsequence.go) From 20aa5797d73b6939f0f1f5bce1c0a53caca7868d Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Wed, 13 Jan 2021 23:11:46 +0530 Subject: [PATCH 147/488] Fix README.md and added Contribution.md --- CONTRIBUTING.md | 0 README.md | 167 ++---------------------------------------------- 2 files changed, 5 insertions(+), 162 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..e69de29bb diff --git a/README.md b/README.md index 70f817aa1..2259a3212 100644 --- a/README.md +++ b/README.md @@ -2,172 +2,15 @@ ![golangci-lint](https://github.com/TheAlgorithms/Go/workflows/golangci-lint/badge.svg) ![Go](https://github.com/TheAlgorithms/Go/workflows/Go/badge.svg) +![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  ![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) ### Algorithms implemented in Go (for education) -These algorithms are for demonstration purposes only. There are many sort implementations in the Go standard library that may have better performance. +The repository is a collection of open-source implementation of a variety of algorithms implemented in Go and licensed under [MIT License](LICENSE). -For a full list of all algorithms, please see: [DIRECTORY.md](https://github.com/TheAlgorithms/Go/blob/master/DIRECTORY.md) +Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. -## Sort Algorithms +## List of Algorithms - -### Bubble -![alt text][bubble-image] - -From [Wikipedia][bubble-wiki]: Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares each pair of adjacent items and swaps them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted. - -__Properties__ -* Worst case performance O(n^2) -* Best case performance O(n) -* Average case performance O(n^2) - -###### View the algorithm in [action][bubble-toptal] - - - -### Insertion -![alt text][insertion-image] - -From [Wikipedia][insertion-wiki]: Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. - -__Properties__ -* Worst case performance O(n^2) -* Best case performance O(n) -* Average case performance O(n^2) - -###### View the algorithm in [action][insertion-toptal] - - -### Merge -![alt text][merge-image] - -From [Wikipedia][merge-wiki]: In computer science, merge sort (also commonly spelled mergesort) is an efficient, general-purpose, comparison-based sorting algorithm. Most implementations produce a stable sort, which means that the implementation preserves the input order of equal elements in the sorted output. Mergesort is a divide and conquer algorithm that was invented by John von Neumann in 1945. - -__Properties__ -* Worst case performance O(n log n) -* Best case performance O(n) -* Average case performance O(n) - - -###### View the algorithm in [action][merge-toptal] - -### Quick -![alt text][quick-image] - -From [Wikipedia][quick-wiki]: Quicksort (sometimes called partition-exchange sort) is an efficient sorting algorithm, serving as a systematic method for placing the elements of an array in order. - -__Properties__ -* Worst case performance O(n^2) -* Best case performance O(n log n) or O(n) with three-way partition -* Average case performance O(n^2) - -###### View the algorithm in [action][quick-toptal] - -### Selection -![alt text][selection-image] - -From [Wikipedia][selection-wiki]: The algorithm divides the input list into two parts: the sublist of items already sorted, which is built up from left to right at the front (left) of the list, and the sublist of items remaining to be sorted that occupy the rest of the list. Initially, the sorted sublist is empty and the unsorted sublist is the entire input list. The algorithm proceeds by finding the smallest (or largest, depending on sorting order) element in the unsorted sublist, exchanging (swapping) it with the leftmost unsorted element (putting it in sorted order), and moving the sublist boundaries one element to the right. - -__Properties__ -* Worst case performance O(n^2) -* Best case performance O(n^2) -* Average case performance O(n^2) - -###### View the algorithm in [action][selection-toptal] - -### Shell -![alt text][shell-image] - -From [Wikipedia][shell-wiki]: Shellsort is a generalization of insertion sort that allows the exchange of items that are far apart. The idea is to arrange the list of elements so that, starting anywhere, considering every nth element gives a sorted list. Such a list is said to be h-sorted. Equivalently, it can be thought of as h interleaved lists, each individually sorted. - -__Properties__ -* Worst case performance O(nlog2 2n) -* Best case performance O(n log n) -* Average case performance depends on gap sequence - -###### View the algorithm in [action][shell-toptal] - -### Time-Complexity Graphs - -Comparing the complexity of sorting algorithms (Bubble Sort, Insertion Sort, Selection Sort) - -[Complexity Graphs](https://github.com/prateekiiest/Python/blob/master/sorts/sortinggraphs.png) - ----------------------------------------------------------------------------------- - -## Search Algorithms - -### Linear -![alt text][linear-image] - -From [Wikipedia][linear-wiki]: linear search or sequential search is a method for finding a target value within a list. It sequentially checks each element of the list for the target value until a match is found or until all the elements have been searched. - Linear search runs in at the worst linear time and makes at most n comparisons, where n is the length of the list. - -__Properties__ -* Worst case performance O(n) -* Best case performance O(1) -* Average case performance O(n) -* Worst case space complexity O(1) iterative - -### Binary -![alt text][binary-image] - -From [Wikipedia][binary-wiki]: Binary search, also known as half-interval search or logarithmic search, is a search algorithm that finds the position of a target value within a sorted array. It compares the target value to the middle element of the array; if they are unequal, the half in which the target cannot lie is eliminated and the search continues on the remaining half until it is successful. - -__Properties__ -* Worst case performance O(log n) -* Best case performance O(1) -* Average case performance O(log n) -* Worst case space complexity O(1) - ----------------------------------------------------------------------------------------------------------------------- - -## Ciphers - -### Caesar -![alt text][caesar]
-In cryptography, a **Caesar cipher**, also known as Caesar's cipher, the shift cipher, Caesar's code or Caesar shift, is one of the simplest and most widely known encryption techniques.
-It is **a type of substitution cipher** in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of 3, D would be replaced by A, E would become B, and so on.
-The method is named after **Julius Caesar**, who used it in his private correspondence.
-The encryption step performed by a Caesar cipher is often incorporated as part of more complex schemes, such as the Vigenère cipher, and still has modern applications in the ROT13 system. As with all single-alphabet substitution ciphers, the Caesar cipher is easily broken and in modern practice offers essentially no communication security. -###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher) - -### Transposition -In cryptography, a **transposition cipher** is a method of encryption by which the positions held by units of plaintext (which are commonly characters or groups of characters) are shifted according to a regular system, so that the ciphertext constitutes a permutation of the plaintext. That is, the order of the units is changed (the plaintext is reordered).
-Mathematically a bijective function is used on the characters' positions to encrypt and an inverse function to decrypt. -###### Source: [Wikipedia](https://en.wikipedia.org/wiki/Transposition_cipher) - -[bubble-toptal]: https://www.toptal.com/developers/sorting-algorithms/bubble-sort -[bubble-wiki]: https://en.wikipedia.org/wiki/Bubble_sort -[bubble-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Bubblesort-edited-color.svg/220px-Bubblesort-edited-color.svg.png "Bubble Sort" - -[insertion-toptal]: https://www.toptal.com/developers/sorting-algorithms/insertion-sort -[insertion-wiki]: https://en.wikipedia.org/wiki/Insertion_sort -[insertion-image]: https://upload.wikimedia.org/wikipedia/commons/7/7e/Insertionsort-edited.png "Insertion Sort" - -[quick-toptal]: https://www.toptal.com/developers/sorting-algorithms/quick-sort -[quick-wiki]: https://en.wikipedia.org/wiki/Quicksort -[quick-image]: https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif "Quick Sort" - -[merge-toptal]: https://www.toptal.com/developers/sorting-algorithms/merge-sort -[merge-wiki]: https://en.wikipedia.org/wiki/Merge_sort -[merge-image]: https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif "Merge Sort" - -[selection-toptal]: https://www.toptal.com/developers/sorting-algorithms/selection-sort -[selection-wiki]: https://en.wikipedia.org/wiki/Selection_sort -[selection-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Selection_sort_animation.gif/250px-Selection_sort_animation.gif "Selection Sort Sort" - -[shell-toptal]: https://www.toptal.com/developers/sorting-algorithms/shell-sort -[shell-wiki]: https://en.wikipedia.org/wiki/Shellsort -[shell-image]: https://upload.wikimedia.org/wikipedia/commons/d/d8/Sorting_shellsort_anim.gif "Shell Sort" - -[linear-wiki]: https://en.wikipedia.org/wiki/Linear_search -[linear-image]: http://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif - -[binary-wiki]: https://en.wikipedia.org/wiki/Binary_search_algorithm -[binary-image]: https://upload.wikimedia.org/wikipedia/commons/f/f7/Binary_search_into_array.png - - -[caesar]: https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg +See our [directory](DIRECTORY.md). From dcecf5b9b85d8730b481625d38a9ab1d23334714 Mon Sep 17 00:00:00 2001 From: mike zhang Date: Thu, 14 Jan 2021 13:30:14 +0800 Subject: [PATCH 148/488] fix stack overflow problem and add more test --- searches/binarysearch.go | 19 ++++++++++++------- searches/search_test.go | 13 +++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/searches/binarysearch.go b/searches/binarysearch.go index 48592d67f..5a7f32fa1 100644 --- a/searches/binarysearch.go +++ b/searches/binarysearch.go @@ -1,12 +1,13 @@ package searches + func binarySearch(array []int, target int, lowIndex int, highIndex int) int { - if highIndex < lowIndex { + if highIndex < lowIndex || len(array) == 0{ return -1 } - mid := int(lowIndex + (highIndex-lowIndex)/2) + mid := (highIndex+lowIndex)/2 if array[mid] > target { - return binarySearch(array, target, lowIndex, mid) + return binarySearch(array, target, lowIndex, mid-1) } else if array[mid] < target { return binarySearch(array, target, mid+1, highIndex) } else { @@ -18,12 +19,16 @@ func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int startIndex := lowIndex endIndex := highIndex var mid int - for startIndex < endIndex { - mid = int(startIndex + (endIndex - startIndex)) + size := len(array) + if size ==0 || highIndex > size || lowIndex < 0 { + return -1 + } + for startIndex <= endIndex { + mid = (endIndex + startIndex)/2 if array[mid] > target { - endIndex = mid + endIndex = mid-1 } else if array[mid] < target { - startIndex = mid + startIndex = mid+1 } else { return mid } diff --git a/searches/search_test.go b/searches/search_test.go index d4a3f2c78..fbbc226f5 100644 --- a/searches/search_test.go +++ b/searches/search_test.go @@ -11,8 +11,11 @@ type searchTest struct { var searchTests = []searchTest{ //Sanity + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, //Absent + {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, //Empty slice {[]int{}, 2, -1, "Empty"}, @@ -27,6 +30,15 @@ func TestBinarySearch(t *testing.T) { } } +func TestIterBinarySearch(t *testing.T) { + for _, test := range searchTests { + actual := iterBinarySearch(test.data, test.key, 0, len(test.data)-1) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} + func TestLinearSearch(t *testing.T) { for _, test := range searchTests { actual := linearSearch(test.data, test.key) @@ -35,3 +47,4 @@ func TestLinearSearch(t *testing.T) { } } } + From e0f764a91556d7d2040a4a9f53490d17ec4f72c2 Mon Sep 17 00:00:00 2001 From: task4233 Date: Sun, 17 Jan 2021 00:56:15 +0900 Subject: [PATCH 149/488] make directory for polybius --- ciphers/{ => polybius}/polybius.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ciphers/{ => polybius}/polybius.go (100%) diff --git a/ciphers/polybius.go b/ciphers/polybius/polybius.go similarity index 100% rename from ciphers/polybius.go rename to ciphers/polybius/polybius.go From b26ea003f569a811fb19325a892452d745885e4c Mon Sep 17 00:00:00 2001 From: task4233 Date: Sun, 17 Jan 2021 00:57:06 +0900 Subject: [PATCH 150/488] add lacked error handling --- ciphers/polybius/polybius.go | 67 ++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/ciphers/polybius/polybius.go b/ciphers/polybius/polybius.go index 534b87fd7..e17666012 100644 --- a/ciphers/polybius/polybius.go +++ b/ciphers/polybius/polybius.go @@ -1,59 +1,88 @@ -package main +// Package polybius is encrypting method with polybius square +// ref: https://en.wikipedia.org/wiki/Polybius_square#Hybrid_Polybius_Playfair_Cipher +package polybius import ( - "errors" + "fmt" + "math" "strings" ) -type polybius struct { +// Polybius is struct having size, characters, and key +type Polybius struct { size int characters string key string } -func newPolybius(key string, size int, chars string) (*polybius, error) { +// NewPolybius returns a pointer to object of Polybius. +// If the size of "chars" is longer than "size", +// "chars" are truncated to "size". +func NewPolybius(key string, size int, chars string) (*Polybius, error) { key = strings.ToUpper(key) chars = strings.ToUpper(chars)[:size] - if len(chars) != size { - return nil, errors.New("chars must be as long as size") + for idx, ch := range chars { + if strings.Contains(chars[idx+1:], string(ch)) { + return nil, fmt.Errorf("\"chars\" contains same character: %c", ch) + } } + if len(key) != size*size { - return nil, errors.New("key must be as long as the size squared") + return nil, fmt.Errorf("len(key): %d must be as long as size squared: %d", len(key), size*size) } - return &polybius{size, chars, key}, nil + return &Polybius{size, chars, key}, nil } -func (p *polybius) encrypt(text string) string { +// Encrypt encrypts with polybius encryption +func (p *Polybius) Encrypt(text string) (string, error) { chars := []rune(strings.ToUpper(text)) encryptedText := "" for _, char := range chars { - encryptedText += p.encipher(char) + encryptedChar, err := p.encipher(char) + if err != nil { + return "", fmt.Errorf("failed encipher: %w", err) + } + encryptedText += encryptedChar } - return encryptedText + return encryptedText, nil } -func (p *polybius) decrypt(text string) string { +// Decrypt decrypts with polybius encryption +func (p *Polybius) Decrypt(text string) (string, error) { chars := []rune(strings.ToUpper(text)) decryptedText := "" for i := 0; i < len(chars); i += 2 { - decryptedText += p.decipher(chars[i : i+2]) + decryptedChar, err := p.decipher(chars[i:int(math.Min(float64(i+2), float64(len(chars))))]) + if err != nil { + return "", fmt.Errorf("failed decipher: %w", err) + } + decryptedText += decryptedChar } - return decryptedText + return decryptedText, nil } -func (p *polybius) encipher(char rune) string { +func (p *Polybius) encipher(char rune) (string, error) { index := strings.IndexRune(p.key, char) + if index < 0 { + return "", fmt.Errorf("%c does not exist in keys", char) + } row := index / p.size col := index % p.size chars := []rune(p.characters) - return string([]rune{chars[row], chars[col]}) + return string([]rune{chars[row], chars[col]}), nil } -func (p *polybius) decipher(chars []rune) string { +func (p *Polybius) decipher(chars []rune) (string, error) { if len(chars) != 2 { - panic("decipher takes two chars") + return "", fmt.Errorf("the size of \"chars\" must be even") } row := strings.IndexRune(p.characters, chars[0]) + if row < 0 { + return "", fmt.Errorf("%c does not exist in characters", chars[0]) + } col := strings.IndexRune(p.characters, chars[1]) - return string([]rune(p.key)[row*p.size+col]) + if col < 0 { + return "", fmt.Errorf("%c does not exist in characters", chars[1]) + } + return string([]rune(p.key)[row*p.size+col]), nil } From b0327a3f737215fa41d8cea81413629589733f3b Mon Sep 17 00:00:00 2001 From: task4233 Date: Sun, 17 Jan 2021 00:59:59 +0900 Subject: [PATCH 151/488] add test for polybius(coverage: 100%) checked with "go test -covermode=atomic ./..." --- ciphers/polybius/polybius_test.go | 121 ++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 ciphers/polybius/polybius_test.go diff --git a/ciphers/polybius/polybius_test.go b/ciphers/polybius/polybius_test.go new file mode 100644 index 000000000..7d8c62b55 --- /dev/null +++ b/ciphers/polybius/polybius_test.go @@ -0,0 +1,121 @@ +package polybius_test + +import ( + "TheAlgorithms/Go/ciphers/polybius" + "testing" +) + +func TestNewPolybius(t *testing.T) { + t.Parallel() + cases := []struct { + name string + size int + characters string + key string + wantErr string + }{ + { + name: "correct initalization", size: 5, characters: "HogeF", key: "abcdefghijklmnopqrstuvwxy", wantErr: "", + }, + { + name: "truncate characters", size: 5, characters: "HogeFuga", key: "abcdefghijklmnopqrstuvwxy", wantErr: "", + }, + { + name: "invaid key", size: 5, characters: "HogeFuga", key: "abcdefghi", wantErr: "len(key): 9 must be as long as size squared: 25", + }, + { + name: "invalid characters", size: 5, characters: "HogeH", key: "abcdefghijklmnopqrstuvwxy", wantErr: "\"chars\" contains same character: H", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := polybius.NewPolybius(tc.key, tc.size, tc.characters) + if err != nil && err.Error() != tc.wantErr { + t.Errorf("failed NewPolybius: %v", err) + } + }) + } +} + +func TestPolybiusEncrypt(t *testing.T) { + t.Parallel() + cases := []struct { + name string + text string + want string + }{ + { + name: "correct encryption", text: "hoge", want: "OGGFOOHF", + }, + { + name: "invalid encryption", text: "hogz", want: "failed encipher: Z does not exist in keys", + }, + } + // initialize + const ( + size = 5 + characters = "HogeFuga" + key = "abcdefghijklmnopqrstuvwxy" + ) + p, err := polybius.NewPolybius(key, size, characters) + if err != nil { + t.Fatalf("failed NewPolybius: %v", err) + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + encrypted, err := p.Encrypt(tc.text) + if err != nil { + if err.Error() != tc.want { + t.Errorf("failed Encrypt: %v", err) + } + } else if encrypted != tc.want { + t.Errorf("Encrypt: %v, want: %v", encrypted, tc.want) + } + }) + } +} + +func TestPolybiusDecrypt(t *testing.T) { + t.Parallel() + cases := []struct { + name string + text string + want string + }{ + { + name: "correct decryption", text: "OGGFOOHF", want: "HOGE", + }, + { + name: "invalid decryption(position of even number)", text: "hogz", want: "failed decipher: Z does not exist in characters", + }, + { + name: "invalid decryption(position of odd number)", text: "hode", want: "failed decipher: D does not exist in characters", + }, + { + name: "invalid text size which is odd", text: "hog", want: "failed decipher: the size of \"chars\" must be even", + }, + } + // initialize + const ( + size = 5 + characters = "HogeF" + key = "abcdefghijklmnopqrstuvwxy" + ) + p, err := polybius.NewPolybius(key, size, characters) + if err != nil { + t.Fatalf("failed NewPolybius: %v", err) + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + encrypted, err := p.Decrypt(tc.text) + if err != nil { + if err.Error() != tc.want { + t.Errorf("failed Encrypt: %v", err) + } + } else if encrypted != tc.want { + t.Errorf("Encrypt: %v, want: %v", encrypted, tc.want) + } + }) + } +} From 39efcac498a1a8f61c88391a3bfd2c46e885ab4b Mon Sep 17 00:00:00 2001 From: task4233 Date: Sun, 17 Jan 2021 01:01:34 +0900 Subject: [PATCH 152/488] add example_test --- ciphers/polybius/polybius_test.go | 37 ++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/ciphers/polybius/polybius_test.go b/ciphers/polybius/polybius_test.go index 7d8c62b55..07fe46189 100644 --- a/ciphers/polybius/polybius_test.go +++ b/ciphers/polybius/polybius_test.go @@ -2,9 +2,40 @@ package polybius_test import ( "TheAlgorithms/Go/ciphers/polybius" + "fmt" + "log" "testing" ) +func ExampleNewPolybius() { + // initialize + const ( + plainText = "HogeFugaPiyoSpam" + size = 5 + characters = "HogeF" + key = "abcdefghijklmnopqrstuvwxy" + ) + p, err := polybius.NewPolybius(key, size, characters) + if err != nil { + log.Fatalf("failed NewPolybius: %v", err) + } + encryptedText, err := p.Encrypt(plainText) + if err != nil { + log.Fatalf("failed Encrypt: %v", err) + } + fmt.Printf("Encrypt=> plainText: %s, encryptedText: %s\n", plainText, encryptedText) + + decryptedText, err := p.Decrypt(encryptedText) + if err != nil { + log.Fatalf("failed Decrypt: %v", err) + } + fmt.Printf("Decrypt=> encryptedText: %s, decryptedText: %s\n", encryptedText, decryptedText) + + // Output: + // Encrypt=> plainText: HogeFugaPiyoSpam, encryptedText: OGGFOOHFOHFHOOHHEHOEFFGFEEEHHHGG + // Decrypt=> encryptedText: OGGFOOHFOHFHOOHHEHOEFFGFEEEHHHGG, decryptedText: HOGEFUGAPIYOSPAM +} + func TestNewPolybius(t *testing.T) { t.Parallel() cases := []struct { @@ -46,7 +77,7 @@ func TestPolybiusEncrypt(t *testing.T) { want string }{ { - name: "correct encryption", text: "hoge", want: "OGGFOOHF", + name: "correct encryption", text: "HogeFugaPiyoSpam", want: "OGGFOOHFOHFHOOHHEHOEFFGFEEEHHHGG", }, { name: "invalid encryption", text: "hogz", want: "failed encipher: Z does not exist in keys", @@ -55,7 +86,7 @@ func TestPolybiusEncrypt(t *testing.T) { // initialize const ( size = 5 - characters = "HogeFuga" + characters = "HogeF" key = "abcdefghijklmnopqrstuvwxy" ) p, err := polybius.NewPolybius(key, size, characters) @@ -84,7 +115,7 @@ func TestPolybiusDecrypt(t *testing.T) { want string }{ { - name: "correct decryption", text: "OGGFOOHF", want: "HOGE", + name: "correct decryption", text: "OGGFOOHFOHFHOOHHEHOEFFGFEEEHHHGG", want: "HOGEFUGAPIYOSPAM", }, { name: "invalid decryption(position of even number)", text: "hogz", want: "failed decipher: Z does not exist in characters", From 97024554ad6dfbdbf78ad674c708ac4207957c9c Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Sun, 17 Jan 2021 00:30:48 +0530 Subject: [PATCH 153/488] Add Gitpod Link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2259a3212..0d8bdddbb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # The Algorithms - Go - +[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/TheAlgorithms/Go)  ![golangci-lint](https://github.com/TheAlgorithms/Go/workflows/golangci-lint/badge.svg) ![Go](https://github.com/TheAlgorithms/Go/workflows/Go/badge.svg) ![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  From 867a87d89b9381ab7477d3c8d93c3d4c98ba401a Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Sun, 17 Jan 2021 00:35:13 +0530 Subject: [PATCH 154/488] Edit CODEOWNERS --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index baf4f9bf5..251a00707 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -14,6 +14,6 @@ /graphs/ @vedantmamgain /math/ @vedantmamgain @Mystigan /other/ @vedantmamgain -/searches/ @Mystigan -/sorts/ @Mystigan +/searches/ @Mystigan @vedantmamgain +/sorts/ @Mystigan @vedantmamgain /strings/ @vedantmamgain From efa32bda4c6a56b2a873feebfa31a03b0186ac52 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 17 Jan 2021 06:10:53 +0000 Subject: [PATCH 155/488] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index d0596e056..7210a6eec 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -4,6 +4,9 @@ * [Caesar Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_test.go) * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/CaesarCipher.go) * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) + * Polybius + * [Polybius](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius.go) + * [Polybius Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius_test.go) * Rot13 * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13.go) * [Rot13 Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13_test.go) From 2a71f7b7cdd089ea6967e8533c5beb289117a5f4 Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Sun, 17 Jan 2021 12:13:10 +0530 Subject: [PATCH 156/488] Fix Ceaser Cipher --- ciphers/caesar/CaesarCipher.go | 26 +++++++++++++------------- ciphers/caesar/caesar_test.go | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ciphers/caesar/CaesarCipher.go b/ciphers/caesar/CaesarCipher.go index d0f506b65..6e1a99be9 100644 --- a/ciphers/caesar/CaesarCipher.go +++ b/ciphers/caesar/CaesarCipher.go @@ -1,41 +1,41 @@ -package main - +package ceaser + import ( "bytes" "flag" "fmt" "strings" ) - + func main() { cipherKey := flag.Int("c", 0, "Cipher shift amount (-26 - 26)") input := flag.String("i", "", "Input") flag.Parse() - + if *cipherKey > 26 || *cipherKey < -26 { flag.PrintDefaults() } else { fmt.Println(caesarCipher(*input, *cipherKey)) } - + } - + func caesarCipher(input string, key int) string { var outputBuffer bytes.Buffer for _, r := range strings.ToLower(input) { - newByte := int(r) - + newByte := byte(r) + if newByte >= 'a' && newByte <= 'z' { - newByte += key - + newByte += byte(key) + if newByte > 'z' { newByte -= 26 } else if newByte < 'a' { newByte += 26 - } + } } - + outputBuffer.WriteString(string(newByte)) } return outputBuffer.String() -} +} \ No newline at end of file diff --git a/ciphers/caesar/caesar_test.go b/ciphers/caesar/caesar_test.go index d3ccb8ad7..d927a55e3 100644 --- a/ciphers/caesar/caesar_test.go +++ b/ciphers/caesar/caesar_test.go @@ -1,4 +1,4 @@ -package main +package ceaser import ( "testing" From 736a23e7255fa7562c4d9fb54dfc34809011b495 Mon Sep 17 00:00:00 2001 From: task4233 Date: Sun, 17 Jan 2021 20:11:49 +0900 Subject: [PATCH 157/488] Add lacked tests for caesar cipher (#261) * add lacked processing fix package name typo(ceaser=>caesar) update package structure for testing * add tests cases(coverage: 64.7%=>100.0%) fix misspelled words --- ciphers/caesar/CaesarCipher.go | 71 ++++++------ ciphers/caesar/caesar_test.go | 193 ++++++++++++++++++++++++--------- 2 files changed, 176 insertions(+), 88 deletions(-) diff --git a/ciphers/caesar/CaesarCipher.go b/ciphers/caesar/CaesarCipher.go index 6e1a99be9..4107e7c55 100644 --- a/ciphers/caesar/CaesarCipher.go +++ b/ciphers/caesar/CaesarCipher.go @@ -1,41 +1,38 @@ -package ceaser - -import ( - "bytes" - "flag" - "fmt" - "strings" -) - -func main() { - cipherKey := flag.Int("c", 0, "Cipher shift amount (-26 - 26)") - input := flag.String("i", "", "Input") - flag.Parse() - - if *cipherKey > 26 || *cipherKey < -26 { - flag.PrintDefaults() - } else { - fmt.Println(caesarCipher(*input, *cipherKey)) - } - +// Package caesar is the shift cipher +// ref: https://en.wikipedia.org/wiki/Caesar_cipher +package caesar + +// Caesar is struct for Caesar cipher +type Caesar struct { +} + +// NewCaesar returns a pointer to object of Caesar +func NewCaesar() *Caesar { + return &Caesar{} } - -func caesarCipher(input string, key int) string { - var outputBuffer bytes.Buffer - for _, r := range strings.ToLower(input) { + +// Encrypt encrypts by right shift of "key" each character of "input" +func (c Caesar) Encrypt(input string, key int) string { + // if key is negative value, + // updates "key" the number which congruents to "key" modulo 26 + key = (key%26 + 26) % 26 + + outputBuffer := []byte{} + for _, r := range input { newByte := byte(r) - - if newByte >= 'a' && newByte <= 'z' { - newByte += byte(key) - - if newByte > 'z' { - newByte -= 26 - } else if newByte < 'a' { - newByte += 26 - } + if 'A' <= newByte && newByte <= 'Z' { + outputBuffer = append(outputBuffer, byte(int('A')+int(int(newByte-'A')+key)%26)) + } else if 'a' <= newByte && newByte <= 'z' { + outputBuffer = append(outputBuffer, byte(int('a')+int(int(newByte-'a')+key)%26)) + } else { + outputBuffer = append(outputBuffer, newByte) } - - outputBuffer.WriteString(string(newByte)) } - return outputBuffer.String() -} \ No newline at end of file + return string(outputBuffer) +} + +// Decrypt decrypts by left shift of "key" each character of "input" +func (c Caesar) Decrypt(input string, key int) string { + // left shift of "key" is same as right shift of 26-"key" + return c.Encrypt(input, 26-key) +} diff --git a/ciphers/caesar/caesar_test.go b/ciphers/caesar/caesar_test.go index d927a55e3..f70e6d7e3 100644 --- a/ciphers/caesar/caesar_test.go +++ b/ciphers/caesar/caesar_test.go @@ -1,63 +1,135 @@ -package ceaser +package caesar_test import ( + "TheAlgorithms/Go/ciphers/caesar" + "fmt" "testing" ) -var caesarTestData = []struct { - description string - input string - key int - expected string -}{ - { - "Basic caesar encryption with letter 'a'", - "a", - 3, - "d", - }, - { - "Basic caesar encryption wrap around alphabet on letter 'z'", - "z", - 3, - "c", - }, - { - "Encrypt a simple string with ceasar encryiption", - "hello", - 3, - "khoor", - }, - { - "Encrypt a simple string with key 13", - "hello", - 13, - "uryyb", - }, - { - "Encrypt a simple string with key -13", - "hello", - -13, - "uryyb", - }, - { - "With key of 26 output should be the same as the input", - "no change", - 26, - "no change", - }, - { - "Encrpyt sentence with key 10", - "the quick brown fox jumps over the lazy dog.", - 10, - "dro aesmu lbygx pyh tewzc yfob dro vkji nyq.", - }, +var c *caesar.Caesar = caesar.NewCaesar() + +func TestEncrypt(t *testing.T) { + var caesarTestData = []struct { + description string + input string + key int + expected string + }{ + { + "Basic caesar encryption with letter 'a'", + "a", + 3, + "d", + }, + { + "Basic caesar encryption wrap around alphabet on letter 'z'", + "z", + 3, + "c", + }, + { + "Encrypt a simple string with caesar encryiption", + "hello", + 3, + "khoor", + }, + { + "Encrypt a simple string with key 13", + "hello", + 13, + "uryyb", + }, + { + "Encrypt a simple string with key -13", + "hello", + -13, + "uryyb", + }, + { + "With key of 26 output should be the same as the input", + "no change", + 26, + "no change", + }, + { + "Encrypt sentence with key 10", + "the quick brown fox jumps over the lazy dog.", + 10, + "dro aesmu lbygx pyh tewzc yfob dro vkji nyq.", + }, + { + "Encrypt sentence with key 10", + "The Quick Brown Fox Jumps over the Lazy Dog.", + 10, + "Dro Aesmu Lbygx Pyh Tewzc yfob dro Vkji Nyq.", + }, + } + for _, test := range caesarTestData { + t.Run(test.description, func(t *testing.T) { + actual := c.Encrypt(test.input, test.key) + if actual != test.expected { + t.Logf("FAIL: %s", test.description) + t.Fatalf("With input string '%s' and key '%d' was expecting '%s' but actual was '%s'", + test.input, test.key, test.expected, actual) + } + }) + } } -func TestCeasarCipher(t *testing.T) { +func TestDecrypt(t *testing.T) { + var caesarTestData = []struct { + description string + input string + key int + expected string + }{ + { + "Basic caesar decryption with letter 'a'", + "a", + 3, + "x", + }, + { + "Basic caesar decryption wrap around alphabet on letter 'z'", + "z", + 3, + "w", + }, + { + "Decrypt a simple string with caesar encryiption", + "hello", + 3, + "ebiil", + }, + { + "Decrypt a simple string with key 13", + "hello", + 13, + "uryyb", + }, + { + "Decrypt a simple string with key -13", + "hello", + -13, + "uryyb", + }, + { + "With key of 26 output should be the same as the input", + "no change", + 26, + "no change", + }, + { + "Decrypt sentence with key 10", + "Dro Aesmu Lbygx Pyh Tewzc yfob dro Vkji Nyq.", + 10, + "The Quick Brown Fox Jumps over the Lazy Dog.", + }, + } + for _, test := range caesarTestData { t.Run(test.description, func(t *testing.T) { - actual := caesarCipher(test.input, test.key) + actual := c.Decrypt(test.input, test.key) if actual != test.expected { t.Logf("FAIL: %s", test.description) t.Fatalf("With input string '%s' and key '%d' was expecting '%s' but actual was '%s'", @@ -66,3 +138,22 @@ func TestCeasarCipher(t *testing.T) { }) } } + +func ExampleNewCaesar() { + const ( + key = 10 + input = "The Quick Brown Fox Jumps over the Lazy Dog." + ) + + c := caesar.NewCaesar() + + encryptedText := c.Encrypt(input, key) + fmt.Printf("Encrypt=> key: %d, input: %s, encryptedText: %s\n", key, input, encryptedText) + + decryptedText := c.Decrypt(encryptedText, key) + fmt.Printf("Decrypt=> key: %d, input: %s, decryptedText: %s\n", key, encryptedText, decryptedText) + + // Output: + // Encrypt=> key: 10, input: The Quick Brown Fox Jumps over the Lazy Dog., encryptedText: Dro Aesmu Lbygx Pyh Tewzc yfob dro Vkji Nyq. + // Decrypt=> key: 10, input: Dro Aesmu Lbygx Pyh Tewzc yfob dro Vkji Nyq., decryptedText: The Quick Brown Fox Jumps over the Lazy Dog. +} From 59b4ff8ab3b908dfc837cd33615ec55ce26d6303 Mon Sep 17 00:00:00 2001 From: task4233 Date: Mon, 18 Jan 2021 03:11:57 +0900 Subject: [PATCH 158/488] fix rot13 content (#262) --- ciphers/rot13/rot13.go | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/ciphers/rot13/rot13.go b/ciphers/rot13/rot13.go index 30ac8a875..1f43497a1 100644 --- a/ciphers/rot13/rot13.go +++ b/ciphers/rot13/rot13.go @@ -1,26 +1,12 @@ +// Package rot13 is a simple letter substitution cipher that replaces a letter with the 13th letter after it in the alphabet. +// ref: https://en.wikipedia.org/wiki/ROT13 package rot13 import ( - "bytes" - "strings" + "TheAlgorithms/Go/ciphers/caesar" ) +// rot13 is a special case, which is fixed the shift of 13, of the Caesar cipher func rot13(input string) string { - var outputBuffer bytes.Buffer - for _, r := range strings.ToLower(input) { - newByte := int(r) - - if newByte >= 'a' && newByte <= 'z' { - newByte += 13 - - if newByte > 'z' { - newByte -= 26 - } else if newByte < 'a' { - newByte += 26 - } - } - - outputBuffer.WriteString(string(newByte)) - } - return outputBuffer.String() + return caesar.NewCaesar().Encrypt(input, 13) } From 219d8a139cd3e77c36e7b9b13276f5fb75ec565f Mon Sep 17 00:00:00 2001 From: Vedant Mamgain Date: Tue, 19 Jan 2021 18:30:27 +0530 Subject: [PATCH 159/488] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 0d8bdddbb..6070b354e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # The Algorithms - Go [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/TheAlgorithms/Go)  ![golangci-lint](https://github.com/TheAlgorithms/Go/workflows/golangci-lint/badge.svg) -![Go](https://github.com/TheAlgorithms/Go/workflows/Go/badge.svg) ![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  ![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) From a8f855dff025983cab79d13b0b9d8abb41cbe34b Mon Sep 17 00:00:00 2001 From: task4233 Date: Tue, 19 Jan 2021 22:02:25 +0900 Subject: [PATCH 160/488] Refactor xor package (#264) * refactor the code * update xor_cipher_test --- ciphers/xor/xorCipher.go | 60 ++++++++++++++-------------------- ciphers/xor/xor_cipher_test.go | 41 ++++++++++++++++------- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/ciphers/xor/xorCipher.go b/ciphers/xor/xorCipher.go index c280ccd0e..b8500fe91 100644 --- a/ciphers/xor/xorCipher.go +++ b/ciphers/xor/xorCipher.go @@ -1,44 +1,34 @@ -package main +// Package xor is an encryption algorithm that operates the exclusive disjunction(XOR) +// ref: https://en.wikipedia.org/wiki/XOR_cipher +package xor -import "fmt" - -func encrypt(key int, plaintext []int) (ciphertext []int) { - for _, char := range plaintext { - ciphertext = append(ciphertext, xor(char, key)) - } - return -} -func xor(char int, key int) int { - return (char ^ key) +// Xor is struct for xor package +type Xor struct { } -func decrypt(key int, ciphertext []int) (plaintext []int) { - for _, char := range ciphertext { - plaintext = append(plaintext, xor(char, key)) - } - return +// NewXor returns a pointer to object of Xor. +func NewXor() *Xor { + return &Xor{} } -func decodeToString(slice []int) (str string) { - for _, v := range slice { - str += string(v) +// Encrypt encrypts with Xor encryption after converting each character to byte +// The returned value might not be readable because there is no guarantee +// which is within the ASCII range +// If using other type such as string, []int, or some other types, +// add the statements for converting the type to []byte. +func (x Xor) Encrypt(key byte, plaintext []byte) []byte { + cipherText := []byte{} + for _, ch := range plaintext { + cipherText = append(cipherText, key^ch) } - return + return cipherText } -func toASCII(slice []rune) []int { - var converted []int - for _, v := range slice { - converted = append(converted, int(v)) + +// Decrypt decrypts with Xor encryption +func (x Xor) Decrypt(key byte, cipherText []byte) []byte { + plainText := []byte{} + for _, ch := range cipherText { + plainText = append(plainText, key^ch) } - return converted -} -func main() { - str := "hello world" - key := 97 - temp := []rune(str) - message := toASCII(temp) - encrypted := encrypt(key, message) - decrypted := decrypt(key, encrypted) - plaintext := decodeToString(decrypted) - fmt.Println(plaintext) + return plainText } diff --git a/ciphers/xor/xor_cipher_test.go b/ciphers/xor/xor_cipher_test.go index 0b3a2aefc..b9d6120af 100644 --- a/ciphers/xor/xor_cipher_test.go +++ b/ciphers/xor/xor_cipher_test.go @@ -1,10 +1,30 @@ -package main +package xor_test import ( + "TheAlgorithms/Go/ciphers/xor" + "fmt" "reflect" "testing" ) +func ExampleNewXor() { + const ( + seed = "Hello World" + key = 97 + ) + + x := xor.NewXor() + encrypted := x.Encrypt(byte(key), []byte(seed)) + fmt.Printf("Encrypt=> key: %d, seed: %s, encryptedText: %v\n", key, seed, encrypted) + + decrypted := x.Decrypt(byte(key), encrypted) + fmt.Printf("Decrypt=> key: %d, encryptedText: %v, DecryptedText: %s\n", key, encrypted, string(decrypted)) + + // Output: + // Encrypt=> key: 97, seed: Hello World, encryptedText: [41 4 13 13 14 65 54 14 19 13 5] + // Decrypt=> key: 97, encryptedText: [41 4 13 13 14 65 54 14 19 13 5], DecryptedText: Hello World +} + var xorTestData = []struct { description string input string @@ -61,16 +81,15 @@ var xorTestData = []struct { }, } +var x *xor.Xor = xor.NewXor() + func TestXorCipherEncrypt(t *testing.T) { for _, test := range xorTestData { t.Run(test.description, func(t *testing.T) { - - message := toASCII([]rune(test.input)) - encrypted := encrypt(test.key, message) - - if actual := decodeToString(encrypted); !reflect.DeepEqual(actual, test.encrypted) { + encrypted := x.Encrypt(byte(test.key), []byte(test.input)) + if !reflect.DeepEqual(string(encrypted), test.encrypted) { t.Logf("FAIL: %s", test.description) - t.Fatalf("Expecting %s, actual %s", test.encrypted, actual) + t.Fatalf("Expecting %s, actual %s", test.encrypted, string(encrypted)) } }) } @@ -79,13 +98,11 @@ func TestXorCipherEncrypt(t *testing.T) { func TestXorCipherDecrypt(t *testing.T) { for _, test := range xorTestData { t.Run(test.description, func(t *testing.T) { + decrypted := x.Decrypt(byte(test.key), []byte(test.encrypted)) - message := toASCII([]rune(test.encrypted)) - decrypted := decrypt(test.key, message) - - if actual := decodeToString(decrypted); !reflect.DeepEqual(actual, test.input) { + if !reflect.DeepEqual(string(decrypted), test.input) { t.Logf("FAIL: %s", test.description) - t.Fatalf("Expecting %s, actual %s", test.input, actual) + t.Fatalf("Expecting %s, actual %s", test.input, string(decrypted)) } }) } From 7ea29648d1935130eef05ce3532618af07fefff4 Mon Sep 17 00:00:00 2001 From: Taj Date: Thu, 18 Feb 2021 05:58:38 +0000 Subject: [PATCH 161/488] Fix: Major restructuring for fixing the linting workflow errors and module style code writing. (#266) * fix: Simple fixes on multiple files * fix: Removed the improper way of testing the caesar (sub)module * fix: properly configured the test * fix: properly configure rot13 * fix: fixed polybius test * fix: fixed xor cipher and its test * fix: Tried to correct the implemention so that the redeclaration error that appears in tests goes away. TODO: Maybe implement it with interfaces. * fix: simple fixes for the dynamic array file in order for it to work as a module * fix: added hashmap tests and removed main * fix: separated the linkedlists (singly and doubly) so that that there are no clashes with the definition of Nodes - can be simplified using an interface * fix: minor changes * fix: changes to dynamic programming (sub)module so that there are no redeclaration issues * feat: mod file for go get command * fix: simple restructuring of the directories * fix: TODO don't know what this function is for? * fix: restructuring * fix: restructure * fix: linting errors * fix: the automated errors in the golangci-lint for datastructures * fix: automated errors in dynamicprogramming with golangci-lint * fix: automated test errors in math directory with golangci-lint * fix: automated errors in graphs directory with golangci-lint * fix: automated errors in others directory and removed a duplicate that already existed in the math directory which I updated in the previous commit * fix: automated errors in strings directory. Still need to write tests for a lot of functions * fix: minor fixes by removing main * fix: commented out one test because it takes too long to run with go test command * fix: linting errors * feat: changes to workflow file * updating DIRECTORY.md * fix: minor naming fix for the algorithm package import in ciphers/rot13/rot13.go * feat: added automated tests: * fix: some issue with automated test: * fix: some testing issues * fix: automated test issue * fix: automated test issue * fix: test issues * fix: test issue for rsa * fix: ignoring rsa tests for test failures Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- .github/workflows/golangci-lint.yml | 37 +-- .github/workflows/golangtests.yml | 13 + DIRECTORY.md | 43 ++- ciphers/caesar/CaesarCipher.go | 15 +- ciphers/caesar/caesar_test.go | 17 +- ciphers/polybius/polybius.go | 3 +- ciphers/polybius/polybius_test.go | 11 +- ciphers/rot13/rot13.go | 4 +- ciphers/rsa/RSAcipher.go | 92 ++++-- ciphers/rsa/rsa_cipher_test.go | 24 +- ciphers/rsaBig/RSAcipher(Big).go | 85 ++--- ciphers/rsaBig/rsaBig | Bin 0 -> 2514312 bytes ciphers/rsaBig/rsa_cipher_big_test.go | 8 +- ciphers/xor/xorCipher.go | 13 +- ciphers/xor/xor_cipher_test.go | 16 +- .../binary-tree/binarysearchtree.go | 158 +++------- datastructures/binary-tree/binarytree.go | 82 +---- datastructures/binary-tree/btree.go | 117 +++++++ datastructures/binary-tree/node.go | 13 + datastructures/dynamic-array/dynamicarray.go | 38 ++- datastructures/hashmap/hashmap_test.go | 73 +++-- .../doublylinkedlist.go | 62 ++-- .../singlelinkedlist/single-linkedlist.go | 113 ------- datastructures/linkedlist/singlylinkedlist.go | 102 ------ .../singlylinkedlist/singlylinkedlist.go | 116 +++++++ .../singlylinkedlist/singlylinkedlist2.go | 104 +++++++ .../singlylinkedlist_test.go} | 2 +- datastructures/trie/trie_test.go | 24 +- dynamicprogramming/binomialcoeffecient.go | 37 +-- dynamicprogramming/knapsack.go | 14 +- .../longest-palindromic-subsequence.go | 25 +- .../longestCommonSubsequence.go | 18 +- dynamicprogramming/matrix-multiplication.go | 26 +- dynamicprogramming/rod-cutting.go | 27 +- go.mod | 4 +- go.sum | 2 + graphs/breathfirstsearch.go | 72 ----- graphs/breathfirstsearch/breathfirstsearch.go | 73 +++++ graphs/depthfirstsearch.go | 72 ----- graphs/depthfirstsearch/depthfirstsearch.go | 70 +++++ graphs/{ => floydwarshall}/floydwarshall.go | 37 +-- math/sieve/Sieve.go | 52 +--- math/sieve/sieve_test.go | 28 ++ other/PrimeNumbers.go | 85 ----- other/maxsubarraysum.go | 30 -- other/maxsubarraysum/maxsubarraysum.go | 28 ++ other/monte_carlo_pi/monte_carlo_pi.go | 96 +++--- other/monte_carlo_pi/monte_carlo_pi_test.go | 24 +- other/{ => nestedbrackets}/nestedbrackets.go | 29 +- .../passwordgenerator.go | 27 +- other/prime_numbers.go | 85 ----- .../stringcombinations.go | 11 +- searches/binarysearch.go | 23 +- searches/linearsearch.go | 18 +- searches/search_test.go | 7 +- sorts/sorts_test.go | 6 +- .../levenshteinDistance.go | 3 +- .../levenshteinDistance_test.go | 2 +- .../advanced-aho-corasick/adac.go | 294 +++++++++--------- .../advanced-aho-corasick/adac_test.go | 28 +- .../aho-corasick/ac.go | 193 ++++++------ .../aho-corasick/ac_test.go | 27 +- strings/multiple-string-matching/sbom/sbom.go | 114 ++++--- .../sbom/sbom_test.go | 30 +- strings/single-string-matching/bom.go | 236 -------------- strings/single-string-matching/bom/bom.go | 228 ++++++++++++++ strings/single-string-matching/horspool.go | 102 ------ .../horspool/horspool.go | 95 ++++++ strings/single-string-matching/kmp/kmp.go | 99 +++--- .../single-string-matching/kmp/kmp_test.go | 10 +- 70 files changed, 1840 insertions(+), 2032 deletions(-) create mode 100644 .github/workflows/golangtests.yml create mode 100755 ciphers/rsaBig/rsaBig create mode 100644 datastructures/binary-tree/btree.go create mode 100644 datastructures/binary-tree/node.go rename datastructures/linkedlist/{ => doublylinkedlist}/doublylinkedlist.go (53%) delete mode 100644 datastructures/linkedlist/singlelinkedlist/single-linkedlist.go delete mode 100644 datastructures/linkedlist/singlylinkedlist.go create mode 100644 datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go create mode 100644 datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go rename datastructures/linkedlist/{singlelinkedlist/single-linkedlist_test.go => singlylinkedlist/singlylinkedlist_test.go} (98%) create mode 100644 go.sum delete mode 100644 graphs/breathfirstsearch.go create mode 100644 graphs/breathfirstsearch/breathfirstsearch.go delete mode 100644 graphs/depthfirstsearch.go create mode 100644 graphs/depthfirstsearch/depthfirstsearch.go rename graphs/{ => floydwarshall}/floydwarshall.go (66%) create mode 100644 math/sieve/sieve_test.go delete mode 100644 other/PrimeNumbers.go delete mode 100644 other/maxsubarraysum.go create mode 100644 other/maxsubarraysum/maxsubarraysum.go rename other/{ => nestedbrackets}/nestedbrackets.go (77%) rename other/{ => passwordgenerator}/passwordgenerator.go (63%) delete mode 100644 other/prime_numbers.go rename other/{ => stringcombinations}/stringcombinations.go (70%) delete mode 100644 strings/single-string-matching/bom.go create mode 100644 strings/single-string-matching/bom/bom.go delete mode 100644 strings/single-string-matching/horspool.go create mode 100644 strings/single-string-matching/horspool/horspool.go diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e58ca3adc..27e280a89 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -18,22 +18,23 @@ jobs: # only-new-issues: true # Let's focus on this PR first - run: echo "/home/runner/golangci-lint-1.31.0-linux-amd64" >> $GITHUB_PATH - run: go version ; golangci-lint --version # Fix the following and remove || true - - run: golangci-lint run --no-config ciphers - - run: golangci-lint run --no-config datastructures/binary-tree || true - - run: golangci-lint run --no-config datastructures/dynamic-array || true - - run: golangci-lint run --no-config datastructures/hashmap - - run: golangci-lint run --no-config datastructures/linkedlist || true - - run: golangci-lint run --no-config datastructures/trie || true - - run: golangci-lint run --no-config dynamicprogramming || true - - run: golangci-lint run --no-config other || true - - run: golangci-lint run --no-config searches || true - - run: golangci-lint run --no-config sorts - # - run: golangci-lint run --no-config strings/... - - run: golangci-lint run --no-config "strings/multiple-string-matching" || true + - run: golangci-lint run --no-config ciphers/... + # - run: golangci-lint run --no-config datastructures/binary-tree || true + # - run: golangci-lint run --no-config datastructures/dynamic-array || true + # - run: golangci-lint run --no-config datastructures/hashmap + # - run: golangci-lint run --no-config datastructures/linkedlist || true + # - run: golangci-lint run --no-config datastructures/trie || true + - run: golangci-lint run --no-config dynamicprogramming/... + - run: golangci-lint run --no-config other/... + - run: golangci-lint run --no-config searches/... + - run: golangci-lint run --no-config sorts/... + - run: golangci-lint run --no-config strings/... + # - run: golangci-lint run --no-config "strings/multiple-string-matching" || true # - run: golangci-lint run --no-config "strings/single string matching" || true - - run: golangci-lint run --no-config strings/levenshteindistance - - run: golangci-lint run --no-config strings/naivesearch - - run: golangci-lint run --no-config math/gcd - - run: golangci-lint run --no-config math/power - - run: golangci-lint run --no-config math/primecheck - - run: golangci-lint run --no-config math/sieve || true + # - run: golangci-lint run --no-config strings/levenshteindistance + # - run: golangci-lint run --no-config strings/naivesearch + - run: golangci-lint run --no-config math/... + # - run: golangci-lint run --no-config math/gcd + # - run: golangci-lint run --no-config math/power + # - run: golangci-lint run --no-config math/primecheck + # - run: golangci-lint run --no-config math/sieve || true diff --git a/.github/workflows/golangtests.yml b/.github/workflows/golangtests.yml new file mode 100644 index 000000000..ed3341b96 --- /dev/null +++ b/.github/workflows/golangtests.yml @@ -0,0 +1,13 @@ +name: golang-tests +on: [push, pull_request] +jobs: + golang-tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + - run: go version + - name: Tests + run: go test $(go list ./... | grep -v /sbom | grep -v /rsa) diff --git a/DIRECTORY.md b/DIRECTORY.md index 7210a6eec..bcc55ce8d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -29,17 +29,20 @@ * Binary-Tree * [Binarysearchtree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/binarysearchtree.go) * [Binarytree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/binarytree.go) + * [Btree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/btree.go) + * [Node](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/node.go) * Dynamic-Array * [Dynamicarray](https://github.com/TheAlgorithms/Go/blob/master/datastructures/dynamic-array/dynamicarray.go) * Hashmap * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/datastructures/hashmap/hashmap.go) * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/hashmap/hashmap_test.go) * Linkedlist - * [Doublylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/doublylinkedlist.go) - * Singlelinkedlist - * [Single-Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlelinkedlist/single-linkedlist.go) - * [Single-Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlelinkedlist/single-linkedlist_test.go) - * [Singlylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist.go) + * Doublylinkedlist + * [Doublylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go) + * Singlylinkedlist + * [Singlylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go) + * [Singlylinkedlist2](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go) + * [Singlylinkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go) * Trie * [Trie](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie.go) * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie_test.go) @@ -55,9 +58,12 @@ * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/rod-cutting.go) ## Graphs - * [Breathfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/breathfirstsearch.go) - * [Depthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/depthfirstsearch.go) - * [Floydwarshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floydwarshall.go) + * Breathfirstsearch + * [Breathfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/breathfirstsearch/breathfirstsearch.go) + * Depthfirstsearch + * [Depthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/depthfirstsearch/depthfirstsearch.go) + * Floydwarshall + * [Floydwarshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floydwarshall/floydwarshall.go) ## Math * Gcd @@ -74,17 +80,20 @@ * [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go) * Sieve * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/Sieve.go) + * [Sieve Test](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve_test.go) ## Other - * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxsubarraysum.go) + * Maxsubarraysum + * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxsubarraysum/maxsubarraysum.go) * Monte Carlo Pi * [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi.go) * [Monte Carlo Pi Test](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi_test.go) - * [Nestedbrackets](https://github.com/TheAlgorithms/Go/blob/master/other/nestedbrackets.go) - * [Passwordgenerator](https://github.com/TheAlgorithms/Go/blob/master/other/passwordgenerator.go) - * [Prime Numbers](https://github.com/TheAlgorithms/Go/blob/master/other/prime_numbers.go) - * [Primenumbers](https://github.com/TheAlgorithms/Go/blob/master/other/PrimeNumbers.go) - * [Stringcombinations](https://github.com/TheAlgorithms/Go/blob/master/other/stringcombinations.go) + * Nestedbrackets + * [Nestedbrackets](https://github.com/TheAlgorithms/Go/blob/master/other/nestedbrackets/nestedbrackets.go) + * Passwordgenerator + * [Passwordgenerator](https://github.com/TheAlgorithms/Go/blob/master/other/passwordgenerator/passwordgenerator.go) + * Stringcombinations + * [Stringcombinations](https://github.com/TheAlgorithms/Go/blob/master/other/stringcombinations/stringcombinations.go) ## Searches * [Binarysearch](https://github.com/TheAlgorithms/Go/blob/master/searches/binarysearch.go) @@ -121,8 +130,10 @@ * [Naivestringsearch](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch.go) * [Naivestringsearch Test](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch_test.go) * Single-String-Matching - * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/bom.go) - * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/horspool.go) + * Bom + * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/bom/bom.go) + * Horspool + * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/horspool/horspool.go) * Kmp * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/kmp/kmp.go) * [Kmp Test](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/kmp/kmp_test.go) diff --git a/ciphers/caesar/CaesarCipher.go b/ciphers/caesar/CaesarCipher.go index 4107e7c55..902f9c114 100644 --- a/ciphers/caesar/CaesarCipher.go +++ b/ciphers/caesar/CaesarCipher.go @@ -2,17 +2,8 @@ // ref: https://en.wikipedia.org/wiki/Caesar_cipher package caesar -// Caesar is struct for Caesar cipher -type Caesar struct { -} - -// NewCaesar returns a pointer to object of Caesar -func NewCaesar() *Caesar { - return &Caesar{} -} - // Encrypt encrypts by right shift of "key" each character of "input" -func (c Caesar) Encrypt(input string, key int) string { +func Encrypt(input string, key int) string { // if key is negative value, // updates "key" the number which congruents to "key" modulo 26 key = (key%26 + 26) % 26 @@ -32,7 +23,7 @@ func (c Caesar) Encrypt(input string, key int) string { } // Decrypt decrypts by left shift of "key" each character of "input" -func (c Caesar) Decrypt(input string, key int) string { +func Decrypt(input string, key int) string { // left shift of "key" is same as right shift of 26-"key" - return c.Encrypt(input, 26-key) + return Encrypt(input, 26-key) } diff --git a/ciphers/caesar/caesar_test.go b/ciphers/caesar/caesar_test.go index f70e6d7e3..e28a3fe11 100644 --- a/ciphers/caesar/caesar_test.go +++ b/ciphers/caesar/caesar_test.go @@ -1,13 +1,10 @@ -package caesar_test +package caesar import ( - "TheAlgorithms/Go/ciphers/caesar" "fmt" "testing" ) -var c *caesar.Caesar = caesar.NewCaesar() - func TestEncrypt(t *testing.T) { var caesarTestData = []struct { description string @@ -66,7 +63,7 @@ func TestEncrypt(t *testing.T) { } for _, test := range caesarTestData { t.Run(test.description, func(t *testing.T) { - actual := c.Encrypt(test.input, test.key) + actual := Encrypt(test.input, test.key) if actual != test.expected { t.Logf("FAIL: %s", test.description) t.Fatalf("With input string '%s' and key '%d' was expecting '%s' but actual was '%s'", @@ -129,7 +126,7 @@ func TestDecrypt(t *testing.T) { for _, test := range caesarTestData { t.Run(test.description, func(t *testing.T) { - actual := c.Decrypt(test.input, test.key) + actual := Decrypt(test.input, test.key) if actual != test.expected { t.Logf("FAIL: %s", test.description) t.Fatalf("With input string '%s' and key '%d' was expecting '%s' but actual was '%s'", @@ -139,18 +136,16 @@ func TestDecrypt(t *testing.T) { } } -func ExampleNewCaesar() { +func Example() { const ( key = 10 input = "The Quick Brown Fox Jumps over the Lazy Dog." ) - c := caesar.NewCaesar() - - encryptedText := c.Encrypt(input, key) + encryptedText := Encrypt(input, key) fmt.Printf("Encrypt=> key: %d, input: %s, encryptedText: %s\n", key, input, encryptedText) - decryptedText := c.Decrypt(encryptedText, key) + decryptedText := Decrypt(encryptedText, key) fmt.Printf("Decrypt=> key: %d, input: %s, decryptedText: %s\n", key, encryptedText, decryptedText) // Output: diff --git a/ciphers/polybius/polybius.go b/ciphers/polybius/polybius.go index e17666012..7c2760334 100644 --- a/ciphers/polybius/polybius.go +++ b/ciphers/polybius/polybius.go @@ -35,9 +35,8 @@ func NewPolybius(key string, size int, chars string) (*Polybius, error) { // Encrypt encrypts with polybius encryption func (p *Polybius) Encrypt(text string) (string, error) { - chars := []rune(strings.ToUpper(text)) encryptedText := "" - for _, char := range chars { + for _, char := range strings.ToUpper(text) { encryptedChar, err := p.encipher(char) if err != nil { return "", fmt.Errorf("failed encipher: %w", err) diff --git a/ciphers/polybius/polybius_test.go b/ciphers/polybius/polybius_test.go index 07fe46189..d75b4ebb3 100644 --- a/ciphers/polybius/polybius_test.go +++ b/ciphers/polybius/polybius_test.go @@ -1,7 +1,6 @@ -package polybius_test +package polybius import ( - "TheAlgorithms/Go/ciphers/polybius" "fmt" "log" "testing" @@ -15,7 +14,7 @@ func ExampleNewPolybius() { characters = "HogeF" key = "abcdefghijklmnopqrstuvwxy" ) - p, err := polybius.NewPolybius(key, size, characters) + p, err := NewPolybius(key, size, characters) if err != nil { log.Fatalf("failed NewPolybius: %v", err) } @@ -61,7 +60,7 @@ func TestNewPolybius(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - _, err := polybius.NewPolybius(tc.key, tc.size, tc.characters) + _, err := NewPolybius(tc.key, tc.size, tc.characters) if err != nil && err.Error() != tc.wantErr { t.Errorf("failed NewPolybius: %v", err) } @@ -89,7 +88,7 @@ func TestPolybiusEncrypt(t *testing.T) { characters = "HogeF" key = "abcdefghijklmnopqrstuvwxy" ) - p, err := polybius.NewPolybius(key, size, characters) + p, err := NewPolybius(key, size, characters) if err != nil { t.Fatalf("failed NewPolybius: %v", err) } @@ -133,7 +132,7 @@ func TestPolybiusDecrypt(t *testing.T) { characters = "HogeF" key = "abcdefghijklmnopqrstuvwxy" ) - p, err := polybius.NewPolybius(key, size, characters) + p, err := NewPolybius(key, size, characters) if err != nil { t.Fatalf("failed NewPolybius: %v", err) } diff --git a/ciphers/rot13/rot13.go b/ciphers/rot13/rot13.go index 1f43497a1..1882c9201 100644 --- a/ciphers/rot13/rot13.go +++ b/ciphers/rot13/rot13.go @@ -3,10 +3,10 @@ package rot13 import ( - "TheAlgorithms/Go/ciphers/caesar" + "github.com/tjgurwara99/Go/ciphers/caesar" ) // rot13 is a special case, which is fixed the shift of 13, of the Caesar cipher func rot13(input string) string { - return caesar.NewCaesar().Encrypt(input, 13) + return caesar.Encrypt(input, 13) } diff --git a/ciphers/rsa/RSAcipher.go b/ciphers/rsa/RSAcipher.go index e458a8c7c..5752dfef3 100644 --- a/ciphers/rsa/RSAcipher.go +++ b/ciphers/rsa/RSAcipher.go @@ -1,11 +1,13 @@ -package main +package rsacipher import ( //"math/big" + "fmt" "math" "math/rand" - "time" + "strconv" + "strings" ) func generatePrimes(limit int) int { @@ -39,7 +41,7 @@ func prime(limit int) (primes []int) { primes = append(primes, 2, 3, 5) lastIndex := 2 for primes[lastIndex] < sqrtLimit { - if exit == true { + if exit { break } for i := primes[lastIndex] + 2; i < primes[lastIndex]*primes[lastIndex]; i += 2 { @@ -105,7 +107,8 @@ func modularExponentiation(b, e, mod int) int { return r } -func encryptRSA(message []int, e, n int) []int { +// EncryptRSA main encryption function for RSA +func EncryptRSA(message []int, e, n int) []int { //runs in O(k*log(n)) where k = len(message) and n = e var ciphertext []int for _, v := range message { @@ -113,7 +116,9 @@ func encryptRSA(message []int, e, n int) []int { } return ciphertext } -func decryptRSA(ciphertext []int, d, n int) []int { + +// DecryptRSA main decryption function for RSA +func DecryptRSA(ciphertext []int, d, n int) []int { //runs in O(k*log(n)) where k = len(ciphertext) and n = d var message []int for _, v := range ciphertext { @@ -130,44 +135,63 @@ func toASCII(slice []rune) []int { return converted } -func toRune(slice []int) string { +// ToRune convert a string to rune +func ToRune(slice []int) string { //runs in O(n) where n = len(slice) - var str string - for _, v := range slice { - str += string(v) + // var str string + var str strings.Builder + for i, v := range slice { + if i != len(slice)-1 { + str.WriteString(fmt.Sprintf("%d ", v)) + } else { + str.WriteString(fmt.Sprint(v)) + } + } - return str + return str.String() } -func main() { - rand.Seed(time.Now().UTC().UnixNano()) - bits := 17 - - p := generatePrimes(1 << bits) - q := generatePrimes(1 << bits) - for p == q { - q = generatePrimes(1 << bits) +// Compare ... Added for manual comparison but didn't work +func Compare(str string) []int { + a := strings.Split(str, " ") + fmt.Printf("%v", a) + var b []int + for _, v := range a { + temp, _ := strconv.Atoi(v) + b = append(b, temp) } + return b +} - n := p * q +// func main() { +// rand.Seed(time.Now().UTC().UnixNano()) +// bits := 17 - delta := lcm(p-1, q-1) +// p := generatePrimes(1 << bits) +// q := generatePrimes(1 << bits) +// for p == q { +// q = generatePrimes(1 << bits) +// } - e := generatePrimes(delta) - d := modularMultiplicativeInverse(e, delta) +// n := p * q - fmt.Printf("%v \n%v \n%v \n%v\n", p, q, e, d) +// delta := lcm(p-1, q-1) - str := "I think RSA is really great" - message := []rune(str) - asciiSlice := toASCII(message) +// e := generatePrimes(delta) +// d := modularMultiplicativeInverse(e, delta) - fmt.Printf("asciiSlice : %v \n", asciiSlice) - encrypted := encryptRSA(asciiSlice, e, n) - fmt.Printf("encrypted : %v \n", encrypted) - decrypted := decryptRSA(encrypted, d, n) - fmt.Printf("decrypted : %v \n", decrypted) - fmt.Printf("cleartext : %v \n", toRune(decrypted)) - //switched to atom +// fmt.Printf("%v \n%v \n%v \n%v\n", p, q, e, d) -} +// str := "I think RSA is really great" +// message := []rune(str) +// asciiSlice := toASCII(message) + +// fmt.Printf("asciiSlice : %v \n", asciiSlice) +// encrypted := encryptRSA(asciiSlice, e, n) +// fmt.Printf("encrypted : %v \n", encrypted) +// decrypted := decryptRSA(encrypted, d, n) +// fmt.Printf("decrypted : %v \n", decrypted) +// fmt.Printf("cleartext : %v \n", toRune(decrypted)) +// //switched to atom + +// } diff --git a/ciphers/rsa/rsa_cipher_test.go b/ciphers/rsa/rsa_cipher_test.go index 0bc7b64e1..3a7a04153 100644 --- a/ciphers/rsa/rsa_cipher_test.go +++ b/ciphers/rsa/rsa_cipher_test.go @@ -1,4 +1,4 @@ -package main +package rsacipher import ( "math/rand" @@ -29,6 +29,24 @@ var rsaTestData = []struct { }, } +func TestModularExponentiation(t *testing.T) { + t.Run("Test for modular exponentiation", func(t *testing.T) { + expected := 2 + actual := modularExponentiation(2, 5, 3) + if actual != expected { + t.Errorf("Actual: %d and Expected: %d", actual, expected) + } + }) + t.Run("Test 2 for modular exponentiation", func(t *testing.T) { + expected := 1099 + actual := modularExponentiation(200405, 5, 1342) + if actual != expected { + t.Errorf("Actual: %d and Expected: %d", actual, expected) + } + }) +} + +// This test is not consistent - consider commenting out until we find the problem func TestRSACipher(t *testing.T) { rand.Seed(time.Now().UTC().UnixNano()) bits := 17 @@ -51,8 +69,8 @@ func TestRSACipher(t *testing.T) { message := []rune(test.input) expected := toASCII(message) - encrypted := encryptRSA(expected, e, n) - decrypted := decryptRSA(encrypted, d, n) + encrypted := EncryptRSA(expected, e, n) + decrypted := DecryptRSA(encrypted, d, n) if actual := decrypted; !reflect.DeepEqual(actual, expected) { t.Logf("FAIL: %s", test.description) diff --git a/ciphers/rsaBig/RSAcipher(Big).go b/ciphers/rsaBig/RSAcipher(Big).go index 3dfb3446f..3056ad3b2 100644 --- a/ciphers/rsaBig/RSAcipher(Big).go +++ b/ciphers/rsaBig/RSAcipher(Big).go @@ -1,10 +1,10 @@ -package main +package bigrsacipher import ( - crypto "crypto/rand" "fmt" "math/big" "strconv" + "strings" ) /* @@ -13,49 +13,51 @@ The primes numbers are 1024 bits which is as secure as u can get really crypto/rand library has been imported as crypto and not rand This import style will make it easier to spot all the cryptographic secure functions */ -func main() { - p, _ := crypto.Prime(crypto.Reader, 1024) - q, _ := crypto.Prime(crypto.Reader, 1024) - if !(primeCheck(p) || primeCheck(q)) { - //they are always prime, no worries - fmt.Println("These numbers ain't prime") - } - n := new(big.Int).Mul(p, q) +// func main() { +// p, _ := crypto.Prime(crypto.Reader, 1024) +// q, _ := crypto.Prime(crypto.Reader, 1024) +// if !(primeCheck(p) || primeCheck(q)) { +// //they are always prime, no worries +// fmt.Println("These numbers ain't prime") +// } +// n := new(big.Int).Mul(p, q) - one := big.NewInt(1) +// one := big.NewInt(1) - delta := lcmBig(p.Sub(p, one), q.Sub(q, one)) +// delta := lcmBig(p.Sub(p, one), q.Sub(q, one)) - e, _ := crypto.Prime(crypto.Reader, delta.BitLen()) - d := big.NewInt(0) - d.ModInverse(e, delta) +// e, _ := crypto.Prime(crypto.Reader, delta.BitLen()) +// d := big.NewInt(0) +// d.ModInverse(e, delta) - cleartext := "Black Lives Matter, all lives can't matter until Black lives matter" - runes := []rune(cleartext) - ASCIIs := toASCII(runes) - stringEncoded := stringEncode(ASCIIs) - bigNum, _ := new(big.Int).SetString(stringEncoded, 0) - /* - TODO: check that bigNum is not larger than N if larger break - into two or more strings and encrypt separately - */ - fmt.Printf("Message to be encrypted: %v \n", cleartext) - fmt.Printf("ASCII encoded: %v\n", bigNum) - encrypted := encryptBig(bigNum, e, n) - fmt.Printf("ciphertext: %v \n", encrypted) - decrypted := decryptBig(encrypted, d, n) - fmt.Printf("Decrypted but still ASCII encoded: %v \n", decrypted) - decryptASCIIs := stringDecode(decrypted) - fmt.Printf("Plaintext (original message) :%v", toRune(decryptASCIIs)) -} +// cleartext := "Black Lives Matter, all lives can't matter until Black lives matter" +// runes := []rune(cleartext) +// ASCIIs := toASCII(runes) +// stringEncoded := stringEncode(ASCIIs) +// bigNum, _ := new(big.Int).SetString(stringEncoded, 0) +// /* +// TODO: check that bigNum is not larger than N if larger break +// into two or more strings and encrypt separately +// */ +// fmt.Printf("Message to be encrypted: %v \n", cleartext) +// fmt.Printf("ASCII encoded: %v\n", bigNum) +// encrypted := encryptBig(bigNum, e, n) +// fmt.Printf("ciphertext: %v \n", encrypted) +// decrypted := decryptBig(encrypted, d, n) +// fmt.Printf("Decrypted but still ASCII encoded: %v \n", decrypted) +// decryptASCIIs := stringDecode(decrypted) +// fmt.Printf("Plaintext (original message) :%v", toRune(decryptASCIIs)) +// } -func encryptBig(num *big.Int, privateExponent *big.Int, modulus *big.Int) *big.Int { +// EncryptBig Main encryption function +func EncryptBig(num *big.Int, privateExponent *big.Int, modulus *big.Int) *big.Int { //encrypts by modular exponentiation encrypted := new(big.Int).Exp(num, privateExponent, modulus) return encrypted } -func decryptBig(num *big.Int, publicExponent *big.Int, modulus *big.Int) *big.Int { +// DecryptBig Main decryption function +func DecryptBig(num *big.Int, publicExponent *big.Int, modulus *big.Int) *big.Int { //decrypts by modular exponentiation decrypted := new(big.Int).Exp(num, publicExponent, modulus) return decrypted @@ -69,7 +71,8 @@ func lcmBig(x *big.Int, y *big.Int) *big.Int { return lcm } -func primeCheck(prime *big.Int) bool { +// PrimeCheck primality test +func PrimeCheck(prime *big.Int) bool { //primality test return prime.ProbablyPrime(256) } @@ -83,13 +86,15 @@ func toASCII(slice []rune) []int { return converted } -func toRune(slice []int) string { +// ToRune convert a string to a rune +func ToRune(slice []int) string { //runs in O(n) where n = len(slice) - var str string + // var str string + var str strings.Builder for _, v := range slice { - str += string(v) + str.WriteString(fmt.Sprint(v)) } - return str + return str.String() } func stringEncode(slice []int) string { diff --git a/ciphers/rsaBig/rsaBig b/ciphers/rsaBig/rsaBig new file mode 100755 index 0000000000000000000000000000000000000000..9caf7ba306c976ec6f84cb44357eaa19ba88d0dd GIT binary patch literal 2514312 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 z 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

^-)`GY=&Tbc0r`~? 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

owmRgeAFb$2+LAjeg#PnJ$7D@IAg$ zjMkYR=OiR-iHT{D<07#M9vwFIxvc;8#EFND!WUMD^)YU0Sxz{~ILV&3g6@AHI1GFTj4|5aPf;E>(LOEn6h&QZRcauu z^kOG-wWY4K2#=Y+P!XIfajbPBivc1aHxJbP`%;{kGEK4fFV-iBHS6zgjq|E&h^<(K zS{zZ4L+I$ens2khrdx4`Wff_MS!$EN#4S7^DJmf|GA`PAEFNX4af&!|ZdK+$u~M5? z8~RmOoJeB#7ai(;q-wnUqNBVi+-FkRbu=eVfw{{`(%QwCNso#`43Ex7*6 zrfbQHRYZOwHi$jqCyFGs0+O^%885Q?Vu}!XSZ<|YaO?)gUDsFRwS&L*EHL25~>=J3|=< zgLOcTc)yd6dd52st`g7ViSGSi!EwuunM6dbrHfZ}tXh2NDvVP*2dI_D!GfSL941P` zT{65hW>Kh;wdOkeGo{v=x0u1#vf%Tm;4=|?9u$1`H`?}>5cc#bWaj1wR;FXf^w5Mv z_3!UbVY9kPU>3hIpALRc=l6b?1090Z#R@gp+>?1CV-9oDt~y5*m@2%)k8SI2JMq40 ze_-ZHm4CGTOKs;8HgQQ1-7RUmXDc)0M0fxVICo@?Egnz=1*+^%4`IG&bTnqTT$Ox5S zfMNqR*YU>S8rFx1TXxzhxH#AJ&zmJovDFYv*Y_3!c8o~UL^5ov<(?|Po-w4pxz22i z?y1|iF}SB82cI>xZ&mXl{fqrpu)wt3O1w_UTzhlaKjzIW_m5Mce*|s@asL>306KLr zAIK5=Vb1Qc&r{SrjCnu&!u~O9)xv|8FOxOc7Ikwdc&@r%#Lu+u`Kn;N!q(9a;IhpZGe{}Toj)?&to)C8>ye)|;ENKuj{3>BToN&a=$@7Z3B+CH(56}I` zv;Kj{STI`b^a$HB*c_tssegI;Wls;&Lvg#NVe4x2PM>-1$qDB(?hb~5f8*wuIwjHl zzP{Xx6L_$WL#-nlI0pSw`s_<0vYQL&e1_2%9z=FO9gG@h1kyXp>yO-AyZsp-9lt4& zfgUU6x3zy*?kf*cMw6W2SP#7k+y>%uujxQe0&WI!#QS5c?`6Jd+NXQDiyT7ugh}Oj zgOcB@erg6{h(z%D57THnj4bRQ6?|U`{wB+KBT2*>CqpcLqVfO1)!SgqZKn@mSy%}E z%C{cH1DVnDt%Un-!g(tZmEao*v&fPvp$n-B{YOfY04S6;!GXkwhAx!w-ER`J|4y8T z-JqQZMLNPP5fvlkZH2!r26V_9%lYQ$T6kXg<(LnSqd5m#N(9vrJd2W+(9D9O(C9Bk zixE7l+j)_bhZ>HAmksVA0*7H7Mpcdt?6q8kGfi5WDTNXpYX^q)H{vVh`kM~@HSi4( z*WVS;zXmS?IhI9!lq-Ae^ASDP*z}idaO1AiH+zuE@&h(yr~0k=o;Vwi7H8wOOD*H! z6fT0q>&rT6y9Lc-eWZ@%>|dL?xK*fwjzt?r32egef-&aEm`VtcFWh)Z8&^3q)b zs9r1Wd%hGnBZO2$mtcC=N?V^#VFlNMLJa&UPr}0I;*b+-YK_X}t7SfS7W5);6o~n? zbD?hlJ9~*o_qq9>eAMEF$H=-hDu_+$v@o*a*?hsb-N8=0>1KB3E)aMdLr1d@%>+YU zX6{0jiQ{bF;7pZOirtDbN=%&xkkv!^CcKi&bP^V18aWM4^WA2ajCpNgzPwrGd<}sf z1NH=QzP<{*7<}n`EhPB%s-79!NXE{V9Q{lgH-1iz*mEi7N8|K&OLxi04GzIJnAcA`hk7+c9r1}Epnh2@y~UvRsw< z<#LPwY;$`f$Vd+DyJ)CJttX;?j&&XTbh>e0+lBI7hg~TBBu(BRf zI{3_8l=d!8>pA)y%eu<4PFMQ-Y3sQx76qnt7n_u%$V=wgTViO^y1x4&)Vy<{=UW6eedF&_mr)NIzLR(`1IEuwnNGFm8MB0V!K~W zSI#}v1*zZGF$7t^ed_4eG&;bbiO^GxcMruD)I-c^ZJ+P|HZpC^e(U0H#huDMh5!Q2uSwm-Wu7U;h z;1Q_-R-zv2APmnMI9mj3_vz z4dyJlN__t`&Vv}fAp4R%_6RY+SVdGD(zYJX)CSM=(|CJ&%qc3+Oh>mmz@HCF531PG%(qh z8Ru`7S3p`|%rJ@&wFh7GbJ4xefce{l?=vK%r>w?=TZ}owRGBlBn0^10DI!NcPm3AC zjeCUkH0X%(JU0pYtKbk2&$p|f&j354I77YdC&;eFN6uamiJ*hnd=gOO*Kh>{)EGi1 zG1@ko#V1p$+Emk!kLOVLE_z4hrCU2ikwa$gT+{WwP%=q zV@`P;I0kwm*cZg@?CNhI(*lnIIlf3gJ?FLV^ECWK)V5;IV)bzg)~q5LXE~I0d}aYF zmE4EoKmIh?-I_AC)nvxgQXa9~f3X=jW4Mgw|EaP*tuiq>v7NcD20`y_?YP zCDrz(YMlOTHu=a{BmFm7nr8zpC7Ak5`!99YYjwIYlMm1GAj@`m$j5cohuCVl_wons z9o5#I7~R2GGd^NU7ry&}YU@Elf^~cM)7ADfEG#8@B@fwAZGTwBmI7&Ore0z7XR0XV zNh4{cV=y@WquTzc+HG=WbH(6H#v0eNEBzF9C|B0lFIQP>ZR-vZG|+c=<_$I0 z)irt$n)tsd0t&MGOs1|qoC)oRYOVWl1;FNhh&7b(DMaPTn)XRH*0{WwKQ`?@)Jnd7 zuDlZ0VMuC_#@g?hB=Skidcm@`ni^fsUrn=>XBI&LW|YSk}{))lXk*;rTGc zySFZ}g{SoopLT1VeGgB|Mo-I!PkX4&dA!bQBVyBGQ)@HmM3#HIfXKOdYZl0ysMZIlkzN&DHv97ThlTz2Q&#$TaQB4zWtM!S8>zmBZRY_KfmEkB5 z#LDj*{$#`n40ebEjB2VsQIGaPZay*0=Lw|WixRmW`aEzMi1T?r^zXqAAjfOby78V! z-XG6zP5b798>YO`eI1Rx$cly0#z!cV&rx%e#!)9!<*Id+u5LE27b&+n#DZ<5p(P*8 z=kCqx`||qUyk(Zc-Qp$uzZf751ufw~I)W?>1uTcztsYK?MVM+1(l>8Xn6LKv<$TS8 z{u=l?h~@+PNa$~YSU>q(l&?5H?W4o|#I>@7owDL=6x%0Yg>=-{j7L?2Ii#L#g5t0b zT{f8*7+N81iPG~3?~2!hJD}eIe*^LSRJDLLEr`?8n;wPrV6=Z%Xiz{K8F97fc~%hj z?kE=GAF5_FI~gZs6Y_%1;pj#_IP&zQ|QCOZ@kY=bNNiDzYwv7IB#+Ohzo ziIfU&R0kJ9(6*os%HP5(!M29&z1yu(ePEgx)QyJYp)UhJ z1988ey_oR~v@Z$!_2c)4{dUNGpTF*Z?oZwOwX{Pv?^rc|S?jQ%;sVi7+*?*7Fq%0$g~lXVihm6uHUd{u&cAKf<5obcy-P?o)qP{*GX# zC+csz3Edy7p#EO2=p`I>>Qma|S?tKm%EHyzVwP`9@1fc8uA09o@-OLSCfF)79yX*x zkMz$IQ|~UFXHQ-s6}S+{5=-bG3+KBVa3jct_@bB)h=fmW6nnV%yy(K4frwb;n%pPf zHK0Fc3DP_NKjPj4&Z_F%``>G~v-dvzoM~tJFq8oXh7JPC2uPDM0xEWpt~4o%CNUU| zF;=X>jx7=^QKQC6j2bmYu_c(8h_Ob!kr++9#>Dsg>@sI&fRKCN_y75C_?^9WnR8ZO z&w6S&D%*dP)|WuYqAYNw5Y9sYLbF&bd=Nbp?Sl5-44=s#`M=3FEKgdlk^U0RV_Qi-0=9u@JpGMy&0=WPz3hXc9@4S@tXom+L97w8P%L;u zT$rEmlCIswxX+-y!oEF)W{QrY+0=xcImBto<3h1ouWs?!rKAq>X0jiar19iq|V zF$It9F{6$Oj2c38J=%&x%YOy^$xg3Ok8Od@g;sxXIL}e0`f%!djr0d#7l_7F&n3v0 z!RbJby_G-w3hm>6GoECv=`@_$nSe`IOeJWJ%=yPK#4krkJ7ZAsf+crbNJ?>XQ%CQJ}dQfW3}E;T1a=OFPZcE0_lv>0i~{b z0tso^W$Wg@N`LWRrM^l@x4%j{oRVfT(8v|~kyC?u{DAt2`j1+QpHa{oMD@6o^tZqT zK#oKxe|%>za>%bHci!i8>{nuYDKylBI!3(JpaMHyW*l?uwQ7vW)s@6TYdvI4vb9wE zf{Jr5G|dYn(1O{hyNSVi_A0fOjbDs5zh|6iEF8pvvqnk}Kq8VZP4cH=}%Q zB7Hr$5k&dAo%H=+#6I+M$=3uw=%_hhTnibRq#c$*RWnr9lo>Eo)|81U?*z)4p!>oLSs7_FHo zRWOx0gyi&C;5_~jvQj573VQ?mv*MK1%X+=VZCpqp$~tu*_=Pwqo?DzZi}#^F=7y6c z?bJFmXr~7$Q$!a&OZru?14QNCMcP=7URp?ZcilHd{rD8(qEKvDV)+3}nd{6J3Va^A zT6zs`|0TR9|8UVw(Ft4WXB%UAKg8Q`vJL$kMSL4hBl+D-y0x}F%;#M45FKkspAOCd zQ9dsqy;*Q$XSyi5j`A6V-HCEKl$_SK#I$8AwEM_tv&2j+Do10upz z{mlyd`HEt`hLRowCIXo!DW#QN$u&3?$gwlbU-gTf^XWh2WAmSb`%!*5li8En)s+^n zgs44n-3oSV;v;o~eunck%&ujp?B9IA*S7Yg-ea~^XZ6TX-4Y%YUNtFoq2Bztvg)m& z5D+mdm(fd3aOa8MFJ=h!MlT1|vJ`>4Qz`zoo{gO2*%d53@k~tb2{Ryh`xb@&Hk<~AL1|gW%0v)04(Wlu*IXlV4tmNr{Im7nhTFrhX?KY0qs>E z-kY+Dy$JXrh}OSFCqY+$wX1`6Jvx-bRs6kkyY8G8>`&iVo$+6c+7&+Xg!Wk?x=Cnw zXe?1l=-q$8%C*7&_NMRnbZIfpLC4!G*FkjDZ8N@7j~i;6k@i1dG5ph$x__$nKeyYD zv%6e&nK8p{E18jRtDVsuu3qo9)U4F(qh}>&PoH76O`qYk%><)JFX8;Mt$l0~I+%D5 zuAOn>X{WN*bj_LyqT9jllGyAy9WzZQQv?QZFm|ip@WB%9|>=Q|;%K{#;@Go=$jX-04>D{8Tv)DIyAB zz-*O{KzWp_7EDxXdS0%q6GqvYT8#V;bK2-w35v1OL;V=s`+ z97=CFQ|a{tUM6*(GE0r|B!+@xz` z^$9v==lkJqu|*w9Ck=B!FFj9rrS5n-=}>SCIGAfc7j)WsI_;6N3jpyh*JgOVGJG!b zp9x_)Qt*&-=li~1!eyei$oMsCZ3#Vg$=-BSzh;6_lxhiQx8Th+eO&nCME2UDFS z(RGx3%$*nHYcszYt>@cFzX<*SqIv6Iq_gXo+khNh^A%nD5BVtRx*jc@w_x$gj`7pi zu3U=uO$eQDLg!?C#I-qxmlaAy?q}k~c(isdM0=y2-(nPQFq|6==LW;P(a^7F2c2_q zuo4k5GH9gQQ7sZ3ljw4m6!CDqfOUn#Za`O~aZP@FP~P=nIV8W|Cw(!v97OH#Bht@+ zh)=gS`eiX(l6l8VpxW}bTht6n@C&7FVTaWS&D%{c=U+_tLmjg!okt*{HU-4fi?Urq zClcfYJfaQ58l4~Hd&J4baWjkbvEXM|^Cj2`BgN>nJ&0?zdE3nCQQSo#np^Y`CA8>^<{El7*t z*c|5j1M(F0ugob*YXCh!RNrezKMeNGr&~OK+)5ZzE0-->xZ1ZF>D_flGEB-@@!cH#A;JCg`~^LG%x4mUe2=P4&EyW8>l=-xa48`|~lRSAcJTXx@2^^sLj6zXLh;)<67*@;tKJZMS>dLwOdiSP=A< z;%s`*qD2G`CveF`m^;r7j^bHTg;tGdUJn$oT`AD5b6kv zL*rQ?5iNbJ>Jhc?#$`djY5PX8zn@Qf3-~FB`c3ScN~;5dfgJnlH&6a&{bm{LISDht z7Cq`a;znA+e2WHY+x0p#X9~ETz%+E0f(>Pl*{{_gh~6fg47v?v87B$*t|$E={gjh@ z#<3sfhU^;&Np!zs+>0fpv&9jqHa^+o?7y;>3E9Seo*fwRO+Cy*P<|fX-eW$M9#hJk zgkhi1&C-^iigIamkNJvN#h4=)Hlc-}Je8x!4EhEuf_mLTeMNkrwclc01h;^wUjIe9 z>U3xnAjcb_f7Pz~7XCv%)}GXP|I*ZF595)Y>Vlc;R`?6)#Bp8fckz62g)cV`JbB*I zW&UCt)xCV1Jn7wkVV9U~%NDUH%-_R<|M2Jg%Z{q3I!ljM!Vd zgML7qgwGjQ(O7O{3$V18)pTr~TmM(3J?$}5*rl(TjV~1JS8BcA*4lRY=Os>0FK_F$ zIn$2!jNKBmw!}~pvrCLZ@621C`zc!BL%p~tT4C}7RhrC~#$kw9Riy~|^6?IQT|a(i z3mgZLki6f)Khm$I?OR}f2M+>w7vs!Eg{GWQqjG4`mqDr?n{eabbmFmP*nzGJ`oUJ( zH(IY>BK-#V07U)3hTB*IYJnUPz0vjTKjdS`#{nH5wcIM!?+K!wLa2jz%Yr69X#G;* zeb*1EQ}xHyG23=yvW+p>o`u{o-e9X6;?~Xa*iCWs=D3(CrD1yI?foJ#a+*NZ=lT;E z)&k;aovto+11Qrgz9Bd=Ck5r(NWP=;Jx2OP@CJy=w`_ybeg-mU{AcC+D&M)EFP<+N zU#picUc7L1u$V+8U%JMZD~?~eBA`}&7f>sIH+^d5YeoE_Dd1X5`yx)fcm}eLS|#RJ zdZr#GN`;e3>SN5`; zMHehfBT!I;rII$jNpC|zE#RtjT%w{Srt3LcY9x9>hn>^^voDl9evN99n!;G10y#44 zg7)4(J4Wq&Iq7S`Z6IpzS4e*d{sH9Z+K;1a{~;e0!@IWk;q#WRoe_lXU?I51-wQOO zBou2>y_@^Y(B8{7=z6_-*BGo>e>5%jRZ?A@Z2lKv>tL>81?wXFhEp4L<_sRB1Cp{Q zmE{xIjU8`EQJdkN#0*6f&Cs@oCX&td>JKU1Z1Ocmxw-(PIyI5v%Oe;mU-r?2ds~7s} z0PVLXu3Urngbp!qnIur5nKk?H&Oa==ZF1kwjkxyPV!xnPU_X*?xSBnJ zd2>SDMBE|!=0uC5u1~m|62|3;xLI|7!d_ajB$ZH?=W1@uR;+gtnN-PG>+@XA)48Nq zs}~aZ$~SWiVe#LGWcz{=_mV(Cj3pssW+Yk~oNl-$-PM~J5m{$Z!G9S8S?{G7N_nXi z`p3<)oCW&D`P!>sv*YPjoI9$9ot51#Vm1;K^ zs=HnWTN6=62SNZ%Wo&(6ZK+E=`$Ft!(dup%Q3s)~kY9Pc``$QW~pg~i1+hu=R@`**{dD;InwnIc#)m znKbL%+7f+(QJ1R!FijIGH9;R;+gNjmc1>ZBjsEH1OZ+M83r^~cg0+MFjCn^+eYfEL z77vc8J90zOkBTFUtkBb`5oMV^dA%N^fWAPCAR%mRb#Z0tvdWZMU@`N2{oVpBmk_3)+QDt0Zab`&BKu*|1P;Es6B$Bw7l=P@nX}mOOjh5(6;5fm4JkdPa8j!h?>JC+UJgSF{Ke6hsRad3`02IZosWa+Yo@XJHHq^LagI@meMC z6}XnamHX-Ne2x5i#}_0m4o9LFL_i^5D7%AycMdXuIlh1UgWn$+#Y!whT=p5yU_Iz&K^)$A92*lNRQuSU^K>u*R3gJD0g3Qj;GW1K zh*aV8)Yo(F1LVB|-y?r3ympD?DQBG5c78!#F5$Dju$$=p1nkjqV)xU^_&t?XMMnD}en+v5YM;g6vlkAbjZp@| zwJI7V7mIz3&#P%YFDU01;PIa~YrcyiAF8xhey;#qL zR>X=-nLUgq)yr)TU0ZYXOM(+xZ!=vg+Q^YccWZ2a4^d>BZC`ZMR-nkx$b;Fl+azTe45RMZiC&% zp31cjb8xMKqgRx7b;nJ?B57vE842+=mmpm=1kl0$y{vz!Rgo-L6*iCabE)vfhp~ zv-TLH$!#hmz4BowxY}$==stNp_HD1hTb3VgtvdE;Sk5~{;77nrkt=G=& z?HLj=IJoDvuV^eJ+!KgvLj*~@Gnnqz$A44a7I}EbZ;E=*zRzi26|@6;fv9iz6QZLu z(I+axeo^cvo?F{~50@(Kzw74?zMCu^m2|oPPx2@W$Ul@`r)Vkv*m+sdZz?V+_M0Zs zBfw}7$#YI8{TPV)N7r*S;lYQBwAgPGp5-8LqOd7HG_*|((ls&+eNV4W#P#7gjLHxp zIs?ImbuxoF;aEa!(Lr$5jYc*Midamq-#=>=@*Vh(vh6!x`hnP~mO*;koTa{m$VN5I zr*5RJ>ve627k-=KmA*3ZTl5LJ;8(xM~0>yL3$xr3Zi=Y0qOg}-qz1zJteR5)hVU8Y0IB+K&>N+v`kb`}wTDMCG|{`eGH8b_l%X{&=!2x608fLcoPQ=Q znA%0&-nE=d*RGs5e(A|rU=H}XC~lN#bN-;Tn;TK1W7MI)2*;q7Vlm=$+cjWwz6+xDaT{sDlR%EBKD(a%hkUG>oAFqPMe#8F8Hq%vIk)tLh60m$m+CMcAKDQ3gP@3RfH$?o?q=!7N$l9ugN35L!~YKE%l3Ny-^$w`TR) zl)A>Tuf*Fx${QPxRn^8yduI=@%*vzM=hPjt>^D+XXG`MS;66pWQ~_aaV8#b)qJ6R7 zAyYu`Hi>UTlif$C85edZyH5{}r{}WIj`8gmD8|GM_{76No82Xa4UYPof_7-Tx~O-* zi1bN-KH1(5SCPIGJOt!ebw@x?N8=)zKZ0+?p6A2hc{Fb%UND?~7bR>BKi(tOu&K0_(p>)T#Ixbjxh>FMD@<6mMr%JY@f zcNAt`+a8vy>6)mdnzoMgcflqQ^{8hU=m1}fc=lL)yml$bGgwl~2 zEh;lJo|qr??!Ri?nk8bN+2O$%$t;pp?(HEfstukz16cPJC1-j zgetNYSu^TlR?=&;_A||idga0GbthEjDL`l)(M=Zed^CMEpvPq@br_aiBq#nKQJZrZ zltY1Rl=ve&f0`j94uvKHSfydkv31lmMD3S(& z_Y2YkHlwo${Q3>;LpFxzXk6|L?XwfpJJ;{x`3DmAXiexTE9#&jFI%Yh;IYru-s@AJ zDMsULRZkmtOYDHFlz%$d|8z0<($-&VOwLRhs2cUbpb?DrwKBFS{Z=N{ zQoQ@r=Gf~%miF`rt!}y{?y>qY_Oa$6LlNj!V3eaf@IPUX8=13=bVWLqf7xk#(a{g2 zsX1b2D1!(w3SP5|=bLNX#;e_Q%sNs(5wAgpdcTbpJ6>xGiY!9kgRKo<1RM-vECDMD2Yp>9@e38-w=#;>W=_+MB-6(f_W! z2hwI6)%1&mD!mckNSyBQl|0uk8{@XtkFi>Rt@?SXn)-5*xiMzz-*oMrScBcu^zb(A zm0I=ct(f~>41U@BG3&Efjh;X(S7X*>2C$zCDO z9NHh$700SOmETZX!}gMUZj&)t< ztG4z@X%FkEth8fUgz4CA_bPM-M}dB*k*_~|auuoyDAi7?o2XCfHMx08dLnv#Q+jKc zxMDJ$Lc0{1+f@@;VIP=kJTx`tsGm)ZZLt#Ewr;odyYR^gZ^u@zo6T>S>4z=vv8mRb z6S>uSl|7i5V+E+#jwrF#2SF@UL5 z5?@enQT_J3g?Ru>2T}e0kn~evCy*nm&#q_xAs<6_tKSLBqz)I4TfJ}r>SNKI4=q#d zM%3=ydxe?PQwX?AW#{5d?mne_a=Bl{?xa?#R-e*Cdxxq`<*E?UpV>qkO5rax-X)OSjI`yUUY z`k}$~djqE)n|59zl#q3s+Jj zstIpaoh(te#D?4!t7U38F&!YbByL#L+phhEYntgk5M|TcHeDYG`&@0wHhec{9X5Cx zGx9L}Y1vHnt_1~*m0KZMyZ_ay{$Nudk#YJFOQko?Fp^deBjMl@3N`w>^upD8q0;L` z)bm15Z=jq8c>8nm?UDjP^Q}Sy$Wn8iY{7(J7F5!|6ttWW*8ma{-ux^fO=z(rAx=dV%!x6i|!;UH`_WN~9Dx=zHm<3sp` z5IHYs1b!i~Tk{J6Ioh0xB`dLU8%!u@zYyFTE-N7!_6vb)^%77rEtm99RsZar+z6`tA5o0CH465scfTLw_#Oxb+|M@kSTBD;c+oR?l0$@RTlE>!>$R zUa@Fp|C6yeCz?dvM*S^yk&gP@ow|Rzh$|Udvy9p2S=t@R7BBv+VLXQhX(?O+dp6$P z6ONa5N}z8oT(lUtX6sg6RmFzbfNt#DN`bAsi+%d&N>VsZw~jOMcZ%o!gxgmifg~Y? zE<~ZccPI+D4bl7z?HhlBdxM7>7z>rRSv_rr-K#quh?HZ>w z{90}8ZhW=ztLJsHx{Wl}*RDQwBF4N}53oFKRuAiNm^Q21EYYD_|6R1conf&m=O$uD zI?t(C88u@$Gh#`nyS6bca+?y*P2^C4PO4Zrfu619C3O}tx##P88e?iAq@HHosSwLp z7<2RyBijr-y3Bekx%I@Y%DoL|dpTe8LqCN$LNkp+jPJ#*Cq3(YWpp#{ROa~f30P~7 zN?jVq+S5*75ocoq)lsG=zU_WT>3whw0s{k*lE5sn8H9vvu)100?(1>u(>Tt*Fs{9f z9Y+ivwiU;F$ayMujzZCf`{bz`zT%rOwKeWg#we?lMYUiJA`I*8O2XFH7)@Ra+=8p) zj-EOfSF7%L>ky0V@y)>-`&oyDf4$V|6+11nJc~0FFL|5SK`Ql@OowAxJ%t3s&=XIu zB)&yrG-rX#cfuwVBk}f-kqzoC;Zn8#AuRas$&GK3kjTLTp~S_SMVyp{K_tIxKvECW ztJF7HN|i2B>@q+bD_139ApwzvJ#IeYGJ z(}ke?o*1K?sbj~t{su)~`dYv1f%lUoysG_s1@ z6V`^LHH$6o^$G9XM2BX1U0Oki%!5E5AT1!=hv7v&;p zK0#(L{_!_%%J?rv^p}*I7-!hTwG(_rr(Y}3(Z*wb^ls4#XVtoJLSs3()AHAmll{-5 z{l%nZ8o@E}3|`Sz1q&<=Y1oPBhh9t;}xdG zr+eD-xt1G}yEzDd%&hn=^@&u_N&YEr?uy$9>wVAsz_b7ESUa5DupYlpGcwKeZ__4P zO{tz{Z>x_BtWxJMY3Gk={grfFcekf)eA~woY=C}@y0?CpGXCWm|HQ^3p0TlZbTW;( z5xw@ug@BXj=Ja%Cc$4;nX^wa4e(4g;0@Nd zQ;C2Pyum`}d+};voZ_R|B=!J1GF)f4P{7vkM0tEv!eNtA5+9$!s|Iq>So%YiviSOb z$s?&N3yXdHk&DE`Kej&|^slY-o2KyITcrO2;`bK&*Ttmo2d@D+&e;cl{rppQ?_b#Q zu35PHWYkiLRa@*#VL-*Dp(7zUJ{z!&f!9+hBFOd6!a~(+vFeF2@QvvwPAi}8OzS`W zRBclUo43(P7;$(oNhKl534~FbY_OUWgqg6q!NB=Zig0?49?yEV`l38`Yo&RQZv3r0 z6<2>MH}1*mN3pL`*0B~7HI9|oHxpaaIZUPrR?Q}z|+pNa1C)GBYu7OOZJ=!?%#<>L>#@p zI#udB^K8>@jo8*V9QK0geIDJhzok6+Ydxvgtba)6;6Ei{HN#!G&YfOvSEpMlX=U`ASJ!k_l9-*85CL@R#01 zuk8VSnm7H|y7pmd1MWf9FS71)<=yuCpnz7o2mQr5CV7SnI`YZ+y6|K-ILU>Ox8B)k0hb1ZckR_ z^i4_Y^;~R6&dRxW=e$X=FSE9-KFONzSneeW{n@m6zoE|1b7$$9%M$vTYOc;+9)tBVkpMQ$rEV*Qb-Y>a0~#g3@ADX>D0asa;Z**K@VFic4pzh%I83 z#Y$5ZcnmAVs##BKP}Em=w>C002!d-$YD;R8-EnJy_vJnniE^jRbG(`dbavcyIIZo) zU_SbQaa`|@c1`;y>5`u+Z6Ju~lFg)tJ%pcgAjjNLKE9!gd_4RLEwP(E$M|*2R|Q-n zM%s3DNsM3Ku5Q54i_-vK%GSVub7s`Horag9#}!n>Ni&SLZRU*bZDrb*WepD`)k8_= zmnn%`d0*1fr{cJ(>b#75e&%sPMeyI%UzO8$W$nbU}+^g3~}`%{U|}d8Wg7Y z+!v$1=C$ib1l$)d*uuz{L|<0?0uQ@@bZ8@x<%c|2JtFffK@!y6|BC|Y5@V?BnY$_3 zx`=N(>0SxC*`P2jl=i>tqS8Hszmc=Y-Y6`}f0!c_cuSlFfxE;vDST$GN@4?KgWkYE zb=XX%)oG~TKCXD{By0}0nR<6clA~-QUbiNCFY+O_k(VUamEqi z;JgKX!%S_}tKql^^C7>d9)XquX%MZ`{YZ}o&xHEFiEvy*`Ha@-Kx=9C(iNv7J6Snj zM9kaN&(-6yEqPaIUlBv18L~8G(DY7~S&1*TbTSRg%!@i>N*zHK_mfs*QiOmJncxw$ z>VCpF6D@u@=Drr>`$6&)9q*I=JE(rNSkEVt{x-M>$gwYdgsC$+uixUusC}*NCoD56V`H|7&n&GBt$Fe8I&Ki&}-wkMv7zLKu+n51q>A|4pC5~;s4(hk! zvEA!;0QaJP{6DSV=cjhAUth1XLk0gjs*~RYb@Fo7crj~im(Q+svNdnrU96L9qB?mg zYrUNH?#`#~kUFW~5tL(RhjJtzM>Yr=K~#=oNUsKG0y(07-SzB0af9BMo!L(mlPf9@ev`M~2%HRDsqlx? zgGT?g(zd@I)W@!{oKl|BZAz;LO(3d|14thMRscD=)z zyL9h{c`^EHJV<)kxsAmhK zEawyTOiMLB->k!J5uXNMMt<6U8l-1)K}yh|1OV>_6n= zgN2>@FN_Ai#b+%OU+jK4SBs){P|&D0{9E!+ESff|U!a>LjX!9jH7PdHogyB<8kKWM zv*%7~&@O`?oJpyF=+?jV*gti5lcAnAE8aAnoo3_fux|*;)BKd_o^OqL4yqE4)2zF0Lr}8T-zmQWoF|I=wJOp*z+e#7 z*J-400nYm`x_vD4;eD^2l^qyXHL|f zr2OJsHD>lkV-pd}C2ELnpXl1IGp2i@vH~yMb}onHIAxcm5{bIwd{>}@hU@k~YdJg( zg$-YEF%fE6*1Y}T-ii2FYzmJ7Vk#!G&S^nywZ8^mLP&@s!7)J0$6CN7sX@r}A?gRZ zIoy~S)Eeu_?}K`4`nl5T!eOFaTq#=C7Ry9mCGWfSEh* zIEQ-rruGP~!chx}rwMyvB}($`gG4l`8UvjIN!A8>@B{u3r4S1Dp@!*js!05BXUCPUm{+)V}_- zAeAO-#(@hK6qk+pOV+J8ajdwg(DSW_ViQw0Mk;b5a;%Bk*+ig#x+Cgb>|WEnPh2bG zcqxT)Y6lO*($BL}D>X`z(0`gXkp(~OxdV0v<^6(k)Q6che!&_5E(K9}zkG)BKZ`FC zAjkQ41?3sgh5p;wKN#=N@8~?^KUymFLcp%_ba5Ugnkc0CHl)j?LV+; zo)Dt5)-CV9eBS!@yPfjoe>t3yC{MwUEm+@wS<%B%@m}$({d;W@Yo-0q=h2cg=h38o z^a)>fxiyeoz8CPEuQhz8^HTqFlP}2Jpe`17t)rR0$D-chnKkGpCoxcp8*8~Hc(^}{ ziBw!cq>ZK{w6Y6HFkKa}6TeJcW(n6+UTg&7GQXTZp2fMD9o8#~i@Cg%(H^l|x*-_2 zOQn8}VX&!UA1e1JN{#ad*k##Ut%T4QI&AQBn5iODAZFD7 z`&TMmRwO?;$%w$g8~n{Kvq zBP^$fuFllGk^1wh;aOGbW?oduO@?*7ZS63v-Xx10&g+r|L>3%t>K^ASCMu81%eyH(Gff|Zs<_rl{LyqqTb~gg zOZ`}W?kiRO-ztZjA%6cPu17WuuiRzFU$mVjXS%h{>Rs7~kROYkK}3=wSo|k?@=Ill z0(!tZ-yj}B`qCnmw9eJC8Qm&(MAdGVi26{qIgX{Nl{bXE83K;uxd@y@({T~^dxXzN zay?##bc+hU6%EKP-^vzg7J`cQZ{-afQ~1$2{BI>a1uWve|E-+mTgS-ka2jM}mOh9Z z8LQgPDSD!liFpZJ>AJBLA>Caw6Hl)dFK;EWd=3?bo@F?uEyp7iBHq!}W>ssgTa&1@ zYqIr3i|$sgXB#K>)O$4atW0P0WI4hI!^*{aHCDvR%e#Ax<+*q^(MRuH-6zw#z;%+e zRZpxsJ=W;dTXo%=^}f~3xxPdD>-`$~SN4dEw%!`Hqu%+sScGzniK*u0KX2ib;7nw|gjK+5Ub|pPA>2{EGuf&j7PQRG*iS{vo&z$Pv|F*R%hS zk4M&auFpkFQLS9Ibg^uUqG`9oy>Rv?(8vbGPGKVWNVUik_?n?T=r;6m#S8<7mMYzJ zK+8}QZ^BI_2?R!JG$F5Q!v9NS9M!?Ce+ufS;#bA`8Ap0HI08iU-l?Q-27BvgQJG~O zlJ#l)ytVUs_s1z!L=KF@W#iHXfu(2L8PbnZ;CkhEBm&cH!DnBUolLmGJ4yAjQLC`i zJ%%At8rIQ}>1g^yPas58;MOc+8h29R^1$!^^`DAC z81Wj8T)2AWnqfntzSZ@e6~#yWQ7~G(V*JWe#6jjp^}6ND^1dIKk9^8Wdfi33b8HMV zq}W-?IWjhFacYUP*jO^cnZinyiFIF`U1A{^VXt|1T$;tpr3x%Evs|;%Bmm^W1|Ff& zf+ysYof)dzA9;D0bHei>B8LB2ey)nY;Ko$qHP8GtbR2wJn|M-s1@j=XE7kig7Z!3} zPjvdL%0GL!SU?;@goC_Z;-*YpJswLvL#B+UV#fBE>l!5vmjC5Mi@|`s7dk3lmtRis z%dfiDTVf9tbN}E~2C*p37zlH0OA6&j=V68$Sv9 z={EXb`)P7Y(Vu7!jHOG8l~&<)>47<+x>+7>$?w9QP1NQ8QY*U~`)#itU)=go-X z^mMgooMga=K*MC~uAqEd$a_@2XGy;a-Uea$%&M2sfd`X9`<3Ur*s-*R`}Dn+bMeBk zoEz1h!Js(IA0a(uWSsuIu6;m>$6}p_3vQ$>c(ar=9kZ!7Jl>3(MgNAl=B)jeUYnq} z#1wbqMFTWnr(hhV#TTaVEgq1P$~9(cObnj}<=jjeqH;b-`X%rhh~}H}S12bK2jqBX zFL8GLhkPt~x9h&FYx_dQw~KLF@0TXVpDHE(NY`#N8(^rrsR_1?5-z^miEl^%(+hO# z5?a}7v>3st&r%zh*gE3IQm$dbS9ek(dsuPLn*RDdWyy-1G) zQGIqjNA=6EFI}@_%_(pPk6X@W9^S8`t)8eYsYyf*EWFZ?hm%o(Uy9H+q%OJ?#^#1F zUt9Ri$X?+=(%Zl*AQ}gGc)Sz9Iv~fs*4_J#$@niu`Gr3xc@+lE6QY^7deyk*@$R_H z_%s+udXOf;Dt!JNk#y8fqxp4%lIRdqneU-Wtp25EzDAcbbC-(U4&xbqu*8(?xKF8daU{lJWenPMD_Rr>0UdC$OYtx z_6d8lV=bxdT#tS&iVNMSVmq7bV>?6@Z&Od{=v{8Z%+EjFkDQDuKiwG=bMb9?gX#2$ z^_*-@K~BAmN_RaXdg3cLg?kU^J-xcDMkbkZ_hrL)mT+q2iA;@Ao3An&pm(PvyLCh9 z%+pI^pA-L0VaR7#b*^6Ol#GiVYh!-OtaPwdZ52{|aC~2nTA+*si}1cC@n^Ec=SrA6 z4D)9Y$cPaNr8xVIrmc5%8lxjyt~9)kq`k6}6$!628mhX%%Ylrzqm6uET^7!J?}`eU z(4Ubzb_wYh(4)aQaK|1f73}j%{fYB*eGuKiFm5pQ9;zoq1Qi(`JHHIaIqe(ugVNX0 zV+R93)DMm&{S9ylkYiutY4mRVzEDuOaK)N+s~65XW#KB(r*6ASDEe|B$~ToV&`uwf z7`;LQq_E+u^CM2iom`xt5DqMe#QQ3Vk3SSS5&R&?bCKp2C)x$na4mB(1itE|#MS;l zEV@+~6Y+F5fGfgk(02YKs0Z!0#rgLR(vQmZ?~3*C)EkV2-z%-(AA)*#q`Cjtp7sy=R1#w_7IZ6^b(DV-Bp&RuUv89+Lg~8kgtCwRhe!ZH= z#5Bd2oYdo!MovsjYGg!?pPZaBbD}w^8q{N0UOUmAWK8TaNlhF&X)b@%3hKF6nCwm& z$@}-J$>}M#=%iFlbM0-mcAe3JYsWeqg(l8Hfm^Tf@N|@b0*5?L_Z0V{`Y>at@tz{) zforDv8T}<_yXvo=E06!E!nmy>;j2x3s>jCYm5l_`R zt>!V-U@vA3&)uq=vTV*dM>j9kowIf8Jl(ok=$ZV5%yJWvx|$D>pk5}+4cCvt7_jo5 zfb>yI`NiJ~2ahI1uSU-;d%Yb+n3$lzgil1d}3`IBV zcsL6qx!2LzB|8`YI-?}M807U{$6_9Rq`(Y8a0$=v=Rd5_BXJn0v~%OIj(e@j}h zH~CdmzWK{m9)JA8)e;hz`B7V4r(J@u4wo&Os+C{b75-l9&f@PKMS2-H6-4XkcG7IM^j4N)5PO1GQ|s9+{iGKt_aA~~o1hIU2-vhgV9HYbiZA6zw{nCHP$2D(v-QRZf z78O~H3^*Rf>VEK5Pdk80`-VihXD0+{eJ9R1sSVZ~JV(Tw8jNmYDO{M`CwoDuxP^}8dFP}lwlamUI=;P<$h$yMrRqFm2Gth4Cz z&w7sk|`{agwr-IFx%(07=AVGNUQWqZ%5i07eQMkLI|MDzb-$ zgoTD}s(e3;L&Mte_lcxygPIt^AB%2i@E&8$e~)D>davMD%XU^3sf!(yIco2}kk;PC zCLKie(oA|B_$nM{UFWIY>m{(46x#k+NcxGO0kVG8pXf6%PH1*mV?;nNOX$^A7BoKP zrXyg3ir3v__YMp(ncK^OuMy0ufJN9)%w;^iVs*JDFq}j=tb#a)REJMmjMkw%h6NP|!(aZitY^+atewj@%n_2fA!*CnKH0Y3s!xn3gu8Tik~ z~p6MtDUHl@K}!Hd10jLS}s8K2Q(;#^7T;3uSma?X9fSk5y@pARkqQ8}+9eFxZg zImLkbcyR?df62o6C$50^;D?+-*RGCYR-$XSYPPlo)sZqhf<`kWF-M{eBfnS^Tr!dS zbED)llL_+a&;z3Oi1OK!d;hoj3^I9Nd$v}Ezqhf&@7+N99`HDb*25~s)luMbAjca| z2J_Y<&vu@_b{-V$N1M9pPcK{>)(=#~FCib`cRmO)L1(xKHJeEePEF3inWWudW)dm7 zcq*5uHC0`il}EIg!6F>n6IPoPVpXD`37O{5ngd6zb;PZ znN(f8FZmAZOQE-`Nmu&!Vy=8&IrKb#OA)n;psdB%Q&Gg=*o;|-q;^rCQ9G*-NrO0u z+PR!`AF!|f$m-YL|Mtf_&Z;@u9r!bnU<@$DWfVz}P8mVv>}o<^IQ}K93h8~gQjq*? z;J3QwXXF1aKa1AkGVZaCnc(~9hQISchu`@JY5OB+01%bCigbUluXypS0tig}pF(r% zAQu1B7)rlVdx0M=l}TTm@SEv)dmTvAh;2es(I1f5Jv0XN$@VaR=kVLndbNr4&0q_N z^7jPk-+<3TKL3c&k5xn$M(foQ#L6od`9@&)dJ~~CJsw+^KgJr!n79u%^(1?eMkwWy zSaCLoaypbuN(=S!r#QJmHeEU&0pzufB|&=)_&6Ak(solx9}bQJQ9f6aJ{Ls!>Uxgy zxhjanByIr3bv_fDm=X+F;7?^_d9%{KLwrlrh4E@!E$4IxGb^dnW*~l+I@mOJxh*4M zKxvR~?Z1lkJDBtVU>b<#o0CYN4{ic-bj^2k?LXvWNWL@wOEyrmRxV$7xL=Z}lyI)Z z5ntfdaOs+Zf*HHK?Lb;)4PKU39RY7?$i&Q~%tUumLEG#w8!_wPBWYvWxiqai1IyIk zQklP|GM}Z~zogPZ_**!{J||sx2?sG*$RZpP5>f*lZ~Mf=5s0vcz%9p7q)`Y9kSPo5 z#rbowUaCm<2K_+Tp5{{0XM;P!{oJbX9M#9Rk-_{Mm3Z~S`72j15L0cReq1P&;|n^Z zV-t!Ux8Vz|ytx~aC9g-8-PS-IKSwz@`uMTV;@~XJoK=dfp;qQlSLRA2i^?ig7B^-; zl-cxl`H-ozsW?^sP^QY@0g0wSipqRf9=87{#d4OBE`Vwfwg17S1+#%1QTe)_!|Kz% z>f$GE>555M0?d$zz~W8obgk)h?FpA?@P{WhDQ|!40^Ph2mcDJO*A3$hiCk>jV*^XA zvj5VJ^K~qClo|-%>0pfy&%}6(xbpbwApm2!-eekAjjU;CI2BGJJ0D{4o0AuX!P#yZ!4o-+A(T-mj}xw2KDNB%Xa&Vjw9LMqL#P5 zXEOgkth4)TYU;D1x9and;^QzMxv|cH6=T(bQ~UJm9qTg!Jfqn1J%L(J>^B(ASF!b` z{vfzXJ?E;|xtHV~JtMe>TYyg2FSzRWo!&toYP+l6?0WByuFJ|FyMgV9dW_vj;?Xko zh@5XoBpjp&pS#&O-cEP8vDXL>W+f6>@LHYj+DtyhcG@(W1FjcrJm zgf@P`L>cX2j9@jbNhhqUd5nIHrJTcHDjnwL@X=Ahy^8b@uOEJE`E8Ye8Q6edfA|q9 zkN@!oKnm_n1F+OsCi3lsZj&~ChJFzB`?pB{1!VtP>@U}n{ss6GkR!71+}dT|>p$e< zzRX_w3lrJ0c}o%LmhV)b5z>MPE#uzAs-tOa|71VaKg}e`$NK&w`dR(0esPfCx}a@{ zH#9Ze%36!!wz?M$HuruLr#WW2+34#Mec5o5)kalD)Yq~xM=wk3nL4Z4O!cMRjlY^{ z!sivxq})$dVrzU}N2w?0dIdbK@^(FuK!{f*3&FI+C-ym>%kqx9!@0{RoykHJhFu^cZK`P@7ZzJ;NrsFuR7bPHmYH`b3( zl2(5fOQiK?e}BIx>y5Cjqh&=KfS#Sy?VQhwe&J6h{XK9Vi0FjApDV2mBz~6m-=DfI zI7jnRaioUhH*Ak_qBswya-04K>v0|L1j>hk7@TLS~4YieU>$&)+jhCgSV#) z9SHS#bgkLP4s*s>LtxT+#!zpVF*pld(F*}Hj(_^O@Rw@vqva)&O^HIj$|2^Ul}RRX zrcr8jcXZ=W3{R*lQ_mt<_4L7v(L~xZS!US!TN&J5R69w1ikqmggo=V+Ma}4glgW5K z8B3~!*s29mhR3BfQb0VLy(bqHK=@cwWc;*H9vVTm9A)4=30Wn+aE0@JP_(;*@6#=) z=N;5xy;L~IC#1gy#@~wLp@#GTus@Ka`Szfmj}FgKeeWC>tmE1{!Smhf-}}q`woFJys9|%!1EL#Ssx`fYzDx?$LZ#le%HOjRbZ0o&u(t7|1Wysu zQY>!b|7AHi6O0+?XQ3(Q65T2lI39ovU5D?Ed3Z((lqAT+uCQDcUlhwVg7kPW2}I>O zi}Yn+Gmv9n>u=M)?LX5OE?lriR5yjz|6EGf3-(OYW4g92)u87`OW3`bnU<)*#~8;O z^N^b;b*Y`Z!iE>c#D&@RAfqMU$EYJ7#eh_{a4_t~sGDt&u@o|(Huz&mhRYS$%&RMc z%#;5CJ%jel{C9C38AN(4m;$15uONK}*a+l^_FY}|2mOb9l>FOrPxE&Hfg(8!#Cv3C z)*Fc0c+(^lSlFTM!mC;dTsQBR@!0b)9V}d}cy`=|JkZmHK4tNm_L5Gdpeq0tVltp6 z(q&gLSNM@1Cn3Dy+gf`C<@|#DH-(wp@Fl+7!EGQa=d7==`3C#_GbrcI-v#6Uv+x|v z4^cVSKem_kGO)rCy1zIC#eQepJor_Scx&D^ySb|GqcN&xJJG{44KQ*bw;s({ zPorsRmJl}QS(GNqpHpRhy=MDd<*m1#Aa;?YWT$eJNOmgG}Cl}&w`=*dXSKC0r| zlwFdz*E8-%mJ&Rdx9v(~=a6$%UcN%TnM{0;Or@&y${!`%hZ0S{(!G~;eNcJh@Jn6y zMpu75;rdQVvS;bpoAL1DrfziO*SpSpG2`8sw;9=Y!Ne+#rnM$pzsXhoHdi+db)dn< z5Er^pLL@;avNx~>%a3NvnlqD$b5hPv6V`)qB2!jbKk$<0yKaB$Rb@S(th&6JdR2L+ zSYuMH)=!j&fk`vV-FoX=R*x#SUuAm!6F2!c*YbG;3D&Yq##(Qk!n@9^%DLHeUNWth zP3J9BFO-es$&Yc9H;}z*4_3}HvxlBK(RtHx&UdZ8;rVA+*u)-DPA{&#vt8?V3G0PK zUMC(W5jv2CB=NN8d|&B5vy<0B1SU@{oT;a-kUe|Aft^YRe?vBUXUm5ymNS7c&1B~< z%nB^3kjQ~jRFUqG3t4F9xJz%qy;!^VtdFv>ge@;Rs{g~ooEMG7Tvzca)$J=K!4=+>b z|7Jil7{bj4;IqOHg|h8y_BDpu2cboG3<`2*szf3_jsS1pQ5hEoB#v^>`^Z8e643>g zq=8Gz18|Xg0A3yW8;JcZeQoB9>X zZ>Ylk991}|=%#c&Q<_d?Cd^44o}6PG{+8n6JG%B|zQK!KpUz)}x7+OX>C}zs^c+;% zm;<|Co=5%Sq8t4Xuk0Mlf@r-FjFyo$1OCQU$ z-RaNhAmTt)yrB!%ta$cfcnFluP+pbN3={CsnnbSpmLgCmMfQ(2sBTGYqQ0a3%{`=l z3LXLBYv$9WUjyAkxm8!Y>pu)(lf9+)>D&9ahW2YJ0xC{#axxFZ-N)kk=c%F>t8H=p(Rk{yc>Ljb?vc1%6Kk@2 z#roTxcX8UhB%Qa_?=x=9+z?NGV5#@^w$Ll~B zRNn2tu-)@_(ulrZXs1Ecbx_H55NbdMS{Pd31ZDzkZkRW58|6zNFi%x|;5*^1mK8dg zR4GD(XZk8Vd2%XAq|!yM~4HqM^5szh=@Sz-SQl^LeDN0f|r!RsCG&`LIJj z_h~*qp3Ulo%U9xJ5HIl4Z~}jgejM$5o}pccvz$CCD7I*WdH}u8q|3IF5#XwqmDxcR zW9|Q_qT97L)<$(1oufKsvXU^RksgZhJ}54ZvjHMLVrS={D~dlE@oy&IozRPy}zb~7#+_sTH`F4@_sC;sX~{`Bgf5 zw<T-WP)f_d7d2d*sUMg;-kaX$lPf^{ylPf`^MtvS# z@5<#z?V&D3Z*MI1*9MNktp z3r+u2@SJVf%Pyw!hxBjlmxV@Hq1{#~0#eiwsIxjCe&A|7w<1?s_6t;X%%>rb)h`(J z?lXD!7kT{!c0st>vsvnX$@3ESZOQF<6f$ltU{++aMWLp5iG_mA&%n9>-M zv=afs?-dB0JP!;9vdT{DLZ*^#!e4o$242$ z;(xLj`%Vf)Ir$K?)yUd?t;m33XKT<7+o<12PPBvcJK!S_wF6R+|HImOz}Zoi{eRAx zncMH(yS*p7*_2J&YvvwBw#t5g291k(nWSlV}-umZmYGRd}|3a3d-P@3;iN)Rr@tI^^?QubvEo9l*?-JYwPze=x4!; zz_#Dn8SR`4ZUl0ib5AgS9NR}6_7Pt$EEhaQ9)iP2F^=iMFk3KJZcJO&u@vV6me*z` zzGuuReTIzEE9B!C`S`YyIq>NS(l&PC(RBaX0nx_fuy~Y4Uy+SP_Zqr)JVi*2FAqID z{^f=fW!DWG3YCSj?qZ!hP9Ndw@>$UZ{^3L}V#m(?Be*}qpUVBc{R3I^>`gpxT{fA! z=9p+<+;EyP3LeEh7#BU(hThbkn80s&sK59%NH||K}7;za%ED0aslkc7k9+QiS zK^MzEK&7mrd7jL0V;&eIW6XH`^|K05!*GOH9T|#Ly&*b1R)kn-6d{)z|9*c|nCN20}rFkaqETX=^(-iQ7a{2SPG)Md3Z z3fOtQ_c@=ARVElY=`hV_|E|utq7vM2nL=kY-k)~zE3~ERWi&|g>4Gw2i%+=Dxb zT0|3;ktYMkNt7kg8iZSIFX87)LT3c&UPGGf_(llc6%7z$$-!z zWekMfP|M&Dj^{EAU=y(8 z+n7@A908UCId&IUq~U_X@vWd73{P>FB{a8lN!J|AFpa(YH2ieU5>XTGnZ0MkJ@e#e zsHbz(@RQ0G`zQ5Ze1+%SN>EFMhPsFMbN{IRM<)n6qTh3C-bDui6N10Gb$`dsE1Ia8 zS*^>DWo?>GeI*)r@mbtd%&<`B*C#%5qknhP%=Wc^bN$uCPme7~obUQOTt7RQqV`Am zM@5fL)n-~VhlIVN$ixgfopL`DECc({LvSgf@Z#t=0}8*U9*9vCm9KI1>NvwCn5Ng? zt%=m&GXf9W(P4>}cq5iAQQUydAjZN-SkHs;OyQ@evJDog-yuOg#mcnPAQiyT27NU6 z8nE@WvYh<@cn-*6_2ZX^^Ryi=%$I!J@W2<;(~2(R;KtSzd#`2PvpR9rhOy?U#<>!b z{MGI^BcE%v+THA#)1~Tj@_3FqKjqvS8O0Q?f9Fkm&5OV4#h&%>KDB2(dQ>S@`5WXk zu{X5)u40AyO+R|2n|epZ-d17lysJhM>a>aR+x;JT@?{T8L3(K?t zJ>A9C365*%^(ZH~Ui1`f?%%^0h}~HUzTxWpL0M0w)9Fl<0n$s~tSUnPQ>Ej0ax_X` zvC08;Jc3$_d8B$8_xIyRlVyq0ei@W35M$W2QFdm~PB&KM+vyhQKY~94+fLV13cpA@ z9|JjdH=b;I^b6XlkzI!Ev2wM3)&E?n)%pqbxfv}Uk2)_!;Y`u&^fx0zD{4RX~GR&i??a@FLAtA6+HQ8J>gF}yRCtphzn5Rv&TW@o|ZCd|DRwl`76ilrEZB7DbGu zs^Y4OCKNB9P?0V_9qAO2ft5sOkJq*$#2Qk;KFUv*WNLZE)+2*!#a6|(=+q-_by;P^Js@^aY+CFa z{`cMFZ{5_S*u+#z8PEPp`(@s=SUJyLuLuFp<0Y!7qH-S$!0XEJHg$_)2uYObq9Rxy zMZ7p79)inC($$%9;*U>;pG<5-Y*l)tTNgVZSrt1q_L7_Vq3hSCvc<~Xn;>YZ;;q;- zxsPk_37vghC*IM?w~5-PFIM_AO`K5Q`Z37`r61y z7;&+F-dpj??QvMdDy`kOvr>@Y6U+C!1wcezY4`{tn z-gO1a0eZ5o_WjEviBJ9Nb5(34M#MC@AeQAfiAsk#sCE}}{*}0Ek+qTdYLas*Je#FA zbp9Nyq3rkhbCI$5==r~*Ehn9-_r3i81mB5Lm^_nzN6+ho`vN+Wn4~jlNtc%=v4$=9 z)m{H*AcqM|&2cEq|FHhWd9(_$4kt6nI(=T&dfD)t3eSa-O%cKbYeM^d{#+ClgB1}n z;3g?N7sXq0bpBrc`{16ayBXocF3*Yh3ohg5;*3teOe8797JgcU;c`xeXK|V**M(;h zamX{lxd|HeN5{EEa$zX+*M`W z^@#@5b+B*M1NhJSM>SKSgf(}z&JE|k`uw=}B=pheUTbf_fI_S#BP)9vFqwFtlYiUx{?bPJlcAW8RB$uuTho(u966t?Cumw5N|~ zPtuS+Q8*^Wby0K_=Obe%HbZ|ET2`79x%Ohk(P_|C&hx3pC!JFoH2%kEVq3KOkJ0e{wy5`qX#C}9NqPvh*Jzm@O{?3co$qIeA6sA3ke(2o z=GG8PR7IQR)2+nYtnbxF`{5hY^O~v$;;#o*R(VzUPCkiu02Mf8s`UzMdr zzxG9P1ruE@@~T;mG*JtfkFv7ziTA(*@b^y&%4s$ExBRWEp??B40b5RQK>rhD1{U`7 z-ugXG=+DvX6?dV4KZ3`j1C5CaVK5&F!YS8C0L*WzQzplz^jneHvt>$ZvYv81F^bfv zNLwsAIyR!;({AQ}+?H`TCmpNz9;y$h%w}rxYU@`>+g&5O%$)wlDAnU;;2q)=R&o8j z41SE*7ZZxsX;>2GpL|(47fmcHB;-FB9-2xR0Gc1)J%LaXjbg;c=971e?i6WfE8LQ_7v_7I(5B{ z;D0EA;rO+>c8!h>B9hnV%3rU$qy8X&?^qF=E{W)P^jyy$?vEgP^^j}}TdA)lX80$~ z4Sf9uyM5y~l;D#tx*5vEZ(8UV3n$aHWiBb!etGT?QBGhp-gX zznYa zLRZ0rvskpahd*J&W$Q&ddpM{?_IH8Wn`I_FD2LHTYWm7r6>GBeD(88;NSE zH=?*M@2=a#O`RHy=j&x}Jw-V z?#9i{yUqWhwmTFS009-c_w8Jq@TV&)cgs@9|WOHa{{Pr$#08`-Y>0qsS$yUh=WJJIp`%vOJ$3Lq7=q z2iW|7YbdfX@Bom*yEUla-u52mOFs6zrEuN|#>24w=PwTY39Uu@^b(2WT46p1T*7kX z0yUlhFe#KttNh`3U+$+8eg&0Q64{fH9DxvU=`}TxFX1~e>tkAhv;2g!PO)&EQT#1-wg#A>y zz9>=R%2o!mDzm^S-ZO^D6gmNzp%9wZuW~Ehs+!6#;q*USf}6Ey#%Nw{SP|6os$uzd z{yg+w!MNf1dVU)EpMYQhrYh~Y-&cJ5W4G+8p2MNt^z&Jrrq*q1Zz)`^ib+Bbzv1TF z1s%bH)p$)Z-CzsRnT)_-tohuo%;^x39$cVC;cfpALa!^@huG(qs^rPh<(_(2`J*Eh z$cL+RNw)`2KOVtpkz$lk&1gfVV+mD_;&0Y@QL&5Semc>wUnOx~@HRI&J&Xlq^|`Lv zD_Bx~)AfeNA9mIGe#!grs$oo+tHIxBD9P@ zD*svhkmvnFdn^ZwA6N0G_?Z$M!F{TjW@`K0t`Z-5>A!l3hgJ1$Zu)0#q$t;jj-mM= z22n;^URVTFraH>pRLb}?4mVM|evmeXnhp;#Y0zAQozfv#Geju>T*YAf<>6Bh&rG_c zC|QD@Sn0!X28piWml+0Pc|~2awyK{(3&m^n2F9C;kvNtQ_69ZMq$ORG=wA&3F&I5I zt_s@OR@#qUUzCs3&JZvH*zx2jXu%vH$L_|{4Z9pqgLZ z6`;zwNL{6!y)*EHi!gvq;WPveHLh?)o^ zXi5z*iRNR=sX>14B_DP@+4_LvJjeC#K#)7feGOXBS3dhlIvt6$);nDc^)z-BTHPYo z4BtDWC11`9pic$g0JfZOffn2a<`hs#c8_19?@3r0`B|4=?iC(Ln^9XvF zFH+$_NRiUpOpy`|wXjIHg+omDJ7CLkk5=^2!89Pp?#gk`gLXA822B!Y#B-O1O_rv4mrEh8m(m;q22kJg zVI(HpL%mU8Jj|4N&Z87;5l(xsEJD7BX?A0E&l#V%FkTaODOjk7Yk(?O#UcZT6x^$G zVK+Bb7pxUBMe(tC{3IHIY@e=y6*FHiW(GPGf2oK1<6}#r^Gtqsd_8REI;rojnTIN(GC>NxOcgXMBo2A6Yud(Kw;G zNKJybJP!6$HNht$u;G1Y3z`X324SEgu1iR~#DUp^*{7llT_V+YW8N51@w00o7MBT%@Q0$Ptxl1bdrt#=zWic@+IZw~@Hm*w^4 zhBB*&(%@)d7}1SNv@0fn(ZDchrCzt38KiqNX|m(|Ht4s&N5Hm+gBO5J_W|RWpTIoupQQVuFKowB4>Omr96FRWeb;NcQ+3sVZ-7i^g4`U1 z#Zwj>t zQ+~Ex$H%jW1cw7#&dvnN7Zk~vV|U}~yC?5Ft`@eBgXh4ZqMW_fEi$lvQwG*jP)jk- zrZ~&o>8z+lgp?!;l_-|=yp{lm!}w0j7~v+mway)0#v2n9K4Fg{f6^Iz08ql}ZCThA z6nOf1H~O5LecnZemV8IMp1T*~MI6jXxql<`cg>m;>GID1x804tm22dQNcXGf=Qk(u=m z6zOcLsw^_yY?T3)p(BoQU2vs0DIZy_DYP@MoRo35E42J%lmetS)59k4u4z6v_2k z>F3pAqd{L6rb>*n?+|3}k8Wn0TO%H}-*OY%@s(Qfwwrjz)xU8EJ}sX^p2FvEIUM+rRBUqStL);jH1CySUJuk@TI?`|R`7-n$!JmN5=SR>ut#wL) z9J}L#cz@cN4j%OdRW|NTL}XOPTtS z<>O_#hmqJMQrp9FB)nuDk3Y)ugZ37il3!2NLpOs~VC!KY=r4n>0y*0I@UvmQ-AK``;(4sN0*?7qsl!Pb;72!N8q4x zB#Zf0`<{k1LHak7F1sFl6?!|^0c`s99@;4eH9(HtrT^eQ(|>|V|KwcyCz$kK0AHm% z!nQj0X<_>J%cp<8ApH}1rhjdi{xzg)QkbcY&`*O`fldFMJ=xWO9|Ad^3hhwKei4+j z9pA#AaBiJhIIeXs$CsW_{I@Ntd6=yczGFGCQTCC_KYM-yZLT;>T%b50-l02TNocAY}e6j36^O%ob>?fib_~fe!OCG3(MBbsIp@d zLwYprk7a_{llDCe7?p={5FMt_jXXDafF)z_0IUb|fP@irobM4m4~iY~Qz}9jlMy5A9gBeBV>qcgo22 zHAc3zjNTjZMwE@=Z&DPqi*m-^GM0@m9NM@PRdYEugz0P8JD-<-@_3i8?Ox z=fy$!y~Mlik)6sI4C;aHPy0e23FZJfEdRK#I6n*DDICv&ay98bxG)eX7Tq074ma)& zO_59B5%j?-+wW4y4c4j`QICgTE2dPL7<`nEwEv-YKQLV&zC#aW6RhKE99NdlUJwe**7-ur$0xn|4M5%TIl(mmSpV z@qxdm!umPH%#0|tZS~i>uls7NpM0IY+FG?4=Z!c9tJPzvs+nXegT+~zuAEIB70K2o zrIQ63RH9%g)?w3th^M{`4kzlYi2^i66?{z=zYGqKl?Q>)$l<0-f_hy?+HL-R41FiK z7liq9pN9Su=xd!&n6Cpw@d4?^#Uj~Q%TVXMh&yN+9PIRdFW;cC8K4*)}bo&Y951ffImDXBYJO!1jmUXPZvLd+s1mI2K!_ZIhA0 z44x|8<22_gVZ)$in~DvN=emX%B!~f4f3_Cktl8rhop?u>zE60!Eywge%#ENP*#0pU zTCgvWqj&o3wfT~d`~F?nU|*qzubi?fwlcjc<7^}#Jdxi~sY*QO zrHN-Qu5rElJlMYvdg+I}jHCDuHqBFT{E2BkzrXs@u>MJpT^Iip`T_7Tu;sc9I=Qdz zvp?H%?I!qo&$1n`!T-6w##bBs>DQQ+{S(*u6(R28UM&jYWAG9p?YkK76Iq>2?-@yo z1UzWj9hA9k*~QRhppKR;wqnLD_!w322(6{(BY|u1*2{wYttIWYUVZ@mBXB3M_3|q8 z4)8gU!`4IZv-y&bt3C|srTf&Sb6di8RM~c+7>YDwC$d)UvvM-El3I0ub567|hBP}9 zS9o8=>qA&C?sYzj^w;{S>+pXzIIU&b7<7kKG_)ET8t$%TWU`mEKk*7UnYv4<1Hy!4 zzZ>Ll_I~;L>xMoDd<%s2=iLS!-(NcyJrbn*j8Jda=C5JT!tn{0oO3(E(FtcVH{eAE zXEJx2fNE>iKRxHqDe2JYY#@7oK(RcDNA}MMJCa^b*qaH}rxaST4i9Tkswl5E7Sw8> zGL|r2VA_~~Y8eN_!~G}%t?&GN&I^f*5yPd{t*&G*{l!w$7A08D0M2cxvSclqh#vH) z6uvkDmlx&<8*ZnF6tDe$P@WqpE8AWkf_@Tg0k%Bffv!J*G7sZCjO*p6XTz?_(#&p>}D_pb}uPw)BM_J7lE7R;5w|AAoe z|D$s5&1JF)uft7fDw<|ezKcu-J|Tq={+3E zCd!IkR90ZEBw;o9>}6p}^jJnWBGnrV4$Lo{d)y)e8?Ok`Uo|7&-o`@j4fX{#{YOAA z1bz99u<36emdgQJhJgWFY5M}SE3#N5pNATY^Bt6L)99a%WExK3`O4IStp8eRJNUFi zQp&hfpSz?(v#+}{NarTfVCRX~q2B<11~#48gZGpi zUnBQrOYSRL`XWaC5)fhJKToty9zt0G58;t!^xe->*>jaXTj5|UKO)MAH$NEOg`6Wr zd=mRtbS+hXNq5^1g7R+tQa-<5f<6Y!2DZGPhmIbEpO`QXabNwiuw9T1nl;NzeTk@N zyn#Ngr2MIv^O9<;s@D_sIE^^OBSK=VIr3GM>twU2QRvl?s!C?xYPTWV zKwk;20k%AU480lj9v|$rZNJj9TE+^;rGatbAjXC7sBbCf6}VcJdbADdB)v*RcEXEJ z6q~XAK*IbT%KHPv;)c`+x(0P3N)DonUw4@!UDMgT$Z)Gj$x1&BYPfchonW z4G4vrktCqTipL(9`rYCl2e!Q=P9s))Ho1Q7q$AI1Lw`QK&Egm`# zT*~0-wN0e#PMs<#x(DC5*w$t;gNWytDWYj*)Ih0KimY%=MSKu6Me+|&gl6@SI~O5c zFz$m%|LW_4tZXK2c75~;^jqLvVAKC8bnRjPdHVP3FzMebm;U?klWNjGJfHqyyGy@$ zAeU~NkDlpoyFN(&8q#Ll!!^*ifZKpg|0d|?!0yVwdDzMmObESY9jK|uc+kdpAYOJG z&L!d;Q*DY6HL;2sjAm+@DCB_Ef?2U@v}=NTu`)(S32~jXB}`vid%k=ZL!S=L1a_YL z5%gW)K_G`s=S$%{V8^S5y@GZ9UA^Kdn^XtvA=|WbSs`N8+&RmbA-wjJSU9wUVTYkw zOqh|^bf%&vTUj%tUt%;)ns6zjy^5Pv=2n$R;YU3h|DMVauRt2xOcwDO8rvds0UI#9 zxEcPWsz)@(Q}l-$g8FFva=t$HgZ?Tw8QA>34PAUVyg(p_&95C_Y<|s`d@Me-kWZV> zFY;v!Z|(|AB#1_f`Avh^Ni=Lxu_T`OVZAbUd18(W*V5UJ&_&!VU~ZmBdc|WZ#5L6z zzrI2HTgJ3m8dn`bzOArcV{x_Bc*sXh{kn(U?AB-zXUC@BAplxwa(L%#(+0=E21X5z;J z%m8xO^6q^$U-I!(MPd09Kg+NMQ2lLR)RoisXdxbEcL%YxR!RS_oV~~KYW688F??6e z#^yc^8*Y+QCOafg_j6M*wINb=wFEM~DpGp|=K(oISf(;rA&3!Bg*oFd(Ui_EzA%cI z=J&l?Hxv%+2+LtZm_NzKBhXKQEx?WoFGIftdgt3-FIu|1V;TOXMs;;AUfdFPt>fil zX2-HqItZg|qAlW!HHJ!StMja?MT;tK1Bl_;Bj7L9(n*-+oQ9i%`k6E2mAVE#w;;5j>k%TyvO8u zU`QfD7IDfg57q`fZ)J@W_YGlsx04pTPlz6YJQY*{o8C6)xuETiU_ZII7r(Ucay+c7 zLt@>`ep_4-jYV3wPW?(d7a*;xA>Fl+Qe5I2U((FP;s{R|6!p5gUd-Xm_-n)Y$gX-N zkcH$Jkh8N0e5S}QdZlPog79lbiLEyW^|6_>+xcTV^he+mVDpzbQaeLIU*lBY`P)}| z1Q~3d#YA#26UjRDkaB)S{)pWZDT=|@idIX^3K>9yL1ItF0-4hTh+NMwj`pPc%S;|X zW*7MJw*={5L)vVAzYh9l@DpIue?RmVVEx|q9%pTPLfe<-wC^0_bUfg1lr~I560%Mm zOYn7(G%!WLh)m=glHpO1udttxErff^mN^(*lO;ah)&6#!{1clymU=N(qdFaryrT&! zq~F&isr3Ko$omw(TER}PLfkGU)gHP6`AUD5q`tEu%wNON`TR|VJ{%kcZ2m5Xz70GG zgOT{!evjebLjp;7MmL>yP8d(npa&rVOyE2*5h+`SlfRQSaTrThYPJYWW2j=Mbw!zvZNF?^ zq8`dECpu?mH&sU4^da^LGhyYB=KXI6Ihu`R>bpsOcxNeX| z%ZCRM-Sg%{++Wa0)Vl|9=jKDwHyz@CbP!(W{F3}YD7y1Q0goFm98`cB7PLe26{Xbk zt3lEp&sU65sD9F)-DrX*hDjba{WK_-d&#dYm*=2g2Cspj6ddmzXo2O+y?aw(yK9>m zw7Xv8idhTcJZXvaNw496{xZ58gyN6rSL+zccd}~U3%TpYARX<;=F`yuy#kyDZ2kNa z`epDDki+_8?CrPEe96b+zXa*rRk~z${h`dRi*hsUHjFtV%s|q-VR0r1i&S3Z7e!mO z9)!X&p5f0@$z{=#iWlqQ?$n}GdUoU_zs;Sh+X<#IxVnE$o}s;*`ZM=QcXfVw$}wNXh3pIZ8XaCt=Tfpe;usG#}f62rm6zBPuY`9!)DDKkQIsX*q7 z@MyRrNN3e?`FVFN^i(hd*m_(FeJ)rBbRI>(14Paevk2Z0t~^VtD?8~7`b!;aGr_o|=SVgFgZ>-HKjxbY$MBF=-W>vsga!i$rz~ z#f&3GaPF3p@fIK>v#6)ZSp-ylU)x34fA=FY8BSs&L{`FM$6eugFgxGg=Rq$Ar-HE5 zz3)I@2WEx*fOVl>nJwqlyB?Q1gT?h~eMeB9WuFr~;z~sj+j)(#N)a0n(ity^Qh>VD zD{mx$!PNgP*_@6K#@cU*6=tgpuFlrGgY;(S1X*+7W8jne(bw0|u_$G#%xvwnb`zJ?eT?aFk#T)~2 z6y`|DRCk7WS8A;GCdMWaOfMB{NMhP4aea!=Rz-&#E+DT)b*MsUFv7Xtk+% ziBsLvaOj3k8$q?`S&7=Z8NQ}Z#?zHpW3&GW)d6Iy_K-BP6TnxP0aym870^99VLH5) z;VFMVthF&}CGGMdF_Sw1{4ak)s%E6Yv=bTfLi}hwdln zYd>h`;qHzlbLP^BrQLdMjp15-tTW*@;w1|oDuJqbL!yC+o0~yhTqoTd=53A8D|13u()cRpXhMs59(Mi7ryf)>?NxF;u2ly zl_z5rx~}f1_};MAX=d)TD)C#zr;EKUDipft8KNwT>++H!fhbFrOpG_P{m3YBVml5s zg44qWA!RiPhtd={wDOh z-~(Xm{d4Hde8%cfPvGEt3)hD|>wP6|{Z~jqwH-~p7dsP{qA4vAzAM;mQqev_n2fRV z7GEYb1anEc2a2=Ggs_Vo=l&pF3wftKRziORoCR#UE{0wYZ2k2<+jMny2UBcm!)P}3 z6ApGhQ}yg?M9ITSVVL6L6kLtww-I`pi*g&$uRTo9C%ns+Q)~g{0q_f%OHV8GRM0ye z_S&Y0VBkyVcCBDg->A+-u}p1L>7O!3O~BXoI%M)yj5=}Tmx)M;o5}my76*;Emy!*s zkfY4pB;}L+RZw2*c(+a8tS+_ zD4W?LX96+oo~Gl7B*J3@o6;j_a8X5>AUC4OWd9^uSVL%fMLXSu)5J}VwYc^$#G-t8 zmOu{xlYt#q&WC;qq)!ZT&{w**hV$Lg^LpaBcLS8Ua(L`)A@ z=Vrg>4reAOlBq8JNLT!wUx}7Si?A!tFA`*TE)0$+5dR;R9^8YL(PlW1vpmnUh$jaG z75yLo0KI$=5EtlC{G71Em*!!z3LoVN?BFNhENyZTEBC$ueJ)r7 zY`ghB^!1>3d$!lMT`#f2z(g4a4tF+t_2QQRo@-vk8U28P!5~nC9!W49wLcW3*9Pr+7J56;0R#ruM=8e)7|@Q>kr{1=|*HN9=bhtfZ~6C#+j7p+R8g^IoB-F&R{SR*m9l^eJWT3eJx3fzabF&|mZSEk} z`4d`k_ZMwQRSlbX+9Y>krE_HjX)D_n{S!ZWD^5oA?SAT^$RO=ssw!iH^u%~{t-@7F z44I#npiIG@MtbKNWIbddN#~PG!!~NgNk`O6>0$n9EH5ifCi&R%a5(-g&5zfEp+|$g zfGwXRp-%6IpK2+Rop%Pea87sovX1$SR#6u1i{Y;w z34d+9I((GZ+A?ZT>mE*9qaOWl&-)i%#^Snhhd1awuPRxcHx8C*T%;jm$)rd}M8&x@ z&uHA~Ys#b4NUfd2+3&PqUbu%%@1{qBa@axsY&-Efu>%FAz_#Ch(4#?L-qT z`{giw&0RaEZ*T7XH|aaVxhI#TwT}hmuyz;kx%vP8o|$5VGi@;vI#GcOb1(U7+Z^_b zlXuQn4fpFbPeeKJ3F3U-saUt|~!1sH+Zv*t5p!YauukCne#^LUTi{>M@C~cdG&CGhW#Cad7 zMUx(EwHPw^B=iwqdnYZYaMf2Ei zm9`#e=7hPq_O|rIbx-I+Mh*Q!F%Ll~oD542BsIs1th`&dyxJXEvOi zxkiw0I5%z21m!pTlzjPJ3w;N88rbzk(@NyY;CvuQ@A9+P=1V>fo>jR1T8`4F$wN0g z+59rh+?u<1PIvy+^3LUR7Uv#i>483RpjP~@61C#>>h!4xwGEg$wM|d00c!uc^VDzE z)Uj;|=LW38O4(o)sZ7Kjo@z~u^0LXlA^eN$@mKn|3e~=szS^JqU0+}9*L>U8=lkjo zukJ{{zt_MfXn3qS0VB^ZJBR40*ZS3N&Dr_I%nh&zS-B;0ju~b7BK4j>2aNnl+VBPb z9?!j3=4y$iJFZ7dW>#JdGkpE+M5l77y zzz(%W8-B&d%A6|9=RgW$E@kn8>wHXMltz+-4s^e%Q|E~m0S^7Q>LElA756WM(c-T> z7W2kXji)BPx$eAZEGaHN_88w1t0|i97bVWpv41N%30C9yI1N6fIQ}N;^}?XIMwscs z#Sb*p(_9%JyTJpL*)<}@+3A7F6rqggSK=j41;H;VkA@e6a@-o0kCf3rp#Kf@>ACjp zCZMZrstgh zCOz|)I-l4S@WUIz_w3*|ZTqP>16>I)14#Q3HK047UjUx~IksOH@PTKAeBoRgSBMXqw*tp&K7Xj3 z>tN!F7a@W=W4x5fCJ46@%XlJWr<27AZ3Kg<7{`HA-F@6??mp7zbkct?<~ef46V+Bm;-L&LXxq_)-BcQ7{Sq^keVyjgpXrQPxfnJgTL#Tsrx0z1 z!iulc)cV85HjkjhQV$9qc@s&T8{r2MID(AhQGiTvw7(RzyRNSX<$n!#&xgJoTm{0~ zk8Fni0NfP%cUTq1`?KXPzt!_t9@dX-k6p_;x?nae57s}-avRn8?oWmNY*@SN)xEBB zTVjkZ#v!MdW^#wwGv3=TMwdkOc06{5er!MKps{4E$won}QO8gc)%d-UUH2@|6w*_? ze(YYEmqw~%D4A+h8AT6q7HA6TDT#jQGiF~7@_+O<^6hUi^cmnR5a!>#9(oJd-MXbP zldb2Accm6^AcDB{>RRnQpTIG1DiLYII6WyE%LFtRgU?dkL_+<%ie=yrIbqaslVqpN zW5zV%RLN`^B9$V^U}HExhYv>jA)~@*qToTeQnqf|{t)E1{meXnWeM~u@O2R8*Si#Y z1K1JDzc=;Li(ei3^|tjpXWl$K^NMciejTjb4p=s4i7@cHmcSh^?UcM6he6j7H0RJs=Mk*dN^OdFgz3$$&Zl=M^f)jT*!iUcdIdNW$gyWAU+aq> z)ck&-{*EYCoiayS=n+f1=ggP1w=SdJ#1dh>8gs64&qEgB+?8sK5Cq3}aTcC(Z^R96 z5lVQHmlzJ|iOJ|j@&XCm+Gc}Rh{#w)vckz2!#Ke2I2&IH>R~(Swfa%|EbWwldSJ)B zN9Eqx$h(0YPdyZ*`_}slPzJy|4ueL?Zs5aDj zErrD}b0aszI0E9Zla5 z#hsdPKqCn(x#Ta#Z&isl^hAHKSK?>Z>(igBvmFEv4HbBI0^L0_8 zvbfaMzm2NLeD9N#U+R{`YTW8XJt62FCvY$>PRe98D#A$NH3}`54n)=>_t(lSEreh% zAlm+-9XOw{kbr6uYV1Gz9lB>ph`ks`&SZq0%D5!I(GZ{RglWNUbuzx&MYP|0ewQKH9DAXYeN%cg$Tr7uBShxC)?|wl9HGxx{cP zKU2<2mZBK~aK~U1w|}I}C9*UMc-cgx zn0_4Zk0&73^%P8mIhp9_RcLg?L}RWl6`@E~NhG3+D&t=%W`xCEvhR2MI}|_F?W-d3 zv<_RFhlhJ!#bCeG#|t%|vC3b^(~riRu;}#fk4u9-uSk!^C{V|T_`?usDZJ_pbb(nW zY$Z&K#1+rh6A}YaarH@}h0l37@t>M-08*r@D}!?rN+tQL>eAq@i3%EYk&W%Pe9+-si&=>+8rO~+^1H>bLV|a#62Fa<;mdQ8TFD{eF zA(?6dB_-00_;4!CR?9bq&lOym@%hduU3HA@_iBdHSi_~-|ziR=r#HG z?-Wm@w_k`LDISZ8!(=;*(cq26naEVe1-4}fSn1ueYZIef(FbSG$_1^g0dTP?OxMx8 z)9ybOL9YO(0b4FVfPNbERW7#P!`d+7w1vm3*}s%n-|N*Q+Ige65pkE9Mq{N}QFfP2 zD2c4RR_U4|QW*%%+F1$ZSu8;xEW9oV@!ig9Ndn)B7W=Nx;_o3aUZEbce+lZL{aazq zxHlL2M6eXtdN>VQVB2?Zz0$2?g7Mtudp_zAi^F!|&F(l}>f%J_`z83(jI`B+m9Sq> z0ld;#9j4)8O6O3Vs^{={e&%we%IQO{3llw4pBr|8adE~+ND z6o1TCwC|#5a=7m`$p$IUy9>5O!C)y-5aEmZ)rblM1cBiNCd|9rFoDG;o zmcCh<-d-BVo%bHG2i2Rb1R^Md;O}2%tv6VG#D50>g-mZv9(nYD=k?82?sj`Bs*=xlTRS6u3;538M)v6Ki3ow$}+` zQzw-pJSKT=DjRpv$HYl4ld$abf&pSMw5(j^8Ht9C{()=<$C}Eb75{Hv#S}ahzCe<5 zlE`q?1PP?1G{gl{Wf~- zU@stt?dN^%+eUm4tSfEpcQ5Q*v3OoP@ls|kS`ha8O5`emeU{j04ZwxkdbLiWCtK@0 zQO@#sKy9J|L%^b9l&;Q7xo5L5?4d>`dg`L}7#62^M3@Xrme;Y0RyYx69Q`nC|D@Z_ zh_mMAd-vRg|MO)`3u#e^2MXMdnUMAzCOPDalL#m=Xped z^_%07$KnGTn${?HL}Z{lz`ZT%{v_%*`c3iS-eUi*X!M8iM0;XNBC`Jh;k}6enCowL zlW;;=#Chr)sVBYo7B~5fO9+wpSDI3&(=b*ibY-k66EBZe5Voj}ZQ;rOi1ZjE8Zu~|@Hg&V>ZuINV*DN3}cm4Z(b!7S5+8>mt(B+ANv8K$&QUA`U{cnP0ChMmr z4$7XbypjE%j`jTNbU(vhw{Gwvb^}08b3#vod@fW<2dih!czj4DC1r5W?7+MEgvUxM^puO zH8>>b;G$aF*LQM1x7uzbdIwEb<}&ksTs}!?AX)MpNAKqSZ061Txw=^v=2y#yc|VJD z6U&qdr3}Qwb0SrgthM)8p!bYcng}D5mSrNM`?EKjj9I9>*D+q5$14(wQV-EiDT(sp(cG0?xhaI>%S0vnQbm3*Ri%M4o^*^)g8o+Zo&5T-8F~`f zAK3o368c#%{HyEK@b2XD z`O@wOI_G)K64L#GX!7$&EK*({9hma^6{U+4DYe$`)i5sgO;EaEZ5OA8MG=&?jUIB; z#j)&vQRCs>su502kDnznp!r#v6e{|NjT1f}k{_d{<6b{y|*e`Uw-IkKTZ>q^EnG?Tp6Ltwg< zP~7vJ*LXc!aVFs`Ehyo`Zpf&ilpdbL3`y!6BeJ>RSRJNo(s#oYaBn*FOfV1F_OS-~ zZtx0_!>(_8pUsziJlu<4VdRD5h3)bKvA{eWz6*vh-Pz@h-SOoy22; zqV8!@lQUtRws*os%}q~p=PV7Y_YgB3?PaE+ea+|H!JM={I2D_F4{LJ@E`rZwFlB90 zUw6Op4>dM5ZjZ57t8rVEvjy>YJdsWitNe$m;RXbAEXY(UQAq1f)Yy^| zZ-gG6DZ5yuzD-|&UsO{PDXC?Uxf;H#kI|Z^_l@Apx3Q$Dq_O10yG}=!$B*s{qGp)lR;nW zDck>Kzq)MR0iDa*MGcP{ntioq+gib{^#=6<`~l3+y~adBHxR8Mg@&T5_h8bl!ql9W zN&?~MqQYE}Q~KoAi!#g)k_pQcNbU}!ONHG*bUCic(-zWbk2j#-1AhfJAIWw2MhCka zM~vKsU;$|71}=o^U`^bhR^pWnZ+%#|-~t8CT_Wvc91QzDuk0wyVwj~O)Spg;z;cuH z>#k=is4)i79GGNnpE%aTW_xNG2Z8@9ttymhS5HJ2>6e}q_0mCs#VHQ4KN#2(< zK2}g_&N<5sFLUBqXExS5lCI_}^6g*-^s!(eu>JZw(6@u9fE?DYd0Q{N1M?*x2lpE9 z76dkcHXG(@fAQx~+4X(J z%S5$bA$k?MHqnoufR^ncyPXNBoQUtzMW#w9fS^O=zM=swqCe5}Fk|LF<#jYnUWZ*s zP#z6e=Ig5!dLq~Z*!tQZdKR$t)B9{QYU-;S{#|M7h*2@JHk~kdq7y}^Bg^J0BdMW^ zEM!U_DSpofCqUt>Q4@R-NVa1%umg2=$8P4|&EK+ZxH1XzO8UprSc4)|$ zY8T-OFREAelF)RLD2~~&AbneSw=Ks%LjM)~9oY2MT%(;~z^147xgdQDsbeX|%|S8N z2E_=sw0Xg2EKdJHb$$b<=L9lGYFijBb!3#W|bEMGakRrtB{4Yb4#P zNsCSIvHg|vJ+7|+HoaZkI}_|~-4W#SLmt=M@T)?S>H+@Scs~`(hjN{a_gM zSTG6L`R!onW57Hhhkb8veT9bU0l)gzcZ2n8LAeEXFu5h`38$jH$vC)HExiPx%?%O> zdK<|b^h>t${M}2F%l97)B14bb_3FsL+x|X8s+i#SR4mTikbKYgQbS~_MQrXq#MkwjmfRsw2k-NdAd5sujw_-)WRpSu){$;IUi}#QPH-=Hq1Z$=D_n#=f5a$JIag_B zPx3^2$OP?Sb69RCQ=s)Xz~cq`0x4exlE_ogBYuc|8<4~LYuN9$UGF!yUL5QkZCdaTwz~)C2tKoz0fwr5XamO}2pCQq5W#@7g$u<2L?9(V zB?!71jk^Av%gZe4%(G-V>qJFW{z!BP7&87AiV2#aj%YRJ6`ra+je94I1`+f1I)-S z<2f^PJyvhwI(|p^zBN7Gw;uXNa2v4W#1`oP0d+qLQqcQ-_S!UZK2p8)nmd=x?O1@D zyv1E2!>?@rOur$?EVXRJlDKXzEspizH}ep^SZofZ z(nY-~7~1i1YE>{A*+G24L$dsAV@%)28{y8UAD0H@y@q@>go(c#`g(8&u=)QGI&zbC z%77ewjql-4I8RM1=)M6hWK>?p4m&e&*kB(!BSSdY`R${5=&V?Dt<(ro&&DRmG7Z#*f5Q)Qv^LTYEbdx;rGR0a-SY?>;2|x zHx_st5q8|uGQOQ9ADuAcj^%uwTnOX9IQiI*aqDRrr_NF^-^??d&yzd$8B^!gRRp=cHzjenI^Z(pC?7T{rK=hx0W0Y6QK;+#&d5cDYEg z=0nYtnmJcRpHz68)ZbJ!6>d?Z7Zkc5DWC4nh?NlB7G{{gue*1&4t5>J4t^$!<$6kI zz5TSB7t~A1l0`I%D2x|6RdLcy7MqC(C#uGgsxae!F9I(KjLd%-;~1G}E|WSboLTI( zu`~I-NU0`JC%J!uzD#ONL{K|}e>#c1HGve6srhWLU)NOC+fve7YlHgv;2|fs&TjuU z{4rJ~!$D9R_#0$zB53aAC(Vx2vqSrnmW=aI1Sf(!!rxuRZ`gVlJBV*_eNp~*b9NcM z{TJHbwe!vibLQc#pHQAHdpl3SAFByjCarZr`tjSj(|bPrFWxi8dA7$}n0CYW%=k%I zB9z_n(DT6}5Z-l9hF%S9`g@;ym_r6N?4_thWPb*1YdbG z6K7MHo*lf)9?{$I`2)&rWo`Ig`F)$dTe2Q9UFQ+VYIj92RUAG^!z?MhvbB}tPyL=T~7q4}o)6(p$K^|;u zO^iJW?Ie8P8h*>R`*qMagP#DK@5iCHf&T$=*m-cLeXIEveoU`?(-juX38Sf87MR|A zixaDWUuoxtD0`Dn+{i!N7||A|vg>1N_dBCKTsMm))zQrCGTh9}FLlgqCU|o@nB)l% zt`H1|$Hsm^y)N9CyXCBcUIT6dHh&*Nr*CK93goc)>g|VPc4&9B^|-?E9A8U;=NHU6 z@6#xwtyR-Z_NFvP_loZA4H;?9u_43SQd2KcZB0{s0(jIoPedD2al{f@rQVA~zY_hb z_kJXS2f@@o%vJ2u$grR26kJ9o9@#7ojQJt#^L@@8gw9fUPb|l zy057B&I3mEy-_V=1kT-tHk#~Hn5NN5RwLn&;=;%umPo}(bW>cSozO}++8cuMyD2Oe zx#!dCU9Q=WRTvu>87N8qYH&Xj^Vh+pFO2{5ddj<}59I zbO{|v0_x@Vf(tr3mYyQ}@eS(dp4sQkxJKIAmrjeGI)7Qi$+gTsZ1m#e+N!6<+G0~Z zLK2bqTVjooOd|0Q75_}Bf2!!8{OC49f6AYFNey^`7|g+y?Be1dM;iVbLA741&wc;w z2={&-i~lNy3pw4yrtmJ!5;b<0_U_aX=tx;cG{~ZQ5TeV=8Sk3fY z{k39CB6eSCw(X)MQjQUyZ24tp-U^NYixG_MlkWtrIK!!@PSY3#4dlGjzmVJTUu3A8 z9Qe>tQI(Ah@W){_DtZD`eR3Qdv6xtXWFl#b!yHXv{fG4`_nw4)5xfj+{l5!cbQgPl zAV=@<$X=T-`PkNLe4zU0p0s3c=ZYR8Wb)qvQP=shYnFnWyhP#j5lB+V#_br_A!_o|-rs-7p3arp~g{6)`w!7F-^ zD@1D%b-O=Am)?Q%=uDy#clp^!sh(O~e7|3;O4s@m6Fu}<8Y#{pKqPb`R+a0)EC5-Z zxr>1mx9GaanYDF6x&QC~HyFn+R7js2Xsa&6{(#67{~i??=pSQBoB3sM&@S8V$@BM) zg%~Y=<~!n*AXwS+Za65?F{GXG|?kE{NahdiS{MZZ~qT>)kDM-1TpF{fA&NkI>a0 zmsY=5sve{aWqVX|TV=^VNLBno2l?LYKPQlZ)R!KUSLYE1j4U}s#~SBqfgr8X_=4(j zTZWbmLxc2gCoPu00E@#Z0TsZu(_^74f59#f$nkEdH~Lg~w&^!t@-eHsa6Fkir+fag z&LziBCnV9*oK~oDUA9`igAtq4@_fv>HQ9*YPcfP=(or;IQe|heyZW)Fi52xwa=e8w zAo9hfy}wx7(|}<-b;I;$HhuvYO7xS1>lm|`%vv%Q+wbgo_bQGue&qk}|IcscTJ&y{ zO=~yGa1h=#~9J-tDT`Hd7ozRn7?+r%J8$~KleOXL;d&20_SpS>^NPnw`dfoZ_@ zle3|31Wy1t`pSp-l8-YE-l?DDl%{d-_mq}7b-dH^zHlR|jRtEO3&R=C1t=$H^t5Jr zzA8bOT3J+1$e{?UfQRc`Cjp6^|#XYx|i!mMDvf z2?hqjJ_CKAAzTH``kjCuhBxxX&xjjhIBq^e3(B=b@Qp`jn5=cR2KC*1f4;o-fj$J_ zOEy>E$3l04zRIabeNUg&8EWv&WDJolzPL)Mk!}9z&fin;Fd|KE504V!8YNg?Q5Auw z6sgNV^1UNW-)7!z<)LptzXx^z+a5oIPO=63Pttb)16-Iw3F=*H8l*|zD(9kfJr&d3 zGkrnm50kb-bLr|D9hBQD-f73y`?8I+)U>eN1Lf39aPKB|BWB z@z4yj0;V-b!wGZ;@>=lkcb6<=vaY z{A4%f^RqYfVc;lW^YapP!-Lpa06DCGkh}Vj*FIcb*#CRh%TbG#FPw?r?cDONYtg*L z9awZyVVl%n-2X@3n+M2Il>h%-ea!USv-gqgmCdo)B)gkybCUZekR=J>5X`v=3rTj_ zY#<0qI0Zf&0fB%bL@v36fPjbyK~Qc8h=>Rn5EYOk0sA>53uWX!B^!qukwZ9Mi~+!>fev70fzRAQ1U5kfq>RT)^D;V$)P5u~}S z6M}OVX1A*zQ7mxFDhEtgSlpJ%`lW1yF3h-mYeY1XUH6k$8Yp+_3) zx5wSoi|$wbe#U$dEC#y%ULrl{A^Z?Q_xk%NSl`g?()*H+T^HomU$^$SPXz{h5XqDY z4xxFQr%9MQbIH;}X0d}FmAexsyxSxu$xqd7BEI_zQK=bj+u6cvi3z2KM3a$v3?<50 z5E(nKb}oCtrfRODUhN&Oy2?f4exc*ukqEKGL0h+@IC5iK##JG)%IxpPoGS?zqgc;R zhSW8&@b$6$P+?U4JeB-38Ey$BD}I%-F0Cy4QBr-vGrcvDkKEL~$^0KDnU6)SSR|$< z)Go%^Z$DhzQ5!h15*S|jxD1;R9lT7f#86qLV#OdI$sg$-#kpfG;(8I^6>t_USrwwH zSQd!8Shq&dOarI^!>RwwW7q5swRfV2w6Jgekk&$zLq*M zwodTNHSg!yaver`4OjLR8)Rn{V_ z#VxjqoRXqwKYXpiY%1y$mrW7}U+-_R)hi#C>DvS7v;E<#q6a((QVJs%Rg0YA7V2x9 z=jPm(I4IrvwfBfn%+m|@`Uu*}Ty&RFM_Lcw>fSkch_s+tW(^h_thd@8iC0Ya+tW_! zL)Y7bq@M%t09|iqJWA*zQ1O^wZ}$cJ%PoAOcYVu!Iq|#Jws+26x%#LUZwS8I@rK|V z{2|!q(xD-Rb&)}iy4Oa>(#)WItZ{8Y%{5s1+SlSM7!O?^FXW1?_da8VGl3yR88Mg~ zGcV+%i_j=JIOpIM7cx<%qw#WO>`pRvV^bEA(L0jL$3)-TMVrzypwsU_LAYK<>Pj<> z?}=>tsct8Fm8Y$_K9OceUqUQ} zc5eh#bZZf)MZ2cQ>xn_STeVK7qBa1w_y`Z-oQHg|o~dO8vIcH;iH!``RnbtydlYF| zTa}@IVkWkR7Z<~4*&$U(`*y5*ZB|#O5uN>5`sY-?p0@_|CzZdQ^flo7K=X|UNxup- zpU6Gyp2s=kD>O&;BdtD7!9My`VRZE%JA~n#UFepw6|ne4IGpkSibb=6&O~S>&0fNy zVLXIAI^0v-pL4&!Mp2HP)BOA&`gnHUv5xd6a5~WK^mEd6PcT;ka-4L(-#+hqu=jR) zZC+0~#M?4VJp4O;AvWqKw8J_Y>wGQXpG*u|E>gy|I3XvmN!r&Z)pg0x4at0_lxaJL zCPMb!2(u0l#!x*$m~|&wYQ|#{$djfOBBTw?G!h-`rtI>N{bv>qJd2k%lc_K^Uc`@s z*N3CTV0U5?g+`+OP}PHy^PIWe0*i_Lgfuf*2@(=Y(-SUox^(MS5JUwK8;bRCJP8dX z%wUML8F0FyVYPC@3kT5XEy#z|pG>>KqHw`cJ=3T6qtH?Fg||t61neiX^qxk#6`TX) z(EPkKh=Zitk1@`-dp&obeGyyNWMc#P4mPb@kn9-xJAPnN1v89>)xx_0Ydyu0GUL(W zq*+{9ke|YwD14EXI>k~Cg=>BhR@=ih*M|wp<25>pOv4*UI=Z~z^5Wtviu3&4JVfkW zOt%!Dy*L<+ z9kYD88BYa0ihKE_D?km<dAn z=VGI2wqLFngZxUK-zEJw5P3RVuER)g0p9|0==H*jZ|m9rrj7U8!+mRd_CEyq16z-u zEiK>x>4i^A6BsGI@Q)I=Q!)I`M00bv@n%U)yx1)MVP5*~JPbCG$YGrTqj)-9KQWRw z)!Bv7a|_i21>v6+^ovH~X)(Y1T|xZyg3$9S^{k2xWl4mXP)>H4RXUQ4mTN&95T3ox z=S<#LG=;VFsW#4{@LDCZ=K)Ok*!~SmaeQ}Yx|o%sHk|Dh-`F$9r(61&YF9(e`y(8O?WZ_hdC9s$fBA#aAVbicxx{!!KMG&yQ zv+CGFAfJ24gPsq+OZs!*KAWx2 ziKLGNUjuSn5yUxd>cfugq#QYy{w)?Q=|*5Fm{&{y5aI-=ZfMm z3X2lPn*33S>;1&WlsVm1#o?=qBPorc+N7n>?Vj5P-lzK zh>Lz;Jm-97eZe-Q{@eNa3MtS6zrNn2e0qHNm~`klY=3}m*Aq#v1g8QywEtp9u2!BAqCGPd998_ zpOmrxFHK`07!5QX+DTsxo&j>`{+&DD^uFYyX}_NRyQ`rKWdP zBh(=#Ae(MGsva?VGA3}c)hY8xgcRh9yGopUO4z;CVS-bD;q4DfoSj@VVM!xVeycoo zX*p6`6@4I;X*5EGkVmMf7sWyd$e(({g;=1=_rABQC&Tslxe!zToOHLJ3sdm2%GdSq zi^)>%g+4u}J@3;==p%z4^t_hzGvFg2$CuIbonG{X-S}n4W>F4KdrzkJ3uS7L zYid|Mr;MBW%ltl%n1ci_ETwn7#4d#DkvZYV=Rna{8qyN_()$-J@Qf+5ZiKTbmM(2E zX>mapnN5b2Zar?c5Cw>cRtzMJY`32Yk-Cr*!z!i-7{2WQpFZ<`m8H*fR~W|OTptO7 zyVlFx6X^bxd(JeVO&x6;F;`e;G!z*x^)EC7321)7C zKn~r%>vHZXS9Yjd18<`BZ!4E>-XeN%(`{RT6i>EWdCjJO;6qBMSL8FEgd82y%+H!K{jQExWN z)ZA0o{;3hi@(6aZA-=Eo%wcQ0nMX)F7HNAad{X!XTR^e;UXLM~e8c`wtdr>a>`|xQ zA5xD?;TjUuZK9iUfsP@J@7t|bMU{cn;F3Hc!#5`7ia0*SfX&{iKUtu0|znyeVQ)m)mlWc*S!KN2}t zEp?Xs4`OOXO|%lZBN|G)qoPlh)jnMo`ekMGrOHsK?qam*gDH^X8ss7dRIcAgzU+vZR@3IT0d> z;_n+)j`*SagQ7gAl1l!8Orgejqhr_-ZH$ZzBH_RpnNUkF7RQ_X;7o8`YbXO^ntMfH zxGyMrPeX_2KaE5Tx$tW=1L8%qJ3^1AamRZa=giYc7l9!nTegYSnF=9XR;aBeD-`2h zMKqpsMUI1vhOxwN7ahOJ@`KY!UkEM%x?TK=^q7}S<2)dTUSD~$5B>b-`}EWH4o{|H zw#I0@TQL&fX|+?)*E`13mBJ(kS`Iq0INrX6X6&hg(C&grR9IuQ0(Dfn)>Mxb<=7)U zT2xliZD^hgX@tc4fl4o0X$0GoLMEc1CI+uA1HSoWuJE94gIM+{x;)0HIrf| z-E82ik+ih_9_@S3ZzQ5}e?)elWqIt%djUb?j_~rmb(vq@JwZ9-Cb7Sb&*l2%?6@?T z^nB3Qc&*2!b*p7XPukkF>t#@$EoC~-G;Z|@lL#e<#954;f-Kkh3MPsY&QFykx;3b2 zLG2BrKq8*xjJ)30G>Dw9rDBb3hxp|o&Ua?~+eP|Gup0!u&5FN*e*)+$E}||^>z3Bl zo4w7rr@bNNSs~^5BYWvcdEBb7gJ!u@gfKH%K)keggbBRsMnWtavT=JfmY;CZ+L*D@ zSW@MAdZ7&SI)qYw70AZyQc8>T{yrxH@_ryir~CkRmeQ%@T_GO!?Su8~0Q< znt5^O?$Jb4``##AD&6Ewqrx|iN|?@-qrzt8_eQy2!*zJ5Ju?!qqot8}wRvw?*1nS8 z3KM?Xc8G3&hH}p`3Gs8hyTCly*~_f28^B`Vu!$;|wnmaiKbnml~6Mvz#8~{2dc+ z%Q<_1d*y&Qj@`S|PzKua5DULVC3|H#BWWQ=Z*+{F+9Xlkh-$2TN%Drm%g$t z_MN&=DDubQ?(c_(E>Ynd=(1$<63lQ#`_5YOclx_K`lsB%c5$>IIxw0zyUM+(s$pQ9 z_~s>{;a_(zvYnJVYlM320QboQAm!O3FuY;{UuX4CC7YZZZTA-2nd5z9W9rIhe4mZETSjue+fDp;@}7e(h;?m3oo0P7lNT`Y~k`rW28 z9j19#rF&0hsrQb`$dF^hEJEj>uV^?;)`NsWFRv*%zsWkU3FXfnO__ZCuu12uG8V5$ zn}c~Okyi4mA|;XdM;J9Yf1=G4B^+X|6BiOW`YXgbf3L}*<(@wZ5$gw|;W>VM3j8=7 zYrA|9gHK8LElg-7)?x_pT6{r5me@Op#zm%$f0th_1tJ)TSj|2t{snec-e1VC7J~*b zAKb&HvuXed3AZ>0en_8zH%h3lFsrQoJWN7hjR8x$C6GF_`72L zW+^D0kXM0wdu>10HlEo&7P@%o&6qKM7MyP(mn z41d#%9%xp^EY>}(_`sMOw__MKqlZ=1iF7iSD8M+PBCo8tzUT+4Jdk5cE;lRPitAN% zq^fX0sHTLV`TV>#Jup_As&j`NR__kIKn-_?U8ov_U*?UtLyd}!yxAP%j{du9w#J6X zd$-5EY$4*f@d8;?GIp%<$FnVOWaX{1NnZi31$sPtob+qpBOr$!zjDvsmwc=*={cTt zw69-}@t1f!Pg~D8J|5(QBvEP`7Q^E&z`J%3S}Ec|q%W^^chvTary?bn4Y#%rmtZ}4 zj%lUB>|U>@9-<+b9yG9E_w(+zyj{>2Lx$-%vl0q^+fjZw=lvmD&aaYg1M7j7OTIz+ z0+3rSeXR#ov3x(UwX20*dPGWLA&n8hQsbsU{n!j#SPhGi@pvL|28@d_l8PXP z@Univ1x^Vb$@T{MGmvfcQB1l93FH3Ur8sB zwU8*7Y3y$E>)}oEul1klKM_X&Gy+}D?WBJJ-UV`e9;}P?(lue4h6OLMte5m`?AJJ}4gD}tk%5fHI!SDTD?poDY(u+UG3F;X#V z5MA-^Va{E{FjTS4r|Z>&3&Ri34Lvgm1OF?B#cmu1MV=nURM(6?b%67a8f;r19i%=& zj~f5cLhIgz@gFaY-oMa!pkBmomWA*|!FoR1n9KQlna&CivC$6-6C46{XLBu_R7?hg zMFQ`qFv}i4McJJFDN6(5^EXERmPv2e3Nb~FSr&t_lPC+Z*B~pUaoLk2ywPYmCg}ff zX4~D_q`wVz0$m?BzeQ}>w}}A{#3R9C$W0_ixcT|A)nhy!S!Ev< zDU3xUOYMX+uGlRd?3xv>^`l6?dm_msR>coS^6!Wcs*xAn!kp73L>lWD48=uJ^>&@E zp0Fzw`gE;CON>5SOI4YFtxH!s5vP>DbS_d(Dz8ajv0ot0+xqGxCy|`!OmHH#vz(bu zViZppW~LW9BOKNi7}{6a%j;K!k1WY^SjsLzxN#!Ij|_0G9^f$k5Fo&eRyk%RBbYOa z@FqpwCSfzFKe3XKA^33#;vk6$K&J9y!yx8q(*2|*i0Oo!rLhbF2LV~9l|f!whFDcg z1FHjK^%e#4Td{=mhvbYuz)TvKm{cTy|6T^V2|(2OnfFQyiU(r*zZ z5(VuzM$&vx$Dl1{a#)IEnuRVQ`(EJ>XIf@IwnxubOYQ#B7>J5e9VL2<^`XTd(;SSg z9ez8l{&O~->lo54;0U1G={=->2h4Z;c3K*&A1&-74)Uy=xci>pT`&(4zou{E(1h>m zBJcBX?=$MTINfD2O<4?P8~4=JV5305UbNj#w7!s)LOceEf;%cQjBQy5+ryHf(!m9> zadCETWwX2?k%Y3VoTus{PuEeMO;|NfDpUPSob7dyopm$?BA*VZqX}hM?(xt|>U}9_ z2g6_vBGoMev-~;h@sL$?rb|IPRWb}UpXkQrCsSqadKcC^YB3IEvc$Tl)2HX5&`H~) zZy+uH@Lik(ZeV?b^m(AKedhIeDA7!OD}?1lQ!S_-T;&>150%hnSiZ@aEsN)#5=utD z3MDy3Id3#=^7HX2@6hAHxOcIA11&(;>vg1egTDef`qCSCU-D7i+LQlC{<>|ZAj`h% zGBad`!~+g&KV(Mt8*{xItR!9_D)s;IY~eO~jEbo*di$Z+vcQcho}yH-CzU#75Lm-)dEfdC|b|)2gVH{#{azSC@;Dq8#HE_WU9~Kq>Jf#Ky{0;UbHLNX%7I1G5Vt zB3w_U!U!^IA#Zd!4C6TbnTb;6 z!uL%~SbrQ;?A|V)?j7%C>3%xt3&D**(>?!vd%%1&FXG!b{NDR3t@e3TIem$4dkA1MX$Yf zJAb+IG{Z%EJQl^NtojY4SN7#C^>2hGmqC3H8aX9ZsVmgVOERDf32kEiC#skbp;RsH z<|kO<`3bfh@7FiP&-AlzlD-IB4s?CrM*3&q8Q|4-5O+-L9krb4eaXkUIq~0u`tH`% zut-_mI=6j^IJCnVR@Bo1rbz>sGH=S_L`txReoNiaABadH#+oD-?wCe3y$%;F3A^u zNj~yR;!~<)i%o{q@@!S?`Kp8)PL{rlWEFeIRNot%%f#Lx4i}xNw!~FW)a3M|$7{;7 zn?8zT>?r!m3|c5|p#OK?w%$YOLBT`+cYR1aY=`gDhi0+=MaHi-;q{kYU-Rp08}*>a zrK?Hb3LXTyzCI^i@R4Z@1af@YxD-FFXML?}KcTI4{Tf;ot3#K|>d;JC91@$65kZBG zrk|vYYllglrT;eA`FwEcw_r`Ni!AlXKJ|4G@j9umU$ONRo$29nL_IxY9vjrogzOM9 zmLX&Y%M;x4JC%b(nag2@C#NI`4C5cWPW0(=Lr`A1`vmD1z$-x0<$coTUx|SLOsqyY)``#C1Tt+tU^@&X7r!swV#!Di*YV- zA1ginK`ts-b@ndB?tU7pgAv}_bdq15E#y&nn$f4!R!h3t# z=Xqc9@%)P1dY1CwE>P0(s2IrpQb{$RVFh)36PDvtaFWnySl}Q8OLVtFWJ(l`80QV( zTxy5yBEk|7`R!e){=JsEZb)u-{oKl*;LIqR9+_oU(hO4llI9}W0TNeDs~F{Oda`Yf zHOmjkGzy7eAZ`?|OB^d%wJnBR>qyJ^C%Y?ko7@kkwTMr}>n5ErhOJ&PBIY_IeX*)` zJ(pk4Id`wQkJxdIPc_!IzTwk*H+0nNC$EqexpNQa;CI#sqy@R{MPF;V(+hKAPB&g2 zF0L(Xc*(!83k)@ZwP#2oips|#^ZlXL-l1}Zc{Do_L?dal6!M!GtI63(q|FNK?J7#>o&HXL;s!Sc zJgoQ-i#3_^$yw%s;^`!F208nG!9&F9Z47u=6tH5%=4}MWxyZZr-66!eiNDYV5V~x| zcv#Mt1$2`14@ln$egt$qK0sQa>n-=J>oJFFO~V?YSd;NMRzn0Tk@69ul6UM3-kbiL zZc&CYob)&_5$N|WB)uBszE5BG_TJ^x8Zk&@`m!H3`4!^Qv)OpAp+eLG*i}TsvF=+H z2rb2WL3&K!*wgKnFd2@fQ++zUNM7{uk)%I^-vHh2Mv*=UtOs)FcGs7k+hu?9`A)Cp zShxE4m3aH0-Md)qOeTnWZ!9CqUCMZ)K~#LPyXu{LQAX8y4w{8t+43VeX;LK9mPiO0 z1|hQW5=tp6q+)|1GI5bV0g>1`nXgF8oDM1(M({2vNA+ob`5z6+CHGz@{XX~*1XQtW z|85%7fG&5}ojv*Lj@f>H>#e-LE0byOQm6WgrG7@k)s}H?BmIns6=K~iy()=)b3*zO zp*7}5WokMR%jQxWGpDk6f!8BeQ#i3;7PX4#U;OSupOOZ+n&Pbm()UD3B9m+BF??wl zyHEGaxr;LB<8P$x&++F5x}K{@j|ck$Idpr>J?m%O@-OPyEBEri@+fztTynyunH~o! zSTPs|G*cw*NsN~4cHM}??ZQvO>e5)IsXJnKyD4JAB*sp? z(esKk{BqwDlt=RYBOv>+* znfayg30CdZES6wiwTv@aa%15Nk0l3Xi%ra`Va}Vw7)$5irsS$mhQ&V~R+%g!WI@_4 zDa0L>h7qmBu4%R`b`tc*EwD>v8%mzST-r{dhEhKsp58Uwj1+{^wS{ZS+R9R1Gy~DG zH6rzjeY@zhWclGVVZ1V?PC?MrU1kQ?GMqA$N;?uAnfG^`D;Y^8T<~eK$}|}C`FCC! zSwwrxB)S#5y#~jgZ~FAF`$u+Mn?`yGI0Weabv)@afVOM<^yZ%ZYemj}qTT2%A;!e3 zWG!OL!Jxknqv7w$xM3vZX4|-7>FD58tz%9qXS^DQw${uG$HQKqx=ct?&X_}F_$2!g zQtEQXlORs~p0oV?ze(Qo5&I``bwMf6`5#Vt0?_;+cRb$uuk*j0xJ7;hSmZ~$Wj+mO zw9#;iGPaJA0l3(V6qlAc@gb-wd1I25fG7%h^sJc+vMn6F<7_{_H;@-CFaCn`3*Z%? z+k1*s1DGG&(fRI+pTCi#hs>e>a?cfCIQqH5(UYJ?xOy8czr(n8lo)oZJ0N~wpm}?F z;*$~1rz31PeN(yneHIPynX*$UIsyvz40D(G1G26v9y-GN$I$DkJn<*Xd_}>%uUNsf zg}INy%Ux8_g)FWuHCoOI`ak8=^mvN&OW*^b>9Ijs#tq;#Acu|*dqfVO_rB!gp6mPU z{~|=UoFxq4W-n&+%0Py`MdT}4M~G2*1;*nL1$p|eD6;aMQT5h{Tv_=}HZ(0W)mBZl zQ_2}F+;j}aEmTAc38s@2%T1{d>Y|vt z`VR+5y)4{E=&p|siTz0R&<{E2hiC@KCFlC}w!*YBa`*<)Tfj*`_q&Tp-wa+1^gu?i z4yVVfT{&@{H>_MweC3jku`r3R%M^!b-gl0vky%V}s>H#ZZU&lhHSs{FVZju+W) zI;3dSjgMOtRNOo3rEo_2JU_pfsATe6O?+gH=9l-j?WljXovU#QNJQ0XHtD7lrpvj@87|*>w-qQmo$NsjZr|i^J2#`jsv@a z9Pd2q^VutY*^}P}k1*ozZ~m`mBa%Jl@YCrbF!ACTFjVw9(iF^`Xn^BLo16+3|FIFk6(DX(3? zlq0HJ32iqSFj`w$lIFpLGD{Rb3;*4BWRzlR*tc)v`fGdGFdW-zm z2#y8E!AWG5TSjk@4aMX|WJ8JmFr541@ut0&vrAe%f)a=+;Y#}IX%bLrEvs3L;8?~P z@7c+4LUtQn%?~DnQs6zC1zjApoeE4`BA^o6lfnQ4(1Ow<#(Vy!t{3@aKq%xK;ikjM zcr1qXoLL?Ftx4$0NVJd6eCG%>I$&FB>;);cE%l1+oz74fkm-h>hm76L zqY%&fD*`@H-}!i1Tc(LCT_hX|x#q!kl{pO+ND<53N#b#rVnCO2#>a~YF;J>fiAKvc zO9&egE2F{ngA7F&kCmu%M8*)`-WDK(*`so!leQvGt0RP|jN(U7R2+L-fb84ws8mTO z3*qGurp{wC#@^@n zuXSsED}<&qO~&$RGM2Aq=-LAE!CK>@ajb*=-$zcg&$-u?D8Sl0GNq_ZXtw^fi%-;$P$RF7R!{V zw>~!g$FJ>kAOs$nNuh{O>aX0kQ zbbOWc+u&oM>9{;%8Rvl8fgCM?T$(H2?HJ?p?Om7jlnd6a4Ln~yk;%Yfw*NtQ8YZ$n zT<%cgMTi&{y6g%_@%HFYQN&j7l!>I2e7B5|_f0?jR+&i*Bc~?3yUco~%-mh(W&YxiY7oySMB^4C1lE#NCa z)A>83?*+dEa_D)0mP>Qn>lMf4(z#=E=Q=UpsJ==`u!0kVmO9wjIbNhsX^!DfORY~z zDeDzJt-ebX7Kr~D%TdxO?;ZnbKF(fX9uqCg&`#(j^-+~+k{QR?eZKPdVw%n4Bv3^{ zqBmk}D@|~)S32g^m-}>Si3Jqk{#MdwgY$r<%MVE33myS-XnOQ1r{}~2^Vht4*?cGG z3)60zPeU2xGL;n~e9 zRq5pxIqutjIjiH@a_Tt!6S=4Pc=SZmC-N5%FY)z$JG#B^CGPzR-Q~3Pl1o7@xsI=uS7e7=kM+1`JqI%JpcCdafxs3 z+_-Z6%=R^{#*4vQ=r_T84&|Bp(B~@BcQPB>zk1&xM7~nYFnS$HwVh?Hk%wH;*x1m4d7Y-nWBiYx#F4 z=|{j5AjpNYB!vzJ+y&&=af>f6=zgW^U(SC&OpzT^tg_Gx$$IL@!xntc)R)aHI zc8(vs#hvMncE%(|J3mtCoo3>IXe9Yt(S!N2$DhTQsfMn)Rb-CSWgX=^k`lX{F7Q<_ zoJa@W>~56G{W)*w_2=H4?n#?JEXHSg3re30B=XSK9e#UCr?d4wh;#!O1$4d7AuZ7K z&OPh?7ts5__KkDfMKiL2QMANpI9nOJ_DjN|7|TL~U{87MCCs)UNs3{53c^5tlm4Ec zpL=+hp8r2XTH=?z$XU0GH%SXV1ajo&M_+qi@^R1me!J-{pDi;*9VKe0LygzTWx@Bx zrLP^AZ@YGbKn|U++;i|) zqck_4Sl2EgT2sNa$yhg+dKS(uD;W_hy3jahN`+Z))fnsQG5FXcx)I(187`IGlUXzc zivt5Gk_X88RTHD!LL+^(PiMBS$;eaXqz8j~pzD1B>9wG*@m6=@HQ> ztrZ!RC>kG6sbMM>Hb=8;IF}*1n2eUO18iYQUb;LxYrjU?xERZdnruu~XzY344_ywi zR$Sxfe-C-n?POqqWsC)@fTsVfLfS0&6v)y45x*S_f4JwoV@HE84{rT=PyXSRYYo$o z&h~7W@@|H|M|IyKudaUGL7Q7Qw+?OS*i4jpnKM6PdvoSr`E%wKluvfSV{=^Z{FYd! zPNhOb%_KfO=!g_L3-!J-?w-p2ayP|8H^$k}iK&gcGOl*x;;61$7`f|^p*%V(ODg$$w08zL+HTQO~5yh8A8m$+>A# z3Dd4|W-YS>bl*(AlFX2tig1}VJk0aWY&5nd2xvuQ4$o92GiRA7d%RDyf-)nPRy-Am zFf%}|VHu*|n#zoM7}t_dvFZ?gnEZB-uk`uPo(td1JQsDC?7=5Sr=yt4$sY6aTxyMt zkl@Y(SP7P(Jt*WIcD-T`ZhaMs{N6&69#GiLh^j#KPZHJy1OB2B)lL;v%dzA8e*4`~ zlgqjuyH(SUw#Vn_R!npZ#f(0SI}9p=2LbB{DW zp4Lc%Dp9tZ`1LgBjcMWEPqW{cCgEIg2dy$^nDLTWa;d!}#>PxG)i2JIHN>B=Ei;~H z7Jg?x>x%tig{GNEvJ4CL%3%r^yqbx4Y`Zd1>Z8_)STWQYu8HGDG7m2rmtWaDEsmk1 z!!{s<#r=$vOzcDdbk%G7MQS4FPYL%!f=}V@PKBDuLKsfP2ni^dMg`(jL`&2qBg1Cx zr6c=S+x^`B;VP$J*sS=X$@;X(X_P({$H2&h#;)6MyDdkD6(5q0*csTYlMu2!*_ zlX8o~qX{ip<_z*&7<_N42AaomAcM3-h?AfNsfdUp=48+uy?ohTNCD?uy>C{9#ir9*r9kE z?J$#56Gsw9_6L4@KD0E;kK0Ihf#ZQ5PtG8HCHS)OBv@VPkj3-KES`sD@%*dCt1~L> zWISK=dPR(7Su9AsQ&P~_^zx9vmTm5{NmSyufm~<1E40OLchV-|< zPkQ=N0CDzh8|EMW}77E(1%F$I^neBpCU6W^h% zZS!?P8Bv+`q{^3FXQ-xiQ`ZUQ#QUI!K`q@!)Tw&g4T%6*7z_sf`!dgw&LS~%D2R9L zxZS7gQP4}vC*L4_HaHjP{%|Gf+d-~8sIRqr)wXf91kd&(3`nP#t~y2MTu#P z$r?TtnU3MzIv|#{ZXB5i~ z{B+U%^69FZa7gn;4a>TbU<~Sa)55P$V+3CpElQx&X9fPk`qV}BRvJ6{nrJF|C-(Pg zv#h3U5TDOZuzxloZMK_b-;FwN(%8;dgd#r%kI||1;h|=IYAC@( z95u4Obf{B5cxbrZ8G4~5!ODr@b)2z#w&*5tkT8pJOSi9A?#+r&I5?TAr)DR2&&Ibe z7K)dr>?52p(a}z&bAsJc;D(=>TeM! z7mRV<8J!RBat5&x>>E+*HC*U<^Ve9Nt&%AE$(sB+t`En}Y(HlvT0s`IQftD+j-SH? z>G|Zh(kXUkJJ?^OL*aBRCDD7aSaH?gW+y+N&0QvO>Y7=xU9V{r5H74xxUP~%KxI$+`{@Ex3-30XKYRElnBuou&LHWJWdCZ2)y zQ0zEqa~(hN+wqE;tX$ttdJ8xSXukh9(jy00ed>ob-|uYg!ZR4=xmDd}pNyXTS=+dC zZVl1RldGJSg^0<_(Ii~09YMBE5NtV=mhkKeZ)Mbs&K|^`zpI>ng#L{ZpO6(+ytXWY zm=JHvS?R2@W=5wlJEQ7M+lkl(PNg;4OjP38l_<5w@s|X1K;2c4{wkrISaZ}X6H;;B z=IDo!5Q`<5wri#&9{*C4vb-tGkdW-U!v06b*~35>^!OXDMQWK0ZX}$9b_b9-UWVOE@vsqSoiu+#l3)ZML2_kvR6cgPdOZ;M52)QEpZyA`ahp&^q z7+eQ*d6x~cjGqlghg9d^x#4PGKK#6oxX+xo&89M~AJzdOZ&g~l;mUM|G znHlSD>z;yVEVbLJ@;?8eo*~Z-P4MZf@|mtWOgnLU**PD(xU=Uc&z;Z20O4rzM7a<`@;9I|9y;PgT<2>vr-J+P4`la7v@!pBlYkYWUrW`R`41-kr!$ z@#e&o%+Lsf&c8)qzrUzF7jXuv%WRU~;@SSmd{TOp7!T;4C1*X{i>T23THj|%X}y#? zVaR^j^N;kvF18HaABK@8FCsny_r+IGtP~{1hFpu=1LJqkKhVO6eqink#XGp?3;b(0 zxUbI<9{zRiv4Y&=_x_9h$+J91zej%mW64a+F7hDJOS-=(HzQIiYD*NM{}*(IA9SB+ zNsMZ_&OPf1nQ+?f-$%rkkHJM8nUk0?iZO5@XSpuq{`bU?Q|2V`;2aCi;yvB{zW%<9 z>A(0-#DlYrs>aMe@T>685ri<0&cPff9-O1WS(Ft2YdT~1Ds)b&qnU-ApGUdEZa#)@ zURo%dgCYh0-F7~;Bkwx-Wqg^P&q_C12Sgjh z5U8fZoyCnN;Lv@1E#vZ91U<%T)+pw)$}$KZ7_pj-9Z&f5-3#5c-Goz58WaFMepZog z0DX;5nqHpwtxresobuwXB&V_>vC24Wf9$}`!FDP;0hLk=@z)H0}O>E~+) z@6`U{canY>JOy;U4;W?{&0rRgV_@Jf+*e$_rQ>?myRKi~s$<2O;yhCZLSny82nR=P z$7pvUrkyS_6jo!X7ad}~g7bqSOx>PJM_9&i zFb-(CwUa&vd=JQB2kXhX@?!8<KUDO+N9TqRzYl^_CA z?a*~09B?J(&CSLw2h>IL>7H@Zx^8~*`uT)DcZt*FvXdEwisMCsdGTZO-6yf+h?cO! zS;(nj?`SQs&GvM`qD_us*FxA^UvBem)2#GuBp9*Z<)uttn!TblAty;9-C!Bj-W~c9 z>51S#py~4i(!T(|0dfos>~rs{_UWMOCwPQWczmz)*|fg>c-Gware84MPpiG@1>Wbt z_tQ}0SD0NAk%mp!fOzd6XMAwLC`2$qU7MwDf5j34`+l4G&h`c2OBdK?@ld;g-+p(2 zvtxmC)dJ`G1vJiw%qT4OPd3YmKZE_2-oBtaZ#Chqub8Ff(LtU|vA?qZj_iXgiuY3_ z;c?Va>K(;e|9FUZ3JDQ>{p|58Xz%3V*W#$ka9vzjDpv22Iey8Tp7rUuqA}avI!K=k z&H*93^n7p_(B-&_ z^iJ?oAjer>QjR-w^}qC+b)73$(LtKdm*wGcU~MC#XeT3M1G#6B2$M?V)I~MK&65t! zM3v3`(4^UUEbuJIzhQq&2F(1D`1bvshxd;>w7>Jtg7AWT78t|uQIkP74pXi&Q%7d{ z%elgQMav}9Pw(Pe-rPRtos_5PmwtVgj?B`bp7azj18Barf^-*X3jB<6?K3rB5I%t+ z(n>E%#WwMpPl9|Y@61Ki_YXCp})&T?oGz1^)%Q{-#}J7=r%XlSB98+_U#39}j=v^W{w^Y+T(C z6l%Gw7q+xzt;Y3rL#=V^Vm63ktG;My$S^Aus|^0p66Ei!;JtG9n(rFM?Ofm4Eq_1Y zp5VTJGk-7kmA`{G5{xXvo+XF=orXeV7kP}9D#RA$@j}TfzD2TMr{a@&u-?$K`8?skdP3Py{ybo+xqvQZiTSd4+WnNn4uff!(Vt`P^( z-UmtfTYlxY>l=87K0ZC#H16a20ig2{J;pQy`n|d59{E_)?q#E4ps{0#c(KDLwg&G> zkIj~M1nF^L6438iMtTGIGI=E@#w|2G3E-Dk?b%`w8!3 z&ZmcY8KVvc^BCg2VX8)DZ}~g5?0CVa&!gl?%UMki5GR1^Ujv=*Dclp}(nViuezk5j zo3mFK=Pnhsw&|eD^{Kuqc+b4%Z2vff^g7TEbpN=V^qt@_Ajg-5w*Ly zUE#V~rXUs~w&YoD&w_0_KTP0@jCp4 z$XxnGKVSFoPF>%xklq8{06JeElNS63`C@6YvvmUw^V!VJCR?+O_n6dR1Xt*Uii#o( z%0!nDvm4J;ctwz(72~sXdW`h1!OK9mi|7Q)$Oq*>jxTE$?;O!np2Yr2(+@6kNGBW5 zE^b}j-kIHf*8hcXT{^U3eLG8yx>3uY&fmDEbqlm#H?w{7#;n}FTCSFCMjo-#=O|)r zCP0W{U!#my>6XmwK2$cl@BT(53uC`fk*NKQitQ%IGDa%cF@|tu$}3668R+7&ZG3Q+ z<@F-klg+F!Y{tTgXe{Ejt@LmF`r8H_sy#{=#@(bJ29E(vFKZ%t4^RN)_%eF69Qmd6 zT6%oDPcmjFcKRtPY<^JKKP%%RT<9q5_f7j&(>@Q2nb>D45w%Ysn&88AFV; zLU~f`P+kmo{k$Z!qTs&?3jP~p=bi=6qu`gzfbx=G?z1S*Jg-D-K0C=WYQSKi%l&84 zqbD;@1aj;O_GjApqn`7_;1R~dC-+(Ig+CaAkbkxdCnI^t(6Ir=tjn_mrP2ad? zCdLY#bJnk1*FAW-v?krm{Hfkn^A7u;iv1wItGv^hrgv)lC;FIM)a$PCx?RJ@nE5|6 zL-(2KpP1%uvmjsHXj!*d>SoK{ZKZFs!aL#q*s<8@cv+}g;%vK37&?{MbL znJyN`)dhBh%KD{MFd}w3)}C?LVg9gawNpZ1Mz+1fS1p9iv4zrkZZXe^Mk=>k?q?R^ zzhi`7B@p#zR-z3l+dS|I)49(ac$)X^?G|Y#7L}bWSgEn1iXAx!hUM?H|P zf4;@XbXcmmqRSfIbRY`VJkB-XccoVH}>1}8LX>`i~4lYR-)?c^%=;! zG7poD?-?Fvu|~rz5sq#Vw#;_KsB14JB`R)#8B08mJsOH**J@)t9mttb>*(U7&2+r# zx5M;)*>S9q^h7WP=yrHG=?&m(K#ni#f5UV3t?bs^B&6@=4s7^4ai1(`nt{}l-x#K0 zv>SJ@zyNQ3#C9IH-5=Yr`)o7h)h7Xe1EZ$KfXab6lXuC=4Bro?P%i7CBPD-(f^zL9 zzgq9{2hx89p8-8C{DXAf6vm3c?>1N85yV2s$f&Iwj}v9aE*$J15U0=m#OL!?^@%dp zgJAt=6}7t%l=%~^RaBH*VxVE{`JGSiqj+a-zP51h-_2M1rc9PrcG4ZU$lImdd;I4= z%Cq!%_$$(T!0)>~{{zx$YSw>OuMg(RKi)4{v+aWd%(z%@X(uO~>q4*m+{(D}*rPumsvr)|sC zXSVw}C6wsd<^>W;v_is%F1tkS7oOsl4k{r=WXV7zh$+UIs>VIkEb13NEPS~8v(TVx zLPghyoa;gZuMb(*g%X}2N<6z0tSq?5lGD*Nya9fNdbg-lxdk!2HF3r@THhcqp3gw! zswsYHcf1~ye_FQur<2|Wt^m6H50m~acn`>->mm2-KNWq*fj#;Bx^`)q%QtUq+akKQ z^G$SYvJ>61iIo2v;B;ktTh-zuXR3Ik6y0tLxh?R+_$0ZqCNJ>{9?4ps&!x~SzyeBH z&Xhw7PYgd~v9b!vZltn=X_x|25cgyr_xm!thg5!X0=eLl41LT%dU+eLx z3sduqrwqE1TTB|{-xb=~Wslj$qr}OUNM4mhhK-@5?H|fx2bS_sBitjO(Zkz0i(sJm zBnO|}Oyw>&DWELrd^s}m@_+I-vIt>J`=d{f6*IE**hu>8;1rA~n1D zSc}=k1U-X5d1Yk~sjMusN&xB7{Wy9JEO8hqS*3bo}+Gh5+vwEP z0HzUN~`GKEhMOT?1Wmwh|zIx0yz?|krzDE}m}8u*(^keDnzyis{Sgtf_D z4zGyG^n9?Iwa?5C$4S4(L8FiW`?WY|xR{=sqze_rA(pUD?|HMcWpLp65U;0Thq7%M~*u|aHK z!jME9M-?u^`-f$uP(IcJtUr~x2pCa#fJjY#V?LI`-yNtzkEP_ddz#Rl@A>6O&#{c^ zpwg>J*Mh-7mtzWP!Hz!kzPf#MvE|R2w&M(Qxv^}yu{%VtVls?m%2-OaX#?098EUz1 zU+MS#_us&?n}VD7l71XK2XwogG#7m|*aYM_;z7S%#&`8TKY0H2pxw5vT~FZthOQGj zTGzL2JVu)APV2+aZI;?;4Y>{SENdQFIO?;IaZ|X_44+0I>DV{&&He03D{UTNPO;gN zB`lJuZ4Nc(Sr$U2WtZbqKh7$35x4n9P^54jrit)tg}iDd5Iv_7`%+9%T$Kn-i?H>) zq@_OmrYahpwcrmBgo@$gA+L5Cm8?drrCt63Yu?D+vJ=VuUR^cQ_Q_Fq; za0LN+GUAVr0ik^6JvsWym;Y4efjRXU zHtiaiv1^S4f3@&CtpIR@cjRpPD|M`7trf9d8cD2-s2aRGC?3rU;6Z%&Kq2NJEUa zB!Y`fg2x1Dk-KL30%qnX^davjoOQq#FStID6cyf*7CG^ckNtYS2RdnbcAUwcqg+1$ zbbmjQdxE~!88wAk*D}m3T5B}Lj2o;N`o-Y+?E9M;2WFE#2pj=)|J_FVX7Dp0M_+nI zKhx}QnWN{W-?VOAv)J2q4&tx4Lzc!0SrThn1;;BT>UgVhWyXtU}l^Vv5zvrcy- z={vzLpy~T-(r<%LfE>C%=y+M0Z&x?^{uaak5R7xEGZ}gtSbsQv0~;J}8QRe4H}HaK zQ>LnEL#IZKovPxn#Np~N_wdEWtcv@v4Yhw5Qg^cMX#Ox%We-hxvVu%6A_5|fR>cDKdP9uFjxD@De{e<*O;6u>8T)E>>@K|HozbKa< zP=eOe^bICQOPCw&RO=3FJp4%G8xk0d@S}x^57-SNY3F~FLW=hxG9#_ROm*9J=orc< z0Z3(g1L=R8gcA#i{*x|WC{f@O@X3ZmMx2jdMDs+xr}Zv>w9H$Oiw@-998>?QpP z_zdX$*e&RmL0|dlv0g?tI$J%zEfEODAP{sdGEPSoP}4m-{j=HWud`!p3-WUm@6!1> zgY>!J0-*DAIq4g~znh@}v3x)1-d`UIv<;?~(oj^p#)D|A}9@=7dAqx{i{)X&|I$T3&+U zt81OHgN(&P#Yms|;;Ef&coi50GvknkR}o6F-yor-0s`y|^4GE0%8VZulfD_;12kPH zFTsBY+z;e9Dez~GKjYI+^S9u!#^*WqFq<+xBOB6=d!6m=vUs>ly^Nzh>dGJcTFY|L zT6Udp&F()ZK07++BK817gAy_GqGg3iQ$4BNM`UJah96e;Qwk5I==;jrtNK5v`k^?8 zgzS3fEH&U}RbmgY%aX&MHv2ze#-B8!k71`2fwe@P0m4=y1&m#03P+n_r@$#eW@mQA zE>U?7F_3X(xmP*YC?;byn9^m%1ktVucVSZ`*?`A)bP=y#X}h9v5SArB64U2Wkh7MV z{dQsT>-Be}3lF9b0XaSo=4CJcr1yFqn7e;+ zhSg;2HQ395dflO3#8(uT(e>VE#QQ9#;}~6g&DrTW#6a2wQ*yejVtgvORqkv5a`2)Wa z24njcF^4MbKWUX|^&nngIMsOc+wo7I?l(YB-QVvg{UCT4=>Gm3X+d9dnC|Z^o@Tp_ zVGc36h8XuVzC#x5?wFt(YKXjecktfv%d-7=G3hm61JL#T^+V7FfS&?6uKkjDbxZdd z&m}vH>9#`~j+K}hGMt}oF`i#+^Kpu3Ji9)0zOw%j|4_yY5I&7l6AM1L2#Y6&bDXsq zSEu8w;~C!%bWtsYTEoR5JliBXcaisxn8D~t@>sVdzBr%K(cR+c1iO+L0hNw`_!y33 zT4fWgW-sW4vPWBET&e|Qd?z`?8tC1vu=-my)&SnZ&aA{+Ew`$yYJSC*y-t}`=n_iJ zX^Mo1sz7UkhKp7xm9!Grv`NtDNZKMQw71JI zK|YjuvPEcD@&2|z)MPymjWa=7!dAXj<6NpLwrACoe-VZ5Jy;_XA3(NOWg{DPVpfXj z_BC=$MC3PhqHj9(p=0i^AS`k}F|DQk(uZd2dpPL{U_YSS*=wZ#0d@xUd}mIaZQai5 z>a+E_rd8K$$InDhf1!=LRoBNM<8%j|72U_elEWHk4PqyB6hzb^yV^PZ*;IU>Q)@Ov zE1|AM*rX9+e2})&;dojCY3HS>OK*L>FcLe~?qZ!Cdk`v{wlO#~Xs-BYN(+!%@=3r= zGY_K{EJu_x$R13b32G^3S4Z-!B#y+)-K_j@qy+{&lJ`TZ{#gS&qEVQt+$XQ~kjRT{ zr6SgZ{ue%Bori4t_5_(!Y-4*%q34Rjvi>>)9$XId9a=q`R%4DwgbtLhLvhpX z)4qvj?ns;g{M`ssjF!vkUp^$m`C4gO_jfZq^sjw6SjxB8^~*W$@O{g96!-r3=`>AYBKB1D)^jq>ltz9?3oTkdrsIceSlOVIg~i&J=fd zshvt{=Q!bEcQZ6G3>2A1;FFsnZ;W>AFAvC2B8q{Wy;1u7fpmWk!sB}FY!7+VcArOJ z82mBUUjWUgBS%<9F{lD^*w_xj@rz1|(!)cftMnAM#mBS-cA>(Ra69@G2nvAy1I>%A~*bIfcq^+RZ) zZd_2;+S*?4Qt@WhR_ndQKh2nN2O+d7*se!VPUwA&+-rSbpZ&jSHmkkA_0Kw8p<0aU zMn)lJ9gG+dHz%mHs|cUoY^8}~8woW#>9~qT+~#mPsS@$%gh)EAQjvIbES<0NBFW}N zx=H|M2GRY|0gK9+gBp<b-(-bbz1UM-AkTx@Avha>~pGo-BqKvbo>7+ z5-|Jl9a5`gt*OyYqpyow6I|~co)DLFB-TvpSt9!K!v^%gT*yt9#=(Sa2`zgn6+Z`>bL?_RvL9SjGmpo?QLs6H8gxw`8`hLs!*cC-06gW@2E+6J3{HZ zoT9vhgVsCkR1u0i8%Dzmve1AuCi~8f_hnBnh=O+y`?t{|cAmuC1FKUSJ2}RS&B>d9HsVG z`^6`#N%3>}sXD+w=5>ig62>$Tau7@0in<(r!%=5K{7_oRB7Cb_)S~1<47w#Adj;rc7_=E|KXKx*Qp^w(QyapB zghRwFv|@^_rajSkTR^vIYXb^Fll@6A2Frk!pO=%~2()~ed&aJh(ss0Ui1M+zw#r58 zIK>#_1+vO29DUDco>_s~#gjI72k(E8XKQ(~ejUCV;6R}3?T4fVyMY|J@7LGfmwa5Y zsAs)NC{r?+sVRK$x?hr>zmW|x)~}!2K5yklB6DS3%DwN}y5_Ij*xo5y)Up%EwU*c} zMdV``1zpircl5mCK}92vO?Q4*6~~M{1i%a>6DcztB_zAeraDaG_F_ZO&vgD^rAEa^ z+GA3Ub|}S^4v$5mWtxc#%*a4Iko(2@6M$xio&K(!7#17u3@n-C%qyOoniu;D9wkbi ziFxgnh(&l3^hbqpAmi&oYFr`_%FfV7U{x^8Fjkm#D#d);O7MN4>HiSv7r^g<9Gc#_XYWfs_U8Bt!Wfo%@xo`e z9NdE8bz64|*VW5x1Q?zetq#Y4wT)GLT<$U_hsi3Kjxn&U$JJlVkwiqo3 z*56Z%f3VwUsLejwJjPis(|#PB!Ufr-g(3zKHX!p1*@zh{ovQmS3>(Ei6t;;vGO+5T zUV?JZJ37lJZy#|iz}iB?1jR0;*JROuU)r{Djpofrj!92#y`we}vn2D==mazt&WA&G(2 z1Tftnq{YTcE+@N4&L`dWY1BMW4i(@H#xxs*C(T)~b*{!tygr*wT*zM4z=Xs`w7`h1#nYy&0kBm# z^;JxN5#_&pGZ4r!jc9DdRv5LJg-K)PkEw5oaom8aKi^aH7qbo{3jxhwAnP#0Sc8#J zlHMN^d)52nJt`FOn}hSAa`P~*ZVWf#m)Os554)g$wO0d%5!+}P1Hdq#>**@e4}-UW z9FN}Y*V7TfS=ZB!S$;k39^JFwtz2{TW&-tlJjSn*ObcoaZhQMcA)t5rBBu^_sPFj8 zGgtbjma7oQSgdJtj=st^t_>$~WpS{QaiYcPYBThRavoReN?iG(=*1-rQb7pCIfGgu zir)C`(G=SH5~4RsTn!0MP1rSCeac$ezQ1QN2Nh@hf1)X3;`zUgj__Pb?-IMZp+JGzk)3t+4_0+Sj)Jm6W^vye*GNrxL-f#264!B{Y(q`(Mf;lSwD0Z*^smQ=-0Ms z`l|NMu9lgZ8tKLk*RI^WKI`Sy?F$~{ONb?V)j8q!mD;O*WP7I?@3X}FZ1+Bwc%S3E z&oh*FioFkm+@ap2E1sdEXR7!aD%=^(hmRG}NeUVZBL$J-p+)1`V;$=YlLc|UDK6Np z=GQE6=7;_tb8jA4MRorF&pET)x%3sK^c?Dg*%mmkL5uDw4?NMlB-l zs93FAwNkfImrB)ItQ%UlR;{>Hsdb@#Z0lCV)_z3m@_Riqb8?dl(f0HG=Qr@ab7t=3 z&U2o#Kj&GdSL5Y0OT^5hr;|dvot{o4<{f!enm7qL$vT)o*)*jkOXq zD1)_tQ!=zXiJtGZsAa`QniZ{;A>dPkanThhcD(J)er`Irw36^*M2NU(Q7(*V%~k@XRw!ncp@g`Y~#h z^rF&co{T%|<3;z!qn=5|joaf5dhZ96cfZQuL^|`6xN`$;#Mq{amFf{LzN)Zrb&GoG zvXr02yeaF(_D{Nt601-hEnz1&=6lZE*i1t89TcC!r=2bGZuH}~_^}(&h@zg7dfkuS zw;jnoedA}2|CB>dm#)slj&WOYC!)&z*mC#u6!XL0er%O{mP%ddJ8OOCdA!g^1KdAi z{dM9pCwZRJKEPckE$Vs+Pa)f-?0wq%at`H4h3BljKi?mL!hm=U6Ww`n>nJiMN=+j_vBihlgXF-UXp!^8oF3Eh)}~#D5h@sGRX#-bXc}AQPsqymo>4rXLFwo zLD`eJPFizFAYE<=yB_;;qoaE+vjV1sI?c@0fA@-1_W}R&3(lA=)%#}v!_Q#Lr7#C zRv-{yxs`0p#0jm|Kf8BvvS@K7+DcU^+{d$8)$yvWs;0i$t?{aJ-7~dE)i~8f4bf;J zlZU=X4DkB*=I-V8p!mR8Q_zMQW5c6IhV?7(p? z(MUqKwu&DXZowcbJ!~qx9sX&`meT5f)zHRJKqSdT8&+_ z8DxUHSW3^&cV@w@6N&AEAm$|>A5Ce?pEd&IS;_Z=kaeW}y3E4!IB0u6^PvwNG-d%sy$A z+b7!~d+@rC1hwOwBIqXjyiSHy_7OSu_Txt&(P*%&F$2PO(C_5@dUh1)$zUOfT8Dcr zX~DBVj>7tHu1!0bu)K3SSh%QV($dxw!-*Et-lm7e2~LtaJZ4eqyDCD@4(WR9_9RX! zSkw6#^{kiL>Z#|v)C-<^-b-!s%J@dT?xnVS>P;{8mZ$#grQY!vc?Jdxed%!PkmSVL z5vmjAujM=Gl!?R+7hsTL@vpp;+Y_OWN~B{d`tR)mKc`FQFItA#%R;6ptafSQV{TKZt;WFseC=&et);1wT9$2xTkj;% z9!Mp-Q|!9DvgE~N>ZPRXrxK}uySa7D924~@=`?1rfn>nUZ@J2zfmkod6kf89+9DHt zQP7E2{_PLYhl_VwQD&3}aJbP5e`-(Udf9qq3Q z>ebfhecSkLvrc}G^gqGBfvJxbr`y(EU^@6u>f_~q4d>;iTsl-mr+E}o{{@uFvg68+ zueHu0=$A}8@v?~mU{zH-k$Ev){&G5{i)1Y*iY-zW(zHakxL=T_?sfW-xkoV))(&4T zLu0(wT0J=A=Vs`x3n;g&-;(|e*sJpSJAm{;a3+vrYvjjn7d`Q4U2*)ba;9TXUdZZP zBc41`Zfe zR@Lc#@kHFOxijPZI^*)KcaVE{iLOs1nbY=-XX~@^?66>+HeW1tBOXcHTnXmEw~@lH z;LE5z4&)qs3E%kgJXF^dWQ51OrjTzt;D@R2W#6-{8qg1zdNGo;U_6kcuw9z#@K@pM zj?VRB#gb!0t)6PyzWO4~$_hawylkF1O;*0;K|h}UZhz~79MQkePNdFDsB;tP3lca+ zkbI4lNYLfd>!MHJpOV|~nwlT_&AMl;-?n7Pr8YjwQOVWpPlV z70o}DJ-J;R=$S`L z^BRg^souJ#IHP-N`^J=eONz=GG%JyF4rQueAH0l@9TA=WnfdWzFzHEPIxuuzPWpDR z1;}CODm({Y@^NsX{xZ^L44XPuA;!y=*?|ubkwQNqhEB^t1rT3=4M?Q#RcrP4Q@Z+$ z?^)*|f$Zkzygrq7+(WRLtFSB6IZS&5LNkj;*$ z8ko$t!M9lJDOpi32pVEg0Xy9b7NcwNbgQfF??oBfFf6QxO>6Sw&Pvi}f^&f3)6JwG z1%Cu`42tB8UCr|rmKC%^7_w~fq6PUq&~RC2ZZB@>;Ji;3jwhOL7R(Q};E$&@o`vokmI$;K6zai`tPM1 zI`ieYrL8A-=F6gG&8;W5ES+{N{+p;kThy;Y(}oXX4~vDvr&u@$7j95HBw<{ol*VehFN#uJWL z{x>z^ZKYpVsW+7SO7P$xwYw^|!t)*cJfQ7;b|4Jido5z(+yuMA9_XH__x(!gPgTm3 z-+frSZ2MiI(7aCB_{eoGp^E!@_z$#wwX&~K_;H!apLv81I?%mHk65Sm**bNO_P-9^ z_6zN1(dnM(PT+I4dl*{abKT_NYgNsiY{-@(lBzOTr)u*yhf5HM-6N7^*&vX1HyX&M z!9405;aQdXTt0Tn$LZYuLkG3m@NcPx4G64yB6J!}x{34d{+8PP2eK;efNxNGnmW#j z+m9_bB*k79K;7dN1 z7xtU74HU)=JkQuqn;&Zi(pK1|4Qy@Xzxs>piaj4$L~_GtvS>SK-;r|AP@{aqDqItX0+4Yt&QG z_Qxr>C7Kc(+oSi*J2(Hni%4G!?f`~A|0dn@JlmQGa|$H z#0heOe*-U##9M!0JMY@|zm@%!sNJ}^3b$v86F*nm7tlP#y>{Hsmbf_y5U7)ZuN1c` znUpC@IMovemCL{(Kmxvqn8_fL$IhZMFQa1b?vY>+!XE_+l_;T)MB@ZP(JvSs*1OH{ z%ar5qNxusI7Z|?od%kVW0ZV}#X8bAiYZZLS$L6m1dMta+FtGVd8dUQ#29{OzGvYJV zj4?A)Gu)YJ7FArU(p4&RSS9p!@omFF9at8 zIVMN*v99>Hy>MP8^>V>{-1A^-zbJ@|FzJ2Av5GwU>DzlaSp$1HIEDPxgGjV zK0ha&xDfkRVDdSZ^c-*k_)qfr$v5OPvV_I;*1wZRPt+m-#+=fjC2?iL^bYu-{oVmE8VN zS+6?1*zqENvSIbSZNFf<1ejvet0b#?3lH25Q7t6+i)2UkcY5X}ZdFk(Wml!A$l0cn zQGT1FZ91$?z8%PzQ7&B)B`Mc+D}uA%3G%)&n@>jJl)*-09ku5`E5-VT9Z zIc#?KbvBX4OsQ6OvP<1b^|Pv;bL0atR20c$5xdjdZc6NJ*rBoh&12c zH?!Uhg;3Iae;@P)vKKH6>;>pvf{nN_oTXsGj++j}tXC-!OvT*b@9DwY|DLHy@b}C` zWFxQO@1+~UWf(Ija(AinGHx$eFkXt6&`fa4+H^ozu2)fBrrq93`cd##VA^flCD=NG z)cVflntFKm<+^Ei7Poxi(!GoA5 zl9m#d(r=d=*Q=k);86ymAETVZAES^Z_I1IJQRGAwN*4T>6!}Ie@)_*YYi6WuYU0tq zcd$3S$nP7g!ae7KkT_GCwN-aeRQ{A}zu*pXF4C`p&w(lbqb{|rAA%==9Gf?X<$mNn zyD$Gi=#|TJX8soHwY0Sc{uSCyMjG4QE#U8R@c8AYji6uKq<$QRC4FDrDfQyW>F%K= zv+X%kI9HC!?e8sc77m#19GY9;F5H2I6&eVBU}l$273Ftp*iQtAkWuJJ zCKA#WP2pULavF=R*Z?MFIsS~yTFr-qGj}hV9IOn%aHwm`+yv)o)61u z&S#y=YkQ=Jl)`R6p6gs*$D%Tpmke|&Lvb}{|5;yRtM&Fj?ch`qeBPrjVX3}qtuwv; z&|4g9Tf7mKuNWP0uDr#|rkG_kFkahCc@v+gOmPh9wOB|J1Vb|s9#c6wUE?^#r8I*6 z_5ds<2ik*}T|G=6&a6x8U+efaCH2piq|q#Q&)5DI?e=$*egoF?y@PuL{JXWkS))j{ zXWvvp`R8i?E0rE5A>Iz2k~k34`;yA0UixGm*p-KNIn5N__bA*SGx4^^f}_D{K$ecO zyOTGX*-a@os%8o^{CkQ?{O2A`<2;R7#%NT`N^^;9H^Rx4f_VEm%e9xK#MfvHoE}yV zl3lOf?MAkyf$`ui7D*eXhvhxu@_he%5b3F4IxywEh_qlSkmK9pfvhURk1tQd2dW;b%xFST_~l5zi2p?D`U zD0P-C6eqvX>g+J}l~(75snxbRKTNH$)rDbdt*tI1h0|i~UTouHG_OXwcaUGnb7!z+ zV20-|ACVnP*&44#8K4`xx!u?!?Z$3yH+FNoB~_+xdT^A{rWs*5*Ikk4-*sZkqdvY%O8qoD_TB2|WC|dz45?hbwXE zK%~QvUgZGLGn~YYrIQG5(?=XY9}#%)&CLqSz4EGjxsN724a@+h+;1TLCy=>1ykq3{ zW}R*F8?n#2yts3_ScYACfg9Eo~!k?GQsdT#fwcHi{Wc5lX;EQ(iM?OC6shA;yb z>-;p%RT_$WvWiGn=NigN>-=GUuS9nOr6KlIH`^)ZY}qSVW0erFjedeH$JwcBotstO zlWUw)A1DQczSpAp?-2D3e*{yBP8B#S z?@l^$Onx_x(RCvd0K<=_IU%2qhkvGjlDIr4bA1{x^~uELG5jn%8}2P7Uco|yQN64S zSajKnAw782yy!jeMCBwmKO>#E1|R#tl;@|UZ@iW`7C#Q}Y`r0@zdOf-ABv!!@0y$>%HsBE|H=ee~^9fJ*v;p-Z%Qpn(nX0CL2WxgGs~U0o`-qdc$Jwa#GF??$HLF5}hUjd5$2`C5IctmkMM!6RJN{G@LPZBuBn{OdC@0PmX0?reQD(=5 zkyOp~x1CMIRr6dJaWxU&o4MGD%*FO&F4l+l$jmz#oD*)3Z_JNq^_V=+H${JILdhE4 z)i5+{B3PTt^LgHMD5q%NSB~7G6vU%*s^Dzyf7{voop~-r{zMjsD$G44BPN5w5cp^%l5Or-8W7g==YD@(X#WRDJ(e!dnhj>%3RCI73 z5ihg|4VV9Mz4uryHP#mQ^HTl%v{&|I%>G@>XHiIWm|}LM(T_nFEt^Op{7vFXz~ z{1BdeN?L8OEf<(^=K#`6!M11|Nc}Dx56n1V#vKu%%n(`c4EAYd2E3j1*PBGLT6Gr= zJc@b+uAOacj*%P@A~o&wldV9u-7-}r?9Nx|1fj7t>n$HO{XTK=jg0!XuFathvVZ#w zW)RHi4~S$E?3{@Kj!a$Z!9n?X?;!HupB5WD#*8L-jMi39ZR9bjP1}zT^S_h4HB06> zQa{1Z4j2VYy>V{9W(GWUV|eGLKZW_9^IB&WOFigzVdT+50>EN z=-uq)Bufyr_^Hx_deTYVmiD(5r=}5%BJg9T$JrB|NvR5gXfj5s&q|yxN-A@c_UXs2 zE56i`J*sov@Q*5cd;Q}*-2Mm`e-gKEihGHy?|3C{tQ-K{bbq2SD%`9t(~N!F87+rND*Gm>T6}8Eh1ua^_A;r;2Bw1V0TC!kEe}Vne9zT+Gzoh_nWl+0kv!k|d-=Ptr;}&?+usz8yN7rl{p`J9nqH#&bOhnEs?Y_XMW@C_J0~6kZs+1uxnZ zy=N1@*%ZBdJLxZhx;fu&Pa%CNxCzK{Q?w3S9-Ym5>-G%wpi%|?hZnT6E?d5AIlX=d zXF=ihg!#+o8x2?8V}rg+U$4~${Ua5e&Imr|U5}>Gl2=@-snM?@D0>2lr(YS*^z-@- zOb*rx_hj_QOg3p%Y`EGsRxYkzhpT7|KiH_R6n9*)Vnnpq1*$&ha4W58`)n_(_yyuc z0+oqmbvEwfX3n-t+~RC+cL+U!@~gUu&OzAbPNUXtm8SL>niHW|pi!MhZQLsH;vdtY zaPM+Qcc-(}>T?xcHzejqAOr;+q1usGTmEL`_(XbSmj%C#e3 zhhWm*HoeuimMq3&l%AY7L6&Ug4Rj3^x@HPpt=6hqJm8_$76$bZy87hls?XEa7ST20r|cs}bWJ5aORj;T zYaZ!Vusy1Wh5Xw74Rq}#bj=pJmRjOncWP(C`sWF2XeVq(MAuf{d3*s~f87mTPNaua zNS770liii$Fbh4GkQ%FPWmrCAHs;&s;iMOV6M^BwMWi=?ckT+uQKRo*+U14=I@g;( z=joVJm$xi$4I3d-jOI4B;>Ur^w4}A?Y|(U_s5iJYC50p--o2=pt(io1HoxmN zhhagSe~$^}A9F;ttR~Q$|x90)az90)tDM!5$EpJ0+y= zD&B4Szq?3341NO)eSaqX3AjAsuT`M;Yv_xJYi;K*M6OozMMq>VDk4i>!-QNDPXrBi z+-0Lo(^F^JW|sA942K_ZER-#+;D&50MKYxokXr^%16h((yB!hT&9~<1{x0d$z!|{M z{Q&8gz*Ujn%YQ^SnGxNL4eH_0u6SSZ_`2jrSeod1{PWtXhOv%-Cn}Yw#FE&{bjNuC zCV_T2nSn$P3rW7!eoeNLWrdsY(_%v!Wo;bUx=H%bDPVY5B;h?WIfYE_Nx7^)Ei9L& z+w%FFLi%v<9boczIq5sVO;P@~M&)DbeS5ix?xW-@U*8F#^J_Z@p;IIwbe8-JYdgEK zH02cQ2E={ED0&?1^v+J*I2(Q%wOg0dAa8R())r@Aj+R}Ea_9h!YmUH5+a1?YZqr zMeCRkJZT|6(bh|Le_ftQIF%V9+nzWP~qKs0)-? z=aUbyt3Lv6ZTVhE|2Akd?dCnwAA^4ZLq7{ks}!8l#keuApkHcl-}KGR$4ftSj(%>){GGRN=XD5lO79t}j?xd^E3Cd#l=+to$EeZGoqnD%OXr8LN9Fca=fHS;!cB@5S@;aYTGSTlohcQ$j&+5*1y zQy49BY&tXK+f(qv=*Rq#^he;I!1PP$O{{%Eb2Oe6>UWub>A3vxyFp!~t`}$9MZu>Z zbh^J))=o#Xt(nA1Y$>L*wYqz(*z@z_uLz<!}*5E58FKwAfRI25_Hn0gW{uU!~as& zkKKA*kD^A8${10W*;4CPTajRgjM#Z7oR*;Q*Ir(ykdH&dd`R*Tp?@*{CMxkPS;|np zH}742R+yjWU*zlWQKaXC7GTQZI?{q~+ovK_{31)=qM1l&Ya6j=GEUVXua`Z<-jh9R z-129AB6K5b$tJV0YZNjH|Y)E$h2>SW=~rnMn`J9&3bZg9jA z-Bf{EVEV^lq(=cGKP!w!X$|e%zsr8wk`hJ-^p*y3tnhhz3;(Z42%JWpC6GP@=Mz~3CL0RRoH&k;xAIJ z&3hy*$MHitk30PaOcGsc66T;9DJ}YwhmKK8X2_^Ou-gmh017 z_d;>SC-SeK^#=Gz8iPn|?4J7M-`92VRnz?DC1t*|zjjJ}>8Wg6C6d#Ir4JXc3)Q-J zDU0YAV)k>0$DCYc)=liKD^Y3EwQ0PFdpt2*4`tguhlh)5J*}h?L0V$ZMBfw@#R~U* zg6X1YhR{x^^aH?pnT1^>lBA=M z91TN)bS-Y$vV)k;o~e-6oW$KH6#}BSjr z`iKwY(HtL;{z9&Q)y@Zd9O;F?tb?1P`Ig~>89z>JUASU#%d*fi0Tr=L&YenaQca>E z*09F4wxJnVuUUdJ91f$h9iR`uYTVA0(;Q=IJF&E`f>~@zHze?}wx8XULJN-#;=!_a zi^OeDhz=K6A`1;B1~QXcBeex9%d9;t9CyNR$^SU8Mk+(_ZBv+OGP?S*FyC9rlR4fc zy#xFcn11VP(#4ze`R-~S5axR!k}y1S;MAPyZ_|E_zSVG;^->J+0~xN)izj5YE$&Vj zIz^^a41Gmn1V~ zGe4-27gI4QmS3c;w_}YywGHj^41q=~W%OaL?l@)Ml^V05lL+uT1ZqcTeZLZWez%+0 z;ChKcbSB@?^%x{|Q+*sPz}T;09b6SB3Z#hMl%KsB)jXN8UQc$9_C8A`ymkuIo zNoU(V*@WL^16#aNJo`hb-*~wUqN8_|L(3n@wV)b&H%j~bxco>S@?5*j?;lbpj;1Yy zJDCZBU_`op%u548Xf&bDUm`BoViY)vM)X5zL;)c*qEb-aE;kNk&$4Y;4Za)6k9}mv z{89(VbAb$*^4@SwSP$ENou6l{A^l@;1Bhy;`xa^Me%tB;2Rsz%BSCbZeoBu+YU*`KF zL~O&YhT#Mr=tkKQIK@)KLk?_;-un)}Y54jX>GXrPRR#=SXOKP)oDAeBw3{yE>xg$c z^Ht~(_QATQj})$3iojqnwUO#}MAAt;qOH&2VF}xMSsnBIf5n}D#FH3LrqDI*hP$U4 z&o5@CmT9nyOKSHkp6O@t-W;onp{!bz$vb=&P9xP9L3tqUXus|*o&FK%=JF=1ndy|| zV>|gV@=X6B{LFy~z~uW6q(?uD?hlY-ail*#D6&s2%=a?|dOvLoaI;Eu9#g-f>+xdw zb5IMzLys-`GURh=i(YL9r_0fu<*G6G>>GTZ$pdid5<8j3M}A|f1f8v?W7e8vqt2EV zX;oWR=dtPJ;c>G>S3j(hzf)eWFOxbSB?#>tMu}%fC#QOW2L<(IynWWYE}mTCe;U`H z)$AXh!ZmjGIgVb2(ARBAdb_?D85uPF3P9k zy7zhIrSa$7sFS#l(`cqkMYuVvKXqI3^TzR{r-E6))SqRf*MN(F91|irLgD&wL$p3z zIK1;ZLE6lcj(yRB_B$-jk7i-s<7leJK2ru9xWDxnI+5-lwf&67qWBWGH@dNIX{-Vt zkJ99$36pI8&kdVK4a}G+t)dTMmvQst4Im(K1@kL<{D4}$e&7KKDR{q+|Wfn#mSTOy{#Rh(Y9x~G&J($&C}ci}i|`aP+&l27KttJPuO zXF`0EwVwIYA^FL0PbeH1PK0|xSD#?7ZbL*z8}BgkuC=5u2Uh_@#~q|!15RY;vgucy z=R+OoSk{JjlI8OQjxPv!yd8$aoOeI zx91jrHSOCvL0YzRtlVuOy_JvW>%|z-hk%*Dw2SYOJ{7D5a(vOnK6qH$m`@b=GizHA ztW^rePPvBwYN-V9TCIAC1p3JDGygg`>8GYzFH78G_Inbs*e}!mz1ZrH%NvT$BR3Uc z;mo68iX}4>S&w0Kr4GjaJ<8V(=r!{J_X*Z~pbD6LHIg0$4g~*6z9w{?FKO~oCgzz; z9BRF7GEo*~qGnP)6ASa1SXh{e=765I+r#qN41IOM9qhwMZv*cGlaJ~rZEH9<1jw;A z+AkT=gE!P z;cLY6)Vpct!*t2t)9zo>xOWcDOf(2Y*Ixf7GK-M0$_)MGVc`Y0$$K!6``H-FXUm#~ z1vlZ_#9fe*MMja;d`HNKjpQ%njAi|j^b_EBz_csxDckA>Rz>}GSN#{FPuZuQ_lnqP zUm_n>GV9(*+exxgPW}rcOJ1`HK<_Q zgyqP0EbmKG6WiW7VIJR?MX6lRkj#b0ond}Xf!4a{)`g@m2Uh}k2E;=8u}vXAw?m(4?>k6; z3cdy=ADQ1_!vU&*9A>^>csBVM`Oh#P*henFEP8NshRI`&7_G>|;Nx<~_q5LFuiZ!8 z+`}$4R?0Y|L}t<5!G?Pkf1u-(-P6&GSCB12 z$Z9wDr4tpBaAbW%N98klItG#+0`>)lACpK64gqo$))#Xfe91>?0Uhj1&j_oKRGsNT z)#*>wskL5K{XcMW??O~iZ}t&Sc>Sp}wZTvAi0IqQdvno`zd-tr;LpI&_de-Qz?VP{ zvu{<{|Bcxvlxx59LFe|_wmgU~a`gP=%aMfow|tLm%fQ!2}UD2*~=E4)`B0z z@?Sf-UkRZc>mz!0?uMS4-*-(!C?1r%+M z=sAyf*98<>mf_F!-$2jEF7z}kqX+T#-IwPA1_nsDNtgfF$^9r|3h!;YJ1nQ%b9s4m zchbGV9>A2-KBNU>fE=ct7oLMJ`Pf!KN8ra+s{HVvE@gr$f0xdzcXAh*D&JkId?u{& zZ4q4?d7qJ!KS=s9@C-0?Z6hss6Ub3WkGT%M7|2&Zg+r>!kk%c66Y_dfv9Opc|0G=3gjzh?nyHk*OyWxo6)0 z-?sNHf9qUdTTWTD+}dhq{-JXpA@rr$gvTb6|J}U*$^VDx3D65!_K^| zbAQfLu*2m454+aW1Gs1MU&#M&tEZC--hcAaMavPIePEZrtaC4F!+vYbucGqjU6m0} zO!+@v@c#c~{xfexIRAN|pucEs!_nsFcKK5}_qe=$ee~X@m-FR5j`YD`CNTLvjkMrw zAcv`Eh3ANLtEu3q`WYol%VvjU51P%Q;8jhVL%!{RF4J!GEBJ~6MZnPCgS4O@kfV@pa~*ui z$6kfy#-d1q&js`!ceJdC`a=9Lynpr3{yLpIpSsjjh?K<}iN27Cp3{bizV*D4&sC9|;gp>I~(d~PCr8@Ri}`+r0Fci?#-M_2P?EAkgSbJzFJ zUmVVkWtuZ5nC3K5LbcXg*e7;N_%Es4b0JeQY{JV-OpTFYvWbGi|9V8{h(G4rfhngc z-0O-@rrs2ugG})8LBV_{m?sLSh}xHVOywSl%4tjV{>{9ru%7(x8{YqI^~5RUQ_J#2 zQjeEf>)gz}DtCAEe(Tp^IgNNVzdkhm&jH*s`Ir8$WB+63S%vGbEm1i&?daV9idhLOPCrV^=!XaIY(VbVbMZh>nB5iH?)!GkIL+l@HGiHFRu^=-9zK>k8UO z^_yMO(UqKGOGL+rZ=ypw(1k+G(Mwwv&tJZ1Wy{e^+N^85@_xDA5n*)?hWt4X8Vc*} zP2WIQSM_B>L|4N%(M3cG38J&nEAN)82nlJ6=-A0SjhrF19bc)S0vP#wJ!wHWOzCpbkT0q>+ zNwPm`dh*Z@wYAQv$HidQQPs@HFDgHeJPey+1z`}gUrlf6m1&ug~(wz}CTXeX14GGS`=iwHT^^;r z%cFgyOC3)gLfZvzF+=PMZ!q@rkPs7pK;;B%JD7cIEMb$Snf=p!a)YxqDZVXApxUd6 zoz@gqjHbuJdQth;e7%@JdOA1^n0j#w=|{noU zO*YLw9`OTJ=3-4P*{*_Wvfi<_AVD4K#jt#J^&n@Mu80v~8DF|;ZJe0RXU1tZYvZ{~ z<9#%%>vQ7n`Ej?0T^d7&7x&CL9E`&dUnT8yvP!gmP2ch&Iuhy_xG1Wt#{;}BN?4xG z_hF+aT*l#7Hzo4#V`!Yqq706CBIH~1-}3$GLeeLJmB8@rA<{2{_kbMV#<#XE`PL-- z37XX9A%AW_GZ_Bt5%H(Y@W)dx;RY}MB2g$4FZ;RI{Q=v2_Z2K;Y@dB_{7m3&QT!cB zjOA<<%IxiY`GxT1Sok5%TGAm;^7r5e&IT3kRS8j$&cqJkv;=F z2@F5Byo*lLd#s~?93vkK`A`gw_zH~y89zCdrj%60;Vcmckhkv;$ zxlFmmWySsodV-;9FWmU=QQ@OffPqKWDMr(&T=zKKosB=co{r~~XK}7wf;W52gt}un zJ1gpSM%gtfovgLT;-3egU7m91yA!C*hd8?QZ`yqich3xcy4q7!#E+AnsuWi|CDOMi z0FHruJC*=$8cN2i2~aY=!c&ulk_sm~!)=OZ_@-Lb@J%%|b`QTv4@5VJI4F;4_e_-> z=ZU5pz_RnCajO! zsApz=`vK`MfOvZ|=k`Z%)DA1dBlr7|4?D?YU34$`0rPxN z15CSILi%d(0FYzt9btRyO26fk0y%*gHwImKz@9s7tO(YqYi$};U+Y6yQ{)xx>yEbj zRd}&Ismlv*$;_>~W0;8<%42P>E3udQ<)~VM9`y@JNVw)(;kw;^GGV5D9`k;dsf!lJ@FM=<0mp2Z=AUK%BHxUE&Hyr*nFCIt07@tvsiHEA;n!7+^N^qx6WJr|F@is(P-f7$XL6pyIrvkeZ|_UT zArU`oW`hfW9P6U_ccCAM;7dN9`Y^0_hW_X*aXRMx zNY-H)aHS;f(7}rANry@`%DRT&xe1mb(rFbP>CDCl9iC20in4RuBiv-}yYaEo8iS6E z=SpI!QHkT?Gvn0~uEpKY8H2Ops6*?a-C2pl+*$5aT|;}lE|$6g4=b6LD%;O1;fkNC zo?rr)BAlY79?Ds|IH@Q-qSh+~l)7tBwd#4NsjzkS2Y zQU3=Y4Zl+#hx4==&W7JJNv{UC0689bJmlxPXns<-?pe1hzo#t;dq7yeLERa8sF^P7 zznfC^geJr`6irG8JxUvkvk|(7r>NpIZQ$WmCkIawC>q=f}ltsXB8a3FXN&h*AVl9+zvaLOs`p=*C zoH{7TCHpDcLjF|#Bj4W*B|RP-0t|op|C9a?Tn*&-B5FU2BR$(f{wyx^|13dc(BW=b zo^MbX2>dD*=&O$wUG6pN3hC(n7vV~}J~7ZK#YoCM%st8VnY46wN4Y0ePj;Qy0gSHM zqLqYEn(Y>`_{U2F0XLF~n&?^IJ;rt1MXs{x3j_1o$%$F^h#DPpDwVyrKMpsC`?=xM z-Q;(ZE0QC1O=3o3Tw>2`h25W+8gsd#!sB9XW> zo?0Du{p{X$Gu|&+?KZqI&>S!X63^7*m;pGs->TSZ6;pni9yA-zTXn5d6r7A-p;|hn z8QA(B!=3I?8>pdEmHCv6WD~;9a-CurYoU0r6NB;Lj9-Bb@G)F;j|Q}ke-+q+Tp|7B z4+#cmC$MncCo1>0*P?boc^bJ$_7n6%L3d#K%ax>m0M_0cwujpbk60(U@7IZnmwjGWCg^9yr7vZVz*ZyT=jeFBM~oL`T`3dj~NRW!%y-BA+-c zx-s(aKrJx&A4_^J_%{9HWs8nozM?G{D#$!$;b(Xu|bLFA24&Qn66pCxPh1lec|v(f3^ z02%w(oqRK-e>1ch`hQRQPhdMR^f&!4;|Taq=wH}+@{;x(+^EUHc`C@lv$pl~T)iV% zV3>2TGt+%AmX&1=c4`UN8!lN&6G;)5^>)%NCROdG?3~@pEekR_#wVa0X47Ikoed%u z=Cj*}EaR+8)kWtM$^B4rKP#X6t{!O)nIR1MbI6aU$g4R%JxyDGnkWTUEgH zSA}O&pO2Xzj{6kgDC?Y}T9&*bzO}|g@6nIs{dF{biVYRm7nt{qCM_uZeRHjyx_ZRO zBl=i<=UAcy(g!gKH?9}9bg>u71G zgO{|P+-|^ma-_f@eyygUtn`rTezxjyj_POC)oPU~kHzhJaaAIY5wj2}{!s^rco|_+ zaM4=?%-v-qvoUDe9?^gN&ir_?iu8rxGGOTc73mkiyFiY&Zw>pGuGSmtx^6YX@;U~4C9d8RD5#upD1MAEWL#5m?GBp>nB1lKFg z_r|h{6@eT+AC)+ftqQANr`vQRrBdB)#^{W^Mu9W7z7^KHIiKb8dmZVG;C5j0`vU2A z!A>B@x5O0=m$)a_=KjG23(kg+nwpbE^?>a<5nDt)^`*Svgr(%Qzp#07x#%V ziRg{Y3n@eHX~$=YNN>!#+>e#vhB=q2>JX|;ObmxI;YgV|ZM_mx!=c!krey6j6A^_> zDlo)WT(1A0kRQ#T=k41TkX{B(2Bv*nP5N%o@Ak0V3+3#cvNAE)gO-JM$xMvQ zmVBV-eglF+4NI^8UIc#;3A|6pp)PD=!QW5@7s-sK7ij+*ksM)OSS;XyBUuav8;ScO#2ikvrX+qY2=G8; z+pBFqBSvK$O@9l^Z!6^ziMXx5kp2Yh1g8Eqe2IMz*c|yUEL>L^o(F|7LzL?eoB+R9 zGm{c4y>rD++{%aW)5M~jO$RJ^VhQ0b+G*lH!Wm91?&0Ks#VZ1Lw>;j%RK>vMm59~E z{E|hK2%g3H)oAj*55Sci`DlA5%*Q5ZG~>Y2q+bSq0j3_hU*Rth^Z;_0IO<*XqZ11B zZi4)cU2xKhMN3<#bA&aL?sOWx#YpKb>U*T?RF72MpdN1BIP2DU{m-Nh-Ky2kn5TKS z($eZ~)9xmE*M51wZ?eU)N0_n0$XGwgP<~>vj2E2?oEmUGo>V`Y2(WT4{P{i%E-DEIU4^g*OG!eXk5^;p?{bdum~fjYQ1i&y3k?V-!z}E}jnk z2Aw-MX0MAezrLEfsjrFIC{0RFpf;H8Tj1AXbsa;&p$Sxx1J9QQ> zRJJRv{;w+iwCdL0ovN#3wk?ZzS-AIuKc$?-+tskVeDW$;k4^x)c}8R=-(eF%>0T;_ zL^F$mr;hhb6=7kSN}j89RyDAF)nKiDKddJk;G0>e+)w&3@DwoZ`LCn}-!{+f*oWrr z1&^n`S6eI3!yRBU18-oS*h(|#CFunn{z=rOKo{$@p!lrZ2O(X}%4xUbzL4}C;1|G@ z``<}dYR4K4_WPG`{4o7bL~qao&76PC;+Fn{+g9u{Bm`eGSV%ub z{Rr1ycx>#22fhs|9ejq~8#5x1SjnXEa|AybZ-BEuj&sK){6L6DR%Zf#L6$qy@Ge^0zB{a>L(M-_Bog?Sc+V z)9F--B0x8Iow6QCWxSZ3b&A-lXVI^-Gm?ktM3GnAf@}PYxba)}g2TO%eTb zpv&~%t4N;(&H<+0UQGHr(3RfNH`D_{Fa_n#%ze!G(Z03vJJuV7H{3U`3Q|uYRD~T^ zJq#~prk?vK(?1JR$hsxUyUaT1|?hEewAILs%J=<^KrZ-!GQu_gK;g zgBif^`vlTwfQx_}-!`5v-rc;!(1mM7sTq^m&Ted_<{vrHowS$rcD9y1VS0M4&I|u25(b8%k{bb}5{gJTU2GjWVTj5$#2wnY2Narcg zV2+DO{}|i?4F4Y|{U*RmSn!ykukdVsWA$$N-x~EY6hvGViHEf=a7|I)G_iGn2nuIE)wErCwUr0W8J%S&q8@ z4f8oUkuQ%UNgoGJ0H)o3kMw#_m@ji(P#(?mmolL#nKzz|s{!m=t-O#me@sO zdKQI2ZJ!g=_Rn#T9q^i{PI@W~o}SliMBxbTP7f9pLA5zP2!b`8=|#fY^l8Y)xBeYb z1aH?v&z0aBVCcMw^xeSlt?&%bh9Av9Gu^rv;bpIm0}bZJW;sJL8fbDm!}t2Be81O& zbbqi1Fz+2rdKxHvpSdn5KWzRdie;aMLBE7Sj3}>QBSpNlvPz~SY>Lg3m}q80pUn^> zn^BUECWG)`M?~Ki-d#8jZsVS5NB`|OxOjKt-~p}B9n4Iu2a4+NPcYhTNvMYtjCNZR zjCL2LQ|r^gX!juB1*6?9GA-uV@>$5o=5)TjA4hr#I0+a&o=*A#VE9&e?!?E*E%V!g z*^-PBhspfmBO@45lFm~y2;skRNo|tf7 zxLyBVy{T3E>F_t{=r*G8d6u%*svI7#PK_&MiR;x$>)1xL04mte&9Fk0U2@S|N!2Cv z0G->DSTnlh1K)lZKRSu6PU>05|03pn8Y|ry^Zpg{^w|FH02k5gldiKAWAbiebT^R^ zg)RqgA!L*|@>U{lKNU2v5$JI(+d{I|?xYUgsBYm)hJK!BQFST&y#tuJKYg=uayB`$9x%j!I>3a8i#^;Ud^y%e?W~Y0HzQtA=h4z*koL=V2U#p%D zPd_aRu71dO+;`Sb7()+VOwL*H<$C)5z#Gtu`fx*G4Xe(GlB-J&E^hF6z* zNZSwM%N@s*vTd(&o3#I~b|#?qpi_SJ4Ke%rm{-bHr9b*D;>?EI5Cpuf_MdY~jP zF4p!%I-cQ+tb3K~PWNZKUn;-5`*)QcS^9>Zd)>~Rm&%=;DqfiLQs`x**4nv`nPunh zaVqX~N;f(B4#(@BV~i=&B?Ij#-rsfdbM0NA{j=Qod$z}1isdS5hi__oyM!JpPi)e- zvGlG%Db}8?=j@THobUfkxrYz9MftaR{#w^h<~A$uEQEW?KfotLztZkpcMtaMboLj@ zzDs%gx_j35;WvM*($^_uvg0zp)&5)PHTX%8^EPY$Z^~W(!}cDgr|G%gL3Hyv*FW2v z4L+af7`?>Pa;#Ubmp(z);D&NDJ-tqy?fB<7L@RJ}dNi>~#KSjBy$&EuNP2?2*8kY? zpR(QF=(*Low<`B(rE7cy&q+_;s_fq?`*(^wIX(7=CdaRSRQY$S(&Sud8Kv9Uo_Eqv z5nq~d(&@?|AO7QL!ul%9RP$WrhM#9Dzotez*qQTso|5WtT)y+kE6Y- zUyCLF2jQR3^>Ye^2A^;ckoux>7uW~qJZF^MXs6xj6rJCq`}X@tCvVdJtI9n`3M?f4 zKuR0>pHu!-j{hwB3$@AASR1ubyPsQIPLRlc@o)NzOWfG)j{8S1c9YJmPA1q&3jST1 zvVWZNu1k4?C|;fEwc|bZy=7! z)szy(Vw2K)+sRw)+z(y%8s%?s{degGb=sw_=o52#}yAGGIL_x6YB=z=&ipb`9V{{!F%o%%97u=>mBQfvJl(+74gIMv*WfkS~YN zo4+&XY=g-C0I-wt9r?;ogJ#(&#jflRh;JF~u!|f8- zVXb`ZOJIk-MD{EXf+J^x0LfL6m-Q5pKhKtjt`X|i+N45uv*Y=w+&V`SMmc16cei#x zo!g@nRFN(P5?^@;=L>XCxBf!a;P!f6^>KTbf>fVu@4@}tz9G8@xcy53j^_%_+5SBS zxdTfvG~vdg?9lroP4|nC%&U1?Fe`ND%khpTuF`;=nW zX9Q;Z6ovWPjJQz>jnRBpTIs}oed=FD*31fh`zMc$o!p&0{ zvb8$o%MS8v){C)f$0`T)z|3R!Aw3hE0OT-wwuSNff-m`4Tj=LUTuz2g#ugrf`*YU0 z(*rrcT#*B8R1<@#=UQdmo2W-zT{6u+v|iKq>;8!EB59t)|CV07fm@<6EgL40chL6R zY%EKp>%cqcMCR}OVsLDz3G=xH`px=j8|inz-+`(3=^Dps1{hrq+dAb( zT)J+h-UliMR=gLw!8=FV{}Pe=ZF}`yl9jJ5ss9*$Vb@s%06K> z*dr48jNFqw!LVRu1gm23G|vXA?XoEzJQ9^}`=6Ue(DBa`RdJNif@Mx=A{8nE%sv=ZHsDKg>wek=mqOTxB1%y6D?L*|DPvrMqd${N3W@vfx$M5s`{m%WYbJjWM zp1syyd+llMwf8>fTmAJ&z2vlOF#Dv)50x6<8+knRNW|@pu=4u>_`5(&g_fV4FLI>u8?yanE59X!l{3e- zHnCZDTgUQL&)LJ$`;4b7y%&n1cbEHwHdNfsFPz0i%^l~ekR zRi#g5kXLh%h0c$1jjMS_GNwBbTsADI;DeErO=H2uCLuC3>NMa}Bv?Z}orp(r>QiQO zj3sT%r(*qiLd+1bsgIo#wH&u2A6t&y3*HO-1hDxeJdSbBKJh^tjGzJYa?)VRizrfa$&0G0C3#J z*_FM;ykpt#o4$20G9b-nS&~X>aM3Yc*6C*SaOGYT|CQ$c9Bpt{!63^MfJ=~Pp(^9@ zR5{l#m_#XF6MDCYBD^P>XuV1>I9^fyOwn>ZfXph5tltIq#`{hbFmm-rf=>pP8$Zly zQ%_jE?470UYF56o7;tlkO!n$^A7qR{3ZNHU=SPWg%zDf6=tCFhL0(q`$~Swoj@1{W z+AbE>)Umr#^Vbb++kUwg{0`vjfKB&%z<&rFH2e)^mtUXGShpSniRqm2P1kvr1in<1 zPxG}BDNWRDt%NHwh0`!q^OKwq$ZI_KOrRF9{454P9Y`Lc-ss%WwsoECjEAJ^k7a24 zbmkE4!WQoAhnFnMqdYeeIWaJqcEA%`7)u4%0Z(=*yb4x?7J>CbvqDLZ(?s7X2aW`6 zIdeVuH-R4la?H3#=a0;Gu6oJoq6|MH#V@&JqihS5N^BZ{jT>7#Qx7&`)o*X>U@pfQ zThy#bV%N=_7ilG*BBu&DUlNPKj9E_pMpOdE4C*i zx#5P`RHg>zumyteO~_6rqKtLbWaUQ^;iC|!PKPCvf_7yCcpGpHVAJ6*;4>!s&PG5E z+wRVsU#ebmiY>^nkG6HRZRuizi4E4rx!Zk7$@f0p3zt1+8s4c7g zICWdPZI1H_OVo#d;zgeHB1{DznHas#jVP;9;s?I}HX~;vbHmZrsj(T6NOmNT7J8f& z7?y@B|CE#Udd@VqRK$tj&3)2*6pj?Vh>@F#O9heq{G4!*vDthsz1onXE{;2xJSzqA z0qqV{B%9v?H{m=js(qW30=nU@uj)gRqbODi&<4!-6xZ|c^~{Tqr7Q!U?MBtxZb31greUJsU zcB#eBmrC8dmx>>uOJX&WR!wY8AP!qIR2os6QyCq_C5QX-nP(Qx&C8KF-csqqp=7BD zR&oX;xZdxQKyS+2rHdHA=OzBFH9DQTk$;5|@|VEB0o()Fdg=GzSXGx zaX>LJ4VbO!t~%AFJ&)o$cj2TXN}Ye^jq}G|9|_$UVYhaaR#q9IBOb}~OZ?K`#r;>} zxxb4~dOV(1Cd*1tt-w6M2q=k?wF2`175_S#hv(shnd?sql{)Qnv>bL5Kbx2X)!)U&k=~@FKVIBfYDo5=frh(}-OSS*ibP{GN8s)$!X2?-eGI zehB^)uphALTsFgZRspvFax6FV@+$7@UvBL`(X8{DxnGO)@0qEZ5#>Jj7rK-G3pI~m zm)p5;&JjO$7fw4OpLGg8&vt-C<75>UY>jMa=av0BG0ls=keCu<6g)Byt5;#HAV2&@ zV%i@P`EMlR2NKJol_jAmX`2nrMljO(pAHnN+8}N^656^Ws&J%wXET@7AbEBcu=*U~ zO{csW^mE=FNtqM~R)4N$1b2FK+#kDa29-~tMr1hl&)4#P7dcveDws)G1B?S~J8u^F z(ZEpo$?B0bJCW(K3tHB+ZDtvM+~^C{CNg7>iPHYL(AiT|?kB}_C4X#SFPP3K>_qLL zIi2RkSiM%4@Yk@w=mWGXvg?w%gy$=#N)aXSCZ>=Dhmjr1jqI zULviuN;$=pdGnVvlZ(*y7*mIlzKrCAv2(;njSa_(V!@oLjqom-&G@2J5*ro&aYnmT z*;Tht^WR<-lv~@uzX*I8u=>0k{KvpEfE*WnqrV>8a$ddUH1Spa-pajl+Ul+g+VP6+ z>_W2{8!oQvIL56j1hS8bJEOnnI_p@{_=S4YC$HcKR? zvh~t7OV>F<$ER`@Z3gpjG5CqVM*yoYo!|mP#bW^9w6)vV8XN~e`X{4-Z8WlKS-Ih8 z>hB5on~e*{<449|}DbCN^JxqZ|6_Qo!mg;2K!A?E|rfMbryc1B<3IoElzNJWBi+ps@9UJ#m| z=iTBKf7zW9%n}lLOB+!Jux0{sZzk-jSL9?_HDM+oGuPFe-5?;@QJdx?jQ z@5|u-lz7zy@m&Odr`*@-_%1NzW938r^~=V0PD%gzu%o%NZS(ofvUT55w(gT|ZnJ9L z-4Ifj0(Jhe@~#{GR@ix)c*`;`vX))M%ZlaYh0EMU$)juV+el1JPK){x??STD7PmNF zR8v@0Iw>Bxl7*DS=B+!UEr>y^E0X|gQjrPFK}#d9EW^RQE;!HNKh`Ux|Nr&-)X3L3 zw*_&I1tw95=5Un;c(%EUsEcU4O*NKOY2aDMku!KF%e4&rzqY)a;fTxCMhA>yUyI%5 zXp{euzfGsBz`q6D3s}882)=SQ{|Dqa@-dx0cbk1lGxPsBgQwGS$^e~CyWQ`&sfdneim`|gj8}-r7^v%Y$h9CF^rs(H$7b7ZcScDqODJ!n`;uRES^7( zN@osLxJQze7M97-mQFNjQLh0c;be$27mx(%pAds5+^K{9*Cv{TlNt+>7Pw6E9}AR{ zFtW0ej0Lf#le$XFyoiBC*=SgA`f0Cu*{2TrUlvZF8KTFO)N(;DN#fO#cwbZrkzB0P zuX;|9ekX%B0?mL;zk9$(&h?#bfE2{ZSD>sGIs_Z>HRA1f#5ET>ZNtgyF( z)LT?GA(eWMNcZ*sl5|HOe$qW6JzdFkGEgk5SPjfXgJ-&<2mP9MaVcP>{0yf=_1s6CTkYlKMQ|cwBx10K>o9y9Q)z!HE6xQvtb((r6 zrvVT3&Uz<1qp{li#m>!`Y~oqj{}V}G8O3*CtXGlixF^ddGubRn$7nAOX>OG1R`|Y} z`0RmCTaG*d{tMt)z{ckwxWNAcatu}f_L}`t+7}KIAK~5cj&Vj$3;BM&vnxttCgPT7 zSKymbVx?ahrX@Lss*k)!f^^23(odkJR0(yKEv;Z`2oKdfL{Sz4Oo8f z0)G(rIUq-cX}4wCHTN5S4-CdH@~4?uy@*LlGnuV9x{(p*G0x-BNi=oBUV%>qln2|f zJ&NtPw)Tssw3y*#MbTPm_LLK!FjIwHccwIZ>d8{B7YmP3d^Mb?^=ZL^AU>ypuL7C@ z8=udEe-(HDkmFG8i@OJl4{eKj-L|NoNq6&lms5BtCHALWS_!M17i6}#S8yr|5G_lb z!K6G7ZP`c+vz}#Sbfh;WgwJGPN|o`8(*f10&<#BGh}cSPhto_xWIBijzi_2(SPjUZdG|@BTmMRtvI;XIHPNve?;T! zvs*DkviU6vMr(&C9r(jrN zUB6g35t%S;8oSiyF(^^(eaxE|Uzwkexv`AIK0dcBCp;lGq978gW(+1PFA)~MIB!GE zNPGyBcvg{!+G*e-lKMR<(Z#aR4jcu1Rvx@1r)pp^aJk&zU(5VeYP@VfO>n4n_4g=7 zDn4}14(}}N&RP>I)7h(m;PGg*YX18dfcb*ohCcI;I{Upi=Fpm;96>ptXluf+|&J1 ztV~Ha7CQ=$+j1rZj`Yfk3L^!$Db9+xSF^fp_+{UJ&Cj_q%pJYcE5h+tvtq34@T#A9 zGwVn%^qwF4m#@ze3^O^vcsecar^7ke-r`>5fBew9e&Sy~qrIik+_YzP-Qj8q3;oR) zzA3*pT$G=;JzO#-D{`vhXHujB!xftlhr}rt#|B!K$#5xCuFJi1Bj-kDd(*utuOzD^ zTr#p`YDw+q-7T0Hb0d*e(e~`DOTv+*v8A7ZLdj>{tjHJ!AtjQF(u2h3lUm4ci<}VY zid1?8B)<{@yB<9)8Nnnm9>(I{t&y_Z;3j^1q--ZLo9UH|Dv6flm%L66!rJfR3wc>M z{~bU2nQ(kpWT98~c_|TfW|FbXdO)rdfVqI!R-}=85mm(`K=~(50Fh44Ym%dS9Uxy{0DJ`40N4<3kw3{-5>g#dVeZSh z9$vpeRj}mq;otKM%JQcbl@;P2 z$r>@)Os8^JIqj=VyPz%@C;ce+I$#rE?IGU;7Z|F3v~9<=%}s5r<+DX*4*JzQWcjR- zz!u;hxhVybPOr<7F&E}W3S%Q9qiH#gpurffE}JPuMjm_ndLFP}ARb4+^|8Qm zpaqyr4F2Fb&#-s2a@nT`lgE$Uq&?P!2b0AI3iERFy%Ky0nOBmno~fr<*n;xnVT_fz z?hA%3?3fLj|6X{r$E)Cf1pWe8{@(>3wfNBUdz!EhZfI`WbhhkAwz#pQV`Fnim27q| zu3*w4i#wC=bDhmqI7cWKX59}iFj-9UoHkITWwmkc5U=Ts?`+ikcf*@K?f~Bfd<(Gr ze;@pDz_wp9uU3yN|6&kWtEO;S?hES|vAosfvz$AnBuw|(nn1Z=ytY8i%&9e+uae^e zzFOY&oLSu00+z3N;3oi?{Mh>xUmF@*JDXeA8g6DB>s%2!R;&op9M26H096ds8~Qg9 zwmmHUd;gF0JDQu$H}rd>5SL@8jpy+Jow?wj0M-Gvo$@pAvJ)832ISah+LbemAC8T$ zddaEcjsET3wasg`td|KqO1o^D6z_K%UKS@DMp`(ZqRvLyx?CB3A)IY;`kg-$y zOp5bxe&uu)J@-zb;nxw4`_sL}Gh#Et-f4j?PHHUNXI!ag7IO_zwH(b=>YSsvvJjXn zp6yaG9nHHW12f*s-JK#Ad9(o)jl}<9}$|h4`T{$M+N=7n{Y+%1; znU>CMreFt4stQ+fzBsR%jHDhB?Lua?3bV=en$HdJV2?||uLM2=SU#@@zZ0Fr)urlVFdOoX9gJ;u^)_<0vv_7MNjktg|1 zDPZ}T0A33miXWz@b#7z;6-OCi%&=A8`AAd1@G~Lc=b+(dJGAU^C-^sj zZv&Q}AA&y%9Eu;sMN1QVFgK?}RM*TZAsf0~XSX|MCUntBvBYL!Nu8%6rG~1+^eqMeF@0w- zp@3JEF-`+sr4ubb6)Yetc*)5@JZFO+0UQO`^f(FpEWnn3nOCc?%bL4R+{h+OGBlV< zkcx?8W6tJd*inp?Fw%8ITB;@^fr{iC3_rV|Wse_&KfBp=p5kix*$4g?Ad?S!KO{f3 zGPigc(|OC<;?Cod8vIX8{Vp}s9Hb}>zf|+NJpB>UJ81Y@@{xeQCh$!_8({gn3j8*} z>O-|zM>vx|*1bFFxccUfCUTUOS8?5KF2hVKdR^zS&}=jqnPDx7VK%_i#EXw05p{D! z+QiFM;-|b+%SmkWND_PZxjKE{g%^ALWSQsWe$;pJ0n6|6JbMGM{AFIPJlE?5UJR=% zs+}kB7Lau!O-a4q(Az-R_Sku&<6Of1Woh(wfZqmK`3zP5rPHf*RZh~o>O=VWguYVKNd&7H&z~pCw1eU9k>y@#oEq&EhPhWNB@&&Nj;53zCAQ=!cW0PVgGZu7 z91WYb99Ntg@Od8i1;Ay1Ef2p0emC#{Acy7m2IJRc^-8^z_Zj73hJ4Ab#qGDaZA9QQ zw`6Sb80WE)Y2GB*VA>t z13hgweC>p$J$k`^20Q^+zMcht70Ber-uLHgd2>e#rLpXbYYUgciV6zj6^op`rTFG0 z{nCK1cJPaUZosDd-QZ6HZvt}IbkEG!Hg5X{P4`TGCHd<% z(I&gx#mQkskLSDu*K`xdxW5{aEmN}TTzd=r@4!C+%TMHV)-C`J<=3P0 zU8el!P`r7C6_Z3`>YV#Wl_TA>CLUXYS-x`gG$5zW@U;P&_W0%ov*KvyKG;b{R4w2*-G=VF(6HlYBhCN^rT|t?KMF2z1|Y|w*3o-mUVl6E z`liL}CC8uL*0CvQ;cRwR#M~;6O*|^2Q<9ar&OPO^+ehjpQ)1r)VLj%nOCvXwM!#R0 zyuTC=3Jf&vG4!0K;}Y#vF{~B|MVU6L#sY<}gC;(E4WIJt_u&5x#Fqu}ITQRE;88%1 zU8cW!%cHuTY2~S2%KO!ajE^dFzwOaP`Z!Ib6+7LjOyF}P(@Lk7&?RF}64#sdUDxRu zGdszqP8fK`c;d(F-B{~BdP?;1lOkW3$*^3+{oG9VZD#u?9ylfR;3-)@I3@n0Q@qP- zld)nJ?~Ai8Z-jVCo}!oCWkW)kiqC7Xo}FnR+KZ>U~!`fBDrLg-LOTU*fP>v3P#3oFgpA&ZGE z-2t!LPCPmCkzUW~35~-|AHN4L>r=7FWw8j3yA0KOk&-eT-wU#Gk}R3wRm_amCcLpD zSQUCyiI>1ii&O99vKm#e;tgC@1rlL6SQ0d`77WBSL0|9}W%3RW|OQ&1x>_AS^9~j5|B*5}@ zxcz}O>yeb=$_T34t#+OfXJ_3fXfX782-_at0Dk~@9I*N6Ab8#i-y+jYBFyC>x?IpUaK{{OORU|tsg^~Eb zOpyVmAm2O0FMJ!{x5+45g4i+W%Z(RT6^RA zW|eF34K+!D-?K^$niIwKmy35nJ`lmC-R=I+b$X-IXeWgul?ky8FglV|;HT|XA%jgF zI&Kxjr$yr8RG)9k#g7H)csBSafJVUby$Sq6;81+C?m%-(d)Ec2?A37E>X_5M(K#5I z%${9onk*%hu_H}|9b?zpY53`bmOb7C{~Pdk!17c2apv0rL+O*1qu61VwY4;#y=Ke0 zPRkT3^pI#z`-`q~56jJ$vVtemuVN#-$=M9cQ*4H);G)dLN-2tryo)te7SJ{g%*Alc z_94+l(huq0YSJH`?C~}5`+z-w<+~63RlxFnj#1;IMqVx&G7kaoRZ#$4siX~g4P;-MZ>eZ-x*3v@hU=LCK)mEd!L zg@BF6>ENFO4yDKa@}I1zoQg-o(ac!CS~elO!u_M?+?h4WtH5g{*DIqr7%o`lb$V%S zpXum}=uMG|guUjOrD-H$!Lzj1kNS*Aiv3bdefr8se(LZ2K9f3JAGZIpFkIYlL0G-P2d9Uz~RW@O(O?l(M2Q*h{U8VrRSG#@y~aGDb63yZ6~&{cJsQ`r=|}+JQ1dGsA~-RO@`iqGNfaJ z7_jsXcbrwN50g%<$34sG&Y6l0Qq@uQ7wdFbLD=@N^xFTg^rTEQnPgW$N(H~$(A%3v z?|0w_fIp_u`>WuMhtaNF!)_RAzXe-x6;@Q!-LLqlb6cpqWJ+<$JfzKo$giA^L(rnU z#Ka$3_GkmY6u1Jg^1dJZX~5QJy}SGOPi&Wc49tH#XwhksqZ;$4cEayh1p7NL?2wtF+=?bUAg)j72)Bw*B^^ zY|5e@qDU$leV6KZEm;%9Yc=?0;Bvs03lD<-5_k=eW2k(lUUHgvME~-!Uwoz2+HjX_ zUfJVPZ`|e{bBH_ftB4)oX+JoeI7JI0vxtTL*qI zkXawvd#l&&9nESACM}(fO{oTEVck@Wn`I0*-{yY8+0FE`3gVc`a#HEznr%j-RMty- zq&jsKmuo)v!GrBjya!&$>KKmAr`dAuJT5+)fPKI$Fuyb62Cfh5(|dm zJj+DxNM1Z=dN>(g5}uI5$QJ9&jU;K!UPuO)#nrxoN-*C??L;Uk z-SBBGzlwE1Iv)pqDsTp16c4ie>R*_0dz)?L_ ztbS%*ZMtXhON~=lF_!xNHunf;d!e{Wq;K3Im~U?hbXC& zpV9JIL6~+NW)t}Nzy)b^E(gB>IMg^yijJgAvMkR{vc`*3b)@q!s}B}pw>FhS0>>@} zKy~trk{fi0clCy!1JJU^zre$r;196zE&v|~WX9Lt+jy^UW2cCzfj2 zYgS?8xF%8Kt+MVMV)0IrxiWjyX%)i|uSJU*KC9EUdUL?HjQ5?w{Zhd4eYoR&@Z8b0 zd_yyezS-Ics^&XC&0&yFj-7_y&NO;I1Yhdn+fJQ!HlLK~GL* z?5E16hUcYW`R2??-glXl8#IW<3=mYh;Nt1E>0$g80q(q7%dfp9kY5k@mw;OVE5BXf zF9VkU%&U!0dTf-zAQh!<_c~cAsOo#3bKk5w@9BQ=lHnw+0I~v%UInJVLdg4m@%sRu z5YPReGx@)DU_7_+?8Av?t@GHdD(`nDYN9U{*J!#2(&$FoSmO~G0oeY@bnqp>DnJg~ z|LV@LC#sj6p3U%QZDv;sqeSc2I3OkU`p>#cvz@AS>`Hlr^Hj}|wA>i#i@9&iNW4Cy zG*%o`a#AhJD*e(j!@|Wr38t!(%2~ajx|0`JN7pgwP9k-VD-aM(V)@)Pq&aoNH>w`9&-zpXMiFz8e9E);!Q-92Qw-SnEC4?fXa(f3`M%4nlV{_lUUFKV-`_4#Ijv)B%N8c9Pp#?@ z`>a)j;<{t$u`WA?9emuam-^lA*v5i2acB87$^L#=*2e*J4~G0dsfl6kjc&nrq(apW zi=w|HR3R`KEXfE;vF?G3Hk%g|2gz6@N>|Wvwqkc+US%j@`Rp_C-)rI}&tC%nGw@fy z>Q$(V{f>Y`>6KYVF%`W&_fxD4<}Qbd$1nEx zxfg!?f-`756fJ(zpMgDCewAPLE4|vAeI{M&-+wU4(WH7VqLL9)aXd(eS=@`8c#GD7 zL;Y<7BJR0C%Xb&N+v7jLp9Y>yduI9X+_bU1UhRr|W@od^%b-o9j2fMe*X=ovyPQr0 zdcL5;bgx!t@%!ut=JFwDWg=Eje3Stn1-CfL(GAJd5(%+O$a zCJ*Ni4Ge6^ma@2kVDY4EiRSX8z+>CF5dY!Z2<0SqVOAlJs;?wedJYk$is1+oX3^o0 z(9%Et$xIz^9F`(sREw=SJTW{Ryiv=iVrwAxYVg^>{Iq9Q?v0%|9?HyWmw2(4SxCFr zIL;SM{@@$iU)lnGA#jNaN0uD6;jC{HDf!jQ2rtlpn^WNhg4u85tLX{5(jpc`tXa zxyO%)Cn{!rhHl-qf$~{to=G8Q>C&cR09<*PtnS>pv8!o=qa?iFgtMJ*tbA?(-wAxp zgp)IPIF9!f5jLmWSd<7pNm^zE3g?VkQ^%-SnHcd-RD`MN@?Q42^_MgsyEM&iNIH*#KMw3Qe8{r_e5`J5YwD84{UwcuP@foyl!)IQIz`Z(r!matTWv zeTMEf!mKdQt^yaj*8`b!V@BSC(WUJ53VYn;JKR_g>ytkyWb1Fya@&^{{sHi}fxoAP z|1a>Yi?Hh%xeXS6P3;258`a}&+2LjPcm>4m+w6-R zTDtqdh3;!WCf$9*(4AXDLXPQ)ZP^ja?uivRy^5qxq=wsc{HiYw=o||!bWY`(NoUV+ za;>f<<;L_Rx9mt}_aqCP#{xph+l}6*(fNj<^Zh~SEEpy}wbgS-z%e})TXs}r_f!-( zj|X&m4ISr_AU^rv<-mBr#%Bt6EwE=8I&-QQl3;Us>bC5t%kHU@1p6sjFUE;%P+=8i zqgE6x&z_w+p526P)9qStp}!Nzq`zR8e6XNqAqh99r`z4Kqub5qTHx$e)TsyW&~y%@ z(fNm=lXdApIwixzvu57x1tc7V$P(S;iEc8*6Pi%5OVbiNy zl>S*or|#>T&I-b`da&8hxnvMJdxw)7`FHMookB{tm2!)A|3)VgSt)s!rnfhZ-V27_ zp9i70WSDr>Rxg}iGgl{+QgNl@qU8Hh^!6Ki3qBRZ?-X#+i%)RPl;hrE=*_8FIA?aX zPB5kFO4mi%pHI=-y-UY$R~o&C4ZWuZp|@lheP1wp!Gd|!I^mScE1egme<4M$`x}~G z$>l-(W`axnj^Uaazsh0aS2J(^{Q0#tCILnDmF|o3zhnv4e^b-jo<{FhL+{=}=b-mT-eFOA-x z4ZYB(2gYyPF!XBYEtoTV?i^{2h(L9g(0M{K#p^<^=i8dz62i9e`vkb?OXnc;-W`S> zrSXFK)eCD(0_rTG^MquI146Ii9!+mg8oj3tz1Iezw{O_;W&Z5>b7~eyYeYp*s)25u zDI{0?!6qW*O!d8*ZpoFYzJT-2=UMih`>M2Owp}bn(+f5>Z(d7dAmJR0NgqtQjxJ%z zQD?$yPy5#PqpuF0xiQ0kD%>q=Hg9ZFGx^MFCC-&u1X^#x+rzik-cCWXIt6JG2p72j@o)-faG2OgdBZZ$cPm{V;)^arW~+csbxj(bw^f5k^jP)TPE+>!C1djSDrfUyLCFV_GYTz zeM*Jvgg4Q-1{;?sm}r0vvEn;A{d&{BeGlNAx=IX?_<`g!KnyvHnO zF}doH?Ad&yLx48n^201BzjR*Y9})dFb;e%U@0WR>`TYmr#BeYqCm8f%{b(!c>Dbuk zHg4t~?l5y^#-V=<2Hsierc#C6+kU^v|DOx=@x^yMr-1vBfITwwn?}b^-D91H3$;cH zTe2-w7FS#h`KZ@~yCN;zbHQ7H^M(#r8W)QRda?6-Drm9Kr3bB8NR&;eND!rs!HZbToHu>1eHn z)rfO5Gq5cWbtatpv~N~}uL0JXXHsO@aMriUNVCIu=1&DI2*q5;CO*l8{Z@Pu} zz2FZ6kD74gSt^{S^cB4*AiKS_@4Hy}KP#086G~nm!Q#Z2!=(}-=Hxha&PDskO1!~h z8XseGx0t}weoWg9a(>!#`ycq-qtj!_HG$5Y1HKN}WS+^&50>B5Iz(sTUK#E6E(t{SFQ$!wEzT>YE!q@Vhbd6EY7QEDE7HPi20stj0$6$%q`g;kGwE3);DQ}~ zOdA2)o!3g+wFxkw*YL2G+upSBehn`4eg_;jJ!|}1up<@|W`e;_UV zcfh^t*bfk}{3pQs9hvE&jeONTbqjXX#k7&{Q?B!7DJP74qdk)(bwASaS&e7zy_hoU{aH~{Z1x#Cy=iowHgsP4AasmT4?-S<&~5439ZV5wctppi z^7=qN^T8!PCvrXP_!y%ebbRQb)6%7TD@Es^q0^H_=XOKqo)1FD81+WeD)KjDbk#ONccBU9su?jP%hVt!~Uk`wK51j=w+Z~G6+1_@ue44>S(wt1U#bD1i8H3xkrob7{zbIY*doax+|7SMhZPTwHmyfIWb z%jjYJ^!oYY{^UNMrZYo}>aL#nTYXf>z%fDfeaJCK~P7@mdKWKwV zns9av5>D?S!#UG=%mh?n!Z|odIR1^p#cQ$igk^@vSDSDa@J(jApE`UvXFAUW0o9ps zx(5m8reVXGtrF~c6I8tkXYU~4{O-`bW_{ci#s8 z4sbtU535JmTbed^oYuC4#Q^Ht*!xax)_GajdBWv1M)F}Ou3dt}El7jK?7i4J3}9dA z-y^Wr1$))KdCV{@Oi1TfSuo@a``q@}L&_eab1de#%>OB#^nc}_Vs~ME9`ZF^Nz5o> zP2st@7d~ATf_$Mdp=oIaPb}~DjlG&?3+>yzTD}Lr9Q5~{Ti8zw$O7z&-gFV=1f5+ z{Za(SzAJL&7gl1jqLPqAK>DYJW(8+Or^RWLIS`>F^5CMh$)6HjD&eeXbwUSc`^8Z2 zUDfflZ}n9hG=g(x7{MEjX=<1%L{3;JMV65TA{_}&I`d*Wi-5@dumAu1ht>a1EIqh2VqW2>|E0eC8z(e|(kWAT=+L*bU5q^;h zf232Z-4>PBLq*frX~KUuE&TjDC=-FvfITe#O`F>~n==SxD*`#r5*vYleP_1`e}xXK zTf%Dx-wJ$kknm-;Sw`?1PtfRC=^;Z0|?rCRYLvg0-TmHsN-s zg?lUbSAkuFgvNR1)vTPotpmI-#!&Oz)P)wdZf_ zpW=_1phb}|(rQ(0H{sUlFqB-*0dE4<4-#%`V{4o6pTYjAiv6VyYoHLi2uc@@#Da1| z-%BAc^(XtnssAVrdJX;FH2PMLUl@e`R{R$;>EDQ)WYjBNUVSFqlCK8oJs12)piV#Q zm)@Nl*EcrFdaD@`8?PcZ(b*+5NEMwf#KPwGUunJS9)!;AgVT|r=9b3JP3e>#8!Gr} z6aN0R@NNEhfAH{`f35wK(~7GXO!zt_Qp{5hn(*ts7Rbrwi&gqrKRId#Os()17-lD%4CAqTuvr7DS*Jq(0@$9^FzT>Vi?VE2-y#CmL7JWoiIFk9{zC zub7h>5mlsFYTnuS_8C5tcLnKL2|f#$t)HpCTDh=rQ+s++BA!J`JV!a*VG)n~gh#FX zQUK~K04LIHGvaZQzt-~Eo<`T|>79eo-O`#t8AlOAN(v9FqID+R{b}La^5GwYguA74 zb8~aQ7||h9;px($-h@}ZE0E7I;8O3OsGs$d59M{&W=7fl`og7nGK87=rQWxjaJHp| zW9!H31`CG?yjv(tpXFD?AH!2b@sH%R!K&fC(wC9_n{QYo43 zysJp12k-1Q;V<|`Acr%+KL)JQ&-%$>Q!|T2X10K;RQT1-l@XhCIx12UND|6fIzUwP z`whKaY4mJ8`RE|@)-|>E7uVg2hUlRjL0o>L_0IWb5Rav6LrxL*CHh&vc*xX^j;__6 zU0c?WCr@?y)WE)JaQdNGR)q22RG%Xp7bTZ=O1+`8A&t)G!EXR=8iY0 z^a`AN6um&(x(&TL9d@^bZ|SuiiXNF`Z8M9lZh&h4R#|Tb8E2=Vvn!3x6X3rDemxAG zCZyOuXoNRLMW(`eCPl?&AX{8Jy@p=N-GN@%a-&8+Q=+tTRP|cA%-&RCr!=k4gts9r zJS(Sb1_{rmi<*l$Kmq=lV%(nD%?{BLQ^q;OjXg`^38ds_HbKHnZD{HC_nwFAU+j|x0cQaGzN;U5?z{G5A+ z&KD~Dt&RQjU+=*1>rMDebXeUY4BHO6VjZ518DR zr*d1q^G=FJDwi>T($MKnqhr&3=P-0OZQR^10^74}6{2%QuL*ZwTDS+m{{sAVkZ{df z2hzMdLGgQ%^I$4ST`SRU0Z}-HJ84I$HVsXzwD=_V>3mYZJCIu=_y%CJe%4QJhVBX> ze4-+}#JP=?%XFh@AYqsolyHNgyEl!ljqh)Vrd!|D;k-T!xgq1Z+t6F^ogkhkgVzJg z^|Qg^iEFW&JVV8Exzm@O8BZNwwVk1oHRO%OOL~53Vs?_xX*usnqyGf>FM(eVLthDc znPT8f=fT9G7?3m{G@aWG{T1I0?8xolp9C%i#Bqf=aG}e=Zv-ZqeSqw|bUWW#_P4F7 zYCf;ZRwS#{NGgkk)gOn?%xSD}6aSv;_<)&Iy_|{D%$N_A>B-Z}^#uCR2tCuU`gtvv zgV418m9g*P!wVDxmakFZRlwo%rQL^__;)OPRSRD`;0sVw|8m{Y@U#d>2w&y;7T(xZ zNfe>i@UP9ioquXhb@QB_U5LI>_!}4;rJ`k<6a_;)Wn-OvtE;Bqrvde4GkOb4<$WX zI#Cq-X-)Y1)58A;_< z`B3DlH$!u}P58Uh!WaMGSGj*3u<7<+-~xw?4-Ujznz|}JSz$BS`cv3$U{UI}wSqyj z*|ilHJMoE*Khbd~s-)X(_*ig%5YKw>mB4Di^3eo-K5*Fjv%X2T5Rv@7l6+Jp`RH5Z zBf#Wu$wwarigf-~x9C)!&PNR|YWep;^Fx*YR#_01d}_k4ejo_{1n_!b8DQgm7I-so z*zs;zx=dybPb1QkmqwlVCdc1ovyUz|RQ6e(r`cT^$=+*W*~2tYZbX*-m`= zQZGJclM#;(RSdfGqx$w&t7bo@@6fu)d|ZR$VJ zs-XU>dqu~)8(KCWd=dOk;A?>8XBYSbz+v;VS~hJKhL({J6hj@3j}Y|UEW%K2z|hPT zL%oKd`QWT=lG`BV`p)H~{q2AEhlSbzm@E3vofQ|pF;BNtktp_c#<7fvBSfW0Ms85r;e1YR% zU?YA4v1L~;Y0I8Ky0g!TaMWk`S@K8_?;F5x2krzcKVJjC4>)9c3}}~G#!@Xa`ygnm zwKuMPN+8D?(eWo-LRFy_`uj_P+^#=TZ416uH z0kHgU2LB{*Nd8wcJ6B5n{*6n^^9PAU{W(?xKZ6DWMgteXyU{>FwFdT?c=W-eEg#+j ze-CgU4dM|7F9Hr*FHFCNtxWVLzM>yT!) znwGB*rCni`qtm&9{*Iy3mqzE`tG{bg^|#R2eL%;f`mrD$|6cgB`-R{BUpoAr4=sG9 zh0;D!NA(|c_y<3<@aOj9|DXxK{>Q<5+4kRsoObRz0h^Duf?o+7YTe_?Y0|J*-neFS z^Kwif>}Rxg?aXy8&XN0n10|ao;He z4m%&HMdGA=-GcJ7hZgnYb)Mq`Xuqs2dn-qieUgSO@G zI`CV8I{?ey*TC-s4qe^^^_O9>u>KRa;JBLn37GsTJ13fgLr_(495npIeiHCA1AIQP z2(bJd1AYc@*z%H8V++6L4sm`sp`(L_D8gF>XJbTmx561ERdY=j3^=zTD zadWdSDE^}9l>97+e>He!`)U!-J^~z4Kdm6vu33LpBRWu6zZe~;LWx@{XVmc6EzMUSG_9Qf3jRJ2 zdLrN}3O*7zY`)ev9fujYqfJ%{HC-gLhoUbmvZa_07#5}ATBFN;L01L+w?4yPJG3o- zSAky#d;zd>y9xX*;IR4IfZw9ZR#NDz{_e$&&pu&6fA^@Mzq=sS->v_vmY4G%0Y7Jf ze+)PWu>7nB7dRw81Dd?zEKng$^4YaPOC9GN+0a!zpEoD%x$O62o=OY8%86GwewE`^ z8U5}y{O*PqE5EaQ9Vh-I>(~O8-*%n}9FpIa^X3n1rvE!U$Co<(Qm4=GxdNUnpY7lm z1DB=o`DySwfWxj&#lb|Z?#1;#a7pP0bPFUz3xuLjw?IVY?!nC@G~EE3qR5U``Z=YO zeLg$T%l5x%J&64x;CCYUe_ic3Zvs}XGkG=#7^-}=#XRd?Z)R%@RnMi0)12fS%%;jF zI#HWOCyHrQjy^+wdm8=y;I9I&1D5`OfeRcmT?gpl7TO>cYueg22igX+t{28giJ4Ez;69%}Nne z=SjFZ32thovic&G6=1kpfrLt=geZ4cAR%^dA-&r1>63IT`DMV@zt_*LsZQ@GR{vdx zzb!5N8^AN|the**9^jDjUsv*g;flbzvyz%%J>p{-ODa zJrl(Dbns03&pABX1ROFQ2IObi)jgG;ZSDxNw6a~zsZKLq)gMKAiFw7O(`j&Q%qpjm zPI|zv$MD^o#`nKxx2m06Gq6JZfXvfA{9i546~7AP`S0mZZEB!L^m4xme@|NYzXsnA zyaw2Oa{&B*fJ5ug?4SdkDpQIZK0^O&r3@(TCC>mxk=m8^s9IIf%9JAQ{-=(2{j)*5 zWu3HU?l%CIuPb>ba2R~eUbSv>TVodsn#AWi{#=PY{Zm6{Pa2)STRI$2ZWtytS=g_}-Pse-7uY-8+0KX3S0$};M30&Zi z{Hz?rdV2UQd1pECvmE~{hh16K(PQ{K0Bu{&{(JhkAiX$q>i=cp|C=EE%4;3xD(*iE z*!b7o?l=O6jQ@c2Xu6pM7ck{9EIE1NdP$ zf~J$EoKcL;)}>hRv{g3o%={};7&6*pSeDnfwxqTHiOBm}t~>uTkn5E%FjfqF5wLRo zGWbKl2QQb`ZP~mzrRSU1sisxHx!R0==+~6m)zY47?!YWQ3mZz+akwitpTZQr`o^_E zFk9I^ei;rqofQM*I9xkV^@eQAqD2De@0_w`OXmeC=2Gt~E|wgc+2vYuL05C z5b`d)+a=CCQpBIuysc}%hxX-1+SYUqc-bm*bp|{YH}Q@x5llLjR&k{m@ZZ+8ZLI_K zx>fBxtb}<6jCD#_fjC=_r-3!t^To@S4fa?hH|TRI)&_Z@*k48qb^x~`jN@T=(3fl0 zi+phwSsSDZ)7jEG6#5?$z`&5()~0ntnoi|5h_G~CP817FW+v)tll?I956%>}%n85` zP3HZdg2S*Pm!24not^kOss7Ff)5-Hv3a5KZqHR`1JEie^HmS@i10O8Z%`lS+Ms;Y? z!&PP9K;`S~QkzjJRrwM{xtqS^^)&=9_RsV{c%0`oxlgLmxtq@-O_?KREw0l?Oh!~M5H`q zWGDCfGK4?y4ebIpjv4e-M|0Ep zgMC674g;CB;M(TRl!oFjHsIC9R&uayNL71A@An7tSp@zOU@0Ja!{J{D{zG8HgL*u{ z?hAa;Gy1;wD7`L%EQc_wv8%0RV^dY-w6hvFZ(%HR8E#p)+7#EHO~PFaEF{}L>+bfP zbH;fIw!dNCRz+5BcBI&gPY-*H+2w`V!)Y`dXotOc(db3xshv96pf}8Vjm(OsW5@)v ztWtK?8p+O!GQHK$iE|FKfJ&(sWhIa(`@-sLwsn9T&-OIsA=!>=VI=IX42umwj)sty zL+p2IT%}u{$$ALWxUbUByKHM?`7sC^OWc0WgZrf>I|t*M((2%j_G&$*Y*d85!$U^UE;_Tu^0L_!7#yIG;QU*NiKsb8d(yWAfcj>ihZ zJc<=r#cubtUMF7*;&VE9Bd`vz@wpNF5#U)sj{SDO@9*n)&G?DF?w_XPbNBIwickBd z_4SQi8xE1MlnU)LF=;JC-wYC+78hF#giU3PC5JBEbo9_v?o zl`dPZ0(^Y}UuCiN>UieZW`$?PMnz{TA#myrYx&jxKFAk0gWm>x1+en#1OFRP_PUne zfqRG02NUqbm-PEVwU*5%#qW1&6=Q^LElleeT!^W^eRN~%TE}B*%s!V>U!>qlH+pGe zT4bs}&#Q`0h-b&gMdI-z<7Y<}b6phAjf{$T@rm*2aqKKObNB}0=9=txP4Xvd304DA z5I5IkzbkA16;RgRtQt|ou`Z(JwjFucdiPi0uL1`EE4SDizB3g#0+8bzQ@?aQpyhMX zL;AYY=-uYnFnX5~$TICIJ-l$GTv@tq9U9p1dGV(%1hUy3dY}80>pT`6=fy5}3$Acu zcd*0mzZb zhutq$z2tPmVd-Dbh)3^=SD-L{=?0djs0{lNYdIXl(jAJvCi|Np~*%m{YlKt z80n32v!zM3kd0kSX-tLOEO)$@EuY70k;A+{yzYJ68KL*j?8>x%O~|x-oL2jF?@bLjUsudq&HO}GYizeyyCicoSyT6 zEVkv{Cwmm`L_*b!;0kiwk_E$AlZ z2W|ZS6vY2h@SB0#0UQ6{fye&rI}-poicGtAK>JU18U^Xx-4JN4a;VD*%6$x}kyI2&@_n!|Zo(q?S*;T^#pA9E|6)uyfPlXe|(AeH^ z;%6FrESz{WT;`WgKoWW;(M&hro8aboyMT1o2H#$ zf^Z%_?r`LL@{lblamUhS3QOD}Z)5iP@lOW5RDT-TFX4>{=i$;wj&-B%h)6WdHr3&j_?93x*+g2YUc?_A z%0*mdbVss6th^Y?rgJid@x_FeS08e)_2^sRQXap@)ygaHpe~OmbCu&zMn^D~n8V?ElJN^03LK`Ax}|IIlBjZ8 zkXPFH6Z$b9{WwNtmK$g}OKkq+M*r+aj%K5c`FZmqv4W$*M~9Cy`NN|aE~j{j;HVX4 zIm~FtMe>8LkaI$Leo2V^MsQ)0M&Y^pyY!k|z%mw2|Qc;cn`OcsU0dv5e!ZoHEHv{(=$drIz8e&QE? z+2lwpGBPxxVrI0$8=GAfot;)P%t|X6rXzzWJ%@~v;Z#ZnB?+mN;(oa<8T^DF3RQ&I zVwtibs-=Ql^0ZtI65k3FDcP4Q@izJlShX;K=vFAoj&le2-N1JM+YfjY{2gFH zMmcZwcldV0$(V|pTbR%#4uf^)(kA%0Y7@NfIuFLB)l?i=6&g*6W$QOOZDBW;I!Y9b zHFKFN90iYJQ_(7EueP}M=CSVTMb@f{ z=}lz0%SA5c$k*|zd?zRmPX}KPtN?7h&H--(GRqs=?i)T{+F~m4a=avZlyvsTF*Ahe z$C(Xxl7^4H(6IJ{hW}wK9JmFrdOiB@?7#C5+Tnm4`^V~bz>%NU*S-JJ<=_6(wcTpY zuZL+TYz)+BQ2xbYP_?o11k<}4s(dsp)h?Aw)(!Qq{++)T(^K@u@Asb$z3jXD{hNGs zc~ak9sqd=Qv*NV#{FhluZ=ZWvzH=a6>&31QMQ;ejW7%I06+|v60XDBcAv3 zpYz8*?J>5;lkU) zv7O-}&%J{tS2+7oP4m7;?9qs2_N(C|eiw(eRhUrMHChzZ@Qa3lWU{DH3}{7*$so{oiotIzM!+pY=pI9xho`5-sV< z4rTu$9Pgn~m#85Nji3Z9_9uE{nS@U#BouRVV`HNsHzy&hG#9!_Hu4*;bK2L zu_QY`9Ljc!OJc?Be&-gbYgmN>t?Z>Dhs>G;@q+crG7Lg zQIeg2f**;I+Ufix$H%;p6NI0F=(xnF6gM$9uDB`6!_F1=i$^Dz5DR7fH55xmz-NIU z%N{w97s^-Rr6dt5Acpyu>dsfK_bJz_LoVgs46lZvo)}P&UshD&R{C>7IVe!IH^(g~ zJ*F%f&CV}KhI1!-`ChqOl9P0+{gT3&6T@D;x5%5H{(W9qe#!VszKi*BZ`z3YBgcW~ zgkyOHxnmOQ>ny$=TT)nBbm<6^>>4?!~qq4`0E00z1;ix0V zN5-w6IBvqH+{tB=vMa|;nKi9+>iMniz_I7)jneN$pl3BCNWFIEm zBqSjrfrKRN+XOO@KuE?U>?mOmh!7RoM2UzJ1tls^dB_q41z974qDG8>7@s_eh=L0E z`_^5$C!OGX{(k@eozLl8cbU3Xr%qL!I$Nc?_~%ji7Q5I1H0O2rglNsGyi-&3#;>gf zfBfC?kMg*;hx9wZdq8R2dyhDzz%;-+0=YxDKH3w=?fr+yRsR*AvvM`c#f@vuFHbj2 zHYn-Dl3qYLg})@eD70JSMI&{Y5!qtM>%Cu@deKO}V3Uj^ymP|!y!q!J3b5z-u)cWm{*OClpo(f`fytlVr*| zCbF`mTY$z)H6pQps;LteU*sW{e%p+wG`k^r_modt!7-zG?$?FlmOP|y7>=kG1#1Fo z&6J25u91|nNSj!xByQfZx6a4I{nW8JxHs+twl@Wy0>XBG=AY07D!b1FdcYm;_;|R- z@aMG$JN>h^$e-_)|L9-Lcl+SyNH$|yzvg^2#vY~)h|m&4tb&}(S-t+l=C)u4TsX+S zE=^nXH|6!Z*rGoyyi?77zsGuauJRw>;h!$EhP`&fhyACY*CqbrQN#Y@OfUU~{r~Ue z>tS|Y61P-o&&RuE!4_AT$<1aoKGJdErksd@7hXmEXo|)c!fp$8p&oC zPPg1B^H#nlzcK%mX@1{uzh*{O^2V9o@6&jnM)Km!ubJ-GP4joUu}i;R=*|gA%dwJH z>Ji(UKEG+lOQ|{5RK!&5dZ0&T6~kNVDgT{^?RY8GX2Q?05NNa(e?d6ggl)CRyqOov zOj0_je0~JKu}ejrWhEUZrf(R==S}x>rusc`hj_$D?$-0Md^CR}nhNthEW`WFMvvpobh<0jjuEvZu5CMwQ6o}or{nQ#vRciUmg(AQBzXzx zy(?T0#O%n~HL%)I{K2RuhZrm=-`w#B6_2$O)p2h3nzo zc|ea@laa71JBE?wAyCl-JYAc(lSC>%((KkJ#(U&J(oTI*WO|qd-KuQfkyi`h)MSmG z>NW(m-BsrWZ_i@ej2Zeeqksm~|L=@(7nRqv1uA^CekB{JL}(0=G;h(VuA3xj0jcXy zgz9#}gpYVuR2Qq_`C`ovMQyPVuP@g9&}6$$7c{#gc8Hd!ZZ<5n>YaMMAx6$y+Wc`z zxmJaI_<`(aPUZPIO2Jw&4~6Ri#SDA#{SG*;4CjSInG(%MTPVE+b3lU;m7`4LO?!j# zJi)iZaq=gmUj|+Q!ujI&Dy^H^qI>-DF^o4j^4tEk=LNfA?BRpwDgnka7WQ!jT)z+( zXy-J@qu7EqkZeU5t&@?o!dd(0t)X@wKgaN`5I-A9p9@?Fgyn(h z(Jlu*Oimt@r=#mY?zuG-tVX*AFyd;76qk5<_{Wyu`!A7qc)UjXP2g=H{QloaqXyT) zxH#cC)NcjfSJspu1b0-iB)!;SAA&6?l+{lOA2mi40Yp6FqEqnwnB@#Sj~paA&`WcN zkB?1!E1b_?C;dLqX_}>Z?2Dx5Sf+LvppNr?;kV0eKljhgfAP-)hx+qa?sR`1Q+6>J z79F-?sB`S1bt_hC!wqFh21lhQysE;yoZmSX*8=}#_1|Z296V3`Kfw~i4EKT_KGpy?~n91nW|qF6Qb45YeF^(o5Xt5XliU^AQGPt(Ilf#G-f+VQYr0O zfvLeKq2bIH(Jtpp*=(@KZZ2AMBPmC3Xhn`Qy>Y&MyL#jE{u@bgC2~~zqYU@gh{R>W zG|g*-dAs0MdAyyriKm~4Cd|*kPB7kW5#~YBLHlMAHO;I1TbKIg3_cr%DFm852kzfw z6$4A#<)-o$C7YF13~}{0!;qHa$;nz1l5-ARx!h<|2AsOyjjCK zQpdP5S8Ya937JQ$M1Jh_twu#7%6FpPN|OaZQt6-akrXRAk#*SN-Q}x-=OI(%$Zk<> zbm`4j9V!O+@<_YW9rf-AhA*?)u8yS4sF8pL=N;3DMV)N4NoJL#VuGv|XB#!1%%;a` zWd5m+tas|7QNH9*icbhT88NLW8w4Z?R6)oA=yH@#m-&dPb*LL0L!_?)?g2vns>3$5 zgQKRl15n2FHP zqqI-SRWkFUBCr?Kv@aLPV=r#JM%cemw|0x86!(*M2w;k56RI;r({(Iy3R$i5C@&eVT~NmkIX`bIj2ByuuLRfjRLAxy;U12 z@K&SQ;K*8GnlSr19VIaGTj=@V^Zq?qQNxRHP`?YN!uo;8`x zW|R6}t@j_QoNyC4T_ze>orq|oQ%qY2%BRz^=`O6LJ$8U~vG+A7FP2jKkntofBN+pZ zDw|JGB6X)4^(>t(?O@gfS#`^1y7$S|X617p8 zsuT4Xf;AAS9VTdWw7TF`rTQQ=n2G9U*dd!0WtB8XrN`FG>TdP4Gna16jc6AAt|fEn zsFgLVqps7YXW{4QJQvV;?h!_#j)>a4TiC70Jo8ZzuZa;$Kek;aM9Kyx;%93w$OdFoaqRU{W-3yel$F7#5^`eO#Y#&lbG>PK0uwXuc*l})emU(JR+z!P zX3|rDK_Kk!|4llcU>pF{aYE4FZ)o%T_5FYK%e(b(zrVkB{{H=4%{Ge(mf#t=Htm*I zn!lD}xBNxKJ2m~<>#wuuuU`)P>%A%h$|R-^MKf1frGCpSl4kDMqIVma7a^U@3-Sng z&20*v5%Q_L}F>`2s!p#Yeg)Qv*IURCP!T^=Q$bd z-r|?Z_~o)%_24n_u`P+?Wx6(1h^EY65x<)b_mVU(k#ytNr5Rhw7Hp#;=2PAi`-j-i zK`eeJ4m&Sv0MMR^rdR>lCW_sd>b9y2U};jCJ?OT~9;(|msJD`l1aHxSy>9D7qMcqB zQUBGXW|L$lVT-0*GMhk3>H6KbG^5y2>QUu)UzZh#&9Wfu+BWl1maeEeyz0JHWt+oy59`7dovFt>*giN?tE>K(v)-Snm&JT{O)eX?vyrv=b_!RmT4omA z_{(88{)Xzt$2v99NsL2G?9oSMd{k^TD)&2OsSAHXfM9Pf^a#Dz?;mcm%%_bZJr_6> z2>bCy()R)nKI->_+k*bPCb-_OAMeu{Y6hNEW-N6;J22ZzW2?oo97|g)>=0B&lf6h> zIuMw~;Wb*#`bdYFhFgLAiE%YtuB3W>28|g^m&qiB1SUbl`J;gYMcZN~#8uE6?YKTE zWHn~!)z*C0M}5q6jnPIn4eG=2Wy?VUKaest+d~NBGU=JX93ZH_aSG{A1Mdd*9a{pu z&8{bdabcLkGy| zw_Lww(mlX*ARPbBB>f8@lJ>_xH{ictV_~k)^5D*(o&g`;`<8zlvdxMQM|`;P{IJ4^ zd%mT6!k2m1>#C^_W#GF>XNYUk9yGgU*0!%Q8Og3RN5U0f3?f$PZY=I(h50^PeNv%! zskB=jeUzG^%*WP86%o`x9fgdYs3C2@@hRRD#{dW;$vjC9wd^Qy;VZdQ7II$KLn2pg zM1sETAeQ&gNZH^@lg7kI!ReAS`D_EoY%{A9rGK&`>^zm#iEVr+{qH87S+U6{o*mPC zd=G%f(9Ypv($@gj17UyqBI$>LO1;?|JNChAz!x$vqHG$*HnKE3n)$H`k?hNYNM|pZ z41fsYZH%5;Wy-Ejc?6_X?9_=VQb#6`up^Ples^e~UabnZOQr|?pRF82`fn#a8JG%$ z<^3(`LU#Z1?h53~AszV3r!_FQ%hs%8O;gk6;ulJh; z*or1I-O!BbU2~+y5RqCV7GsYilr)w;PM@5d7g-%?vz#c>GxQpWSF`PrE@E)XC`xrR ziP9DW8(S9OR+Dkl$YbLeO*ENNn%>mWk;uXrb24wGxvqskB4$MIR?JmYMn=X>xWB1p zBFl)Fh$J(-S>?Sq&ZJbOF8C0_YJD{86PG@y!5FN5H?1ev; zgkN?fTiiLC+wbG|$E!r>a6`h~Y2AM^m&fdBT~hOJ<>f5gH20@h;y8=`x*zF9SM(upA3XuL3H|5$fOf zZD)TUo1mrp*LgO0qJI?U7PQm5#qWi7CBu7~y=O6jNV~ShT!_Rj<}{CPZVWmNT0qtn}@jVe=11HpJ^jVFC3a3i3O z`XG+>)4%lb`QT6dv-gmnMZtL1A3P80xp?iVnBT8l7gTYJILp%$+=9{|roAE-!gG8{ zFx+%#7fq1)yj@i-9s3Bg5#pd7B4%5(NbkeHARwkXC^v)e5?m|W!YYwL1kM%liO4$< z<)MIfEt+I`Py0Ctn!EvNtSqR1QB4Zj;@p(1L8ySF4K&9)}Dn zbDmA&LN!2LA{d}v6Q7sb-$l{RgI(m_%}&BhI#vNiwA*ebnQyAm*qS2~EN+=O^r)$@ z9_YIiKY}`^iqXY1bG8#nk%}Wrk1!sgB4k>Jk+kEnI=_-_#LaXNX`4V&clE=F2S{$- zv1yK9-yPJYIk@**(stg|5l;^(jJ-;17ybtWlFZp;MQZ}a9{#o>+Hm@IDDYVTxLO5?POY;Wdd=fEAyV6g4 z_LcO07U58)9%+EQLVquA)`1u#H>yTc=tXli?GV2ncCBBJtJI`GdLl3j2*=6GNWTt5 z>->6*e$FrVgHHwLpY2n;)Q?$qa5=BH)D&2U#yBc-O&WYn&aweV6V3~^2#nwXi=T|22Kj$}lvTjP9W%x9## zS(+`jUeg*-NVOb^fmtfBYeH%YOB{tSMB8EH4I718%7`gtEcPTSByCn^oEmAQTXU@7 z(zuMGaMF{QKcte#3WImZZH!MnoyI(d-m_&hpP6KiiMBd@2vPFUq&p>AS@2XmLBq%d z0aAo?k6@N)921~XO)quQinOtDdL4r@_9-lNXE4OoC$Q+DzeL3dHEK1<4!zCj)DwJh zhB1Ps^dBJnI28pXTzTr9469q%j>WyQ2sOAjq z4x@qkIAv4gh{%SlPAzJhCBb+1l4rA55>4x9FtusGEFkQ+t4V(f_#&W=%K2{1v-{Hf z=6(CEYKb|6-rk^{V}}SuGoRoWq3&Rxhi9)HBGv}Y)$;`bPLi?Tu}d7~1ZKKT^k%MSi=ujb;4IC4D4t91!AXGwHj5hXHj|`ZKHv{6D>i z{Ja*72f;Y74+@6X4SgtjLgZ{$$Qe^Y44z@Hh$3qi_BLA)S;;^z#pw{Q(9eh)bqtGX zrwuxDCmNJPdFK@&`vD%~=&FN{|!Wz;MgSiO5%3yqP)uZV~x9^6O^25YzPzD?I~0*NinH!UCqL zCSx^~sO4xM9q`h;l*ky$Oe?2Hhoj^ySslqBk9TAt7PTw{V-sht9-BmRPqj|YG3pDzmL74IQG5AIJl2d^T4W@WGPG$KpX z_@|!EU85Mbt>PZ(aUgx(ui{V?((cCd!ILFLGu`oI+>K#45RbxC91K}RXC>zlF&7Sk znH2H74zcLMta1{y=tIC#LvkdNCU_0(BiSscgi4cjeiFG0k~z#GB4)GUAl*~yGXe)% ziC7h%!19TwimlD*6yUcfI9Ml zo_l-Xmlo=I!z?!LKfZ8X`jwUKjWXL1^j=Ig?7V-)7!eCpcifu-w_wH5~xu>)fcOpZI;?r zqp0{U3NNdZXPXz)+fHtz6TM4hwh38N6U!HBhRY_?$P%JZOcE{_Ndc6jG(pJh%u%F+ z+80%*3UZw&d*wVe$S>mEWw0(w!}1O-_3^MRsGqvO<8Wf*bA3M$&ZFNW{VWj9pOxqG zJUUL>Bc^IY4F*nt%7Vh@C~Lw=v_{!Fu-`-Q-R6;Hc||YjgMmYU@ViS$p9)mU2|{^A zFdr;EI?%B%4K?c7o(@KPCCB(Lu~hq5L%hjIrAoyyB@(~kLJTfFA%?pwpbNek$}e6Z z{cGSgAS~D0q!X?Cmn)?E%5tsu%jL7J+5SU4R@|X%*9q-5r4Kg>R+G_?i25sdsF`L% z@MyT0zZ#+?pk~DSs-zA0&(fM4TZ8hhqAcODp7ck7OMtMvSCGCHsBE|W_#kDT(hKI2 zVD4qHLc0#|+t43wOl5kJ^<_U*o*hO~*`>J4eZ1}E8{xXyZ8Nnxpb1drAl!vMg7l%l z{onNaPq_Zi|J1)O+3k1;RMVKZL|hPr^H8=Tix5bTUQ8UO8wni=1f_#tL01#ikpUr& zHDV1c3C$F24yK>p^xOc?KThOX38I1wakV`t_cqEDmU{>3r-0{xu-rc(ZM5%S?$Q6c z+{_|N4x_wFRe8Thd4Yh_qFj_MirKcowgdnSKSIVRjUATUjwAv(MXfw$-;!@S(#Q7z zWttyUW*zA(fsX@WyZ;C2cY!ya_wm~kjMEqW)4yK5ZtPN6%UK&2u@#@1^tOvj<-I~| zN896_tb3ufH^h&1?G*;7Db5UpDD8&wmP+b63}g#-@=3&=qbxS)OHZ_|(v*h283BzN zoQO%FM;qhq%ta$vH!C+`47=mGSR~^p^|_ghnJDE8@tEC`#R*G#lh?Cs63ceHan$d9 z##p_Tv&TAkwH-J*sDDS9?pKjM8@Lz<>wgF7y+9@1hy9fLul8(^YL@&%r=f0AalhXX z&*}0=WrfstvNa<)!=B;H*kjF*egCwM+!RTR-0!ShG#AMwa%NrFoM?(LYs{e%tif36 ze|tvK>%Ff!)orL`)TG^|=de^c5V+h|Z{CFZGidYX<9s}<>MY~oW2CPEt_MnZApJAo zL-7#C%UMT6JT`17VdZ-gtQ-$g_KJsft^Q;=gTFqo0~+}IU)FzkJqHd{&9G|62Q}M$ zykD>Wu5!JWkRAXAfv{fJk$w>f$B`2Pz1gl8efkdec^-S}x}oz2*Pa7`?+{z%BSP#D zXFLLBza{R`wL^;t2SzYcdVWg6w8tf9RrNr*PIWXk8x0WKX5_5`IQJGwkTq6Guv+y} zdCVz~LNNOXOxoh0+G!0&FCIK?j2KZl+v-Yn&1{^8 z(xfL>tgqMW%*jhbiwGRFPdg+0IYk>Nq`dnwEF{0 zr_l{(NIWoF;jhB%KxRkOd}V+?4SqOf)aqZAn60QhbFv|q+8 zPtxxI?*SoQ=Ek7!0QOYagBthlOP9+AHy*w&*l7gi?Gfm0mk?L`ZSj~OVi{a370o3x zkqElVW~I<5dkAzPo;d{eHjv)qc!F?lIwD9lHf$R3%ejd%gnW$h)BH5oHvwTe)jb83 z<3e~H_Mi0|R?JdSWO2j%t7y@dASpGHd}n*`ojv3k&Yyo#`Hw}%3xwavknRRTzAdzm z?G60u!|$x#xQ+<#$jUb;=C}>!_+9a!(A*+)F<`VS9^UVR)#x{%0K~Ldd(+B+kg_O` z@@dm@A~s&Ud@m1ioXc0 zu_zPFR;=+bYSbA3bjj$myoegcKoX9U(;wIyS$4MQ z)4%~DbR#d~s`8so_3P#Kl>1F1>50HWKv=J%NM8cDK|cw{_1(d^9@dL->fDtO%3krL zFZsR569e1IZ1z3zC#j7s!YdC-nVV2$P?0ub{n@O?8-!h|5DYErW-8JuT2Zf~?e$E1 zGO~%`xF|wzB6%IsGsKb0krh|rW2d^8rVaY_d6%*d1?@Cx9PI>L0)*>FXS}I>9e5v5 z$9sX_jQ00nd`6h7?l&*=?Y+(`*&X}iF)EW;8#k_3;fWc9{d=lSmuy@=tVP2o%2R&H z!JZGye_NhW#0B2(9Pf9T_dD79J>UE7P|hjuppaiIc#FvLNY3 z_TwBoUd9GkTR&_@zhR1Rn)o!1Ml=hjZ7P3^@tLUQ#M9PX!^FW%34o*3RaqsuVBC~B z`#8gu@jAWM)Lo{4WAQt*tI(6zm^rxO_6NoC?~3+siskilTbW8ziwaYYj~)}>(0;~@ zW3q+B$Ax_;NcW7xJd4X_1a~+zAwoeG7qyk47C_g7a($SZJW1kxfdsxLksFzHYco7R z5?@ouXGKEqOnF8h6^~qMd93$Ix?-xgngx;LBYm*VB z->;F)RaN!vDs6QrDceF~c~xWoj%SJfs$sR8%kB2aov8gq+-Z-VMCp8Dgikobr^lfQ zWq#>m($@gj0b&2TmGoDDaD1;khm@q4VnpIH>$a<{Wmq}CCyv(cGwZ-aRe;69xm| zTrNS0xSZ;_8K642~asN-4@t` zh3!R!*RBh@XAh)9O2eEw|O#9|a{FH{4n zPbDKcShYYkRg@o9;hO?V+p)$k_g>1>6Ew;Pq?40Ptqlm<^(fNk1DgSLObhtTaNe(M z*F}}>dg|JZN@Bf5T!sxq*oK>!mRw^h15-P#n8ce*g$``i?lg;6O7}83PPOB2RXe_{ z+VPh%xl6U05#bh-a}Wjh{PYDYgScX&Gm9fs6v_HS7(CB?(FzfINFU7#QdLN?1^26h}3c22%IHDN>aXLB#oLEjjHDj z`AfsvWw^gKtlfBwDj&C+tF7pjmU)F`UrHW6tsp;VS|x1Tzw+5Nvl<*Jo#~sw#*6i zE6?B;SKf6#o>%pj`^!0`F9SXcgn0e|>DPh30O}a{nm^BmbQkh--a~#Smh>k6cyjO> z7QoiUrTZ@Q^3Q?$o@(czE#`T1e@?}#+Ih99A$a8_}Xll@Ch1gmQ=F;+@L3!OF z9}hzZ?T?2`xc7gHhxaP*aH_(C8dmSIi9+qnr{AQmu~*HOE-VfabI?NAvE*x6lmCyN*XN>rIHV)K*OUc>#>x}{U=ghXOFbK z>6&l2@jtls9=AlZsrXVxpdx>EIh);BpiPU-kI$%zc6ePDUaFf5POwq>zDa?Fp% z-D~5c6;}V^g4I8|Nu%ixZW7$-@=vbymg{o=uPzoy7-WT*q;spKM!gurlvBsTBkPUP z30W7i4M~Q_(P;Lhkwy4$oWj&Z$gq!bV9YS)VYFAzts8y(oHxDP&#oc;Y2dR!h@Y>J zeggP8ppJMzeRALnD5U!9e>_eKB4f#FmSTk0&}ZarDQsr2x#sa$7(NR8@>{E z?}_*0YUI^Yso>y>)f@~EHk85J6o^pN1fa|+NbomKdM1S25XWjgXZ!W&pRqqbaTxc) zdi=Zm#0wSU#j?S{Gqo>Q75|ZNKS+3N!tXM)-R=wn!>=;Qmov28s~PLHjLZE!nP6aG z-Z{rF-)_nh_WO_y|2V9C|64lT5zt{Sh#M60Z|ANjK)JT5&Lgl_v+iqIkHDT$;c9-E zhrk}qCm$oCiTqLCdNS{F|Ji(rz-ZSc=lbQ`JhQA1_zdYU0S^Ho9{-!P+mB8LP{*Bt zzBZg6EBUh9D*DS=XRT1SK|4@kdLz@}{>Y@*vePO?rDpA=y5iSz?)Kax;OkMj23IuTP_g^bG4E&D3kt zc|JaFrk?6r9e0tw4|o~~@$oL{npyC!fI9xC^~YnC_&A#_R~1GAiB*|l=m8!3G7Rt5 z6`#quJ9DF?`CWyK?I0ufwL;Zb3-Vh9>%M~foq~10Ld9^FVJ4`^G6*Mwl}0KYF6LD- z3_S;87zWPw@vxQpg|@o)l70mE84%(@pN$O@a4evX7hdwmfvtg`bU04z4*W7kR^Vaq zJhqEajMH}U8J|I2;IpQRG8Ti1;cRKMwx_=MP?fu*>QHIkT?;C<*208-uD0sdTKUCV z>&{yDu3BqbZ3QaAkwuLzp5a3Scw z730x7wT%Yo+9E#cEpHa6C92QRsCj2!!ufV%@#8h_bv2Wu`L{Z-^~X90=MQyNd+Ow$ z>a4fw+`rUWf2}(Jw$vCr;=>3?;iku%oykpKpomW4M9nw*^PNjB^zpKX`i6A$SJLr0 zjN3p+N9U0KPhc0Ij%x!w%te8oG+gKGKE$7I7FF;+ivqmt5YPJq%qnk~sos|XnhAp|P|^+}`lx%#T7>*b5})=%r*pVwQz zsP|VowU;$UH#M67Y_Q*J@Fp`Ayca8KOyR?o4m9MgcGMZ9vf@eYv*N+f_&_TjMS4Ae zm6C3fVQaChO(f$O5tkXEnJ_{f!`3~-{tMSVJ1_F_J}`HGyr0Fre;4n~!94$11>V_8 zX`^<(Lf*X!dD|88KACrK&4auv8bIFP74qJxuX?*)zF%*BQ14#SU|re}An)$R=(a}l zu15RLMyjQbB_H$4tFt&p zh4{EsUYoo$Te#I8cZH33KUB}vo37D_Kt?G`i;@x)J;6bXr#IbUiH^4)!aeB~jf zZ;2%b%C{uU8lG$3`=_2D-`;W_-hMG&dCT|2`~&8zgek-G94Zy0Kgf4WIge7lUoYPi z%?HZ&R3(%cp6|6H%y>zV@1AlVrF^aV;ai&MIAFeN@i{!-n@jl)1o`%t^C;!JqI{2# zYX@kza8Wxv>)ZUShk|@>F6U9o_rCHy(R-kLSDrmIJj<~ar1}e>n#$7 zXa0nj`Su{+z2!Vg`6dr7RZFZoP`+z6z_kz0b62UrJA!=Ym-8s)ds_LP*mj_NJ!X4& zzW3>2Np=SLZY}3g%J-r2J#pTF@>R_7@N6F}WvlHD@_o0QM=9T$h2hsVvFU*MdQ9f< zoOgsd?+x-@QqH54@4E6m(SM+PeWq=AzE6kwYMcD=aa%c$Qoc`=?}=j$l&{+ClN~CD zXS_Se*bVa47M1E;%D1_EPYfL>-!=Q^`$mv&bCB;biqIh;Q_x;#mJXDF)A_RnKRvt~y6Q<`&* zW}KrYF`_jPz%LD(Tg&2^sK#xE3Vd(r)!O#3o_s4T&wA1y1vUX;c`hS;EAVbbeB+6M zAMG$ZJ74grCNxjWh=tuKOn%xHv*G(1%~<0XC`nulM<>iD3Q$!jzN12A^eYQbbu?e% z)5~7I8J6on`vBkcpN94zP#LGg4*VudYu%Ey?+-^{Q;g{`!GCt0?Tu#cGIwGQ+cZ0U8;6X@0M>MC|{f~tE#>CYcG$ny&Nu3A2Y0gZC(MVmkKyCEa0Zg{qpUkEWIj2 z4jgT@8-QDYuzWvVifm;W{(8%OI?Dxd-uDFlRh$0dub=%K`0e-0r}obrOKhf%%Qmh& zc-7f!&(yp-t2fM9eLA7gybFe-^&2-Fy?W!SMeEKTTz~M24TG9AdcLG%mV3}Jm{0l{ z<=670`Z*rBN+qTNrvU2J*}?UtC|-K{fGsM~7F;aie7X9UH`LwAtnXJ(yvOPvKL(5h zFaq2xA86Ky+=D%>eSvkpG0{5Bk+ZB>)+B4ZHC^_Z>TeESsD1s8Y_Zh7D5<@c`KG1+ z)rv{yO^X0H8N;ei>$&NL_^$;S$kEnZImbM0N^}VZq*!FlF{WE>)^xqE*^<+(=@%kF zKEwH_a)+O7)f91_mrkur5VY56H>YCsi{Dwbg+ahL*=N;EVWURr^hi51Dp70Z`Xap3 zL_Bt7fN;iiLPQ3R%M;3w}BLcl|6+=l|ZJODNg)uawfeofUHlu>avoS5^5K>*x-B zi{M6weh?Qq{VvxkS}YH}zU>1~qV zF#ajTCi%Mfr-y?7w6rVPkL^&%6T8(8uX$yLLm*yzc!Q1)tam*PsAqR?-J9dTK#n|My!vYq0jmFv5zUwrv=iT zz*r!}&wSGBfF1wo<0G6$cLj7)#t+-ILoD>Do$^oOIXwPl-*aAvdQob-Bi(FJ!K8zY z%gJ&cdZ`h(D&XiE_K03=v#7GjB5_OEHQ2d0kya{JBWrxQdN=l?&2o`!Hv1GirS1HD zKuJZC7CDSFYDA zZ?Fhz=iOd$$_C64u(K||r25E)!Bf|*UFqNK=vofVbdFuiP5%!6bTq5xl`Dwl*s{a= z#LP!5vBSDvK7s+qX8Dw$`ahTK45`c2VrvX1vX>Haq1Yz*`HYHY_+4GwWREvat{$^Z z+ILC$w9qHn>+P$g-lBKe_4YKj4!9`WU|%iGi-^g{OBWIhsNKxM+;$TEE_;xS-YN5+ zlhM!1{3m5@GXIk^kFCSfTfaeMJ}vlFlTU({h%~w>{`qY4aPQxX9lL}xlg&bTXo@LC zyV-8HyX@}>Gswg)+RxH>9Zh;i8({+3`GuiVx!f*eMoAku%rnB-pBVoBHfbGik5&e) z3FDLwd(<3!RWUJ)&QZ4LQQMeFmq$n0ug|0i))Y3_HCm!fY zzRnZ}pQx`Ii#0s;w40d#@D37V6xRRzx*)!82v!koS@%(|#V393eo zeft^z*}LCeHX^S}B>9i{{{Mjl*XXhLzketA3b5(!|CC_&XX>3;6yK_LMse+1h}=l5 zDcdY27$(nlZxZGWvg0nf#2}(0{oxB9Yqo5g%zjOpOPqAe)vqnG0$f)R-+#j#cG-`tMvfz9T zW}V){(~a6lzcGi2ak7i4NzTqLsLm%aeCBDRakjpg@Ai4myZX)8bv#`7}Ik z%zJ}vTuN``63MFKv9hBjP6+3ID;u*2L`@EA?c;qR(O5NN6ytV+xNY7!z{TnQRYcu8 zoB$(K&`T%u9{-6RR_F8p5hvqMa*E2ye=l+(>61%u9bvQu=|*FbF?U#c`27UiCwip_ zzEw?3F@+!ho|ijesX8LPaocD}by&rge9AzwS5VhcY8GOqDcT5&bM5DnDK*X?b zkiBA+GA3k?(h1Qj`BmXxI$S2I-VnUJDa_*wB#g}>*^#tQ_AwAQ%Ii$d;|#j$xBIJ4^-+E!)uSFI(L<~-(>Ts zCehr}WNX*TbG1GdgfY*uj1Yiq5f#|EC*`t0=qZ-hUmoB-x%x2wKzznAgg)v>Wjbk6X4ySpNCHg z%d#b(fKZlH;|O}K{DIK!mqja2q$3qyt$~nAY?%>Z0bwidinvmtD%NwV@C6sD#6$wY z9oRDwOR1O@YT>X*&sZ6jsi~-nN;dF4AFsVD%jKU#dNHsJ2+Mym>5G8n6?Wy}K6hUE zPhaO3KHJ}ikiBlELg5Yk!Y*(;Z)hdga1E!|(7X=~TXX7xp?w5!+q5-UpH`Uf|auz zqG`%ZqJdx`GM=ttuLMHE|5WX5HbJ!ett~NuD`}pc#U6v~?B7G!q91ynqrKGP1D(9DDg7_L< zzdr4(jh+zF==lf}%P5HS3qrdzuFSsBJjLUJ2t~wi(p@EX%-g9nI|1OMt-}1Wvnu0~ zTr3)(SUQl}N9b6Lq8t2X)taC1%c-4Fw%;v~9;L2eJ}6;ppMFMF&D(24YJjC z1$M|@`DxEND>e@LZMu2`p(>aqjh=gyLSzoG0LW9TmkjO8n7CJ4j*3P{gE>TJ(&My= zN~?H$+^Ho^d}kwhaP&~?J!AeK3<9iFw-EW?B#0d%KN9g!np-^k;#u1L}A>@M8)4LFf+NWaC~)i;hw)@w#bQNoUy4f^<&L3a%?l<;ox_WnTe@Re`;zy9`|y*=ab`w?J+!ZhLjx! zWS`@37^(x0^9Gz|aRp$su4mjP46rg-S8vusPEs_hvbj(B^|jZO$FFA6?Z7A?q~i&s z=K+=REi3q>a=k(^soD+Nrdmt22dK)}(wt5^;>L64wi3YU5E%Wr;&Jf<}#q z(}HQo*em1+_6wVe%R`MEfu4DuXs1PYKjXLG6W}7`bAL}-tTiS#)zKFcVY5*|i{_Bg8k2{+wU0t&};e*PB;r+9O;) z3WW7~j`UmHudG+N-{pSwIxVcxk@!!k?xx+Rs|dw##wNQ}(=M{fjBEYD_nX(1?Tim1 zJsUU#2)}!I^3sUoVI$+;Ih>h3}RYB5(@eg7rD7JX4AKX>j8IVrsQOW&L*zpNBiT!n#r4Uh1~w z9M)7#1lRu*Jhb+)B69Isw&#&Byf}HY3~e4x;Ehbd7<`CnAu%tKvpia+oI^kM%Q-|D zLOs+b(jN!50AV>lPx`w+^0wI@h8Q>Z8j%a5A_omJA8swFy-t=9MT z+byxx+9JKv4#zuPBD~Y({^?Es*+JgDqUu^W!U*)-?+p9-v zkD+Wm`Yb|I%lJ_B2Jiea6(AvTj5z`qdbcKJw3r+8rOL2E%D#G{YBHY3S?Js7CHR%L zW&DK(0MB=Lsy6<^Q>gg=F|)DxOS0}ZY2Csb$vfmU%f4IjFf#sinfiv8N_}13{f?i0 zK)MfkDf|1<{(+ZDJSpvGyj1d8nM@MTGMk7bI*s~#EHTlHcgkc&Pgh&Tc>O<7ven3V zpCjXsNmglB>t2P__0zI}EsZbK`yQ8SW1oM@2|f0cvhNXTKP=66h~z;Q4h%2ch&VbrTHz+-S^1k z*VOsTGI^J}zg5P*pssI~$&^v7Cs+#@XM~ z4><+e_T{!s^niZiD>mYfSs$EF;a(kk%AI4UBa2Aq@a~vv6!dzhCE6QL#~SS-E9QE8 zM5LEFBqN%v7SS3XK}?QB#KwFqZzpmi5J(cVG|?iOQR8OO!x;qgQk(U47_}{S zv0)^HChQT(4)5IFr2daGtC_Umou`NlI@4%8lPb6haw!!Q!|qx-&KmDBJm^!}CiZlX z(2wnlOi-2ui$xRl&*wXvjVAImJKOZu7`b(J7@Y}ybdS*;BY3ttGdJm-6O9Qm>O6Xe zG2KQM*l8MsnhDBajG%Sd2vFxbOq=Wc0dc%BQ$C>Pw>austVaCAD*GiN|4R~B+lH{& z)eH{3p~>+cy7ROCd7*#Kw9D%y@@q1H7veWp^slO?$ce3mj!b)@E7zGHO?31TOCy%u z8EsQ$MzSt(?8qYu!~V~BPq4XSY^9A{QE6`vEElbn-q-RUViGn+l@4$i(U@^eLXRdqf8RQQEJ?P=Ce5O$%jnpi6N zu{CT~RrRQoo0PRP6VowwQp!yB;%U+wOFEO-C$bmS)FksZVNB3xvn^~-E~ZqSEL{9E zmQ-q-UGkbgKHqKAJrR&RW#S-7pz`; z+B!7~&sn{G@%rOdD`&Z_;+wv^?fw3VK>uotyi?cSMszXf)Ae$Zwp)o1oM;i^9x8{#QX}VW3=wiKfQnP@v!9s z|Li^F=cOO}&$k8ZxC7uvp~kzd%>Vrqi?@I+A~l}LYNv6T@th%c8t+)%=}!OZbnoKt z!aHsA@BP-ln(N*B4i{<$AJi8ZZ;C0CdY4a0^}cFO8Sf=Np$B)K3Lm{=1b5gz>Ophx zljaN=yMf&$Y`ea?8za1%x`P?qkbM48D44BN?hAUgH`va?e8t*+)hEF%~w-ABgx5;d@6+iS>3{iN}SF+EBzE5%C@B{E&#F zW_(6CPYZKO?9;-yLEXJXn3t;a#U^@D5&Nk5F@8TT47^=L?0oYA^OWQNAW+7bla6}F znDnl({2e3pq`{KoLE)GVyG1&aVnp~#l>SDn3nq*;oPhd`y(U>X*kU9-P+3k@6b+NbBwK5o|*-dSqlF&6EczX18rZ0sf?WJL9Qg+H#(GOkc+u(`-nYvklqF1b8`?G7TI z$t+S|m(G;vG0;Md)syuf^~eSB@zJr)NoZedoXIub-Q=j&GS% zT;75yK!T|9`YRZf_!eBk)-u9JlW!{Tgs>;MW_D+oPZL$E%8Q$s4O5@dxRl z+tmgw!BG8sseKt)=_2b4{UZcEqTdpKde|UcuOtsF23V4d2Fy^29l^RPLvZU48Jbn( zEHyOO9(Y*Z{<8hVGS_DKblK=7UGTFl;IN4+{>HcrYqDE`2A>ND2!t zCSh(ANx+9gOl%#(_OwwanMfz&dc?rpRF7wJiA>U@Bet+MK%<&;*kIC5G_mtsFzHPu z^VMjBC(w7sB+%B&Vmi)mZ8U>OIz}_WDa)!zRB|G7tZYQ;YfS%yFP z`Ro7Q9kX}pkIWW3W*_SPeoA_$jz?yz`RqdGvpHEaSHQ%4O71e5&E)Qq+MdXT4@H=< zc0?dLyI>?(9}uPg64U$?R-xht5%GOFo^|0pc&T9Z|5 zT&hOr8p6xfC>vW`tQ(WLXcK0Y5xv7a7yCT8wWAHu`MkpC&>THQ3Gf z$ti50(5!T;7cvmRB$;ebET@>4Nh@PgYwy_kcfY+h1?`}2UQhZS;2S{jnz4&?)1~NN z0=_LD@Fk(VLYwLPPkQa5oNraXPyxBNi*NYaz$5NeVW>XvFM5?C@CLcd(E5t;4r#e5 zIWx&V2%;)Bf!`5&Dit$MgvuwdY~-#O;cqsiysTB^^0e&GI({%283GY6u0AvUYBc>F;{Z{W z!|2l9nPF8$heufrHL5is^N>K&1-tzJ$92k6z#>$pH$@`&#ABaPz|N1@)$B6n#k%I~ zQmVAai?h$6=X!lP3wWjCA0Ev*Dqqtf-05C`Yu8xlxny7LHxdoA1(~#JpWe&M^0tMf zj{=SZR68kuyOT&?3{=LEuMgKB=MN2z9Xt4uv0j5+;7OSMy`DQ36N>$lLNfr**G_F+ z>4#!>v5wEj*sPGZfWSDY{}tu@7m4P)B8X z`hz&G-a~$#7(U;2bnPR#E;&WAKD^TBIV={2TSc|z%-k#&UM2f9W9ImUyWHBRtq(X44RF%RHnj=e#BwouNn-Toi_6UU#p!IzP${I@fVdEfc}EdMFP zvq$vq=fC8ta`~rzj(C_{p9h5F*M+1v0hM+DA>Ebye6?J|n5B;GJlqG+Vx{u|H*1f91F<_1$iAaImyFb2!Zc|=@Z zyKJURVY#=H-U0jo2=Vqe()CyWUzdB<+Lf5nTP1^uDl_VERhbVS>xsDuof0p0ZQzDW{>lC+u?1GpmkYwe?;_O^Xs!i>Y2^ z`y+lmhp0nX&n=`s3)~Kb_52p;CxL&veO3;J?Q@9NHW8|JvGy!FS5>npZIhC8972S#ep(~h9L&DWIaxu5hB;7A}W?=7UC20}kxEr{oKTi`$Qq4c!= z+%`FoG`mJh zphfDb1alv8EoDtA+Bvd5rYJKIMk6 zW>3_YdZ%%alDPH24yyju@$oVq4kdjQa6Ay=;R@1U2P)g`e}M;o^IRyi|8oK}xZ{bQ za=2Fj$c3f+H(CykRA(+2g3TzAbliIspky+=PTQJ-W;~e4N0_y1BpFAPRdz_-dJQsk&@3BJ37Z}fO~SWA}MI#0I1_7O4dRz;i5MMBl8#hWsa!&XPmH0l#wCA(5E zm8HKX%{&rcWeclb8*5><6v_CjsiJW-p~BVf^feI^|G-ov>NujtcV47E+v7f7@2Bj| zLH+(n`U9Zx`qH}ATugcsa1)@8mje6PJ$D4_)*!AxkcBon;>&p}>#e5SIfENc?esTR z+4u2aIb`*~nQ&-Vsa^Vtgci6>wjX5ob+HO;!CO@ZajVBs*`|YveU7%MD6JN|sa~n4 zS_#tB+)}8jl_RW?E&;^dm;*+Von{vi+GQqFEZK{ohA_n_@(W|p`cczdEZI#RLpK(y z%>4l(dAU`_==Lf)?Ky1p$=2DLrff00Dk6m`hlM6o!93RXCVc$nx0LnKYe-)RTn>ct zns1SQ4fr#lj`exqV&t zlH-`R&jyw;b>Aj0rq=Akv6<;RZ8a=0@G_4s&K=JA#K>IvWsy8Gb`*ick9JS6j(5$> zs>!n9tZ=l1L?=SQtytL*c^+wI7*bZrak~N>hoh#!wjE+6vVvu5GGFXX5d?w25FiPI zP|fgVK>^FaY(J6f6)uK8S;p)2q;CiA0Ybd~igfL#Osxx0M{R z-GkaE*3Ab~hgD#zvxF&SyP24|QHu zcepzVsVKLR`jgmmyKY2yY{s{+*VUNA17u*0v%wBYPLP&@Zr~%J_KLMEycMJV5$Kz|VmY z5ATy6{TcQb1k};|fM3sWKeYae{&1gl;QpZIb)VDUcL*Pjg~4-HpQ^gbzyMe{8E`#J z^kNKrq#iX~_7I<@eVxuyGa-3+7FB$%Mu`szxPEMOKBh>i=sGzxzC;?V!(3#+YIpJ& z8mANv-MCO7q*Xv97zB>dkW6}^BP_3>9akCMu;&y6*2{k%NuP2NkxlbzuW9{RA8$Lr zM=$p#fvAgbG_^Z`p8)~htix_X9tOMysN=mrPp~LB@BEpMNADp&doT3yw&yD!PDe|X zVOJ&kLWT)B4CNHl!*bRhh)7ozq*5#Zc>) z1hQys6ELZ6!b-0!)G)lFk!y z(&N(lp>(T^TSV)vxFDL0kvQnWVo@Ojn#9`v;9wit;wLC9#nk$Mj{qV4%3FyS4tyO@MRqg#wOh1e@5dcS+nNpdmQ`)&1pk9{+s%XWJr zbop@{{93XQr(VppxJ9RB622$b3U2%#_TD_sj-qP(?y6pH-+i5ZyE929Gnp)t$x7A< z*&&bs2?>ajA(@a!Hj>FhRMdcg5mBO#C@5$^Rz--42*?uI40~kpK|l!zh=3ST5dr1> zo?h-uF5siDpZE9v{-Eb`x~uEeN|dVCTg;lJGE-esxC}|1f7a3@t{TMxA_K z7hlj*69jFh+Z!Mjp{*_JBx`N{BzvuSQek719iz25))xl_2S22fdvRi7SD4t2&$P## zsq8*%BYvxgyokDHRU`gQiPB}~ZB>Ox6Q2NBjV1uw9EV*!dLHn!4~n!lCB9|qoo1>r z-jJC%$d|wPNE-`~HWwgm9;79z5OSC}tdtqL+A*`k3xh%Kf>j+yEync!FC{Y1y63#!<~!F!}R}D5QBlW;z8FO=I>rHyJrckr9gxiC#?L9KzfQ zZI@9aJk;A&>*MpHZ}|HW4V8B$>8}Cb1wwp&fV95QHfjJl-oDSDXA^t0Ao5`mq=^+l%$r4+L0IuzcE_dpV>JEYx#}Y3 zTX%GHEG=5Gxw_U8nt^4>bX9k8pTifRMhsm-Jh}oq>LC$e(}Z zj`v!(h&JIZ`U}_3#?LiN`^JyJPuih4)p^V%p>!V7#yJRrKsL>@OFin#1(#kcLc-DLPtZW~#?_ABp*re@PZ-xVK4x4WnXA=fPVM7P z1Nxk{KGbC0_>*1tx;^1(r)zH*aHbN`D@rG_3ji8WijJ5JYzX9|fIN2{w2e17yO|A8 z?;k`|6yh)01p=S81EHFVJ-Y?HpK|DcUw$Gg+qNh6nx$VLj0#(=}hT<~52bq5BNg}ypa z$`}TdJ)|U7G&VN-_1Hlf!+pYkB)2=TLUU#X&9yi9&KrEE806JlOgt!{9SGZNJn6YW zdAxxzUQy}w0fjJ1Oc+Pb-`pQ8G{5m^rk+|9^Dous5`D5kGwTrew9e;}i5~1QW*YWi z(mV~UQ^bp4_vnv=pNx@o_D z(D{Q_`}L9D`3B`(-tjM|bBP(3>t`b99nLk6@C_NwNi3%Ya*i-3SfV7Ch3TRRGO}Ql zuFj=1g=joBgsCQzjA!t~muwLJSVq*Ev0_IFZm>g0kYtWY8%x1NVo7=uqu}h zm1o>xw#v4f!#WtG}Hes>wp6aPz(+i%DHasuDMwbwZ5uC&;Pp2-p4#i;)n$9}IuWSI3vY3&a z$|g|lv8B*4IC52JPgdb<&{D0nxIofYb8@g-RT-~rv}@#@7FxnJ#RfB35kn{3wI@2M zdbe(fO$Z98arF1R#aPU%ExW=MHX}o9qPJJ{|>@^(yE4Pz9f{w!K~GH|$Fg3?PnuuxSblc~mJWk#Y2O@s9j zW9u_S*P$9c1a0eTXL4Od^)NlOMn2t9n_5z z-t~@@&L0&cxbI0z0ZB*z#V+k8CV4*nJcB>gh!3xJD&a6Dc`dN)ume+c>e;ON|5 zFEp~wFJF4RYh0~28TUgKqZ#j87WxL0vJVpQjjDKi14`#?wn9I-`-AdSU)C?DYbD(d zi~z#&bdsI`l*@6$d&&dna{l`N>RG!6E2$deJHVtG111Vg0Rwc2d$rB92leM&nV|mR z_b&LizqhD&)4DaAH)B|8OsVnS))~D2#rJsspa1Rm&)zC=PN(teMZtT!FMoHr7n1ky zwbS7n`utaS`=y3|8oYn!d%XX9|MvSm>Sv{KaE-Aec<&qU@!sea|9-h=!7K5C3(WFM zzAJeDGTs%gW9vz81wJ|8{il(>1}N9Z*#Cq-e}g}5!xr`Qt@ftiQ1UO{7k`Y~#W?7M zq1{ISU(Si250}Xl3Jk*=3o_gzULiA}%y1*=>t1-Pa24jKwSlo07_wuSkALo!{pD>Y z-2rq0VLy%~eGE`u-lqb&l2_h=OGJN>cdD~d7Lg)fjSU@8R%FDHNG(JZn?g8SvUY_1 zCb6PJyR;6!oO>ukXg~KV>9>HYtNPc&9@3Wp_W*J%D)UcpPM{~|{m9AMS8DGq>sR(} zTKh314PKki-&`V|xhHrh8So6x64}p<`gp0&hK{D;nU1dEx??(gp(B9o@Pm;|HxiY% z*=>QFl!wJ+SK`>siq>W7TXlj7sa4lJo3VeDLAGt$EJ^imWb8kAcac2aM5FLx+*qaE zz}BmOTO!)JX-}mq%4Xlu6SpH)y^E=lOypjCunka^87OfrPKD%kP~fOKb(-T|Bk1mCm1 zN%|4s?LeM!{^LGg?s?3=?jG*zdwSnpux9;92hIyP+uX$lH%>X8(5!o-^u=2CR6Y#@ z4+h7zY*2+%$J=uZZyC@hCXNI^nF7>`4e#H!15MXa?C6^Ge=CiKtPrbmY#im+W8T&M z^yrsJUkTg@g!HKKJ^TOxp917KF5rLE2mFsygRA!=rz=OkiyrkDy93&H#p>P_Cmrpr zqXTj`36pxjy-=;R2}5+R`jO8HeuB-W+N<&p(Gt6KE6S@;s;kgxyxugPg}-l~n*2oc zY8|;utIPGFUsv_Fm@RjjNoU%Du&S4s)9!0jIK!u8nwKA5bZn!Y$6n?X2hBXRC0W zfwVo-Z|U8m{r+>W>F>XZq!$9G0%8BT*TSC#z5~edRG=6B)FVC~UR~CIPtAE(|M`5- z1G+|H=aJF7am~hFuRH0c{pw=vaYO&d^e*{7c-_=q>Za)gjf>G;Q_atrFahhKEU~i% zFl|9zI}Z}CS-V}y(a|$>Xv;v>1=!% zs+MMXMQ2~u<|}$Y-~JMv8T$pXZ;IQ$)KK1TtQvA(c%n}11u?qCBlTYGKBQgmY)!M5gmBE_>x# zKyAQI;uBiWVnXH~hwLTnIGOP|4<+<`2}7y^4Bhngv=XJTa4{E_K)@PXwk0z^IO$^tBhUtG!qCba4`)ApDEsMMvS^%z zA>wexT)|4cYUY1$THd*EfC>sr8$3%JrxPm1z$_xRD6NUYv#he35dblW`;gLEK%=p1 zoL|4{@Ar?B!K6n6D^;V&F%mf^#)Ca>~ioG&qeheJLKz zr7kj$B2`z5=!X6=l3>g*XS%HVD7>IF=C?(QUQHx`95Sq2tS&k{=Dnd=E3}Rh3U^8D zu>@+MzV3zIRm#zv$%{##^MF9}*)N2>Z2)^l)I=wZZy(iGL0CV`&C>A%3^! zm#>5tOdveIPJdAuyYRtObSB#gpOY>Oo_1ypY^=;Wzt|0!SKvGi>95~;lw;#Wzg*k- zX4rrKP5M&cDj+P^-$@^P9XccdeGvL5ufMxAZq|q8YT9K!r>`~DF7s+GaZ2|S+jxQ~ z_t`=|*<~dx#~PyDWHn-KXZ)DPiMrSnNogcXg(ViwXk>GY$G>_z?k3W4oz4wv&LOCVOm>YODzz=OiAlHXl`y(N@B(4+xXa z$pQY;HX)zv9nzIQf<^^G{J)U&%Ru^iAOGtEx@5sUe*4`V@Qnl1Fp8r}_`e|-$A@nq z?u?8B;qnFhRf)9vq`pnzN9t7X{6(T73O?Ze&Qx$%gd1YQ-W6yB#rNxI2Z{tj#ftj& z+c?f?>B7m$Eh_RorC!kuw%Kn~;;5#=I=cM#lC0@%ujDALh7srIFq2M02qykRac+ zbBr#+b=VC+3m^)l)%;G79D8^;1Mw=oMIRoFJWSQ%!>y`VgDD1TUsQtChr3k)1Z&V03h2UAG>ydnMle6I8#yVhS896nA}dV% zrF)y(aM4E=o6O40h0UdOhGo}-{b_SVEQNA!BvS1Z*~*9pU<7j=4^6`6UqFbHY{dKL zSOn?<;Zu49TaH%M;-uVEvNF*klDCOWefu>EiQ{SK>3%yKH}ubYhmbxG=)AGNoiDiw zd%>HD(+$XRr}FWCR=a=g8|q)fcE0)E()fVyc8W)eAH_zd(h8Xj8PA%fO^VQOZ zWo=6{%Q}`8mSvXeWtB^-mf0vhK@kxKJ;_eGfP-(1A$h{eStCvGNcgCut%90?>S1A- zyEFkbFFPpA)8mZsU8xbM`XpTdraAoS8!+dbBfbVLryjz5;5Wy(Ijqk<`-uZEYHqUDYy3AHRtarER(F0`B8!S}RV zOfY5SKdlf?XbkVFu5E@X{A@V{_5H5vcj@^6=^4l&g5JimBiDxs-FxLsxC8B&8$ z0dTSSU};L$<7Ux~H{kEnqs}vtbQ*qpI#L5SZJ4e|RiVxYQ>`!v?Jc)XH`)!V5tHFL zlaP*M(JGdhIhImtf|LaJit)HOSxlNLn##qARb2^-LL~@vRGq^8B1?Bpu2Ho) zRfE$CF%KBc*rlD&rH&8MgY7|T@HjTc75R$F3SK(BDp@;xG;PwEY0l`nVqrwitn8|f z&#Z{+VysYQC%CrMkIEIsL`bnXk3_&!7q5zOr)SgpQ9QZVnnk9BnaTFlVF%=(b)t(x zwBy+!i=FE{cxeS0ow~tnV!fP>Vu9&4V@^Mg*1A!p#_LSF4g~ui+F8gwGVwTUmpr{< z>RiR50`Ao#=d0?5s3o&f7Z<@z;YlZt>@N$^Y~i z=*(N8g@KUX{5pA80p;@I@SZ7Ngv28|ja&6nqfkeWL@^u2V8TE42j5xFJHz$;P3$lK zi~Elc_|7LuZwJc#L=TXoY}wo!FqThQIjd*WDQnjA%~3|8G%%YBF}~OO!DzrK46H zk4;sC-$~=ZqBf~@Jem;SqEWp>LUb`qtNhz#;6;-ZV{cHdjeIjaK2G{f;B!D&uCI{3 z0tnkVybh3adF?)0oKw%jWF>{k%I&xzAKVZV^J;9|WiKV04_nj($;$f{H3WK>-?iUG z-3tP`V7ISlA!Tw&r-1?xmZyRAL?BVd*FCO(pX){N)A@}ju{FO_e@+?IB6T~Yvfs5R2kWeuGMs{ydo-6rQh%dh*{W=i;X+NFvS<=@4_XBd2$IpB_u>bIW z307 zAJF{^e_ypN&_5m?`1zp0L$c4u8`uW>J+{HeJ`L}n9p1qn4STjIw6`EE?&g?TViw`@ z+H_kQ-QE7mij6%RPyS*UU|MV{OS}UJX%nj&ygFokuB%Afh0Gr2WSB86Px`@sLbBEM zo6?LxC4(t5nv{)ELi~me%e3hPOgl6WBB=kD?2~pb^4p{Pj{fm;80ilKCjeo4{1@q4 zfOCTSzY_3IFWg<)w-ZjX&)-{$%YtWoZ`WJSMPjx`|4kcHn%TK^cx`aCvRZVTkoZ2= zS!ypzc`3Xir{UzuX2IWP1bh=PCE%Q}9tdw*%rv}Ohg*sY@uz8xgO3u{c(@l8)vGhL zEgtFDv+d4z*K<61|3*E%=)itOk9@B>d3d(-DF1us^X_mS_%7+60J{f#uktS2m<)vL zMCd2u>K~QbRmQrl8QzZ?kLS@HzJb)o#q_$t+V zK0!-2QO%TbtHiYQj{U)R-r${K`}Ud4?|0*`o@@A>Pm?|aD3^Z?Scd}d0AO$XNKXcK zy{11M41a(b$KUoW#qJFFO~qBp59 zy?ax8`$&&Lc|G$f)2{K9vae9)l`=;npplDrbOz-#e%4>k1w~~PxUUAncBms=1m3TF zWuF!=zs5~EZFFIp&)jQR@H*t^4!(EhfOhG882%sc?i=vEQ%IlsPri4PP8wsA@^06# z@O`%^c<&zmr|5mjFrFs;Ebsyl*5h}iUjxeh${rxkJfI2vRj--aG#lfaMY8F#eZoa@ zR@1TDg70?k>Bl3HqaMZmQXu^9v7}c3<#blaZ!T{?*5sQIrA|bYDn3&%G?PT7u`~GI zF5VU5?IWMVA2j!O0O9u}PoR8Ug!g>!#I+kv7&&qkVN*uKDR7Ko_|P|Y1@F(?(@&pO zlO6(00K)fwl=Lrv@O|NR`0b^6Csdw1&4yffMaYHk=&$MGw3txcW0^0y-Pw^9T2I(II<$hxJ1@uG74+|Y9=n0|kSvW4ES!0jlB?bsq zLsmGZ>@3u|xL3zzS3Hwo`_5Wlo3RL}E0R_s1`+hcBZMaFDZbwrX85R372Z+&kYDcV z`}*gF5v0ch2LWNZr;wfr{L^_MoQcDEN+&ZT#aXryJHoJzzGSsrei(aidmsVq#fY&Kz#i_u7r;Jf z2je)u9g6q&muEcbnZR5iEYG2&zXFu^-`>~#@i4IeN@@$ziJw)Bj&I25h~23T3kbR~ ziUx(v7Cr@I3aJFMP7Ku#i%x}6mCqFD+=_~7t4f>z;nS!_uG!!kO9q{LG@b{mnIz+C zi9h8p`mkT0{ggFqU*`ea$O08WSf3iwi-Gd`Y=4jXl+?4NJ||M0byAzxK}w*kHq?L` z{crUsm0vt3`sE)Ql>Z}s`FByau>ALseiV2d2+RKz>F9&+F2D8UyZd9Hx|USoP^xgS zRN-2x0EFWz=nx0yoYx8I43>&^wgPX5()fWVCL!tkLW}*YalBvN<&-5X?-tVAfHQ!w zyxU2CAJ|i-r*(f|zc>(o!sSWIx{k8;NLlw&R$xF`g#sRq*vW}zEDLSfk%7mkQsXx2 zZOUuiSZUZB`-Adk9_laeG}7~d!+@~7N09y~P`>Z159COt@?wg+Wkp}{6UEIRTfbtY z=R{|6k032% z%lcm7d3;g9^ymUc0^@;ppc$wQ(sGR(59;5TNVQW|n%xGfznIK4=xCkQ!p?-f73vdU zjh_+^L4K+$J}lXitRtHC;A~wHRal8zBb${*G(DPO#Z?1w^<}CdzuX;=jfS!O1i#)l zP^Y3-MQmn*dO!Z3*L(i@V8+~mG4Ov{3bcj%A3UCdE--J5tRcfJ<|lWF}oo~2R^Ft zztwD|T%5zRWSVUKF^J?N!mb;V`NPF~+@JD3kPm!SuQ$ za0c6~uTi*tVxooM0j`a1 z0R|H)J`P_v-W-)0*eH_WLWJSfN##yc>Y)DIFZw0jxZ1Bz=F$H7FRaff^8T~>l!n#y zPReQ$+U(!0#O^hI`F2s3@VJHaL%?GL%J&B8<0e&74=th!a_+$xBor|kY`-9 z+8trW`wC;2FCg>nu<8j9Q;VVMAiM?OFTkH?8gOA7(>3PdsCoF6pe8$R^6Sy|QosJ! z6w(WU#Xwk(?WDg4xZm~b5$a8?V%ABc<=i<#; zLfT{#W>lQti;8+u)YdS3{o?mi^5fXBlDu}W_`2Kd@9m+{BB7GxpD-eGFLDJb* z@benz;f8jbp(Zwue!nZo<$N->CkSl?+H*ClX%6I-E=aZkve z(BF#U>sU|d=?@D9FCkxg{eYkEyqc9h(#Fp=XYcM*n zOS;8x_ifavTN;962kG;Hi-54+myzBL3=iy7!|@U750#A%B&yrgR+LB|#%92H6L%XM zM1DTN_Yc*3UxedHJn=xvGEPum3TI^c0{Q2+K8x^g` zUgzWgd-X@4bA)V1B&sfDoNU~XsMJG{#vmDu+C>q|`2Hq$2IaVcZ-jbuuaf>F@E0JI zAHG9c@~u~Wxky-!@LDcEoEP|ye&6zS8U9ag!+JKaShEI1##(N}`o5kuL_gBQDfDpT zc7%k9ihO0%aB9t*VPw#AM9?J1-k{veC{I}K&7`*hX98jST|oL8Ae<*cy+Z5S|E2xL zc+=lJnJ^}K{d}1+?oEtA`G5!~cvHddC)V#b1;02$aU&4#_l1%~l9$%Q@$l%)0NZX0 z#{VDu_LDl~NjCw5fv~)zNgoY_?HXP~y&J#LLe;OkM7d==>IskPi?ng<@p{sg_L3{? ztoT$3Rd)w^&6BOO+=~L%WPcEax>dtGy(*#vO3Bb`+wGV42FilS(mNg?{X5`QAT005 z{pfQ7<@43rr-Js~vTDr+RI$Y-uXj_s=vGPexE*RI&gyW>SnHh^dgtDAX{%r8FI(ai z8=J=2XePK$MJ$Ju-qv$)nt*mJ`d<#({lrRCsYp#FLOvBAC3^pMZOU|`_3^kYDt_g2 zdaO>GlO1fLbXB}2g)BD7B#w&%+>WVKB~H|Ju13-*_{1^d&sfgAJ~?9Pa_7M>d)-EZ};2j4ccI0&`#6-XdCN+%|JMQ-XeYeYsAa|-tk zE~9HS_Dt?Q^4$HZK5hO)MebMTeM;|EMb9+Zu8rtph!3QnRyEJ6;xj7x0-EAIxS?*8 z-ig=*+!6C-yV9I)&%&%Yo2qc_baU95kPJDU!PX#!331YrLR2KPgazj=k-}rBY;5W@ z-lDaY%@(j$&gH-wj2|kpu^9i8u8!!Mnmh(snG}X!HI?DBIZPHZZq|QSv}oyg1->?F zV;Iz@oyz(`UCeHBYz!!JHTj}jCteq0cgd|F^9ges`_0g2-5|p&{Ok_hv!l z8oP+j#Fv!YjB8M_JkXJEs#s05h*tfz-jLjVw~vq8|J1K9a53p!z>k0sAAd>uA3(*Q z1AHv=n^FJM1MzWeIG?`e`bxw!9Yo#Fs@TzEKquGSm?j(`iW77`u1g$&)GBXRkRlt`?6PAP?wYiLd z#Wl3h3}ffd{CcmZJ|TVc8PYp|^MG)^x|a04K)Igq_K*%PtKX9KGKTybTAdT9-4Y-} z{V>t`3X@cVi1c~vTO%{98yr0)*>AcrC3DUiriI;jb3!!_A`n_zQiWsqfV4 zRAc1vq6Dm`^-X)#nf5utqY|ld^^y~_q5yn$r0{#EuvwIWvno^t#-#Otpp(HG;)Qz@ z_27T;e&E{k)AtAn`EG^Zg2kdFK)c->DE#iaFX-pj`}_H4r0)ZM3xxQc`73k*PzA^l zwp01l`;pUeC;9X3I$Yt6T(zlp>qf&%&fkn7f0#VH=Wsu{e#549IEq3C-+O4r37h@I z93ltzjUT%TtFIH*^c|S#W#|W$@dT4n3d3*lwoa4}vB*LdO?-kcG=^79NsY^lPfXB7 zYlxMM741nWou95EHUvJtjw6*~NgT--`eRDz#TXrjud*;qLa&NfVZv$07X}sEcE8_V z+oU~$yt7H42Yej}@#-qlKL*O%C%pISiC+qW&sQy42v$v97&o5P*D9l}S=XU7R7VjH zDwzxs1w9imd5bG`g zwP5}jw)kolBL&Iv&gcyLcb@XFC=h%1k{7_h`|xRbE_h3rax@+^0QqKcmO{(1??J!) zI{)Ui-!{oR>I;T3nfvK}o@A*T2G(zmhsU_xH&%tMzCU=+*7tbN=>y*L_`vtjPF==U z{}m7U<#>^2!+EylP4-Q|Bp@7r3rSxB+z7}~|ERy7Yz_Pc*9Z1`%cuJNVb%HL50zC3 z(FDbK_?C4C_?`=YIbzF(zFs4|J6Z0QuIXEC;40X>*!ly0XkO9_u*t{7s!FjaP8+2g zZdU5&>QYr%sHm#EY=FZ$%qC57e>(!&p$auZ0&kGAFkegP9IOpiAlG){gei#Nx+)Db zQm$^KLavy?y96SRg=^F(#`Q7k6hiz=CHC(kwx^!$_5zF@FI8AMRGE}!(a-(%YkRAo z&oP(uQeZ6*w%?~n{}9*<$Z>NRPc85#b9Hd_e&lp%S^J4mvDbX1mYUzUp@+e{OI^aK z#Ton2*FtT-q}yTAbf2px?of9^0H$}4c`WpDzP`|1Ke6skXt{=Pk;WiRyc*!JpSdbc z6G(jXiWq)g2u5C!ii*o*g$Dt4?jQ0=qa}C{OGPSTjnN7W)N`pgkL1!v%O;~;*Q;)8 zqIsvngJjIu|FGXK-EY6UU6zpd|F&K3FK?GMePTQ1H_ZuDw64CsyD%|-rz)f+6!nfr z{c`N#n;|`){yTdz;6p%Ijurnv2lE}<_!S_BTc%h3)Xxs2pDw-lK>S|RvuShh61;nt z`iHQ;Czf>?D&2iOTMz8UwHr?974L&P)aj;2#s9#k+rRH$?)5Lym+Y?SSk906H(&R6 zT<7|CokHioq(7fFKHiK|7Z+c4PTtvScjOC&Ok{((vFPRA6!4y+ft%ROTJ3dW7|y!rMVA z`eW5|vl{vnmA+ZAJ*a*`<)2qQFRG!xRp}R%`CC=}s=|}S^9tu4IJ!9s?_*YUjrmc$ zwI-thv34P2=T-~7F89Pmxr=y6bon)KY>a1}VnUe`i;y45X-_97;i8R(r z&KH#VMUYbG(oP+g)R8I95_|A56HM2h*)x9Vxb%2)T=n_NSyMvtPPQyKRf_UI5tZ=R zOG%~$>{-p6In3io{cFF7o}BkT4&jN*-dFm~lE4KAeyjgCq&nsheK1Q7-)GZfGmBtY z&s*^|Vm0FdqJrO&cwe-FE9S$tiyioZPfGyS(l^|Q6UQk?|5qg93P{{cgjzF42zeq< z>Bh(~tMfhYqTX-wgWvqSnFH^j(R1d>&^C?myBa+wvh%qs0?WOei3dFG(eYo>x(9Bl zFk`EAkJ-kQU^0*P*h8tC=~QcrNu(z_6m?@06Z3qcCq5LPVJ1#oCqV2xtiX}6L^f#3 znc2%#p(j7Ikj|Th>U>D@7{#ajalO-UO5^(bq<;lG3xwl(EfjhM#(FCNIkpCT&@et& zXTaC+e&lrAwD%a-^F^~7|DfN{4~b*YE0lNnl7IP`f4SZNZQVoOF#JQ*cu_MB(HyU8 zv#Tax;XfFcAg#~?CjDd5B{((5$yowpQ^GB|@S`i)hC30g9vbY})4JygJ^GhA{e(7u zsjDB>iJ$A9NA>7Obox0B6gj|hbqhvdo#KjT%Ho(oPTE{<@{KXgLARSFlVN4bDlK8!qGk!q5|Jzj`s0T zqWJXKBYae}5A(V{^Nf#AkAo*|0Wv&K+A+p-S(!b{toj4Tsplkm^NJ0ddKVrl zRuB(~5t0}hRRXi6skQNCD}_6yLage)E%Pgg3UjV&)nV3QU1m9#TZtH(1a<;xoD`+A zxMge2O(@1=3CKmJB>cAtlRZr{j~9UqhAq?azyw2p5uLM&2$u+sCfsa!=oo1SL?3ry z#&Rr7uvwO4Uh0{&bUyF5M>iJHZh&WpkvSXP~Hw<9FY*uun5D4rq#Ka zYQ~NIdL=>0CE{X4wX)7vM8rhO8Vl0I5nhBh@U>&OJCkE)P@cVfE1X77&(a zgyR^~fd8#L_{!^Dv4+ib`^Xst6gY7`gJAg`;`@9E{x0|Hv$b)lBJ8S*V_Q}MyI^Kx z;50;tb`!)B1^0ywR!QqH6!6ws;=i*it!&7LA7;Z%4Fb}DOsgsQn$E8F75_J2IsM~3BC+q#>SXq!{2a0r=u~fzjd7F>5>}$qDegJ_rh`H4b#>rw)MGQ(a6bPA=^KEb0dkbrC!ELp zw-R5dY+pB^en(>2MnJNFk+6C7hAnGXdU;DWmU7DnRz-JXp%#LZkpw88{R(K z`)pIK6&+k1F)K3l2%~j04_ZadjEO`w-dO5$TnJfXX_c7Oh?}>B7sA~mtL2A-nLxXx zRpuZTtdjrQP_3M zSZ-IscyDJV^D;g!Wn1*BU;Y~?TS#yGk@Q=Dk?hCMVWcMmGXOct+kbUnH|qV!>9{|> zf4w~R^61V1$k<=!!?vvLTeETP$E3F&5t<}Lbze}%3(z8UY-v)u(P_l;5}HEWDeHM< zKB&wG@Mjs*ndj7yI_V+8#2th!DUYZ&bAn_bi(#FIurPIl8Y5-w{)1odUDT&2860<# z-U~bigyWLEw$TEN0OXibra!c{%%5?68J!i>^{}4xRH>@_66Lv)i&3eEm2o*E3|jp! z%Kfu4|D>GPRpO6eS>iQi{Z+-^Q1+kX?$7wmO3By>b&D`i$3;L^1cx|YsIr^G^=<@# z5@(8j#o_z{6PM||l99${!KyTedgU+f_v?Kn^(lHeoYIal2Ff-E#Q%h(W{T z&pXDafQtb+*52&TbD^aIi+w1#>L2{R3rP4rkdkOPs<1E5&@rN>G8fG%7pf5w2xUT%Z$}{l+3dk-O8|t1@FpVD9CUJ5_Xlsihoz9&Cq+tu+@7!Wyycj8fch=~Z!uE4*0#O+}4 z*?85iVy(mfKmyGOLT#K7gP6;v3ov5w_%y6~5<&{1f5YGy>9|dEYZJ~0o^NhCq}t7X zl;%pBW($QL(i_rtoAfH&nXslbn;&=LdcHkLUu@#_7dG1Gc|Q_rJ* zNDsNnX7>zlKfC))AI~y{em-0q>1n`BARJ#OlHLZCkFWg!Kkj|Tmn@rKk)bsy7+NyC zk|51H%Ge91WLOO6duD~Mf#q#e`J`LzKs{8X(|A#?0Hs-9>CPxy&I;o0q=_<1Bp5Z# z|KSm3?0(BH|BIAuQGnz%{NoY8u|POZ=2gNAs&b6wfE;fG@~&Nf_s7fI@A%hkf&AvGY~SP|b!ykSr$VkYzu{5Y7gs9TYG4UN`Z%E{uv z8h2Miow2OD479V9in__UiLq{Xx`UijAIW zPerVXEWoxJM8M;D>4qyaR4-*-ZG+1Ub)eFW^NAoS%ShBBU6aV!6}aO}fW`?unw+U# z%(yn|JO$F9l(ExoIX5{j$gIz}>4~6~Xd$_3hSke`&ip9TVp0&%sYj|dBbzmJ2*A$|WM>AwO00788KOtoX&1v~@Dab>_KpK_Ov=T`^og!dz- ztIO!)6V{yQ;ks_wmpUh`=Pf!Fmr5#vtXg*dg5Ks@X>wNoD_paEn@bA0Ry zt961o@eEZ1LZE>;cvO6%owVD{Mh~Sdd#Kq)exvO+4~e(h%@g$saVQQ-naOy{2FrCm zj<@tUu`+PPsm&`L^9m=LjZZXBckIg?e(`_Jmry4`Lsc;=R06ojwU38?GZE+pwnC(I za_u3%nco|MA;6P?HbfVaV9@$h2T<_m4@ovr}FHVQ}x`C+AIiTQ92<@2T3@a3by@G7XtiOQzD4WfSojV56MdVJ~ zyu+Sk$C}K7nYTw?s3s#uB(UCvsuV?uZGfvzX0<#G1Xq0|M$v?y;5r8%=PfX!CDv7q zJ0v1OU)GV|5-v=m33k(^TkNe|$8l}tI)!W8twD3Bg|NUevx~fux<$4I_rbtb-wB$J zc4mE)cDsT0D@uanLDGK*;&uJ)d>Lt@-Z5GLIm-ECi86V7<~6?`!l`-^ z?SuBUwQ5&wy?37Coo`d#Wt?|z@y>16*2)<8o5Tl`75-1yV3=K2wzZ(AW@Jco7Dj3- zlLXBX7Y)zh{6E7ExJu`lrisy}D-&rat>UfjCljAav@^vnQ_YbhO*S z{by7(gY+u{v=q~*{^O)W)JKrhTsjcSv8HM9@%NU_5!9&S`h~_*vICyR@fUhs$`~ zv_tPR&(&&&zC3y^nhvk)T}jyE2eD~ykEM0Jm7!O1R^nN0vLn+L0plKnI%Ma>T0=lN zJppn_vZt ze~n({l}fd-UQ4pmofUBfQ5-8;6C28|V!I+E6=V#LU|Q%sI3>6?#ikI;nd+rG#hS(o z$s;cU8B6Jdg71tcG?$yLK}4Kk$x8bDJqihoK8i+YGjS8HWPq!H z;iz$rG>Y)GW*Ns8vT|`>et!uc3{omT;7^edl19H3=#KR2x zf9K!)aU8tDc=X-MCQ_;eN%Q8bEY?M757?AT<$ zj=C}Ygr?f^GZ+sDH;6|%D^Bzg^Gr}9e};C>1m6$BH8}`^Y&)i-85?S80%#J;KsTvF z;tLYhNqZP`)xd5%UlA|@@v7I42nZ~|?;9w+?H#KXuv;vF_1T0_|Sp#=c;vm2eUryRbTPt=4Wt`v2~Nhrn!T$HOQR~ zX_{v;i87WfYm(KHCG4Oz0jf4eJTRyNXGU_4n~S1b9`fmj@$fin5N%&?j$`1opiBWC zW3@I;mK9!5N|*ft^t_9* zTn*D!7QF9DwIr9pu+1`c{Z65uZ{~hT^x>4yOu4wN=FtNvzBf#;>=yT0*FBr%1&fY@ zOuk?6w(a=YM2F6-;JXDVb3LchMM7p@;JW7{*M?kW^te_0zvO?-b-#+N7NasE*rPt1 z;;qNKoek#noS(|T*{Ze^QM=n*XhWM}RkGYX-mVD|1ETjuWgViwDOP;!<*7&>p3&th z(&9?QYsq*{1&OcgATcAj&J3;-f-C<@jJo;ETH&iuW-p~jF_OakF2yKirIgQgfo~Nm z5ytduw%$?t9<9EHz8uuep{xR5P*$UPs8wLUh5g$is{vjxIx~)QAA1zNiv9sLh6=X- zT(%`BRH=WkY^!^O###e_75j(!_<93)SPYQuanipBUIRjWts0C>5SR(b5z1piyQ*b3 z95_#&QHHN`JUUYpV?v5(Gu%)y1=_88ZxgoWr@V8kgtdEBU#*R?#Ot|NY>zu0* zj*Y=e#AGQ!ylCq~(xx*v>@G}FVMLk}&_s`$qp9Z9kT{$Tzi>6sDkF3j1Gb8ATFYry zZoQ+}9@L+Dbq9I(l70qw0SN1#7~&Z7fz^N_rl=1HjqmOuP`>2)qloDqWi7% z6oViTo+ca|1j2UhUAkn+cvatN8Ap!NBU*_>G2~G-Y-~H2=^V~BL3SBTWwt$>O1D#T zf3coLrDgko;L_77=n{mNNt{)_CKfZR?7<0%b&e2O%^)DvvEej+G9$50Paq21u$|&V9pmG`PC$<0 zul#m8HSmwP8`)RbMsodg8Gq27jNoWvo_?A zvjp$cPg_rGwU2=H-sNoWq*>p9k!SxA8&sTX*2f0LV>xEIM7kUDHkz~?R#8zXVAfL+ zV)~lS5O`mfl}}W_rm&zmW9(EcUHF8)Ur9!qb>|nPHtN~x!_FK%A!5dD?3^A~OduO0 zz0OaS^)Nz*D03yEdz;uxahvFGmaf7jXyaw_WU`%DAMtp>jK&E9V#NylQg?^<4y>Bo zZz%hI6@xJ!izlO1C|%Vy)!Mc3DpgqFZPoqm$0CB5B06t3xm9`yG2Dr|sE-d*Q zGT=Il(ywV=y%MZx(ZfX1KQ;|R<7I3zijga|e%50nzl`EMN{N<9Q*-R=^zr2l@L--~ zaAe!qKLJC5aQ*)#=~z4R;6RS__Psv7oc|a98X`fDH-0?b@0Gr~H+$9J_-o$<%yTgW zg5Qi96Pul(u@+tQs29u1IrZ!;hv`}(in)49wxT{7&8sPCn>#m4aL;&7jY--m?$UC{ zDiWJj#Z$0AVua8Tz9mgaP#fZ7F?-B!AeJcFsiSop>L?Q093hI(U7lzPo>Gfu*t8-_ z@aPEWt!hj_*;;wDaS;V-qId*%ReF#)9ddqr(J!!-~PcXjPuLpvw{5~?qt0_Il#%R7fIdo6D-QgyL_$VE4fHl&1tA= z{J!F}#8{8W)Hu6j5F=ohMF^f1ShJ|9u9ES`t=dg5N$nsCU>t-yyvhcnk>f@_#zO(-G+ImDz)L z2J_c}csYCXik^+VD}&nZQ#;J372#j*PkNWTneVx~M|qd;aFHgssnR$dHnXdXW-R6C zO3dAzeAI$Gtt9rHn@vQ_P9fBoIig6x2CHsGziqR&Uy!jrXl~CQn*NhMCOpKb{X^+zBq1}n;v%Br-+8jD7F?04TdnSuY zt&>LKTMr$Z7&CjUJw``{PDxCjJ;k03%T*7Zn3ynoBD;XZ(BX-W*~9G)-O^$jnNsj5ZFMlEVmgOf8@ zmX1p0Ocb_B;V?QnR?uBqAyt)}pQ=c<;6IyopTiFdnH0CL&ji=GhBp{-22z=#%A#C>~vPl|I*+JoSx`Fm+(ufo& z@1mK0`FByaP!4)K>HC1aKv@2lNdE~aFMqin&Iy})dp50DJ$k%IrZyprN>JL*DB~Yk zFc2di(PI^Y#29QI?Vz&m27a`ci1nrD-kcP);l7|;^G5ZT>sZn&fYm@)uG2|>9{3l_ zH3oY=t8+t8F2Vv_7)jx)#V;4%Kd@XD3YA{DqIykGuI01*_S(lcGeO>d(jz+2p9I2k zZ6f_$Ae0k770}HK?mTdvpTBt#F$+YQa+{w1jM|I*<-H^e6e z&U1`C5%D1a1JSCoa`9YaT+c)xixs(=>ilh76ZzAcrzycs_zvD=62FmRr!+lsdUe;i*I(Jjg z#?@<9ELgKy+Hv_QDAVQu2Zh>K^beGAgWC+3pi7U7q)|pJ)iehqU@!!V*5kr@ETXLA zys~!B^UJx1GK9xtq@Mv^0K#(qo^-71-Q^7JlS}0!sAp+Bw=jm$xK>8%hp^5WV0Y~K zs$f?a`m7l0(?9)Y!7Y&Z-jSK_mv1%S4(FZ!DDFyF(9jGqsC4EK|2umJeCNzXrjaG) zXaSIRka$BYDCvJmY0LD6LcPp^@jE<&$534;_|C@QI}^wB*XJnGuPm^QKLFu(K0@9p zz`qhF#QTmY%+6fh+e7Q;G2&H=8VL%*>?pxNMA^{`*r>&GF#D{Yqvy3kT=K*1P zzsm0y0p{tn4^*d{S&2;F5~cAwr9q=InrNDNZ`r{krA|k4zWq zwiHqAWn&eIVk?xc%nVHr$+_s2+1Ubgj|<(?X)drr3m-&4&_X2(pHX@Xb}B8A%Gl88 z5Om;Mh10`ssV%>ta+(Nb2h>N}Y6p?U<+`1A4cDVV<1OPM?jHfd_P_60%lHK_i{IoZ zUoTgG-*0d4M^1x}^Z6EGJ4?Xck$pWUF6dofYI`qFPVdTG+0)lkdW_)o#+!P+aXaz1 zW6}6iZsq}W8gOb+M0s;xQ2u!n`tkN-6D;Ex?mq&A<^S|=EaU6IJ^Us|b)cWW=Mul% z;XG3u>DyNi?|Sd@QylLv-3y(b$Fl;U;-3oi9P^bPzcnP#e9_a%WH{4@tZ6D8C(Fq>aLP^=;Cr zNyv795D(f&9}0W~kR$Y87p@0u%lymKKjXJ^*uFA-jXcVWUnR7l@*HvXigkyBb;p}} zdAvSxtnu}zC=d^Q%&mXIJp_A=QX3K03Tp}&BxVOp99qIo6Bkw1G*5g}4NaDWAAcm^ znQbh`8vR%)=c2`a{q|7qaQ^uE^Oo@}_rC?g`t2p}FF@@JKAxAy$qUDyyi<-p?>n%5 zrFj}hiyPLh+pwNG{Sa;ZSng64xkx33IqlYXJrXVac&yop#iqoTItO!|46mRL!?VG$ z4iB+2OZ@U~o!s9ak5HzoxW5Jn%j^EuGTMPjfE>pKe2u<9?sn=={PHay;m;ReNgg;Z zOXUsvB8%>RSqvQ>YG?9ycQP|h5f;I&L8ldYe?S={1gb==P}aO zRLTO#QU1LJxBBhl{m7~M{rb~mT?@v}5M=$L^04)f%6Oe7Nja)Al2165=E;$M)m`>m z%E~i82x}vy3d{uzSdRlJX6K^H91c?N(I0#K)=si-0%4B!`+vEVJt&;Smpz61PXJ*% z{%`SR-_?#Y)`~ISn}nD>Cn2$Amj>hFJ-+kYfAXCg z&S}V>fKq*exW4866yn93I)_utoY5J)ZyWy`zHcLI$obq~IN*I3@xDud_Z!FWYM;`m zjT;vx;zoDy9bFN%D)%xle`}}-TZ#z5D!J7J-yN= z0yme|%C=$QjI!9H1IwR#6W1ulPW*AQ-e0Se*Xx>VwRxdqe#43GLMN#1yE=Y3gyR07 zK6@#9*ly>)WErV$$H)O;eSSjTy}-`_Io_{7ydOE$zh8aWXZckbP!kvdy_;6`tmyTt z(*MYtdX=#Yr<-;|q|y0~g+XrGYKXFrF_tg$@pL<7TpoN>&2Wqwpb-emtqyjK7l8>g z{qf%2?9X>=gX@kq|K14Z!+GC+pZV}zg%0R%p~7W8>_;4l1ngG?HKG3O@Od^B@Av$M zE$r4>c3S7CZ&_-mby>{2oMnE?lBMwZl(9RpxFbE%vF2ELUF%e7^_Hsrhl+m&-Y^Cq zuUkb+{Y|yLjdzUrXUvg$(%W#IY%BkcuD~TrQnw=jOC?N<2Q*UR399fn2u8{q>)Md%kpoiRs{csC3giBIknAV8onP%oqZNH@p8S}H+eM23w-Hd+DjMO%7 zHw#r&7nlvgr0{ghEYZEh^#K&0ZI5=xL_}Jiv?|c(cg|$fWoNGlp+FRTjUKo+5 z^KP;d26Yv>;1PVKL>hr17R+qf)F5`neF|SD?0v#*i8Q18z;k2GTqaQ*6pdHJ3Qkkq z$U+_RqWs{oXsejbRuNYoVm%)*#{qa%ft2%zlP+rlBy6X7yffCG;I4wpJ66v~wh*6$7)bEnX_^KV^>)Vmx#@FxB=6ycltMMA+Q zkJymj6mzi>|Av{p)Esl0uDxByf94O6o9qTv8JiRtCYYs4m^~?Sx;od4 zpDnbdCwTQxum<*g9TsLdic)zj90*QpRUl^u37rabC_#+4Xs`|f6^IgvCS?ahll`^i zlUMKM$uDj^;I@roBSxU^v8uzGg!XHlnrJsTldLQVk7vzDmyXL;<_P+;8J)i|PAwX) z&5=K#rG(~R(!5)VmAV$vG)Du?M1;}?M;2JGOkPtkt5WLep*-U)9&*$Fk7+5?M5>f$x*%?EBx}c&FL@S z=U%alrQ9C}gyp-Dy!(Ow0puuOC&P8#`;pTP??;b$c=E2zHIH6|aiY#s zMyA)V&y|!jtk0dKe-8Wt2;2Wf((!qYkq7>j`s{eW`pn;abkC+W*fRS5|Ex;iC{^i#K$~P=P_J#2H^lqPNZ$?I2ZZ%X&v%SDKo1~CxgXHA zcN|FPU%LK%=AqeZd)Jj#@xBeRuzP(rTPiq4PNNPyZT0%`+otgksr1V#@(P zO(NN0ylUgh)WZLVwrc^5qPp5McOE-CGrK#x+08z(Nj48i2#*9rKt%};DJVjGQ=cG2 zp(3n+iq&egs8nr@R$IgeQBl!ijc>H5(fXiDHLcWQK}~&PeWhyED*pc8oqK0zcLO1@ z*@3frcXl)9-gD2r_ndRjJ?GaX@Ee>CIxLH4V7X?(0o*wu91NC2SX4m-?4Tl0fxVDt zh+x9gVkiV1`{3FvOsOw(HWE4(uy$@n{a5iyzK8OcfNud#JB>qeW(_b4K(A_UA6n1b zc_q&)&L1Hh)oVK^ooi<+fW5X2Mx?a_(Xp4Vg%th`*-nIw{u2?R=?*ma4Axxc|Kl{5 z8e2zldB`?(z|x~5t8`A2>k*E&68RdC4M1E(ASqd!HXQ$Jzt-H3KL?fo0d?*je> zaN7GV%A;q%2M$25#xL18Y50o0=eKvkUfRo-?{4X9@l#3cmX>}B9{h$}D+!zZCq6&| z4`b&JM|AC3F1x*P+r4d=-Co+!nlet?ORM4jgX3p0GD^v`d_7kq1)<|~-hQ;J#cr7( zyoT}zfKLEU`@ctd++nJ47=T`1bN?i#{rP--ejnP;awkB9*~w&=rA%B|DGA&BC;pKH zo&yc8*&_`gLV(Q~4ffeHv$LKrg}|Rj1H@3k)pQ1LKiZX|H*jr1`5%Bc0Z#k%nebHx zOb5{Gqr5l{8~8r1{Uu(`|Ir@i&FM7GMvG{h^6q5Tk>3+xryq0T--zc`qAtaGTiLh7 z|8TkaP>r& z(=grLnOQYd_!0Rr&n0k#%PY}TN!Cddo^8q+^ z^qA)>(csLyu47(j^Z1-4tbOZIZ)g2?`&Cwb`%Aa3Uh0dXvYuABC+6twQ-XfExe~{T@ZR3$PPF zuY9?53y(v`o+=1a_9W+nezT|<0<1cgvg);L?0yV)0$Ru0CC?p_dJufo#sMWFh4p;?n z+Pe|u4*_2R=#@WDjn9i$vSm;6l+)Os(8fN^8v7CvHq*vFBzYc|^jc)2KoDo6#{X)W z`M0vfU}oP)4fnv&(-`5|C#(7OS+mtp5W*uOpua7j1XNw|=g(G$Veq=-(6Rku&sKKy z$CTu;=PQp*8f!VD%Zel2`RXc^?*QBjaOm z>@AreQOel!co{8~Axp|P1OjDoX4Qx0+V2yz6KOHanu44%lZ)LE>(3yyN_du=E`4EO`UX|H-T)@r~40KHoH zd72q~|M4Tfuh%t+?~nG7^Ye_4d3L_VbpLnZvV*x57UQB-9B)V4eUf>)oKwMd;k2YOPX64MwNKB?@5r{H;m`|eqrtp(lw0He@l<`akuo( z*nL{bTkP;e)ILJNURCPi@C|ud65g^7M=XyjsPZNp6ydAzTQ#&=)o$|IlyCJOjDtuD zIZ}-UW132LHeJ(B8OE9>79of=h>P4aAe}elFZNMO<6r=cHrP#^%LrL7Bdk)bI1Ryb z7KkbptnU#y0lRFTZC%0W6+70|o0g({G2k+QL$AM~JZv`3*8u3%#pTOkoorlc{Crqy zGNV^=NxnP*XPUF-EoTO1w$iy)5B8mXcgTq5GfruqKfif?MtiNT%lUrEsiz{b7dX02 z{D`a-#WwNOwKgw*0hf``bcCseH|iTD*6Sq}@%~r0Df*Ef{@75u5jRD?$?)6^?^+!B z3@3?okr}$w#BxCNQt$Wdx1Z@LeCzIi!DAbd*WoS_vd`EdoGHSbgs=-%f)WkAEC&$n zS&D$UEo@+WEnlDxHYWT^^C7fN$b;k?8k8PIq}Lq-JRqqMnI+aIEo!5eCK{@AdKsi2qUX=b~JN;I5{W zkSBN(l+RkuXYJmIHnq?jxZXhdOTf1Phd+bIqs=E^@8?9upQ|P@{%gF3zb|0#slzyb zPTMPgva!sRpvqRQL%vEATeYhL_S+xDt2BEoM}!SUbHb^zMWrx0S1X~wC~2^iRF@Sk zkCkYHl#x})a;6N{lCfpUQDho|d|EOhicI!mk%gVquUsrf&m2WgPuYKUGF$+rN^_w% z$bm;qx;YZM!_-c(=#wUC$6NRK^!t%{M)@AGL^OT0Ruh*!2&;srS0M7vy_%;T!L>(f zL3Iq-Pn$wUlH(>)+~H-?@)#VWkn)X8*jF19o2#AT6K9AADhGJ{o-s9c{i4c{soJ5? z!S^;Wc0f0t~ML?6_D?t5rFqUv+0DdHK7=sY62uFM5Vw~wj5F*%w z5;0PXO&YlRMXPZ_)CffB9z;Tm(^F>j7m^%KVP6D$gxEf!5jW_0QN-`3;lRQed74-U zw+agm{@Q^iHV9&aeaS?LCn*on>Xd`&6LdK~#WNY3L;Q&dtCWMGBoU6whiKCq4jG9} z42X?KCRC-#U!x5lBHIT5P@6azdI-+nPM4=@2geUd)qCRA32ap4JSRxwC}!2%q;(mT z`x{CZ(BcT?$OAamBDo0${Mg{|AiBFVtk@H;NQB~uv2}#!$f3vJWY4kwgc(<7N1_Lj zSPXXl2}ViS*`FDKhGXN13`HoxIJ^>JorhzwK@e&dJ2cfeFLsb$Gm8CDX(n9I&qU%f zMyfgzLx|-=@iiF6Ttw_;?T2rAZA8G^(v=gKD)*Tef}~wo>yUeiYsdF&oq4dFjoT!q4tjqMUvEr*AICE`DqEDNr0-?1McFFaZ&CX- z_PxDZiJVg{kvTXaoVd&HyBl%+5aO@Mi~TwCQJ*~^H~1phceFyD0QT1q69?l#)b8?I zxB4YhA@ls2ig1T9Sua6)04hl}PpxBl1Edn=3;eIt^nf>51wvp?D90f2oZa z8=XF!!m5%kz`F7cUm%(;XY|)jcJ-7F__ajwxdh{e^!vw9ejV^u7XH*6oCyQ`AAnvPxSe(j ze>eHL%@&UTojvJ=>E%n0T9OeZmNqY2vgqvQBbb*eH}Z9mPVyuXJIKXY_3(DA{W`>c zo%N(Gvc2RHHb?47kv>L0fixhA!+3=1D#5^+CD*-d_&N=Qrt(jdBQowQMbYxA!T-@i zAL+3fiJ^%|3EduM0$dSRN4lAci4MX9Vtip@r4BSm6$n`v#{uLpSPw@%F-cPOQwcya z#}q03of@KJ#(zXYizL_UTqiFC{ zaS;9{h6Hi+`Fh?v7f|XEHV1C4Gck*lAe2+YW9k|w}^ z%CDBeYY29M%nEjQ2~EFZd^UTodmf}2OW3-#`TrRIr;cRusqpvQ^=zTb zhHls9dQzQXyW1~A^)3nuAHh>ZdrkNJL&pyOKlQ-HhF>j)EQWX&5V?IsdfxQCU|N4N zl^0C^pG@rqQzO!gX6Pl;cm-z>Ayz#X&|V4nXz6RBy=3nHc|iRV8hL`m;xvj$bUXXm zO92ZB5liTux7nRn0~S_4Uzs9Sm1<=K08@a9ypYiQi=QNBph?8>gP zwCgOVvaP=TAF|YqR#s(iVn1uOSY>f+%&y=d$+Om%X!9Ajv+q}1aK5oCs$Axaukr;i z^Hr`wo)7IQOMBQtMeTP~^cKH#w<_JGdb@o%hkatq6I*Ub#^*l$Va$-`Nca(4&-vn1 zmoLso`AWdm0EZ9Pp!_Ug$J4C;O&-_D;{FXzXD>@5KJVN`)XcTGd66@i5ny0BHP5$- z``Wghb@uV)Z^*Z>aK$S0PB(xVLZRbu63*!=BF*sNB}I7E5m<$WNJnxpZg;_%GbAyF z*LQ_7NE{EXx^)d}$GFqnb{vWFsesb~4u4;V@8qCEX; z{=%g=HnQkkr)3ysI88~<|IovfgY0*zkp5E?9*$MWMgP@3mm1^}gT9i$1E&9eQ_+y< zLK}=MFvt@U4A2>Y`5!1a!W@vxr2sUiN5#3sOT(*s~qQN&_u(W3`i5kf@@ zBIKCIbAesumKzuyY8SZv`IAsS2`~@f^ygV9-w#;yJnPRbeBbFK{@Llz1#{1Co<1MT z%EEbb7xB&cR&k`=i@#wOx)bdWKVf#d`;n?4Rtx8k$?ALrsXEE?6W3Zf3>`=XiBfba zjWkmN+XM}>Ma%H|vhU%ziW326jeASTr@N(gi?WuzD;hG($&6LdbV z#+!KmFLc*~6HxvT&<$|<|L&it!k{V9Uk%(AvZt-zgv?B7ih2OdfjC)?!5M*;5V)89=GKszDM8#p-ywp( zI_qjtUk!J=N`y~~iN_$R)*uO`SgZ=K#wzfD>en$X`7bB4Vn)mxyOickxQuoxlSFaC z2{+CZLzokMB8^%Y1KUtXK`0&Kq4-Si(Va`Am9g(#3nv(51iqxFLFfEuFxjL8LdNF7@U4QiOih(?^lAoYMm7(Y!bgQ}fCOgA&=4?~kh2og(!?;_XR@k?7j zf(k1aV;)kLuycu>&3iEjFMG^ z(`@8-ohpynO*59UVS#={)KLU79R~e5Ce0*c@ID90(-CeA)vZ=W+2vxGFlc!+q8sdo z@Eo^^A-fRq#{!5uChE~5xuJM4wD3`p6*yWze?0|fJ`Tce@EEZ^^R!EF@=Oq>L!$Rc zts0ylO?b^cC+Zbm)2uKa)#%{C)pREthaDJSwd|JgKFVJKb^)Amc*Pl*ixwkp27q1* zxSh6^`$L4Q*|_765KhQD-?SWh+patiJTFw6QK53}U0r*Rh9B`lJH~E8H3CQYkRevCksjBj_w>n%ZX!(_V)QBD ziW=CLYNhXVZ5L83dF$baIx6I)7BWQ9o`ByQEyg7Ex8lf&bbyTV*33Qd2jbllj5j6rPofVls1`YE*jQHRy6hgPvkslF{51w-&B}nbLO~edU!fNCC`kS)YB|naMMR>c9z1+6wS8rTfl7k0vEcaR(d0NK zeyqN@+ECR|Nd6UqCm8ad^Y4C)FlPa%B?#9|!jSrwU# zc=DCxV0~n`7FpXX$w~U~ry{R^;Nlp-{MD8?RMOY231kqaPD zs9*Ofw~C2KBAWD81S@>WAC01-1U3FtB7?ODTZo!?B!mjMV`GZbjiE@TN7)G>XQ`Nh z^y0&aToMco@tIhv4}-a{1n(nBIDs?IC04>hOnCmQA;HQar3Sv8rjPVO_(lv8s7bX- zO+dF&Fo#OMnn-P^)J$pRvbPvG;f90+LZ+8Gons!BkQ3Do+pIt!(B(*-Rb$9LuV2T4 zGfac~xAQmf;Fb;n6zM*1Ob_B0#hG7dh{KH_arlP*Dh{BV0@#r9=HB@ zd1QRlNME=rfnN@iEO-d}V4 zAMAIOsgCUj(9h1hqjNj&JZ<}daQ`1cO0c1LCb~io47FfKgBL)86i0%^%cL;Yvt}4j zl46aHdnLi-QW#Xv1#dQDMhPIkRJ9&3=K1%tKaD9mym$~94GYjoMf-;r1S=|v6H4XW ziZEh;j*VJjrS9}0VQE-kqKV7~#|-Ndp(hA;QbSM+Jc^_R7yuYa>}q|4jsJFxYsb&0 z1LeN}UIjSwecLisxPCdt{#k7NTYR2x;`9FO%G~*WQ=Z&S4}D;=w~uf9%Uny3Z#>J- zZS1gwUFD--SuDB@ad;Iu*oK@?8nziVga)^8Of!L@5i>)ckuV`I#;J!h#71?yXpF(0 zFM_1nQ68a8g+sSnes(b9W{awxF#Z?gO{?-0`x8F85fGE_L9|wRA4H^}gur&Fq8M_q ziqjiY5he(qipJ8tG>E@6uAqWB9Lf5MlshfN#=wz{>NS>rr={FsjlJE{?y&TWEP1$h zjTL}aSFJ^jYb`z!qX@)@0AZ+sMi1pGWtuGRg9R##F+4g{1zWuts0s%#X=##Nl+=7C z4rI`isW9MIgrew1lrc+}g#w}$D7SwJ6*c>pVXdev6hfFzEGVK}QkIMcPO^wR+6$E% zzbs8e)Dki%5DL=2_KE!Y_^UX5zI_%{E{P{A;69%!i6@kJDg}I+{$FPy??vIRS#RQHpNzgxk#<2cWMgtB}# za(Vz9{vLY{;@YfGg+tC|{Jl$H{Jeevd!NniCT-K1-DJn@?7p+EQU0DW_gs2H$+@+V zp4fsvE1cM!TeWqkEL?sJ6woD0hm2sM!?M2PC!o?x>@9!T0V_Mz?|m<;VyC)Qwcq|s zUPj6S94(CsZ;Tj4%oi)AEtLq2_LoY}Un_O(B(t>0h^ar-&P1sHm9W7K#$-<}R30g} z$JPDiLm;cbNdlI8Qw@vQ!5g96Qm)-v9yERTl+(e3HRFzQj15eCDnv*6YaF7+ucM+i zQ9B=OG{lDhSzdUwAiN%u(ISxyju%({*qEt>RkBIcQnwBAts7*hbJdhS9A^orD+h9e zcyAQ_SYqcyQdLs5hQz#zcL}&cGPNHYi=?3PV`H}RY&pa<46{M&%6<2hE7dp=wV^!l zNV#%<>gYQ~ZM|syr%L&xQoR%{tHer=gCf}0WM74@LV!Ao;HQb9`jh2G)Vw zb=@|GV07Tj82xJmC4;Ac7jc>fCFmlm$@>NeVY1LbKnyq3AZkC8)|)0`(ebPxo{2zU zYIWEuiYntt49SPES6QSPF`SCgaCQTcV2fnzcp|rvjWwWDCNZ6g)lk26tH_7JD|w3L zDnz4BnB_jiUz4I1B7&8g5u?o9-8UY&yeBrS^mLMF67t!$H`&df?mD=MXQUVntp2k&9!IP|4szUgskN?v9XHtQgF9`7 z9Ex0l)Rm%X>ORAB88_3wPv}K9|5!hD*Vk&44*)a*ocU)n%D+AjXX^p<%C~pVPvx$! zEA#9c2&O@882r?AhxitY#c-3y4#`l?A~HOs3u_vXuty7~^wI=EM8LdRj(BErku)Qz zloVBpRrJ#!#Be&LShoD-q#C~%&VK=IxTrxKiM$)~U<96Fza+zyk;g*!K7G6gDrl_A zKTI7O7=<|9@GY%VF0GRMAH<=BE!)_&xeTOl)u-%O* z1wuLT27Dm{;in9OZ~Q?hEJ#KsyB1WRnr?H;+6NsmcywgfNfax=u2oa-PC*_WTYbe-Il+VR_XCdXSD3_Aa z@E_QRc)^Q)kD=D)e0vVrPjtTVsb(H8E12i`sGIaKuhO*525g@3}_A(L`(q8K;0h**`m^16%a0zc4;reZH&L z-;MG^fF}SBAMQlC;%BNb9zd@XUS{^iVO!Yyjog0R$m5o5c#GY4R=6~R)E!J0KA2V0 zCoB=uKV6~=yKu7BB!5KeA^4(b>qeM2jDRr}1}Ys3PQ0p!#8OHeQ=w|8(8#LXyk{8K zRp&!D^=@Cm@7hyMb^K>;iW&@2D^ow<#*-~JLW>w5U_*>Q;uUb>Vn z`SzQAy5&uFy5%qIO{Iric44BcBUg*Qq&XJJuT|W7j?|OLRvct5dRe_%yo4aU$Jkd? zpR{zVs{S340JpJ4NEC(uEY_d}Qlo=1a1?`G*6-6HRTf!#V3Y-l*;Mie0)C{-)u~4y zeg{>~6NtehaHzBsm$G2<%uQQ%D^>Jew59iWkCK0=$B-mC>&gbaD2- z-bVQoz~=zRPAy%i3P}nZ7@eGbSLb}c!#8YGiEWe@rH=;Vlr1qp5_r6BgI5V+vf%(% z4RQwqxgDg7iq~kSBH2E(tn#H~95O1|)obJRO9QuK+qwqjTLE_hocjF%Wvd18O>brO zbLzQ^`x`p-J9W|A(?**PBNC8-QRcE9ZDlS zM<9}v%59h;IU}ZDW&N`XZAM`;s}L(Cr` zOv&@Vu(^B0q$NuhWdzwQQh_*gMj(#aIVV&0eqI!=Mao#^EPX}sISN_2G(!`NS9m^B zFDXbt8f;~-SA=>XQ| z`QkAM?pnj!nBK?K71weHv#B1Lt%1F$2V;JeUukJzU{JHJ&Vl~M>NlC zUWjdebVaxL84mD?-Qw?+Pr(s%sqw(-8AXub2m-e&Y7(KyiLnT&Dh-yw^V86a%*s07h5kC>AN(P} zTMIQzQ4WUZP6Vs+$uM3iMhdYLf{?U8Z1|bH&iKN*#9e16qkJsj7XXJZiY`SgBEa_m zdfmwL%1-0&+xR}8{Uu&j-ki%9*xg)|cQj!cwCv_1=AG@T-*fF)KBT;pJSx9T#7^=7 zd70>)Bo4N@l7PTC1ptG8lDr{8Xppf&R$|Q@fmk3qzJv!9=2{sMC&J_);SGH}8A1*t zW3(z&yj2W+1<9@KG01X(4`lB)ETqDqPPT1Eb~QUMN7u2rPrzK>;nCnO#HZCUA-eV@vnqmjjP>md1+K|~!c z)gGmPB8R_~OMF#K2&e{|z;_TLfCrXu1!2`-0t2gI(Wl~*7&mnTd8LR|gfvt%XB&~@ zR%~npX9YDwl$2p$P%2m{2qj7L_d#IAt0Oc}bIM?Nb>Lo1hJUDT;klBG^eUPWwtP5s zsUd0#oXVnlxTt6-Tw`Glhhe!aDVNxS8rJ7B9D+s#Be1C>7Zc2zwLZ~8lF1^gcx;gx zE`!Bv4Akfdsl-$3V7Wd(JUF6&yJB;W zz_D}*T|t*%1x*017V&bXy_EhKUExRAnKLnO&;(+eMB#44GE#nFcz$K5NgZktHXStY zq4E*BBp)U6cgyEx6nL)pLxCSd$ldYrRRqu-aZl6=*snmd7}}O%drPg z_FF^QY)pmc6c=17(QiIz7Bp%)W+@!`@`+O+U?T_%n1Oyq@D#8gj44>w?AYU(fL)Md zeFzac1c$taV2+7PgUO+6S@Vd)u<#>%j&vGaw!JWsBby)%M`ARAZJTVOCvpe*tronk6l9ZbYCWd z2)nS5(9DF;6tSpacE`yqll)Zpf|C6e!?V@U?KK2?pX52mvqE}J@gP4zjQmAawyMf2 zs?_1tJ|y7?HXOmBuurNh=`p@=!NJ;Ny3>aB;7@y zd$9W26h>rFlST-2DSS9Ku;|R4lv3(xR7|FU3`U_Rka>^|ZB2q5t{jvd^X*DFze6YyUEz4Gb0Dev5K^}5{onbDPwD=c+kBZ?~?&Y;=Z093%<_ljx87JR5!fKNIOCO7cg2`V;o^ zB-yjZ60f(EHc?tDDlhsxFTfED@0d=u`3^Rck>ntE#m7m861sZB?mmU!^bPjc6=@>O zq8cVWNg7QBKRcb4ofW~;j7PTT8*gsyZ!&tD6sl7ted#u0Pu5{UFe>v_me#fl}>wolnp79%6i8@3|StHA*DoNvDcaRJRv7=bm zU=xKDt>EZ;5WZHBv5`}c4i73)(IHCLKv+JJG83jfs#)0E9@x5twv{3Ge5^P$WoK9{ z#UANYGMD0+jo6adi99=d@G}mL$5`< zm9y<&#k&w|@QI*ugC*Z+f%xz*5TT>;dd&WnTaOl$Zvd>B2))xX@3s)! z1_)%UD=KlsaTq>v8oXuO1&Zb-fygG2-zy~k;U|be`oD?Io(ZTvtkViV8zkU zLnb`voU#YKra&U5V9$wowRe9rk})-V=O|V`f{A4?1aFi4o*%L{#bTWQ1g}VwH2d8H z|A?gPr`+`c?|;xU#fkPl%3lGbR+sL>Q9c!L4uD=7mk%8M(&YK<_#*_lhn?uKx#{T$ z^M{Dlb|i#0V-UaVp4<=<{$Y z(s0&8mnQRuSRXR_bfeuVe$Szg_v#-`pQH9nADbbCwrnb_^=NIL=r2O%kb#m-g?I>>oJeyU|&rxo;20AN%Uip68=W{!#{Uu(8?YW*a5y_B_ zmn*0YvBDl8(=a%&e09*e6XUXwo*5ESOK6b4GJr$Sau6;(FosIWD?+6ghnzuxUJR3R zI@4qSM^Qp>G%1s?1%V?O5IGF5>G3jV@6nSpVK=T+EV-66(zy+(u)*&E=qzvuz-M-) zKW6mVh<2y=y_Zqm4(I|n^UD_~SN$5Y0)SpOKFsE|2L66!p1r7LxAPo${fN1XPoqZS zIVVG?y-7To^7zd}_!^{9UbFNa)*0Kei@)?$cNVZEALQdo;DFL#y6oG_pci*aH7}KM zoX~+4WH`;*gVTmFQiW{0wn3d5jn3dkBhU`R8Ui^8R0w6(j$^C|2M zuz{1|@?g5d&76t-bf~gJ2@r>Am(e8+CtERSozv^sE%U=zgxpyem1WchL1jKX8Gd}9 zvi7A>?-Z}xDwKZ%Tku4<&IJlnn-9v~UhxX{I z0hjMmue)5!5s}8|rCY4j6b~kKWmcWE*z+*t`)*d>ao4%^orUsofRh1Ee=I|JHQ-JF zz4m6Wyf&{tGVO3g{5cKaKW3l&lPIi=piABj>i-JHK0toirEg_|4S>#YZSUPi*^q0a zjJfP4bn*7Ze&e=p1j+{kjsQ6AyBX#80sjTiYft@Re~Fil-LBtF%!Po?K65eo91R!* z7z1D{_2J;A>3~)uY$&dfm0w28)(Fx`d=<`Gr9TT7OE`i?)bFzIwj%4OBqPn9R37oy zsYA?RQTgE8Bl~?4c6b+BJX@pbh_&ppMfcEc5CP>w&51A8(c(?4ZK)rj!G|J}#E&@39yB+0M0iOft)ynNPne{0ze)-DX)(`#5 zJ(ICOornqITDCy_ng}}*sPQkNKH|MRDn1zvJRL2keeqOOAxDo2j4XeQ1}b13Sb|;% z6EB>|XlGFmb$fpUT75bA*j}>SsW9iq_QHi9$$aT5Mu!CuA@?{8BYO)(X#0}UW5F8u z5!fw7tTB{-1-J#^(4*uARagUf7C^5}TzJ(`^noK6Eo3{omk_Y? zTa>5o5N)P@UW7(2V|M?F7T!cC%S45#{5|gJio;C>3b#B-i4Gc!tkXy(89@qg$n3=X zdO*6l2zt2pF~jtm4Sits?V#w)f zBI7CMF&I#EX|TP((qHSy1TDqQ1gh(aOCIW%ji)#gmGjO`Fwm_{K-O}0EYKhii(-dT zL%@y^K6-@Tlz#zBzZoE5pT}A&(nGp*nO*~<8O*g_PYjk>l_N@jQXd3n}d;(XiQ*F?$)lLwgkTBZ!7c8t(Fjt#CW;M?Aa{+p4XA z0T@a*d_r1q#GLMxjRH+RqN0m^wS2?cJ?$p9-N&Q67;quLY4?37>o>z^0YI-No@d3e z_vPCuPN?4NN~+8~ z2(i?`AwY#$0JT{-@4K~KjDROpiBv-^P|%FS;?Jmje;|r*-jpV(Q3W;Tm$i%0b2aEx z%kSNe@`He<01iFhLOHk=G75lR4|4x~=X~83zFzW22wU^!&*PeHn|0Gt2)jwZL9?iE zI3DUd#vYQw3LVw-FtbU-hhqMBs-)i;1o(_s>p2`EkI%0ZzaD=@$4l+=|?ix3PX3#`O{>E>HfsNFmREmF7gl zvFTZ9v~JEtuyxOg0BE{A`o5L!JkWvzhh&v!=9S0d^BU(59&ifd?BPT;pE!op6acll z)dRjGcsU*La}h6ffLVYi=!Yk;o(#gQvpw$Ff%OFQ_nUF^EyQwxf6LOc?FsX}MEKo= zxie8L%4X!>3G<5tGRVTCyQrvGJWbQRQOv8zxCM7m#lTL*nZ*+R`E??G9yh;?>sVWK zB=_R?E=!n~C+IytyVs;#7&r*Oy&+-VoWQ-w@>25WgxQ&}NU>Oi4K)(cA5EB>@OcoT zZ(`e}Tv37DJ0yitM87>@u6Mp`(D&irjYjD(FsjYwagE^>Xiw$i9Q4m|^@XVc$b) zdHWsqQ#_Hbb}S|+O(}<*OZIbUE$Fv2NJ%f>V*AHVD^!gEiFjZo5MKl6@JawYTeUib zY6^(c;pRv0W&pXJL{gW1*S<3%=S~@Zlc0B$O8fN^c!#h@C^x&sanzte7uPsURZ~!D z8Xu}2CsMw{rk8O#_6L71!uP%|WCmx2&7vp7Vlx6B!_^{r?e~osKh8eLW|X%Ax&Y2N zGuNrYP{4Qqy^{R=w4*=d&yOqLV)B)vDA0U$FpE>o46#nd#(LW>bUKzyntlCf;pUnO zs84=kBGiydJijiH*OlnEl}PJKl113mgRZZ_><8blh{HluqJqm7+$&)sD#tuot=1#w zu-y?fY7sK(Aj(}mT^de@C`41$Aqn&xnYDL4+TpbKF_fPJ{1xD|_cN4(w_{!b^rgM& z-L!Y=q9t?f7GFeL9I{)yh_`s0@HB5RJkE*#krKJ1M1QhG>L^Kq*G(!cvGpLkl_|TG zq1;xc(8>^PL0E?J&j1$#oOSLRl%E8A^b+IC8C)OO#O>4Be3~T<;=nT` zz+Ge~5;&n1v*DkefK(J>?s(`pFeUTT)G?V+lN5Xa6djU0l?Q29uVIed=fyU^jui1Y zmO@6-R@+yX%K9mFr|Um73gz*Di2$emhogJ};QT(+pQ-3He%~v+`u~B2r?vto{6_Yy zzU}RRQJ7nOh_(6E-w)LvnOA+G%fss5g}OQZPfqJNbO&$j3AC;@&>fkSib0J9{~ut{k>t<_|W3wTi2;eJ8fU zHI(h*y$EAcZN=?zaeZ95qQ>0mli&2IZ~3s_^R~~kvgV}Q;&cY{-WVs>$1#hojw{#U zUAs1}Tut9w@mKMwm($~_bjSxV4=UnN0QM^Isz@oYlL?@Sh7r=pJ{tj3681t(dZNS8 zr7Q7=4Nxzz7{g@+ya}KW^pUAlK&&8eszw-iBmttw_LP&bjKCWi(kXTNr!W<(NQ2Jk zyBTzAv?(VDAELYqAl~iLcNWU6fCm8d+8cdWjO;<*qZjrduzic}nQ{u>!YPa>_z%}s z{7o0P>B@CA=F>^}(WJU53F1AT^!%#kq(AE@ZqdmrRIVY~W?gv}cRbJN%2V{44qbVi zzHic%NA#%=>%CIi;8gbYo!UC5G|o!*PH{g?vkOYYog|0qn5PX!_r~A3bYFn-3c$|* z4qxAm@^-){fZfqOKOVN#ldtV%sV8$gt5vJ`YsTIuFz&vZ2pzQ*4Y91?K=AZ#NRYKP%Gc)9I}#bvQopf%vzZuWY6S=5LcOzn0$j!ok^LRU zC5O7q3Nr-u_~BKf%%jYT_#u=2(Rp*8$c59C~d=`M&`FJ$<9sj6KjR z!7BhIZg7m1Hh>VR%{+0Or}xlNEX=3pHCmvrq4yNds3AvL!fRSqfaZ^-N;BLtV8)Bz+(W1KEm%2&lGS1 zfL?nW$3o9>3|4Y^hmP2+sc|b2w$@hsIWBg_l?U>t#tk*6y~w7?QTNC7Ydx*c} z4skjGj?5w?4JFvi1USZF&-?+-Ccu;PCcy3>pa1T2>2f{FcL9D6aOkofW%GVjCV^R;o9Y7}SWlB64^s0oUQT>Lt&Y_IV;vLeQ9cRch;jj^>R{W+TxKZ+|K&^d8uTzQwyh3~|bf716Z{9%0R zKioO75{xwh_H(LnWQd2+O2x&!ij3nCJ%ti-rko`tdTk*wgdp68lBNrb4bCvN*Wk7= zqh~khb%^z80QPdX3wB8p>w^&IUO2U4`oi+2`uhHMD;e!>&&+NU9G6ahl zjzgT3^WdqW>M-zUa%>-FbC!K@Z87wbdDMu8d{a@@uG)v)c1=KeI$$QiY1bT-F9Tc) z*j>Av{Dk(GcuBpLYi~lkSd(037-tUcc6}}iYtXLA|E@7Ut4aU6M(@sVR~+rC#o^#M zYZuIhi0|U)@snY3$B3a8fca=wnzt*)+9f>Vw#(_SDDFA!>TiFUJ=8VPDT0GfV%1WVf=j5_&??H^VdE38QBvNX@c7G7s4Vx z-L}7PMVgu+6>?IB`$lo#wp!1++Tz=4^=oR8^%VOTNbVpJ*X4!T+^D%(@eIq_$H3uI zFEVWqgivtojCA{NBo?7ksM(4adsl*R9OU?7aK(|d{@uLYu}9r@*PuKWFdpEv`#6;E z19SrDwT0&=+4Wb}-Yrk%wtHI7emH8>bTqn6{4Gn`u$(P8_ejF4=#+Yl#wt>-jr>Ec zv8gushg$u?T1%eqOm;B5g4f|%#`bJrbe92D0Jnras-} zLBIuj`>u%Z?qv3->VR`!Pe?`3L-^;z>J_lGYO&0$q?^|NCt~m+`Cf`rLHTDOZ-6zHH_~>Z;Zz^40oh z_9pNpe2IBa5dh+L5vlTI;5lQ-)_)75)bU~KY4ROR_c)r$np_T@^z~P4% zYxT}r|K5R6h-*Z0Md6zWc{kok08 zZY^WBOEFyypA70FNIz#r&|*@AFp=0B!ya!6zF!FEB%f^3c<0?IMu*vt zyMDcAqPzldKER>FN|bK^MQ8!Qm2D(6obxz zFiZxV4hmsAo^?=D1*=y#a5~p_C~Hrsf)C)-D}?d{KpP*o&im@TdM#YMkWS@ICxcn` zvG>#;MEZI^UU(1CsBP#0?0sXSj#5{lrxt@Uqj)B*b_E%aD4Fz&O3LnnRmtkP3U$EM zLSNcYz6)>=*7TgZZ%=g=a0w z_X3^+(0LSils8e9J7BW_&?`T_!!GVWW`Bv79Y(JGwziI**~lQLY2i+!S-?)dP;U{7 z1${y{sr;0L-yunJ%%_BO6XjDfSdb^IM*gJ0_1^Flgmf5llb5XVD%X1lv(79*bSnho zqpsdWhO4uEkQb4K5!(ZdRw4)^ux*SJKbXNzmQsQ+0XwW=L}wU7Pk@Pd2(Iob)~{)_ z%bCY6X_AECgR&3?ICP$e1^jHfi1TxDj-Q7U2Z6@v95JH#%n?q9W7b-7#u-Z%+b%Qk zx2fiQ4m^%uz50|Y1OPFBL+5IghXNV^^va(%9ennecsaj^U%ky^I2}O`P7 zuslfu{|OC)82w^T4{&`lc^-MYIi8jR;Nj=4ZA1-&S$lQ@kHdE}E>VQH9+!pp01kbH zKVnV7{rvH^NBVL>zXv_B*CgvBXQdeH2nXCG2ruGu%VqBTd>+aaj^h4d z`SDZsfN$Bdg{Lj%$su&g|BW19?Ab!J&kl!Ww_*;*(^3#TPO^F|pd8Q6EIhr@uYdhT zjg50zatPixZ5-e1=L*qZxydvr$_|ciGw?a%Yw+!g@HRfb2XOfD1C%L@?-zgA=j8Rc zAmhJB3;|yk$2aczLhy$zkF!C*=_w3h<83|grTD$x`mcZdpOxf=KRd+10}F z%>I+xu7R5$ZDGSk)W-326a)_y9@y2v@zlQH=5;+7mN z4`cW9ud|5B)&T)U(5DFU6quF}XNJZ>#Beil!jO$StB#F>cHl_!y1jz(KLD=-oO*Pj z{2^fLW4V0UmwGr!Ol7N))@HgOPj_n*b!vkGt~tCujW70%pPKqLPVBg2Hl7xaXFc#Z z<7D9Y$rZ}lI38T`e{vbmoGqb8abZWONHQrBNzU(*`}H>hvR7ho`G+VBb-D2;dplTu|55x z8&f@Li`qDzrkDFhxBlUAlw8O=9M8r+;@SJUNi9sw8kjA3ba6bXPM5EHTc7tXcVywo zmbw``Krd$Fs1^7IW}b8Lxl%XA5y$g&0r0p|H^vdiGv_aEdwQc^fBGp~>Yl^#YzCeb zr)6(=`qNK6rEQESj&Iyw`!;U(E^oX2WJ}w;4Q(7x8}O{)_Z~y}DZn!TXT5(O<*k5S z+;7ye7xi54T|E4#wQNnH%lu)2d>CEZY2YeH?0_?RIg>!Tc|B@har^OqTYvNF!3Ui+ zobx~Mtm;F1O`cb)&+T=xT=Qqo;rN8DF1{4XHGn#RL*L;j?+-YE+nM@-j|ESakw6<% zK3b6Bhtq!GYT90RdJBIW_;Hi1RW))v z3$pP1Z~BzWKUAce!=Jwy&v)j{-o}4_=9z3Qs)gfecy-{%J=LDt`14!we5V})HO^eE z3F{}v^K}96P_3zpKY#Y$2TEUZ`#Z<3Sl19;MWy!>zaP(B{64e@8UaC{Bh`quw@ zmv3BruC@a?isM-gJOj-KuC@a{;CO`B3W6tN=;-2j78C}L%MuNYA36(zC!>g@IG%C; zaOcf|n$IYbM*jTOc>ciX1umbtS`Ow-jz`!&@cr*CgCdwH%Baj%VDCzR|5ecw8+9c27H9Rl(*tgk)?_USx@0)Dm=dpV1o7mf9 zEbhI%cjM>VByew_TOy`RL)B^?wgFO#%t2N51_)AZ*)w5!BpYYrUhiA``@Y^zUAUro z{>V||hK$J8!&*7M^}v_nb8&C$d*9{zEPT7s$J#mG)Ek9sXSQC}$?>%o5MQ=_*3Iz= zZ@TU4jjlhWAG7r|YZT*~H1HLwA9ts(HE_H;f!7&Fz0KEs*VkPB$=2JNIKJ6k1Fg5Y z_?Z62216Uiw;A{bR$j=%#|LEx$2abuuHMv}UfOp(Ee~IwzGm&i_@_M!Z*Tfh-}SW~ zcx`bk&GDt)8fblNxA>+ydRZsOyBc^4HBPeivu=)0d)vj=+xXb~ewQO}xb39Epf#G0 zf8cTWbfD*(Y<;bPw>5D*)8290H86UcOTTRWEzR+5EFeCr$F*`isdooj zk8|7Q3h$72IKEck8(4iVA78Fs*RU_+OYObB@k!t1ITvrXe%HkDtpGk}91JwSWb1ip zj&EmS@n!VAR*rA>`vq-ZhIQIGzRiWjm(l+^Ilgf_3pZayN`e75t*WJhV{SbO)>xpTOZ_dB^M$aFDFI!)1<@h@L zh_Ao${Fq#|Olar$8b5T$L2v7MfAunoFIz3^HW9vEaWUF672gf()K z$Fmc7oOyGA=a+1?OK9TwX8*fjgn9|r?GFWShg133SG zSulRgR#Fvy=vlkwiT{j*=m)L=J=+4)wg!_SI@z?&Q`00R*r9D;qYav zRYE(*SNnC}+SgC{e4kNydQ~UKw;K2y{_kzQ?x$X5O^{O<-yBT=s75BPs6tb z(W@w)9KEWG<7)%H0?d~ge3`xG0~vo>yIeh|H@&f+`&t=%j$YNo@wH^(>rKz;=YCce zK4yJx=lHsTuZ6Fxz2WPpUX_P0vz;Ya2Qj)X_^x2%B1f-k;P|#>;Tu5tfwt2Y#+o>u z#{YBqbAacU9K9;d@wEeAfyTM5SG96HvG3h>4WM2{>1XRz?Ho@_;qcgcRVT-@6L{uu zz8^rninhlUmht@51jg^P1y3RNv0QvyuS#=#n}M${e9=$&i{i5Y@f?2-5g&_LGihImDR}jvK#nPd>jn$yl5k9;CN;u?n;69 zF-Naz;`lZLUxE12)~nJSPlH^rcID_*tsGw)@b#r#KVV$v=vD0;pQRKGUyfeY$?>)H z5nn&$^U;o4)y?tj1RjU)dt0absZUWn+3J*FP2}^x+BZ7(zg^60uz}<0C>Wj`bxLUB z_!>NJyLzKz|J#+LP6=s_uMPML({H)zR4d14X?+{t{nVqtC(KK*o#R;nJS+G-+?$@! z&;2Rj;cC<*#)nXZoo>x%im+ zBy@6o4Z5cg`cp1GSA7y1CbNEA54?pL2RZ7K(8Te@3>V)3$_Z#Eley9yPYduk{5i1m zNsjs?v~qmiz}FYKr2pgFR-c4+j%T*%wrc?OC(w_119oye9RnbEZ4CQW)XIh|u?aE>i>tMzo8w-igRhxtcj<41#)O^U0HE}$xz|)ucssDVK zqc#a?j!y^{s^6HmUn|G60C)=1t{k;VXy^F0^|4+3r(=%VBy@6o(?WftWB>8xs7*pQ z$G5SM`1&c=jlqPKF^SXZ*P6=4TWyic|Gll#{nVdqeAxZGP#i})$2&XHxAERjIg9q6 ztw?opJRQJO06mK0$=Q!e{fLc&hT?+pOO8U-$nmuSUjh95GVOB|s#cEAin{m)P@l@e z$K;`Ij;{syS~&0YhOeLdQF-`Wg{o;9>&LHwH^uP|@VLlPsL~wYf|!eM0QD)_PFtaB z<#;-Q$C)>KYu68$Uvd?J&G8MOKIP)$3ROGDH@l>7e9=#Nh~l#+kWP-L z19%F=7dZ-5H^0XzST%8cEx?!Jd^y1LqKz!g z@$3Yi0_Y!XXpP@wEV7Va7MxkLu=lc4oC}0QD!(kL^cUGZ{ZN)wuKnrkdCg}B&0dMjlh@U{6DbsAw$;6@uY?piVt(tCZV0< zYX!c-$Omjcs*~gSx?t_fQJaKrj&H%RzO}3W<2grd609aR&bAc{Uyj-&G;n;=hWD*~ zdzZu0%a`^H$1XH+Jng{a@O^LV^WOC)7f-grl;(J1BL=)ZwxZO^pTA<@pP!>3wR1dO zS$KM*S3mkCM=|Q;c&614c)#Q-M0~F6=J+-OUtiY8z3W98KCl%c>u@%HVhsbO4`rU8 zv!67F<7ok&ftl}e@i>Z53&*n)cm_rf%EjX-K%E><(?}OjZ~DmI^`Cq^Om1m7g7wcv z;A!DJ(How<>pi=}<0?F@9AE9I0q5@=MW>zPY0bj(zpd+;cG(I}Cx3o7p6~G60L=$E zicL4iGkc!_AD^~DV;#x+AJ2E%@xSRA89LdDOap&@Z1jLX-&SCn`14ob`Exk`{%`tA zrv6z{DdHh>JYB$(=6L?MeV;r$Tw&?vc&6>!xBlL{e3QXr4|wY+*5B*#`~mLo90jF; zx1=1W(S3&T&3P~%+Gi|IpKMv5mWg}_l&tH${_hr5B2Y=-# zAe|hKHEzKB-&Q=j`Sa6w{s6ZlN8zxJX5(dBAKTFndgUk@4IEG7etn}?Kk(!z7)>0{ zdf;*B_VY(&;VQtd0ZyKl-=e$;P@R|GQrnT2Klb=hV^3VReCfi)r`fZjbqu4Iw!i!Q z$tceR91d`ve-z5g0AK%}J(JaN|k-@fXmPgRf66CX3j$*&8AtjG&|5FXiM5AIU(Yvgx6T%Zmw6l#)7@#T=&#*<~He=sE{Dor~6M89tu_ z=xe>^Ej>5Ad`bPhh3N&&OIfWhMpae;?5maI*_?%E8_I73KFq@NCCbM5J-46ZncKXK zH$B>P7Mfm#timg$m&*CX^or)ZWGT$jLW9hx75WB}B0@saq1tn=v|;t~Ti z_&-q?T|p8^H6A6pq?3>sBy}W!5)pNpuh_08*eD{_lSyJVDVB7RXEy$mD27q5rXO?u zKM-}`^^BrS`=|`>PCe^TK9K$Y%X_vi5gug1as)tm{UPad{Yf_OM69c4(7>c4|*3yYSOe|6@Gd5P5qS)V;;(Nb@ZzPlc#$PIG$a5M{Ef7XV zLJHM`%-y0E_Q@oynVL`0w1^@}2`wJLvrWp!x*~b;w~DC|zpASVQm+h`F+t*0Q#JaH zqDlChh$O2X$0E(yk*LH_(IP)W`6!fYP`*e+VJQkG{<=ofJQH-ydpNj5 z5rlg3u842`N?*REFD9~LY!K-PYde|Ids?GQ@1syY5pW8?p?3?)*8}qDJ>|YEdM{nF zeC~2kJK7?CDPBm~Wi=7DdMb!TG^_-QR740FP6G0164Hhfy)?rb2ZCH<0Tb~fn$aGW zt{_i}WCTy!A#}`P_3TC+obfdyB?_U59-$cE)U)JyMMwemWDl~}uElc~)t`FCa+}9% z>*%D^JpZt{=^-PiigURX5XJ;J>j|A4?*iaR@taqmd_CaiEWEd({1hM`Z__^*efEZT z*)p4KE5!@N7SXs+M>Xyfg>e8rSC=Cddw2*N>n3Q=4vEGi;z-9mL&X_WFKCM7%EB9CfH*gd6Z=g>ZEK+ zA&hidu0U2pI*n?0PulOAMDIsQP}Yf$Xto#=l{67qaKxyoU>Zw-m|C=0Rm4!SLc%2I zp`Q=1G{aZyiO8mA#FH`nWvH|yq=d9`EpxY2)q*~sNAy-lYhtybnnx&pJ43C{G9n5fH9(nK^;9WPEacuIo@BsCHv`w=Y=3YHWrehu|Hh~Vkr znxU}~q2ZAR$`Y}CMvhL7MDr1cWC82HuhBQ-=nY(_9_$esrb4#;kw=i&Ev5Dl$ci(t zHq2yl+LrGaAMfP-chq+Fxou+5=IdRb@1b9z9i-Z@r?t3C_G+`cU*)e%+_} zD}6FnBns8`J0XVuc>A8|CwPYt;8*N-!+uxsJ^id^?q`2*`2Q^0U-o<;eK38X^8iBh z-9DK9PVq4$yZcR%{fr7!%<><@E5e>@`q_7Nz!CR9&MFf0djl#7`d^lPvqYL*R3fVX ztgP}n;!FAsU%7vq*Vifge<@-XsVC=SjZ2D^Yb@~wE1>BfP19%Uhx*^}$@dxRgNFQ& zp>8w`kNCDPywkl$aBsU$k@2^3(vy7E{^l{meA`Ff^U04IWRqdO?^FKelmB3lCk*35 zpYn-Me%w$y4C7OuvcvtovZvp7`{*xc%#ktW%0#vCOz^Ku%HPM;ixcuC33XKh^?E!R ze%if9aPO96re3!u<;xP}@`Q0$lAw&gyfR_jlT_N1@)Zg4tAu`EQh6{b|1v>Z6UIYH zWn)slDxqGJFdj`R>)pRqexK~?Uk&!JH|5)O^$y)q#1BmK6Z(nZ(`&jMHy#jUFNt!* z`-n(3iM~IGq(d~G6xF*;`F34hubaO!Nmf}Q{yTK}7EN8J#TD^G-RyQgZP)Oydqick zi1$0i*wgf(zY|Hj=(|@W4~jsfO0nnY-TOr4VbS-Hs5~YbkBTN9c$=o)p#|^KmC5pE z;uQ6pML(HN-WEwrP41(gC2s(49jDHJqQYy5zw&rV$rT>!s!AxypLxCSd$ldYrRRr3 zFD2sWv-~U(dtUIjajYajb`l)VZ{-3n- z0I;j57yg|&^`3Iixoz*=-MhPYdr8?%@5z#o5DbI_LN5}MP!vK8M0^jQFBFjyAtE4Z zfQX2wAdwmoA&QCuV(h3Ov7qQf<*5`E;rq=gyU7Ng@B6-+{P)c1Gyj?S&%d9u->Xm1 zXUF4g^2w|_$(VbW{dZ@p_?u(D>TMOj3AT!7a$Ci{-bLbZwRG>jBDKS%DJE5i&1B^f zHK|I5$O{qiryAQXRwbLMb`sYqmNWng3OF7lV5@7?$_7*^tCeh2OO8&oMY=J z4?(%0shic-2h>CB+-Gy2S}IQm;5h}Hr^s@wf$eS~Jyu0e%;X`ezHQv3Q&#I}S+Uz3 zQ>$SQQjEdPs#b-pp{-M8u5(lyIp3@HxwodSvvi}RLkgPo#z#3$w zA6h{G=)xJZUl_AL_Wb|vegkzekt-}KhjivpPa~>_n=&c0<$;PYYeHWnN+y)f?h>IP z%~jFGCb|ccLF0%}bIiP9Mo?$$&Jvs8UiZDj6u!EWJA#qBOta2i0T3FF8ESC6X2@F# z;#Bnp_0;HCBgY!Vj|2yi1I-4lBrX(olRQLv?p%GUD2Yb}V>Z-Eh0q@gZTYTv=u|^7 zPI$pIy{a{um9Pnht029~+?-p^H@JCME9pqC+BxPl(N43@6s_Va;rSwYuI8Dw>Nswi zCL7w`!`?j6#bvh`9bWr+1~dG>pgl_Y0vqI@9?KHZ4!0q(v&28D%O3QcjAqRFO z)blb6ldNgxlufh89GQ2EoNdU;9Cyf&O_QF=cGzO6SZYOoHA)H$7W3%$;`uQjx)~kf zaC|7Ujq<%fVZ|sP`UA@IR$7^N0qS?c7(MHIcgB2Z@`%h|&v*+ybp07;rpzV+)_)*h z4FWfar0^pd30v(5RE8h2q)d$1nW|sP)qIzI#e3yA2F7GHXZsER!}(lvz2O&<>vxNs zlX+dX-{p%ted8J7Z4LDMJ@Wyc=@{aJK|b1-4|t9=Kj~L*_f6z_^L|#4>V3XpNLO9` zJ-fr<-pOLK8hJl>IBw7ri>VWV#5WUHib7PM6F$vYV!I(H9Re8V& z@p{Ysgs60=m*~9+Jf@rk#mk8{{x(2j_CD6nvApQicMCPm+NBVN?uiaKzS zZ_)lCGZ(V1=FGCL>r8FCi?vB-$wP%JfUr^^)q3;5s-zy28UXHik_xGK*w-3bg zb}zhbSiLqA@1C;h)Kk}OOfaeRIr3KVh7g?-t!`Tjk?Q z8FwFeZIpKN##X0gWyf3)f}lM3?#bPgR`%s&*#Eewrig=oD+oPeQA&CN&cG3#9SP@J zBkFWpbjrHf0;6Ba?sb)Eiz2FP50oOtyRBXY!K#0sCv_)JY1J!MqK0eaF+D6bHCgcE z7cJJ7dxP{3N6PtXb6GudF^_UftNC~|2lx*0MRET; z1>RG;n02I;X#-{gY5$x^`3WF<)c>x3o`2K+Nlc7y(o4yiz5414Z{Al+_U)^m#(gzo z<7{Wv%K3wFUoCt0^6o=d9!Os;eq2obU-wnR|7Ty(qeo!Mf=ap>zH~_ z6zkn2&r8fM%HE+fY8k(JTuP0Js0cfm_}yAGKsG1!96EZmp2t%@6Sx9M$JOd%tjs5X z2LSbZHPK^d5{;$90)a@pf?2xu?#Yc=)FE>y#o{R(6Zu z%I^pykLR@SL=*o*+Pq-?rDC2l-NLtz>r&n>OPwC4znaR zw-NrucNS8b=(HIX^Q^2=`_?tbv)rO%7@gW7DXpJ{1@2cuFNkx*bmSRvh<=D#NI#^> zKwPTWXr*6FGw`@TeRn$%q3bM%bBEeeACoD8I&9>Lb<+d&GeiJ+C*uF z60;79an+qpF2|^@uz;G#ycN$uY)?9~rn)qz;QK=UR555WXi$=07SS&1^qW><>7?b>e9wa2$8CL^|Zu&5i#oN%Z( z9^R-=XV7FDJ;U|&Wr$o;kxu6FzU{(U?1rKkotUQO;2w&0pml1y1VtT4ShaTf4Iyts zho>LIg7=INpsQ0Bw2uq@yUCiQhRMlW<8gD$@uT*zjg&72E(6kWa|h)ofWCyEdj95k zyy%JjbT2xAL&f?v*u_Sd8nH$Von`7zIT|>>5t+-4_GlLOFlRx(60;zA%6gK|wX*DH z-4ro;AhP;Iq&-LLWjZwi*<`Bd2Y|DZHdCh?BvL5$@ejrA={sRmk3N_3VZbUNZO4`C?TKc=_acK;i)u-Vzd{{7lTmmR?*-k5m;WBYgrCfc23`B6&_W52{uH;@iSjP6A$)e(EL zd^oPpR^C-l=*=f6e+KwGkk;n`%0C3g*5{CW->g0hF&z{)i+5s6-J)G4GEY&nIkJVC zMT0?kvcxrOh5DokFIau zkKa{zI^{hPd;78#@wNBHEYs03cl#+f^J_FlZlPlNSrbcv$@1gkCSaMUyw)0Xnr&D` zy>+5Cp}WgzDN<*xl9OmJI9fYaJI*yRsXOnpjYj)e`xNwi6{FQ_VFAk9C?1OFX67F2 zo@-bvHs~r0%S0(>xJIj;H;&cLgtj#pl^OMsyEVhLL!Mz8XtInWv=zo-K)s^3%LYT~ z2tX9Nj2Yuc?kL-qt1R<*W4zWF7PMZ&%Fl^v(rHg-8O$3MG>FTsUajA7EYs0SEt+MV z5*jRhmXmjvjZD=J`R|ZXO?JyJY-8Bxa4MK-Ppg=PC3c{g@JeH~u1|4&6K@Jzsle2c zqCQ0yEav{m6)kzYp^*3O&~v-JzDlr}uqD=EabFT4b<7j0Dce6ETuYdQ%12$|}w|?!)O=q9GZq?Zb z9I@!&gWv2_H0Yj;Wva*H&D40%y|-<+J^*}1v^n)kX0xUATs1f&^S|`rKk5S?Fow4n z9sbE`>d4|Rbm#Xv+FaG<*cEC-rHfF*O-6%O*Bzz(L_4Q+bj=8^HnNm5qw2D3JARSX z+s2C22pz66y8Y~kymXuDF!+l35sz(%3F(k=k}x+aBC^Tx@&uak1vjdS5Zt|HI%=r=vA#OSC2(8!bnR+Gf{#f&R=+ z3!0R(E#Huj>a)M6_x?ej{b#)`pAG@oHpNYw#xzr{yy*2|fzonAijos#i{{ALvQ72p zA~{?1>a(?e8hS(AkGIk8)Nko|%HCQlGaX3rbL=`Rv+z_a^D#jEZu@JDkFCjebALQf zqLcjDu)jP@|1MEB=`kpZkHzC)A4SB%e^Wj=ZM(ETx({n&m-ay!ZB|BqzZCDh`(fI% zMO#@us^NDw3e+XI+v##X8tw|TVLqI-fyR3o&?N5DGe5Ehb(~R5?=R+2FQfT!y&k8t zsRr*Fn%=_f+5X(RgwvZ0jqcBP8SPom%z7}zFpA3f>n_dPJw~TJ-R^}~>oQH;qnZuv zn5^=baOBeLerLN4aZI0$5d!0-nz%~4D`&v}L8T3P)SQ(oTLrUKwm)ulJ!zHYq-U*# zdo2A~YyK~-@E2BPk7ZNdV;Rp{#?zMnxV7v_%m233^drb@h(>xyhV6@8A2AF1-ZMk3 zD+QkHN<=B%A{$OJ*BBKzUfnafLxx$b(Rn+_nyB!zw9_(RMJ;EOpLP74npd&GtX1mT zA!av=z`ki`1!_yqctJgyxF2*yC-3WTl)-p!k~bL* zUD?&`b_*qYSG7>C3ZjJi)mut>hh~ht5k8Y8v?@3QMJzgvT7Zb)i&^oc7?gKNd54gv ziLyRjJ0{sSnV%L$msly6+b(`SGZ9Ry<)}^t+njDR*~9Sc9wrm3)>kQ1hl81xZ*Q_r zt2S5WRcAGVz?JeS@jF}Z(w3MDu|mx^LbHN6GoQ8Ez>i=VmcJ&A!5IC9ZjI+(c-km^ z>Z3d#SOlbW^gPPDfU$J+gk-&Xllha-mEGdDSeTy`iS*|wiT+CMA6n)fWoC4$*ywaz z`;@#rR~QIOFz|YSC1|Rg3a#~uUHm=1gjY^^gye*f98dPDUNIWYKFhQ_VdAEnel}9H z<$T7OE_@G3Ml?DI_<66Oqfs>iD|NnUm)8gu_MALS`mr8RZ#2us6f>Lk94~7*HATKN zL$}5FS$evav162F{)6(Rz%@WhpYEdk6W|3v{ZhS6>Zdw9#*VSY99`GfuRCuAj_Eju zC;Cv3*&n+j$7qfA*P!v)cz+@2Jc?@U@8N9CO zPEe3}F~!Rnqj))*@*3cDARRXsQ~nGvc0D^G(Hq4L+<*_^sT2aE5xW)vKbJx1Q%azCZi^1EcU*@9B0gw z%Ktg@*|=ZrcZ~9D=W0f#%6<(<>tCnb4UDaS+P|aqKl+Td=blcbE1Ab+C8K9WE~8g6 z_2fMpct)zPP2Y3z|I>R`Y+SeIjB{`b&pgR{hLh*--s}0#QvMb2{9eyD-)Uu9fPdYN zB@D3)UduFvKR=LJ6db0Hmz-?&Oe+WdZZ>e(mAN2CcQGb#H^iFj;>}<%wg7c_kh#^& zw5}xsW_ME0t<)j)OWRI)2XHTt&ZBQreiiV~jOWpVyW(~J%rC{;L&oqy8}`vJs&RC* zGRIJbU1FPfScqL>`NI*#*&;J9Gk~%`5vM;bI({a+p9-%B6ec_3CtH#%o4T?IP8nx;7w8_m}r(sEg$y~|bN!fHJ zC_W6P*@)aaCMdxXz6_4c!Z?8khT(RyS4cUsENYWpnlgpknh~)oilfWCczay$`dOp> zG@kNwU=EPhdl}{T0N#^vJ)chMdwZe>QT0Azq~6=w=ANkXGvqLp@7lle zN+55Q287B(alp``@@iPM?OpL!?#7i|b}5cQ{r21u*ZV2zG#nktWPU~Y55S*+wBB+( zwm#ss@5c46C2>6a<2yq4?g-siYJV1)C!=cjzZK5^7x=F2jcrB0`0e?8T<@*aX*fDE zTJIY;_J3dRGuLOXL_}8xs*&Nrd+v7>Raiw+w3J5bF7UtxGLcmh&WxhcT=e+FU>Sx`i znZI{2jQ`H<&>R1VwjSrAzqvZhq5QjAl5*Aso*Wf8l^AKT|ku@;8p%}ADc-v@} zgWlCfMV3v?Iz@T9Y!u_w-6yc5S(@@OnS-xMV8TSHHtgOJzBbManu3IEu0)~(-kR>t9&CF!-rhFGelz!&(f;ilQ1o@v`gg8B`@HokSI3CI zZsfl^Q3ZsbdB$2M&WqwM`6nS>6#pG>j{Q?ag8TDY;V(w!LiC*W&t2^q*R;K7wE7AB5 z1vo`CXciu$El6>g>CJ_@uei#7%mxL$t{rTyi(6w*v z9Bf3+Vnrq6-|lfx)7WePmWP9>!@&5My z*uVSCo5%L^DXZ5WwQl1nNWeSfOWK`M?2ymccM|n;rS`NaR!d(-6IRmc(TB~ZZ?-y}z zzpfeo)RtUcGTtBRJ6-L57yHWx^&7<{`T_6P)#xZ+s*5+Y{Du1L3-lA?doIz9_v;Jo z6Ri_oRAV6)9c!}93iUFI(GsL2FHv`TZLaABhQ}7?RCSoJiWQKX1Jw5B4YTst$4EAYOOkoRVcQW zg1|56R`jNL9G0Rt7a4`gn|)0uzzM%IVYuDZH-AH8EzkpN-*ctC-w{)}K~#{TemKNn zjlL8KUdWj^>(tCnWSMw0TDlsEuGa2Nu?9Fdi3qZXMRM`wB0iU!nOz>0O8Q}nhgl%! zAeWBU+D#i5%9^7_YB?+LL+i@*`IX#p;>38wGCr3Oex)NIScMx!{(w?+X;C!f%d;Dj zix?^kgA>IG33r5j|lz)Vi!3o{PqHVh5YT&T4uDYGFfmybrTHPa2MnK&nacUV0JX%|pVj#rcI zP_iAzIkb&Ly;emV_f13AQ(YOMDrFCw<-t)mPDLnrP+$pME{bv*togrl?Q%sX)Nkv< zG5+lLjINi>lzV~kK#ISUC|?BpukaVE5@qG&b#E6ZZ+sdFg7xc_-v)v>{nGr7TFuHdjsTYg}=H!4B4;$0JY81X=9Az)xVOVz> z!Do%E3KuC=igmS6#&OIwmhloo{Y-emakej8e9tp1EbYPxBU26@Splmnq%z-V2Dxm- zt7_88tF;>E2r)TD*AMU!M0aKrbnEB~S&`>L@yeRIsv_!&HZ8;Ka3SYq2Gnn7V%JXd2Bh;YerhH&_s#IRkJ}ZP zj)>b43cp*$+{m}^zYx$BdM^`Vk$fL8H}h9D%9UIsI~R2s*(?@hSN7;V zHdCc-QQgocjOy-{|GW?CT%02et%0$nwsq!Kj~+zjMqQ7#9ebUtCS_&MjUrAfiZq#x zxPmu|*&?U65HL`{Av>$H&#{skmzN2-NW4#9q|K%A!(Wf_xg9*E`hc%dej4~2kmB>j z_ga}5@3S)B2Gp;X$RFDhxovK5JRa)}^%SD2OSO|JN%xY)EWG7GO6 z;v#eS5;J_ixz={A#oJ8rVYBBt9y!a(+SU!GeVy4MjgOe^AA^z@*P6?&Gt0JdgK6Gq za<+7{DL!G=Up9=FjL(bs(4P%$*ffW}Q6p}~m#sP+OstV)Boo8ve zGY)+RE=iNJ)3Y+S?$A>WZP5&RFXF9;mM_5Vw9=(YO@iBsUbd=E-V%0?w5?{x#*&^j z1eWFIpuLcTKI?vKu1ge{$#xEx891I$@!!S9D$G-h*MOi?XP&0}9d?BPP-5DrmOWS+ zryALEi;X2X?sC1$YSv+1DhPpIYpKO9=*8xeRqT|lb-OL!QEGQ^kx=hUo?auGzQOP1 zdAi*dHskr;!xOT}S(df>_Isd4s1{!U{rO&e$4lP ztX`|#K1+qYON17C3gHYMmU+uwfYGrC1E_)=nsD?59nL)IyLEk-J1>`1!LpNs{O_&daUAIE}IBgk{2_wK6M!H%>9uQY77Q*XsmtoTF&9(bZZkgYd zGkq&p@;?EH0_rz6kzZ@ccEzi)d=o#F7M}kmbYaEWvDRIAv0fIN z#c#{L5$UP=^HzZlD%|8`{)hq8{*GyV&(t5wif^G0?em-gOZE$+UmK8SWl-xuXzb^& z?Cgdr1V%yp#O!+7T=^?=i};Nxo-@ZkZ|0=a9+01`%-58L>4ZzQoq{Zmet-*aBh$L@SDny4i*Ji~UNS z2XL8Vku{(}8Y2^-*eE%@K9WJ9Rt!ryS~am4N*tfnz}Kp>X@rr`k@!LA!uV|9&38qvPDIUd;%K+X7$r9Z+_om>vG^Ba z`GxSDg<>66$Y`i+{eC?DW?nez|9B|nb-;&#bo{Nl2z&j-R%R=peqT%MU^{;lkGuCI z{_wjJ`Fh*VvEvWdwl$}(Sd9lP3(;=*QS&=e?3NGe(dI(=ooFFCBEKeDhj3>^gH|m} z#j?EHLX~!p!2GG@eW0yS%r7fAnFs7a*|n!RufimK**P{$QcuDpuL+da?Pkk-(IPzM zIjdasTl2d3gBAYS5?`|BJY*rkKWv@(RZD!u+AO|iiASsj-+<2aDG~n>tNu-^{ZZ>U z>j(0imj9?#xjuk>)wMU^^1Yj^SvOnZC#+z*W!z*fz7g5V`E!u~OY4meZF8sp+YasN zW_yceTw&RlTh2=zMwt78WqdwZa;=@NF+}fYWfvoX@D4j<95h2ByAg?I%FY0}-f7fl z<--yxq`Y3R^Cf41cs>yh=EIzoRY7)m+!w-p0msmg7_3OsV?t6x%zu?qDbn=>jbR}C zeBDNp4_b*aEGEZWqvL*4B*~Xs8){h;HVs-O3vuoaA`(1uF39>hyP`?U>a~5iR@NOv zjwqO~$!hcfVu|9RKZpQAT$onFYjix#nJtfpfSv|45^7Uc4af}!VOS=(za<}r5c8r} zvWul~aZrcY7M-_cedh$x;M5?QQ8fyPjBbHfSG;2tKX(MQeP|?rOGncwq~)7oHJA!E zL}^a3+%O+Dnn=Bhs2)LTplU@lEofX&t2ejTjuVG-Mp1K@*>RXyT=Yv7Eer~+vs%K| z04K7=zK_3vr4laS`GuAhM*>GH<_x(+sj}-ojpxlV?~motpED;mQ2r9I3rOXuahD+P ze*ky pv1u^;SuDxNo^a>ePZ*RMTuU7XntlV`{7>~8U$tk|9XsEjt{=a_?g%3*|Kbs^{+f5EL0u5l>FA#mV@yu*eo!KG-wUR!GsW= z7nfT!Ij(Xbt==s3@p!*Al$FrVm2=dUEt9Y-sf0%**=mGN#Zw+qxh&c|mq5i#ri?9& z2vAZzD5{v%0s?%-;gOL=Zt)Q^@Z_XB%F_0VoX3=DH9%oY@Bj^vKR7@!%yBie)9XU^ zjgjkk&B%2VJ?K5&yBM&?J`-`M#C7qto|py~O04gjz7tmw$f9k{$4_$PX*S|$Pzo(~ zvc^>NLo_v}g5f5u2XI+Dq}PI=%`XfTk{-%Xb>&aSXB&jISUJCRc# z%*1rIijGkouOA%C1@#BV(%;B9b->2c#wf8DtzNIxAW@#SF{eh4tGq}L#R-u7k!=!2B6PYM0&R$Vq+ z(gbIpySH5%zxhSN4(c;j1h2`vXPZ~r2qP^g{M(${2^|;(JE^04mlf0TcxOCD% z2ktPnXAQYSx9-%X*L}P($(S5mZFD@WH_B$a6=h_o)mKg&Y95>t4g>>pD|7n$D!mh7 z92b{5iW9n;I{Sw!3;Ju#&EscQW=tDj88_*`%A$z`p!QE~nlhnUsd&Af?6AYEVFvgI zqI`$g6zbY3+64&zsOwT8#K!jnpBnV+C8vzJ$FQq-fOu9j9zI#jh9QYIeAx|8W>~%0 ztx*X$E|20G6Cd{t*#_Moh#eX5R!_*@JViE zHt5A7^P*ZPu$Wj%#VfUDvqr3eWfa?MB_+hP;+N9t>&>zhLJ1gySTE~lmU$CBQ@y<| zt>_I-^oBu6`25JZ8t3-i8?8$>o?&&ajPFAvN$N?+gd#p;?i+nd`aT1HS`)7)%O0(Z z+KcdlL`kSXcjP*2?tAa(o_b4MAJvW;W-652V5G>hgYr(piC*Q*BFq{F70D0|uN8d? zva%3#YY4GBF`LtuK@O8H$T>!rl1^AEZ6t$=(Sw-Sj{B2oPd8=>6Q+3p-H{=u6#WK} zDviLgK&s9;yKeOHchG3#Z_Q|p{&w=W+nCMYUZaD*ZOL(Uwr;fZw`P#6gum)dHA7ur zkFIHpuCJl2oQR}T$`VGH$$VV!ZcihdfXK3*)=6;UMDh!RBRkzhRcmbu1tOi|X%o4o zxFD3s$G9lvFOp3#)-|hnxV58&`OI(o?_>IQ{gzSw@)63f055!Sl)lZp+RA+SBly67 zG^TGPD2nLWdz1L*6aGEkSI<VjizPSN zm-`*R#L3qScNqCv;j03+_R(CvukcA#dRSm9zE(g7A4jWF_*6sm!1$q^Fnr`|QZGxk zidyOnCk+-SIv%~8>!NLXF1`o;Xymw7$nh*4=mI9@vr*ZM_Opd6M1FGN-276w%by4s z>)YJPdj3Acz1NVJ=+^sj-|UwC7n>?i%{Hg?zDN=a^Z^3z3ZJvR9k%HmE2S)|#Bx@n zoc&lxZW!;YD(j1k^2LxFM*D7P{2+{T!e~DXjVHr6Cye%!(0DqGbHd1HLSs)D=Y-LI z5gNY^k+KLy$$Gz@|eImdp@(f;8qdd;yBX^Dk;h4d><_=;1uJAUsN zzjK!DacquP|Kyl|gwM(Ay4^@V?XEkKXB%L-?>U$88j&5^#9x` zTE-8ZWj}Z9XPh8zxArKJgW|`|qMxb^Iwx}9PMvmtB#0XO1IPZpvuvl^aj~vlz=Z`{ zJmP*+Y3HVB3Lu5=P{vZHAsKGX#7?<^SS9FxA$^_I4%;+syo5j zN8LHMz)^mTv=pCq&tq*Y+4-AY;}h<25H@<|R@eTNyKIL`UlDk&eb}{kxZ0iWB97eY zw%GOST;p1I`E9QKX*avg1!o_0`)+rQ&oL6VxYa9MGdks6;!gdbdy(L-=BmLp!If_K zLHCGnc)=@T>9msci&_IHyTSRHxCIY-@hRuC;=Ii1Mgq5789Se+%il6F-= zUR_9L(uWK3xn`=TPnrYSUcFE6Wj*Ze8lUZ* zI87P3iK!~&0spJQyhzydQ2qrPCQmJ7Srx_>ee$)655nIVw89DHRQAdr6qY`dw?D5h z-Qh2NCU@}PMumZKM46RQk9136&L9{{u`_w(053aTg-gKt*HlCv*+6V0(h^z22$|q$ zyVIJrah$dtC)!$RnM7QQxi@nv4T;KOGvK!+Pb#S`Fo2IZY>ivWReYW2)pGrI$8bo2R4w#j*fcca~E zvUqlKq(^h@Myo&@cvp>9n&hA8D%A4W7E}TgqdIVOqwc<0O_n6J8%M&3QfqT(mxol( zyISp*s^6a0Agi>v`@VlXnqH!1qZ-$3$L+TUzzr&~uvhfW=#PZx(C$#t4Xs|eiF8N^ zSfp_2uTN!`c=}-Lkm0tpbVI1{II`N5XEJ_9I3k2-psaPjESWtS|> z60<#7pBE16t}!?@R|-o3eKB6|ZR}Gq5=OJ$Xt;}V1+pHYd;>q(hJCSQG%Bom5mw)% zO&$BT(r#~BszgD3QR9KoSVT-aXep?cVRThTlh#+KqE&CGuC!M8hxtcEcdTqZysTQ> z-GcT^dCL$x>~t-uEk=!~(#p^y2h$_E?FzqRUrgE~n9RO4CI?5c=ns@vDqJ~wE>PA3 zyWZd3S|a7E8XsX(!7nl{)Og%)Tnrf~M!MR#+D4vDuI^5s+&JX8Elu_~=&(Pi_v-OG z+Kb{Omj4mlg-o1W>ovQ zH+t;uUek`WL%2CMwUD?HJx_v-j)LE2*Gp|EW%rsrez#@%EURxZVm6|LP1|>_^42Jx z#rTbS)uj!!y?V6-yKA?Ut>7fPKTJkB{c|M4l{t!LZxc9ay%wp>*ZD}boq%y<}= z^g(M_@I%get=*liBXhA__1g+e1Vw9Fbf@OEXrfb^t!9e?gTx#-1jI+luMzEYTn8LN z6m>Bk&(*#$L4M^%qMPM!1>SWf9P2!}(mg;w3K6Eqc!M;>B!*%}7HTAr3JX(&2g6H7r^KPg z(k~W;gUVI?OK6|vAifK0Fr(BEFZaC?eYM`rnHJHMkLXTmiSYf|TD>~GxG;B^U*hg+ zSb&omGCK*OwPjO_Xsv3c=CJm>unK7GmB2LeP%5;~er-WBLV9ykeLe9dEx0`u^#yHS zoit}gXR}rFn|=M%upFEj)%AqX50pPpNTpi$s}wSP*Zj7_IbISi`PR~MD%u#HQ#cyg zP!tRr(5fn*ulG$awuoVWUDV(eRU2<)Z-O_}&=P{4ripf&?_aOd(TzjFbJWnZ!NUtj zlY#9>UQFKQ>C-38qLPm)-y@%T_~HIY8^`grg$3NytrFi&T{5Md3uKEJCo%OFx(bs@ z)mh_8M?|=ZYf3g7@tl@FQJ>GSO~=b;Q0=LRGgmNuwN*%Qf%RDdsd-X(Dw|e7Tqh=S z&j$#HP0E*PVNdWgQRvGXg_X!5h&ZJ_`sX<9#9&p!Ria#|*5zR1&qQsw8GZ~{)NI#U znni0LqZ>O}quo>xwTe?;)E3rHY_qG?N>f9K-P|bK4a>@xiH_OrH;b;ho%4FecVEre z?=||4>lFj_eq(@_bZcFNv~(@%>|+~t!PSm4#xEP!H{Ki<+(u z?!>DE^uK>nb@H-F_T)fR2d$}#ri4>ZoMI1=(oem2f<1BBgpTRjw8ojA6*E@NJ`ZeF zXNkF6Rbp#b7_;oz%Vu3B=A$-VP+r)7!0`*09S|-w53m;o2iz_W>|OMdSTbkvr^Hfq zBlektjkg^a-+7R|blE{|OYFtkl0}Q{B`s!snQ_SSW%eQ2W&ZNMLyhIfWtT0g9%wGI z5A+sIU2%~(tb0XpSh(Vd!!8tu|4gjRullSw;@G2tBRh}MkCaC_Ko;TKY(SN@qjSgU$Lc`W3HtF9Ps*OCpQN8?0$nF(-+qNSW%BBCy``=_w6t%jIQYm& z>_&CuMDlaEZPeeOjq*6)GeD|WyypfhGwnuVyaDw~^E?kF{#<%u-x*H)4aRR9mAf$} zF4=hYSxTpf5758i1N1RH@&UR@nW(<^X4=uok#xjbrLwa=;Og%en2;0h9Y>EXBH`XYDCAa=aPJ=y zGHaHcCxdkgcTr??I5;L$oY zvLD7u@^-WW>gDaE(>RbtG{k`&FIR~&{O%|j`58o`H*=Q-M!L`{U4=8dO7T3%+%#%mFH#-^ zrUI#*=5WeufwBHzr+;qLP80dHGuru}(kW4Lm#yMD5xFO|MSpvvzjgHi1iT1k=9{^8 zz1fLE{m8`P$#z_z4QOzCWBX|D1hPkbMWpBoSeYZsz>6fyQuA>qby}(l{GOn^2Y3!h z>-`4hrtQS%CEtZe{jQ$=@@TzdKlasoRs7`XOxEiJf9il4P1@^Z=C3)GTclM~Oixah zdH!}A?XIab(XnURbe!~XM}*TH!kTi#XsugueL7JblNdFqYgmcvzm>YBopB50dw~al zl>R(LIrs$j4nY0J;(zWp;&wzQ`SZ1X;=q+3EPmT@pFo6mh|h>Sh1kKLJ0pLwzst;( z0YOl|^Jl!^=l{!J{72vUgMa$(QH=NtpC55GKo{GI4|N{D`aUaiU3Vf!JHnuFw6lE2 zQ6~3fFEanM%OMu}0pjv8IP8R1L@(BCjtdU&2vn@eLxRIk*)^X4Qu6v~w&z z?&aA3D?Zll=TCRm8GPq+{b`CSe@r#~C4a`Ne*P7I@!x&tZ~o~o`^HQD!oQ|*L?Px~ zRj-*hkLqWaQ9c3K1f=!)(=F&{Z?!TPd^+x@0~7nxdy~BBbB|2)v&lN~%`c9w6Y=<4 zd-jSXtcwuyXZx6q-G!o=1-xy`D)Ft^)J@(MA|4d@TEU!ROr4-)#J4w_m{x>&m(;$1 z%E%IU`W#61oSu0m3_`DkVl$HSCZ`bM_xGq>8@;Z`&ER5?c_4e-6c$!h?5)n)wchxcEvq=Nlmvdo*19 zQ0Q01x5LW?HT-gDKcxOHdMGS^Ic#|%3?I}~IKsWP+T-DQxSds>48_;O{5QkCJQvuz zL*r4h;6y62Cqn!2a5=FEk8Arp$0ilZ<6$?izCSEK6dGR+C+-aW`@_>83T@u;LNL{| ze;3$)4eY>}g0WX$Ec=^gqO&r^RLc@RqYyST&6JIYUUsErFf5dlH+3}mOgh$ znZggYh+3&nBTSkc6uz-jk>3X~7lGC89<9}nWtpH z>WQ&jgQT`xBfx=UnzzX9@c3L2Y-$-h$3)z5TC`=PRcJBh^2R^Qrj>|%^MRJen*=_M zc5Qwn5#AtL&u^K~>f=TufkRs^h}M^_bd>2U9nfzyvMSybv_5172 zc>Uj#l0yb z3uvYDvUrPzw?TMAt%)o>YE_xwc0&BUUxY2c42@retM-J1s{JGkE-YD}!VW@z#2ir` zjwmboanUvG8mV*0e$H$jhY~gG;opiQp+iKSQg;WoSM~^S3G$ZbTI9KlUCHO*?2liX zI6@5JQvPl{0L%EY7StQARMyx~`=9{n1`dIa8EAYxD#FW#2{Arj1W)zoNG79y*2hh5hhVl~u;5LRald>amk|q`x0dGBaOc{~JJBk3VqCnQUg#@9Cx6z2n8AZyavb z9v7KgtmBEP<-2~FtwV7;tGAEFQ}t7R<6C-0du;T3lT$f%Jn+q=U8#Jr?d$QpJeRQ8 zi4)hoONFB;V34es#0LeBIxOvBq%wFd>B3)={#i8fmlX@`vSC_juN6pz(uGe2Nyd`K z4o`~fx083L{PL5OzYF{jNZbE3(zqw*Pyh&!b+=N5kHxX7J|Z zJ=gQhG#=zm$`1jL?Dd|fDZc?cnB?(#KFPPZEr|=+|2?Xmsu%u^URVy8^u*QLiz2fe zX`JB3*^sx2M%F^8%Q({PU@M@0r7`0^o!`+({&fBMt;X4r>o?L9aSMt=M^pQjL6`dX-!FQ1iba`gL<<2S zz4d1JN%Et{X*(5BC_)re0w(2Q3t_-Ym$)3ZknT_A7>O2#equZqF^{Lj_}@c))40f2 zDQi23dj}N$8~84&OL;snHa@GC_@$1_pwaaR`H`k3r;IEiyWg&@Si}(>ja! z1fpnbQMfux6W=#INbUvT8 z`rOk8H{vQgarwIQjyQYM#x>+VDGndS_b;!}-jz8{y_!#%89ZT>#5xQDaLK~F7nxPI zkCK&A*Bwdy`o1t)zv+~h0Ly^1en(M0ADEi(C24-W6B7PppZYNkw~CL&Dx&c!fbAOX zd6Bu4JWw;``y)M1v<5P2@jGQLqJG%L=zX}7EMLG0v`O)*){hr;fyJyqc>H+fsFm41 zEym|l)Fq{lf1><4pxrfE-$u&Az*zeDT0*}^>kEYht^E^^Shr5mkKse2j7wtJS)l5D zlgM00y<2dDbI8lA6spA6Da}UQ1T`8Iim@J%fVqTe42Lj26QOAq{s9pIX~rVagC<{wAf*rIQN9NF1fYIn>$B~vF+GS*^5+FyfK+*Z zJRgbrT!lwhhG&84RV0AAM%y7WJHc{6wg%HnZ6gt(ETKMro5Z)6%0IeE45Zv6S7InT zP%WD)VW5=9bTLXZI6Nc9>#Ni=U0;HGtV}mB0Hk=GN%&pw@iQBP%y_5B2 zhqxwIwXKg7ZhZbq4U@ZM=5kVXX5Y(v1r7(&{<@j+ z_krI5>i6LH;&$mtdx!tIZ+~qeNwm6dwB3q|@3q@EuyOrqG2!W-7>}{hYxg-h(!ne4 zmXOd6Na!`%`{WtooltQnb3J%MDS(U_^zc-Yx8Vh_!mV5O<5< zzG!(g?iD_zdxd)s0}4O8%%wyI7yqK$FYEf}XxS(#yQOix6d%#h8=ho5AcK!fW0QZ3 zakTsib{|$N<62q0Mv>Q8G{LP^o+QeUEQ7V$;Zv3=C6n6)gSkUtXeyIVH{VWp2y2TL z5X(ja1A39sZB`XN<6nJFLg&CwO6R^p`P;x>fE15Ycan1%csrne{|b*o6aN(+M~30> zt#5_Md*Ct@8t)Ot-J@u{PNDGv!@k(izc?0+x8mQX(0HpBd`2O0yJp;^DKx&U(D+GN zy?K8$st<*YLF32wMWg<9w6r8EQuGdqmqhNEgsRav9GV;BZx47$@%IL0=Zna@K#IRv zlve?3fH%Y6*m(5Pe)E0oIE>fB;?PlWaBYKX4iDWe^m|10ZZZ8HzUqAo-%lxCW$0HM z6^Y$2;Mnog2g^Z8tLt3~;DN;$i3``TT;~dDQ z-wRLL{S@s<`KG^9HXcCM2hw&=r+g%EDxiKd$MD%>+r9Q*w)-6TfE8yGiBuUnX{6~) zK$>1pntqoWAvYNMcA9PzD>u^kt4ABJ@;bzgFT&%Hgl%sGv}35vk#|vPHX;;E1qJoJ zQLtfN-0x4(uG9|p3T5j{R;Ck3+rOOh`+*w)_1p1MOxNco>)7~5_oef5|7H6lx-Tnx z1Yb&3v6jQn(nr^5F$sFd-J*1lm~^+AGeI3%euPZeX3u?T%c10uX} z8qHN7gyehYI^HV-#Knv=36ix&k4+{c2viyKwYp+DSi>h%4Yd3mVk9#9E{r(>kF1RT zYn)Xxne&NQz)B=%5XUjYAOWC=)_B#Ha5%=#8}Jb+U77i1^4+S$iz%4FT ziUdO|4v6tH{7~F()xN_h9}k=ir0+kA@?Aix2TS?#Lz4Vkqhle`M&U1Vr!qgEhUxhl zZKupUq2DIVHnjNd2Jes8U!RT&FubB8L(`2wpGV~7 z(S|AU32M1w4b0vVN?v}70SJspNKADECzB*yIb4)l0(pGBrQ#r z<0A>$6}_t78y3a&{w8%w*MVP9eg$|9Nc+LvMVE9EJ>`tkCLXY6&8Cg3 z*ZkYWBO(nM72htdC21vJN;xI^+j0}{ygz}$(on!nO zUQ6iENIO=qU3=8gXX4zTa-gobo>*S=k8b8;+6xSGv_UNnB8TA1CwKsULDvF=T%!YP7U&!+* z(rkxa7Qd83&q&WC02#J!rHM|9x#^(|Hp!dfeNP(Sl?OD=#$4X#%&;)2lKCaHj56W6 z(wUzF0BmEU6>1dG)=zT$H;u+u@*KU;%Aa60tVKlDb&7 z;qbJV*n??hGC2$v>7*hQo;TMxSR5`7*T*T5d+%msHXj`0efW`4`g z%8vox0aCnLU$-*X0kvV@_IIqr7G$4N&KU-zXzqDV&RF9Ah{c}c2*zM zvgSdk6{fM;IXJ$QSOn)V9RoQ;z{u?T1q+pAX!g*j3VXK9%c7`eAkSftKUeZHz>Rt>TlYKV8Q5*G1+vkj_U% z;P$YfV)P?FzcvHpI((NfMJ;0r-%Sw72a`lCZRGoiUyiDqc`>Q)^VB8fhh{vA-UnC) zq;&9X%2xt60O~iEFB;3w{s7ldb=^oi_8Lzc&)&q!K62)q)6d>?=Gw#6!6P?}9v*wc zfh3J(rla*2Lx%%3WXEk9iEMAvNbAlJ$ybV1tr*t$n(Y$2R~DfU(y%@^kbyj1m7rtH z@H%c}tg{%-TqPIBlS`dC7*R1o%o3EU8twr#*nb`+yv+8MalgJw`%^rXzG-E;fdL@x z*SAq#1B}JbxryClq}5}aN7LacPoZH0Ko+RdJU$?^3*NHDQ=h=lAo6@Gj#MJVjr2P` zDnWz`b4ly7vK<;%M(>TgiE5nUb=3*jeVwF*dP);cK0I#6F6wBj4&wJD*mfL}@DC&HfZI7s)qJ_CH8nmVa|vFjA;~fDF0=71*0PHK_0c5dSfHq?+U2W9 z7z+9AO6s%XTch@_?`_LuPG$ccKw6*ml+OWbWB8YpFCMAS;*A@ZuU+qH7$ zR#DEthJ+bZcy4A-^1i2dR@#rhr~DG|I*^X{++*;tzptd`G@aw{ zktp1zqHx=;^)Av6+$=J8p_De)=xh19hBj5r#F%MP47W;EPErCWjYTFJMbsFk>AamM z13|EOCezEb=Q;4-N5uVk8}&^4`1_Q93H%mF+f#fTJ_ncwsNYyST#Co&B!ABRdAu%+ z;I(fcYL2pJoU1+|Fgj7sTK&#-aKCD9D!XDY(8%1}uH7#9lmQ--MBuY>>N*Zdj7I3T z%-N(`P%eTp49JzpcM$tiBe*4Yo*EM7G*0=9ZzmoQkpzr{66;rbXPx_hX-q zU&WhjbnHOIk!XsK`}Xi|o)RKqa@T z3=FuD;hER%wUF_+g-m&M@?t}6$YG2DS*#_OkDkY#6_PqrC3l7+AhHZl#-WIVc~Rmk zvQ_XwqwfoH|3!8dg_3JAkZX@<5nkdE7#t^~Z9oL_w{0-n)ARX7ePa-!1{|Tty ze&hPdefjg(4%}~D8XebB2^*3c^b?ObS_miI@# z@~OTl+jh5Y++*`eP5d{KxnQ_Ou5qW1tXukV%!!<6RerJ9}bCg&d#l?a4pTsix@ys!}R1pw0gC?zo}%efjAbI|3*lrBPRp6hclwES~%^B7gu&vMSf)X$!zwPtoAcIcp7%l zl)A&md?e;FSf|`G_(fNq#y!_Cf}h#O)3$R%*3^6FQ{vb!Y~n#D^-WFp$a(sh$~P8K zZ8}ALW3Ub1K0dh^v8+0j+cI*5o9V9lx*0j4O=UGA5|V_oBt2$zwES99E~H*N$KZ0o z*K4D0BNZ}979EBWLBk|II>0S^Gu$YN%}IKe3|f0NTc4nmpeV%qqHT21*5l)T+(rMS z{rDo~zXNXoX+OH(g?|C20qXbsnDzDf#I6^enRqNiP$m4c#JKg7I zZq=R?nRB76XN!5 zr{1X^`=^xKzK7lkNZZ%=ee!<;(|!=Q@3tSu zeTORaLAgJTwE3*nDl6;`Nz{bOcmJ>+ZC;4??ua+%M#rv|(dM~$vpm{~|DJazrk-21 z2Q+Ph{#9g4{lEDvEnP14%QRed)Cb`Dzb5Q2(c_M}RYllp+G5g?5P5sEa6X9ZDc?Wd z>HD(&MZe$4*W8@xX7x&k1C2M4T|X=^2%BbGLxAfGq32<5i`IH7;(fM2ZeP=SLen1C zPB+4Kt$|N^4i#jRehbOM=J9zmB8aX+Qp%bA+T^YRpZ4TCqlTI7*YNmnC5n+~QC$Uk zpqQKK&tdLKYsj8Mpc*Pge}}H!sb_cS@(w-QY*bFr4$}^6UO>(P|7)W9bzyu%nBP*P zAx^?Ss8atJeP;CKG^DgiiVKdik8 zm>gC0_uu!{cB{Lq_ibi+rf2V-Ei;+y8(By~fB+$cMLS z>pb0#5@sgnyF;{MauOX?i)WMLWj>K{${asVe`B66t%=O%YCzVfaPsqPeqewDdI;-* z@rK3kQcKBVQ0Q0ds$f2BW1QFJpyz2jzeMJP>hpmTf{`ylPeS@ts@q>fe!UE>NAKS} zFU))P`7!gs7k>^|y>0_3k#}O;JE=1(nC+F-&i6 z#lH$QiBwQ8$4LM1eb2gEc>ffv9k)q#e^*c)eSB?8(DsCPwMZ>i`;QEBB}kFLMHS$1 zCC^SwjWx4MP}&sCxM}RKhb?7IS`x&KSf)43XUZ@V=U5O{s*s#U7>H}NlW-$tyT*XM z+({)8u?~tpcgN9(6M5G}CiLt)fqk%7@@J9UmCO!hzt!ks53CQ~J;+8#2!*x~-YDdK z0&~`vK=CGA*$3=>vRLk=%=3ltQq`Cz@~OSZyfii4C{ihvc6Dgi3QrN4IaV(NQ@da%hP?)x0?GKEF#Lpj zza#yg9+W?KBY!pqsr?Z%dw9>7=0?N#Knq{*OYco>a?wd!w8=%zY*uBMRJ3Hr28`i2 z;hrjiLj|43GY^SbY6@dGiV@#xQiT~jh9ZHbv#YA+kqyQ&_s{FUCjX6VseO_h{RKn) zn_eNsd?O|0t@#)FpOcvs0UQOlsXlP9#Mb0|*%NZbt3=4Ge0>q-G&%fYX1J}1iImUe z`n{>tV$+JbW~VJ+g>)v}fVDP>Mg$PDLM8(S$7c*BVTtoWd5Oe+w-@~A0I^65SmN(O zO?Li)3ZOX?na&IWR!00q=bJnln(cSN_H{wOE_&9991?cQL9~y7J_XhL^;z0OzrlwJ z>DS8Ne7IlV3FG5h`vbo8-dK5(eqBgcZjwKi7fZ28o@-w0cjY&Q+Zw&iiabO_PnwK1 z#3rD420chZ`>V*cXI;s{rmIJKvY=`)UEUr8F`c?NrhXue?~~X8mzw>3#FHfqTmF`G zJ{U5Dm9dh(!7T+ymgjhYHoFCh&d14*@sOHzm?N_3WKq)<$^7Az@+GdJ}f{nx3Y zL#aqA8B~leGMM^HyuQ!|ME!PSHgHWH{dBXg0dz2y)kAP5%%XrU;wjhjN1duX%}TQg zq`u%L$uD|x&<{(V8})ZxMf*F@lTdvgeD!z4iaw8B81nn!(QqF8FywFV1l#SQyt?Eg zL-;8{NBDT-Em1tU(O=K3k*x>4aXZxGG+33#um5B;@C_H{K znrGZ8sz<0bYAPg? zdt}(y`vq+N=JT=%ke;Jq2sWDR8M5ts89z@J&nMx%t^l&g9$)ktU74om;I0PelA6CF z0$WyW3dlUq)|r&40}Ik)v7?Aa(Nl#mD{_@B#5V&T1PyP7{%vCh)6n{{9KKgCqNdkZ zpSzT0Z#Iw71A##_1ILWcGV7NO2=@&UDaIb6VH(T|OmY%8rC|tJ*ehz7*+8+Ds4>NC zi66yX=zm$c4vSV2F5vk(dV?GYx6{LIuV%Y&idKA2{4xa#l15(fE3{e-53b;+{L#ZS z2W~T#GP*UYON3j)ZRB?v!lLuKH-0Nv%4^1MaG{%p7*Z9d2{pL~$z-8g>zsuRhE6#` z%;X%zWwDKl#cGC=SNl6LwcMS-eocM^_OGa3FAn9N7Xv4tioNxSLe=in<8%AxgK=GZ zVU)kjrhO2!2C9$iJ7^ET=tPcy^y}~^gK_*`xSa`P%l{&L+xCCsFH3wze>)r=M!&`I zH~R(b{^tUf<7~j0x^va7BJ!v`C^LlwXi!6>?N)Q&Kggj!Ar3NJDJf$fPM#zkfamiS zu}B<@GiUN2Wb`Ge{vfTFq}6sAIr7^^#zuyxTE=l#lwGuI3uO&hRX(7h7;L-9uStJ7L$Ps%0yRUz4C`4mrw*h-hO(%5n^^9g~ zWCfTE%lWmG16+H}m`iMHOwO|RA!*VKw;XRE(7tBRc2asd{<*+ebvCnrHQ5q8hSXU> zKkeZ8w}#JH{13JPs2!^J(}T3X{(EetkbX@K`OT((2K_ZN)Dt#`{Ac+`_S3?38_u-@;cZ&&b!TeFVk+6>e&rk z!$dW=J|0*Nl-P~&Gax6LG3HT{S_#TsfcRdZ_X>R5tw$G~&_i3N;H$EqP%Wz&?NKK) z(j%m&ehgc^{Pgeix&FQ0uc21DibFBsz=fNLye!b`N;D-X$GlTZCctC}9r{ot1cKV( zFv%jqCt>s?BGzVE#g)LqV+!8rU?Nsv29aB7Cuna86KD*|r^$CDPe+)U4i6shrPM)k zoE;Z6p6juC>tsoYcXYBRHHXk-O^M|0(NmLh*9Em3J3sJX3_=5$$Kn=P$BScc&SVSTL78y^U5GOBeJ2kKkbD9 zJda|NbP5bn|J8ayaQ*6~(d%!gJqS&N>eoM)_7Tw7>z^6QSG&0W5rFYVu|Z#d%)fpD zMow#!2eV94aa#)+b>kyKJw@P>wiojfhO6~h|C%ZEf-zBFb4*|J_V9YY$F;Nuw-9-P z_V1wIL-p&m{^&$bh8Bm{_so{yIdAM5V+RPI_uQ2lqxGWrX#ncH*?56#+iF~HMgFW; zJfN3nQOHkbiV3w4(-TW{%Ki%JoMlRvnh)-Qqrg6uu`4Cr2EDYWy&PF;h_qICM<`v9 zZKV0;Zd=~e=ZfdhPZYQJs?9a>4V8&xy=8J zdCW|M2?#!U!BbpYXO&&~YP|NC=0;G`oX;FSJ9pHSqI;P=<_TlL@n0`04y z%{%@6J+!0$OI_B-gZ`@b+dFN$?zeqTqS7HQtE&Si)jh!`sl8NN4QxvH%eJUCO5k%w zv_)Jf1FeuEmL2IeGRcO$K@WNKM1nj61tZPzQEQ~97@ZoC+*bcymwnJ_ot< z`=lWE_4|Myb7STj#Zbn(L^3sm7c=OIOQckP&j@srhOfBBUB&1chP8)$fh~5Dw!dyQZZkl24$8j^^69nXy6)0*F0f4o<4=!F zP(}WGPT!-%tSFO>d6{ZUccwZ#$}p(BQOXqIu~vypfbnXtzTZK4C#eUlGzkVg{ChE+ zK#HX2saO|3Jm=EjK3Bgy+TW+qz7V5GRTQSC%wF3AeuqCVBCms@NYbTMJQoPg0KAG;o3`x)a}+xmiV^x3qBU9kwDOD8 zgEIqHN6?PzRSs@xCJDi5VYRRrI&IpArC+UI4eo2nE2H;y4(%(T`=Gk~(e`KR;Xw~W z`Ze@cFrHry<-wZO(*;(|cuMMO7s5HC+Fg}%Y?vzjI$~iw_qdWdI z%&M%I7^AVNR9F(D)&MxWxlj>mwo8#OV@qg|l{2srsEXUFYS}9Bzwb*0th|6=h|VLk z(N-(}3Xindr7-Gz(MZ;;YLqywYDs_o9n%TJU?ONoh4+k1JuRAlMsiqm8U57iV{M4_ zUC*@wV+QF{G~ub!76b%Gv<*yj{#F5QHEG3DIGxg2MwACP)hO>K{OzpuqCp$}!Zsz1 zNp_)SSycob9)yPtqTC+BnvKMWebF_0h)&c4Garj)$}*o$=Jud+@zi`#OdxEID?A2W z$G7{5c61D45ix*r!}y{w@X_WO)%-1$U{tf?yP5GUNKMcSImb*qAo-QS`E}nC|5+3TOB*k$O^jCdg zBO`+ebBGty(^)Srnw>S^Bp3-#;t-hzdzV9*Y}V2>ugzBk_tE<5sJ(sYfk2^7^YKD7^0bXt@EUXKwdTTW%=p#j zNFRZUA&o2yQ!^okv}H6f39<;~{_@dcq`_rQAQ>MJO6??^Di$JX`W?0LYe7G4<9_P* z{S@t&pjV*!c>6c)_P=8P3geLLahvrzydw`jlzVVeFC1^(1#H^ltltAL{t%?m&6LMpdGn_-?}mOH-Hs6XVSC^0Si??5m0 zhr=$i{>tEf&gEL`xaF&9e;>LZs;>|KqW#Igu||aab5Xc`sWaf0kxU zHcr3J5Sxw541e>C@Hgr@tUz0JJ>NS?XoPNrnPG}O8-P#T%wgn-+a=FSoGU0om5i5? zN_`r3MUbT+Nwrrl7#)6|mw>Mk&BK=(#HkBzS)!yWd}f6q=@ivksmo$w-R3AQ6|%BY zE?a-1^p!M#MnD#NpaNzVA*d`aI0~)U{x|$ zmG0DT$w`bE3(H%cZ86-U@L`_!lI#DQUSkEj z%rTy{vsEw@8y$eqz)<+^dgl;n+(soh3J>0aSZv(uG~VYV?smjo&a&@0@$Wj7n;h|V zXW3RKezTKkG~c$3e^6!AF}~_p-K=}mA^fVN-m8G!1=d9)zs&wG1;5utL@d9f~F8q8Wm zQpSDR6^T4~J5)ApTet%XSwi$FPTI}-nra{`eW|H|%q-gE9PYzJNfA$U8Yvoa<)woo zy#kW3QNeqT-e25#UspTpc%>vWt*AoD7)3#eNhXVz5^YhZSPt7QF=gi4D@B#{##z;b zl^aSnm?X+ltt~tKm7?!^lEGi;HlZDwW(y_&FZq7W|_;5+iq!*?fY`#gd7|$+pzIBnFGr#3X)x za=`(-mfco2^^9g4_MWg{SdJm!u?htG}JAKv}qxq`@zmqjG zNzs^0q`*hv$V7FP-DxY8B3jT&#x*=AZRPxP!J$;L3?$z_lm96VcEI4cqb)yJ*caKM`5PFlO- z#8sp6?D1lwFnHvM$evfi#9?-ZX7E1fd7;nH&XVJ0@XbGObRl z8p|4r_>%zZ`$C4)vY7ez!4e9h=tLOtsxNgw4uvKDb4EK+=_5Nt&A-B!+?og?3 zV>a}@qf&RW#rudas@e1&RH=vb{)bie5w;pOqxZKXfk)GT9ttSR!g@j3o$6j?{Zdt* zQ7B*cP%2X13%t@GCkVarJN^9+l=X8}{e`l=Pc~rrEtP&s@4Zb~KUCF6^-%%05QD7bl%f$Fu16O^sI466si)WQzWA zq;m^-P#1E!rgcyaT8Jx`FHfk@cu)-7uR+h^3=8 zm=&$Mq&0JjaT`8o#j7z31A96_6%@ltRJ|x(!!*?hVHl}u(h4NU9b1EO8F^D^!+cXoex-T%e0W5(sGla5-uhQJ4ZT*~6>;&StE zLcA`1!A1|m2S|P3ul!#QM1Uj}m9<_fKcttYM|9O;Zhjt=vG}IsVZkb1vvty3L5du^B zbSYL$Hzrw7Q)G5jIkL*h4xyUUWki4e3Qsuix{PuCJTa+kk0ha>G21A*XOJ;KeiZmgM*-{G%h57)g@~rY%E+a>92}hG^gbvw*+Jm!PD(@zunf`P` zZVxgk&dO%cPq9xIM7yO9m8A)zOH1e z%`ZPy_?m05(evvQ;2+W&v=<=8dWf?F)?QGFlpv%CfhpJUW5nRp9_?1z+OHAgSYjau z?LPmHv=s-4l{MsV4QnO`>XQv{Fn;53OVJm*9N9t+z{;F)mkLXZW2sK?jCDaaqvt@xgCR0mwkXzKO;*9P}96Q6A zV}o{BU@f%br|fSnwWysEQ%SS9#$8*PYmj)AfhWz&qsFEv3oty&P)3HtzEluWNtH-l z7maPE5?bo|XnYG>FyLTWI?TR!r=6r!U7C!>QPR4N%y{P+JX1|+>S0rbo+BR?vBwC) z7}o)yoNADh$qW*UnZFjsGnj4|d@juL5@9~zdfg>i+=@q)AJ3>Kqe`@5%ks1>Yd7md z`vdmSKXL3{N=V!pHIh0T$}OyE6wY+7j9TA`R&(kWPNy=d??lzr(bzRnT~$k65w%=( z^XRvVZ|{t%d!p(_eT;R#Yiuxvj6u#|a9&{y8{;kH7Hc=-Q?EdfP`8)TKAOp4zk~gv?G8ruXBVg)edj1Q1Jb9l z0B%C4{6-NirO0^F zej}5Mm%KhBnjFRIk;F>M#)ipCsy`EUWe_+!AN$)r7$r%L zL=3Dj7iISG7;=?_=cSjF^5&#$G(XJU@~?TWk5}xD)|h_Oq*AhBt|MA^`izRRdunQK z3jDb}Um6hEDH=A>)S1ssB?lt~8T!?PREwELbaDOXp`S_kTr|@Y0|q^A5TL2G)|}UuV13phSgKvSq*3 zY=vsnFo;R{EsetfGvNRGjNkTu*l*os0#}nAm?Vzr5xp~|8c2_Ge{RD4v zdC$t?%HFkor|i?UWWj!|OJ?jx4bo-(2b2z)cVOk9p#z&IXQnYy_a|d}Gb@h6iqoz^ zq6miiGfT1l?7ryW0iTRQPehju-Kfb!G=ABvP3&&Hvskw zTBTx%1=h`5<*KXFt@J?*O&-~cvhmfJN|zY5O7A6{H^HwwC=-Jo^$BAJ(dQsVN%Kn= zX}b(a)Szu7QcgelNJu;HV@dfQrj2gK^?H^8D=$ZO+!L&K+l3nOoBfS8h}p;jsJ`C) zmNw@2$g_}s9UjJk-8(l}*S6OE4U2>I?zGc(z24z(*z@?4S8X_9CzUK*3in-g3?{YL zjXwvt=k3ymKi|nluX`tj>)s8)GMBXHAGtyuRL zatiQQ4q(fGsW7?Ps8paKDq2^s2?j;R@k&ObgdmpB;zi6QeIG_Ciccz^WQzH%3=`4> zT&!&uQ5ZbHo43p{aYJRZ9vk}3Sb z6#%splOi)ui)1-JYZ(J@n6`B+>vFk|nfD?Hq*Wj>aj-0^U=17tZ`K29!S5g2=$RWLpko5P%qgYj_1YS z7&D&tT5;66BiCpN&HPF1DO2n)oBa2(|Nfr!6lVFY#&7EO$UQ>sR ze%yPU_`d3Hiai&^No_!wSkPwvTtvQdME{g7F>Ymq52{S5d%rF zQm+W;S~)bRl%ZE;4`5>zjH`;yB6(LaLG2Adh+TTsW?E$u4b&Y-CtEO#nNU&=^Qk*i zMK7cLZf2^Upt6#)^8Ol0(u^{;Iif!^gA|!+F68-^iC3^ho8Hg1l8%ZK5>aj1Z_p0P zl-U@ppJk*yH)S?cd!6a&w;MAYRoTT+fbT|*l8t1&);b!`k#|_2XoD#L#pKgSASAOc~gc=3u;5{>btUUOoO*O;1!Q@$~? zG+WNi$u`DI(aG+?+HnZfdcdF2ERJ?vQEPW5U`zNPnM(O~#jL0%MWPi!)=;w@Pjf0b zpBEh{S_L8>cyBcNu{C1J2JJEcj@ZiNGzVmxNuML4{a7wi=;q-P=cJ;|dVyoxXaNsH zkkq`x|5o!aM0QRawi*p4PVn0FlYnn*Q={wPBeZ`Dy$IF)U+>f2$5oMM?hfo0b^q77 z{|Y{j)#8?(uo{Ee4)M5rO6RY?G{BD}0{qA(@~%)SCt+^D6|_!cNHF|4(UW{MNn+IZ zs(UH`^k|=J5{P7u0)1q~6+wF^NQoXGgy(1vZK9#O%;;?kz$V03YS6(~`e?o0bmN=O$(7`&(68lB1oyd_>#zBHB9ZUXeh~T*RPXO+X}=Af7TTL%3iCi+ zJvJZIDI3G^6x{*&H;<5*ejcz$7OQtnFGbv^l&CcY%9my>IgaMHb>38q8T15cf}9GrI+s)FlTNMi}&4Qp;f*Po1`b`ZXqAfNcU=9A9=)B35E>z(~A zs(lkmO3Mi?v!fn651<}erjaVJo~i-JP_%ZfSX?UF9}oSY=*I=>WDrAa%>#Ob-Yvdfs5PNqn@ z#gVObM5|bz+(*yS3oz6X*-#aaxzrT7L}I<-IT;7zH~wWXuCWV5=J+Ev5}8H&0O$~? zJ`Yc!{VnL#hl26DbxW{4)?KI`;YLQUfPqO=}`TCm(e~6x-hJp5)b3{%rNeJ zWS!ABs#7p(LI27+JNFu2Caa?n^D zPdz`($o1JJE<1%5hx0Qynj9XisTU(nfnquNbI zJ&W*qR`XkRd+ldvp9P%*)vxCw+FynKs}4k%SL#F8b3BlIovUXrKUdEdV9I$lKrAQt6N0mMo=>rmYc5ev38Q-C!*CV1@@%YGW``2_GiIVby}Dv zsX2q+$(k=V5FD`}SRXCXWfDKbqpec2mp|pT>Di#aU*x)%`+FjhH)t0!D$)ei@9!kq zzk%}E;Qq|_gZcSf7@zoye+Qq#Q$!veyYA@wTcJVHM46HgQi{#;cc#BNGx&5}uxZhe zr(2BYRpe1jggB>d_o(y|)&f~vh+qrF}d}Fp+%^DrOsP zc_u4}x!;=F5%5Ph>dmw^YiI%fm38jE+_ z8gce67Lknxa{4C8I-q;-_1^{kx0!ya_un0~pMrh?)%$O9PDQSRehTT=*#0{$lq38v zd3$SMj6Up-Pr%w5l=DU5bKCn&fAgc@(_$UixW&K^_#W5{zvC_!-WP;1i>_PNejxUe zWyu4^blrk92VkWmM}OFJ=MYG%4!B)Mj$ch5SQm@hm%+Sx-sHwI>$S=^kAx`@;-WjS z9i*-9!1$OB%was!%bxDOl_^&InC`w_7EBU3x;5R|@lK&Tv7JsF$7fOzI?dsBB-fO- z*yv7drxV+ZxbDPUyh$D<*IJW|@uUU1M9_teVzKVH#XhK_f~eQc9gTDx2H1a4`^&1( zb>Hw+lGpzy=(jofQNBVDbmR!=D5%cY&ZE5rnm8sO$*E)IQ=iXj@TWQS$uRp=f$sRG zh}=o$@Em0T;`lN%(FRbT;1?X(OuTKq-J+9`VTZR!OJq`7j?Cgv0YX3xzL<}Ag6L)! zAa-v4eQ^Dy0_%7DQwnK4Ec)*S`11ALbjU?P}bC@tC`E z<-rFt_;!dxd`0V*fxfj|D_UEOZD!=pEcoeXMe;c@_)n35NvdCn*lVKN$oldNfjj>L zFopK}h~K(C#AA9r zXCZAzPAjWUr=h->Y5<@j95x~M^$*X=eJLO`gp{<0;V;O;aF;<{cbEmaD)3-3kAET< z41?h`j_i0Tc%Dm&Y9x=#k+e5Jr$F`ba5?Sm(AHam=T^^`_+A*FJhILmx#EO1M+MOh z+r&5J?Yeqx^>+Vhy)7f>f^wgZLBNt7AX+Q{DQn0sp(FGut2z2C+F4ba81=mOxlBzRPHvEY#FP|4GI7&5j$Di+h)gZ_(n=gN-lPMYzL*xa7kdDNHeuS z7olnt>C790sT6wDe@yY}Zc0;=*|8cRE0Jg)~ zno!7@2BrRyjC@bXL#SF|o`l(BNSy4PDdL~j@e1qtljq1y&YIXS*3gkv{VeDFCFq~; z@!SC=`LCbSejfS*R3B%r)AkzwoA2!SUeG@yv*3xH23CPbonyQmjqkb492`lZyG$M~ClZ6_mki-PQHFj7>Q)=Y#=@?1d$cRRKwULD9EoE*jVGtW& z%av7jKa~NVM8KFb$~dgPAPUNer3;MO3ZwayGGK*#1E0zqa4wYw814;~Vcc58h5~}( zi8bj2N#jMTC1_2cMomYiRVQL;D)D<|Xgo*YcyzTq_4$Cu4kJrdF<-V@r>RGU{ELvE zl*h==pt-ie#jX}iu|6HlJYIG;S244tI`uY}o5G}Ql^?ezmAw2UXMep!2d`~!2mQRA zKCF+cr)a+by#&?A)jwz#n*VzqoEYX?8R=(a+qpWu*LLx%Af)JM9a4lKOZjuFjqAIC zDK3{F^>GcsO0zfYw-b!9vL-PFcy@rqM{=BBLGA?Daar!=%Xz7Hg6mz+wUokp`0Hy{ zw<|iH<&=r6eHiZhY>n;-kIoOGgn8WUbh!(#G93NRlIhBaiV#S ztuD3fODy|rJI@5m%Ec`WsCgZBA7wznOAGRZGnpnMp)QqE_b?V&(dqKj9JyJ@W$8Kb zlB-S4U~LV9#6n0xQ5`v)a)|+BEg>`VrAE(}jKi-HvDND9Hsb3>yF*0Zv}$i#C6Vkf z|3DP7{d-IQ_9y;_oJ!T_tX>g)${Kvy!n|-oZM8jQ4_f0?MV%C-VtBJUNgi>fFlHK? zb?mEW_23*l&yIb;*4_)_i+22bdSC<=E38ULsfvHt0$97OxP_RfnI00vaf zsWoTC-6VnP_T&^NL++JYWkGwfZE<^J8%mkEyc<7?J4n{DvfJ85_*<<4ys#$bw$UBO zkaJ@b2{Wk000@|LPhX3v9%mh*{{YfnA7%FL643#7Vsy|QmPWKI)<%h0;MU|A(XcJh zr6GrEMN`*v=G3-PyT|#ouY|6H>htd<+P&@A)*$`5`iWqDelOh44Dc${sc`jbXk- zhE#`{7Ye!WOR^jHkI`X}InT+DgzzCFmqEaEnyn1bGH6u%IGCRHA?K$Ff_!px*l8fo zcs$jeOk#S)a|L0@5a*2q;Wr?{Z8pfzCA$#TE)p6j{~Wk?4yoVYHl#7#zJljbw-QIpjpygpa(Drb9YMA%!zxibFjJ6q{zugeqj9(~!^R~Dhe!j(cGZwi_ z4Kfw>=gvthi;`j4dl}QQ(l*-%+pFY}>R^B69y0q_t7k~pJW}7s;Y1V^&0)ZH$K^2O z67h(8ly^UsQ6NfoG12sTyC0;j41421J46FhsZD^Fn;>|tT+GiNst%dK{E!lRfy(y1Rpv?7=_gFMz6YRnG>Aa54f{a}xm>7})X z^v3ero$r+G@$s^m^flwG8UDJojf^b%dAD|s%1h&Ee;hgzs*lr|UHIp_RpiT%e!cv5 zFiusd4<3%j<$n>rUHZ9QtP>~r!}N9ICgDRzejFf3UI{kOnEuYI9e>lOQ6*c98?uq# z(=TbA^ZFl7;vF4CE%&w5|2Wk@Ii9f2F=l?*h=L@wFCa;(eZI;dLL7b`4z}tSR67~$ zoc?!lg=X{-U)4ukiUGV`e&Q?oh>P?QXQ;t1P_{kan6etN+9%c9N7oDVIBiJ%VM*K{DfQ~_qb8?TraF2>$7fEjUsxL>bsU?tN8&d zj?Mi6!#dNLIiCgK4iy8=eyd8qtVNk%fM~OI8nF$y4{6?qv|WR2W{7Kk7Q0|cXvy0J z(r~4743#Q!x3+dP5qDn9vcqYmHJKye%l;9)|8+zMM>G?oavZBl3COszmc!r-qmMtY zVXd8}8WILk+;Mnv2mAH`hY)k-nx0-mj5hY@p*vo0p&rsRtA-Xq+Fsx0q8%C}`Ei;u zos=MSoC@A`&`_iR^6-CrqCPsCc#1PLrv=cnze{c*dm7fbnw$jyem)5i%LL#}vEbMK zo;@fhq0HkvJDQ@jm@}QEFa_BEY_Xg*VJ>(yF!Em$UQyg6SX{hJIom4w^q4*ngUqkEgdV z9wX-+Qno)y7}Lv(!8}=19krJnO8Zpkb5MPr{F?T-8uJIzuiKsq=E>TSpFgo9`0Rhl z+nin5OIEHqS=&lB!XkYO-8DfF-P6IR=D<*Qza4qUrK&MgLtNlCY;=w9!&QnuQsaKC zlK}rnC4Z>KSnD2B>5JVoM>ZD81u|X^eoZF_{xZfd>x*vfTvE|_*1TA=9-4uK+az?t z1Z|`n_Yp?AE|QID16?0>1#Om_q=x}kRmTa;a+DA8hscOIZse45+=xL=z$4XE(PnT- z#wBF9w7P{KpgapFg0`cM`>;8V1W0M?5#6oYAa}NAJewPX{&|__zA1dT|Dp}zBvOXz z{qtGc??Suv2K{rd5%8(j5MMMiw1?OG=jyR>`Pyzl|FGO{GR_XNi``*dtdopg7;Ks^ z_Bq#uZsgkNAeqk(GR1e?hMQdD1>HS=Rm*(X?q5~uH4T6Z?cjab!BcOmjCt}6u5}Z| z-R3;(CfZpfu63iL^)9#i1GjV?xK6p%y;sONZOvK>3D^gbk7U$VMossXtu39(=mb+s z9DS^b&`MjUYqraPyejziGW3;>H`Ds!gm?pNrd^zS4%a+TvSvO3dRM^x8jE3Ho^l{g(5)Tz@)VyB&fU?=8j~ zGV;@Co7n;8hb8`xK!fdb=-1N`f+S6{%Kt}qtYyE~K!S(rM>aqw~ zBoq?RTflprxDMFU0ckprLlB#}u^ou8Gr@CePz^s%J*Hr-3updoyptkj` zYpwd=lI}xrA7-GBeurel1$t9L-n&_Tps!yw9>;A#AmJMU)($7es3pfzMAS zj9YcE0U-x!69|ZrIaFhm7g?Q(($xSbXF2IBIw%H!pC2)oWsJw}+6`Gd*XbnOBnlXK zPkJ*DaWx1{i75UYAP@=t{_tf$=B0lxeeY%G!C{P9@Kp)fU$E%7zJpM1o)W2JkTjac8<7$7WKB3 zxWqOl7*h$xPr1|7^p$2eai5!oBrUr&VgH`bsxJsNoFThD2IWO+f0BD42?6QGm7HhL zk-5h#AP^R(w&QfzBxYylHOPd6w)D1TeZ{t^cV)GJL+L~8KTEXzMi3Q&G#xcs+(HxR z6${I9EUrzt0i)J|*28pN3hzQ9wjgmV1FP3)^j74$(2KO_U(9*UcFT$B4%cl_&9hka zbb^5Cgk!DaLce3yT{5fEz|+^=*AYKerBz_VaYw^PxSVdOvTV{UG#fNWbEto&U671pRzl z=)ds4U&TaBd<92G!k#XsZwXZ*=ga>PApKopA~nEucg}Q8499Z9xTsr0cKL zCv8~GV~}pymszIQCI&}Qw(BnYx`7!rXZ9G4!5!@w2%giT@hY-Dyvd_!pATIO)t}P~ z!zyyZL=|}r(l6B$$QR4Pya}ZczZ{+-Vt$1DH}aegIB^wD!S>De%a!YFvDwDyt~aaw z_v!xopTu>5=(iaEsYc!hWxP~QCj(eip~My%iYi~KCF};p>~`)(msagb)5N$WBNJ?>M;$%P*o*e&Y4x2wWh0P1b|`kQk2vm zgj`x^Is@>Ez0oVNs%-)GeTHY7!|%kSuf+%d8qZAUZ{)8e7u58yKJKCLIO;0t-#=0Y zzrNf!G#dQw20WUdkf}HIS;&QcyEnMa%U?p3IAQ=C>$`;RR_~3g&QymY2fFG{^|gE> z-uLYf?P;`>?5poVf8g@_G8`%MDfeRp{o@UOp4{Oe35;^mddiF4??uUx$0w$%b%_^y zIo{^PUWmu;j>pF{4np9un1uwSaauL?ai@jVi69_R@a#-Hn@5pqKutf2L8k}dAk%g- zzSks2ugxhhXZ3~OEDHA?L2)jPP17nB2-yLrDhQ8|dnGzSX0f|CSSF6d>V*eb*u^^8 z7yNuYQ);jqOGWU+!C2=6^dHQ-X zd7@3Zo=jstOKlPMv@XatpjDwC(rS!>Zn2upIZ@B6$W*^-YiU<)MMq!V1di6Tv>0yv zq6xHD2P|(`-bR`R88`CwEvBBcN6W*U-wL&z7z}g0JQfFFKMN+ofyM;_kHlG|d&_)A zVv#48H9od>vlBL(l1<|C=6Ayr?9PhX=ba}iSs=Lmg~4WXAM#nGhOiG><3WI)D|KGo zUt*jU*Xc4ePm@;y^ZuZ5v57c#g-bLu@k5q&;T=KJHFm1xTH7A~+K?QpN zD#$=KjAEEXOM{W~$$XI|>M(I#!rYoDcv)L#J;1)wC?*7reIk)ztX_j$$DDZ~|C_8L zOZ+RtSW5c>XcJVw{@fH5`6Bcnq+iedC|Dn!3-dmoI;K9=(4o7s6RqCKpK!v8<5( z2Rq=`2?WERCh*!knCO2b(JPW}_u~oc&V=z7FZqtw{x2}x#do~qKQT0D4GsMmq!MEL zTVC%^+|<3Ub&vmkYeGGPKBc3%RGZbF=XbuHV3-8T^90s(P0ElXA(^aArn(&FW8Wyz?T4_~ChFsKm7-hzq8Sl1#geQw}CrNw`iE?{6AFehOa_yP+ zaPoyvvBmO}B$q7%?GfY6c55L?)c2MZvl|5>W3~g6?PlehgiCn{exJh7KM%ili`Gnr z}hvNBi2fEM>A60fL6F+NmU#$LcnzA5Br^8rY|4V29=4Z0*8EL=legc z!@XDrhWswtzE{W>rjO!f52w8xS_ReZ^`E1CF7#3SY{Xu#`PT_2t~u&hFd-KSm=$j? zrof+*sE7o1c9rD%(I#4W-a+SMYbD%bwr-xPFKEf$!S%e(Z`J%Oj6~!N6~T%gDM0mc zIFt6rq1BLnjlHfbe(+)Yz^S|9v&XGlsqJ*z#Cjhx@!0?}@g*7AoB{6n&9t>OZQY!f z+tLSpBh3iADNS6}*V47C3Fq}ji~`JSQ;>Vcn1eKni4@pUnP9oFU#GC3d{!&@x}*=_ zT5%9_Q3u$RgPU8vIJn;zxsOAFT@i1linKueQ2lKUaR1Q^ttSwn@sZ(zO)uQ1Z+tvgJetlZxeOFQ_(sH6<{ON$Q=kZN*4{-kHG8@MPg=^_8G8nRU$A=WD0Q^5?VfaRDWhhnnQ8)3ubtg9 zwzgE1y~ObKS*23`LZQ^h)!I^~)MaH$YW?1^BUGZ)Y!w>p7}c`TAoMDIx>`%olOoRa z9O)L)Sm{XQqwGwMK!B_^e@wHppNf6H1aguS!(4CVv|kkdd8L2e6Jlo*(N-eYIKX>m zq)SJG1k2;y&Rd;(os^dkkZVFTs{#YHgZDEs#WORdGcvxhcY8*ikx{RvRf+G0)WsPM zg6_L}>|Tt)kEPA?05(@Y{1;xux*;?6_=@KpBWwL?(7HKecRKH;`@fRuFUi-_{UtJ8 zT;~m3>e&;s6UevlT~9vmsV=tO&8FIF%HMeESx@y||Pa?NQ1NP^CvTAv{$vJGNA z6A6-S&5V_iR(8+rhWwDgWF~RLw6Kk%>nU6THS8OSzJ_sACDqM_Q^}I>GL+0k3#kkw zQIk5y745Ec$?#Got)ct-#*M3y60V`##yJR3HpfvIAkmkbIZLY9a!v~Tg@=pIKgSGx zj`F;u9B?ToVf*Ls_w~#qBVxYbwIn*K+Hg>tnFkkvs^$_3=N4yZ{#jc%cF$fpGuxEQ zXYHBJjHa31;Orr1MuqL1SbfiMxMz|~O-BmYvvZs`P>Xv*-i&_#Z{joh@x_96hi6%AW}Wi@MRcj$xRsKD`acix-cU%8EdoRF^F$WW*cUOgmcc)7hSxCF2TVo-3xrr*_)$83Zes ziX0bu#J+5E?> zb$>RmJtcu5B1RTf$0+f*$K%Z=m=va#BS&EZOnVW#CIMo;hqe++QW&9=6lTNH(x6Qw?qHS#O%?AO4+3e*`-whVZQrvE?oBZ?bwT~aAY5%aEWJQ=GI ztcP2xzvN{)fb{A>nPKy*LS9UsFXI?{Z(Zr3+dWgFsLUmO6vcM9jid4Tcgwql+a8~b z5uFdtG12|}oyUm%u!MBWV_ZJl-FUAWJc1AB>gm)x1y59_HLndp?f`tRg~X68QjxnL{hHVtjN7$W1>33N_zliVo$il) z)H=P-PN3=b?Xi0c55&aw*tO9I{2_c!TjZfUNIKP!Y4UBKCiCUyPjTszn~(k?ou&|A*Nt|0zWN`g{Y&9oZ^7zUlwP zYGu#J+(L|bB4ft!6tYW?8Y5 z8S+5fw0;(>b#2=IE~bkNZkQ&!lOn=6eMHgGb7-RKr9cV70tMwt=;WBozy^@g!*c=T zDyIT2XCXE?onb`dDs%!5O}n#iVF4imHo`0de4(7B1uMTNJ^%upTQCYT$5}qa5n|XI{c{%vcYLi?$gSp?-icW>EkzvelIzV z4rfQaD){~hTQxWfLC0O60NXbh?Q{1-WXP)l$~ahxj&e^#Gp>?;?b%SBjYO7zCYbk! z?5QG)!by7*?e9X5LiKsywU>(Q4;>BZS1PRcQqN1UIE)JlPZ9avuKWQc>7Ms#>XeT9 z$H<_%;P{nmRvhnV{9JYXQR{S?)WIXy9KT}2r>Wx}e(Nh{ei4~X;v29?u#I<9`c|)X zYk9HRAh<#U9Q_&k*jtBt#DlVnpH)n|rCC8eOvdV}_)F&ex zh=;fSw4gs;<~i5<<6YXNy;Y=Fh1$QBgVG#^y4XJ&Wl5;3?d9mTbqVYq0qF)tizt$)E zRiX6Du_yXPVID;sQ`D_5eI;XEn$hp?q7k1fZ zmID%L*SYK%0mNRCsx*hExDhTg&h15@b<(8rRW*mql)z|PqFGn-sBvt2! zw{sgxOvTZyqIpf8-{XVw6pUXw%u*+E$uNPjUD}xQ2@ObrkGM>V!_Wyby2NmBNP;K;grxqrWj3d_)Iz1<@9n0hZ zF{uq~#VPuOLsc%&<8jVe!S7$ex$AKPQ(nd&$>(oC_21X~G}V7^>~`e$*Yo4o8dD=j zQXB#&s4iiRw~K_a{3frB;qRsP9rbIr)1D5^hQi-7&)<)D=_SNggm{qGL%i*2VVuC` zv3dA?JDwlpkNf`0sPDdiKFGg+sja>E*Bal=M2Pk?(=9#Cv2NRLSe*Jii-=>cBY&i9 zRR?ckh=Ew3M&_4AtFS;AM%St3jVty$2={Ix^{h~zao5L`Dz#oBQlH`5Pf-ZfRBPic zSYV^pm*6ZmU?hYLNhLtN^K>hffVrqrn(`t9jqRrPHu{a$#Kpo|ws&~W`^gihrrGP` zMXM>=n~$bd+Dt|hEvbCMo}Q{%SzP}8Zp!_vx3b;sL%JapD&Y=O>)Dzc#i|5|fI@^U zvGc737P;cV1}M8nrtfD_Gg!xt^QL0PbP@&X;&scIO#rQFeO-W9DE4dy(TbKwZj^LF zq6tLf(uy~>B)dpSN6*>)i9JYgZc8SHB4;-_05sWG2^~`#pbWI+5;G?n2U1F6BKn*X zGpu<0csbE1i7$Z02Y%n_OrdCQlQ}+-psIL@s#}&g6t#MS*=-EjXe`P3Mu~z2F|XIJ z;-(pN+H5fo#U7(GF2u}ZeE((4ybKE+Pj~N(E-guRSu6t{C!*4Wkw6)t>|=TaEVh#P z9P|&dZZQruo@2$9 z^GXS7&>l?5t?d^E^W+)EZo z+PGEVAuO4*NkyuQ?Pv)8^U=1S5nB;^ELve{jsGl~r(iy4 z7u3B=3XxW0iE*rjMnkkCskov=ueE4;d}_44{}{&mhUvfKWUbn3joq=N61iYZH>QPu zvo3lg56`5y+8(ZCI3C)e=G)>bGh>e5t>Z=GlsIW!L?(fdD-F+j4c}7nMWghBVNIwF zXMQgiZ3cxGVJoM`lPc&)|br|zk2%Dz*I5f9E#h83&YK(TrFqdZu&UeBW0gE zs8W=&Z5GoB7^gC%pB(IPpc)+nN*+d5_ILc?4FWjsCbOpKux=H2Wwq&|CNdViu=&fu zxJex_8W+_|dj_-ss*juGGR6$F71FOcp{K_ZOg6Y~3H(r# zTT6@)(2nUL9qWPg!hQK#fdtdn;yx{OKR4H?F? z^eKooDfvk;iKupj$fg#Y@uh}Ig^Il|VanB}p-%LPN|%wsK{<;tl{8&%psBmJVzhRt za&yx{5KtNg6-J#7%702p;L9fo*IkNYFe&<$pe9Nx{-)MHJ$ZtTGkMKICg53zujOA0 z*ZBiS`9~k^8PH;=J`O%b`)cTRNWWgaBk2EnUXUk3e0O--$g8`;3uAZE!S59HeoXj9 zUJuhnUatk4(GJ`h1gr&^AQ{=@3`+GMtNne_75~!`MG8hVSetB1x2ugQP-j}y4cL4Z z^DE05Y%}Q$;;#e!OD32o#dt7}NHCCE%^H-uQ|X%wm}DXoL^ko)Q;@Ur`bPzpYw{>@ zpgp2Gd2cAv=IFY@;ZdB3pl6DiItB3BY0 z)lH2)L*&RXkui-M?8=RHAwGfGsB5Wf|Io)}G12^r?f%(zZ$PxoZM8jPv21wFPAoKJ z@g}?TX4}}Rqba0yGogva8{sxxLfv2o@NVlSyXoejBFs&8>So*9W;a}j)X@4Rhb+_+ z_>Cf7f_C?tHs{i7Xi8-G+by>D2OWj@lHT_fTk*GF$8ir3;Ws<)!IOBY?b*ixC{_tT zQUZALJdE;ZQDe4fmZ34>oiGOzSR9$KWRo8U+$oFA0|nNtd@E7Gc}WKCveVR*%78g{n#yeR zcv!rWS8TO1K>Ez6nVebxbeT-(;|h6$s?kklw!L{zMdSHogPm#Qdb>P3kG-5EkT4z{ zN*Fb2{6(XgD)D#PtN@sGdVOuUNk~M)l--Xsv|YFZBnh7=kg_(I`vQbqK*ZiutJm@D zUjfW(8{^&<2T?yEt7pUo0(bfOIvp4iBM!!i&IIFz=qrH34Nnpz^~kyO$nO}QRw!E5{V!TdV)W25r@WwgHo zeGjV3_y0?~c<6uo%b$2G;6EeseVCkg$%b`Dt~he-r4B|pz5w5xfn7oPg=j$-x%EgChjdj5JVz()BZUm z4;$q#57NH(aPaCM5BN(eTz@-ZRr)-O!u5A!sCPWED|_ksogd0RYu2t^wPEQBY$TZe zU$#o zo|$<@Yjzx?<6rDLN&bOZ&HJsF+mbeEkz>6-X`U?a-5ho7J&7YhoSrWZ(>qu z5(gzjVC|$;V!P|p0QIb$4ixLzr;+pkE7;g z$7rZPk;%1eB(EIS<_8(bwadO5IN3M<{j+0 z)Pi}bL|;^-M=n*#>>0$e^XFo@}|* z_}|)o$Z>j`dUDM2@-lkm-kY5lIUaCoo1FzZz9?BI31RqpyZ+}v_DbT-xbt`I0gl1A z-`eb=cEort(7dNmI$R2lWm@Woy-2ftWfAvV@@)ZkN@5~f z-&3$wAT62cq50BvSO2wvnx9CH!bm3&TTDY55y69&RZ;r-_TVj#vD21 zGNwdXwK3%OPO=W^WpfX=9_3?GewlTEW3|`0(`&8O zti!GAyv`3juH7EzgWkjei6f#{#k}sdSv)(uE=LhcxcQckG+P<=M()L=%k0DoyR)5Z zYT}T@>GpfQaXY>ul|68)aV{(?28k3DUEFZ*gs zk7#x-%(ADP=1SB~%b%S|=V{jHOqBOWQB(ZX3>W8p(#KLWF*|D=p)X&tX+;P!)Fk|5 zVG$t*`{Po5H=g>LFB?1Dvsr*B-TmHv9>gS1BGVrIVk2X67}TXiyQ4Vl2^DTS)&hpJ z*Vuv;d-NU*UJ_g@+@7A1wkW3K<5)~-#2{&^MV=ckrv%dV71HAgsW%I3m=ccZ1@zI4 z=E~aN)*piiN8e;;L>fcLD6&tQ)|I{t+CEgh?Vttg-+idPIln$4&EZdD(w_Eh0*4Ox zW!ozkAn2h>W4>+E5_ClMPvi8tAz711gZ?hWlPcRQ`EKyp#uHjFGP?J$fK0EPdQor9 zGpFF*GuwDJzX#{K%6yEBw#ItouA-FaWFL#Yyj~akiJ5pB5XlTphRw&B;!%BUeOQV# zS-v~pW&qZ`BQhgBa;g<0#PUQm)6!+WStc|MD zS6W=*90erZDKvUm4wbW{++eaq8l38_^>eVuz!{fj`vhgYrC;PcZuQr1+4?cS^F(vY z-wQLva&_%lwfRdvz3=Ua0n}7U8hhkT?&q6GWecI zl&4pFvBAL1qCSxEVDUl2fHjhG4|dR5=4{MUFZm){;=CExldS>a??UoOU|`=4R`?7LgdB z!)kfKFHSgf5GAf((Fy~Ys`ZekDBfl4_QaYt&A`1nb{*sB#xd_ zU>Q|WSQ(?mmoY*#q`+hno4~rZ9u9*>vn!7oSY$)2`Wn)Cz%rhbhzBqR>%316CSt(n*`&+pvG!nojKVoN$7`RFHVg3YyFSSN_O9PQqj)jAakQ zDt>tx*{rC^IE&1eY!B6MY^7#sQs^|r}$+f zpH>@j*UC)!8~n{cU08bhw@;7ECv*)r%6tOdO|oosEGlt&R+$;qni;g%$}KFb^lWO) zD6+|hMnN>Ibona}|9-iKn@p;9V*7N-e3~V$qj>yJlOq#}f>I?>C1~9%Mm}v0OV2j= z=YZ{D=^1fYdgd=Y;dq7|WYa0)V&)}f@i0CjvaQSyRbb>D`ICi*wM%Sekp-q%#oK@0 zp?nw)KME)?-1K~yba=c=WxQp?TP9v<6EC)n^>`!nxKzA0t17le%%!gy?^_oZ@5Atq z16#u4UEMxj!v^CCQV;dGEE}Nfq?SniFl^71o1Ve?+scX|-&dB4&Ut+{2|biPlcoEX zA)toE#i&^R*NpTQ&p(t;g@&7+Pl@f*OF72+;R&)VUtlA>per2_W=SShRD2a9 z@l&p4S`92yV5HjoFTW*eYLia=o|#hh<&9AJ*7%lnMw1N&e)L%uiXL+<@*Dk6s9tPk zSVmoxsgdEM-`CUKCN<&7+jb? z(k&wcn;(Y|s#QGB(+~BF{o$vLiV(*FvOi%(vUMnKlYsW;2pra*up~UJXUuBt8smy4 z6e4jJMilA&h=t=;-Av}%t#TV?4C~u%>2!1stFio9G^=#g{qLn~Tsd1$%gWDcO_R*P z>YYYDJI^@u{sH)N9CUYN-&ME~fR@2@{z;WuC}u zor>4LP%nSF+p58KF_{0u0aMPn3AcKn{rt1}zkKOg)iqVQ`fdR!YUBjP6WEpSl_K}r zYdxg_as6sm@vS3lQ$DMQzZcjX7T+`QyMg1{*-!mwtMNU;<6FLX!OEkTO&E97xT9I! zK8=W{3D!k(7=hh`NNEu^j)>tX0oi)cvP8($uo$iqOu*rY=~#=+uaYN<-Y~vHaM7Xs zSn`ZROyd7BfSDi1!&d_4`3z=wdDj?dvkfEm9@o7DV8cslg&k|*uEpU4Km$XvJB zV!c=s1!?Scr6B5w(M?zQND!Tr7NHA!`iUiJmZ7?UXC6=zeACFMm5Yt}gK~t1_uzjA z@~c|)7LIG-XH+}IeSo}nDgEBPYX3s5vd2=IWypc=%`)^Bx2SoB@bvc|Ft_5&8JrYd zu{0}3Qc<-mXL>bu5$7zgTu_xWtzw07xBdT_3(l@kZZumefTa~Iw_;YJ$@-45y5}Q< zJYbMt?4MdaWYE=?4>dOm0rs7Kq%~_-XgODEPiPg8~pARPC-oSWAVg4rNu=wT63P^Tc7D3J1}~XFUvb%P+GDj zv)_G~Ad0dl_rVa6d#F9pKETx%a}zzSJ?!>iZ*~JjStFC}eJrWiM1ptgrx?f?q5+J@ zSv|wdC^9>zucEC&*M#*f&ccXb1H&LRcpNk2OvhjgYmT|cbTb?lBYaE^U}v-kwKMFF ze4JzE<@Q~9_LAM+&u@fPtonP zr?6z1fxgok@I^2i7fD#Sg4ssHU`Q?JJ;FB9GS$)xReOqt2`Dr=11yCRHvT6&IW@^P z%GNjRpVN`bVUh86ZYSjg2hJBGm5Ue2gkyYEYiu>WCSOojH4ZQ=vyF(TL7-1pdeuD4n5VN!*o+hV;o?OS`P#rml| z-J*SIOU(8>Xp8DUOQ!6;UMy9K zk3JQJ4U_y)y&|z#lEf+0vIObY13b*BN;~3Ao`U8!PQKwm+)jToYSFW9MtOcul~Y+(zk&Y+*bA8T^Zx+FIto2>Tjzaenny>+S zi;-aKDa9Vzizuty;+7)B0G3x~usNJbSCzJAm0tguhvczB_{qRDz)bH9_=|uiRQk+y z5s$oWq`y@z4o`S%cP$l9^U*uaMDOJOm^1=LtA>!wMi`nb2eZ{~tnpi!9;1~*nQV7@ z9JZ()Q0B0VmM!0s$0|?E|7w{^Q?~0tDOXXun=lc5WJH8gfXVhYj~dG}}26u_ha?T28wjIlrR(j6-X*5j!}l3u&+>hn8<~ zO{L+L#oAIPK4QT<*8i9ih|roNuG4-%4r{d5SrR5DE>3XTvwP*j z-D}A!&L03QSFjWs%SNrNywUlCMQ`?YTk@;Z7sWYe*|ZZU&RqP7!>PAY+ahx;+O&yN zG93Aq-gK^0+(qwLir=yf*lj6(!=m+=5z~8@rFe%$OP!I_`!!4P%XGmrUa}OwXo-Eu zVgJUFwck2=pVfYP`XYVFtg$mmuIXlDIO~oK>a-qBn~ zhPuZc8?*A5^^5ScxSVgSd^5w$J!xN3h9D;$6S0vgLB@hDa~4uacc&&7F-m(t*jECx zei@+#VS$p4W|jNwZQ(xKvY4!9ky-1ZT5_Mg83sc!{7Z9Qvi&2Bf5$He14g)Pyio*a zqhns3aN-bwSd>Hjt!a{Rx2CB;PZKezNRge4pInA=3sANsQ=Kls8rO z{V4X+wKHrJt&7o|V-k~g_Fjv(*fSuqm^IZiuuxIVHkBE1z2l2}E=?>>h-Eq@D|vL1 zJvBXr5q!}_hFtaqzQ&azM4Swk7Zn0b^8qaD%e5Z|V)2#+iCvYSF^-MY3AR zg;GDWP|8D@zttixWR37tws8$-&aAcTljrgwO|}-U6gn-vsF3xtsL0P?3P!TAlWwxH zlbw_;USq8g#(3z#$jV;q%w|4LE|EvB`Pz7|#B&bGLw(_Mfgyl;FY9se%Yb9l_}ZK& z81r|d-P2oznyPU#k39NlTDeAT8$bC%pK0P2E#T0C`3%yixa-vB%dnC-FaJmvv_I|2Pt<>nT( zUbkA=9X4)q&NVadlGoF}Oh2r0g4_+mTVN0SpLUi7)>-1EJ?uv7<=U~SGrrP}jh*2- z);(h~fJw6ut+}wzv|5|2RC+Er zF+5?*z;Ykkchh)7LnLz`5_+|MdQ;OE2}VxqB)WT0XKgV9ZEo2_P-=}Q7wdaEPUgBFewmP?IJsVLlxPgGP z2g=eYMwr+_p(e-UD(i7FbFy~J6kBiK=x4OKz3dyc9&%u(*BBI8cH1OA0Gn2t_!zaD;OaL_jr`_cgg8?_N|4yfP9=HZ50djzScVNp2cobL*ECR*> zX~5n(^jN_Cz!g9xFdpa){Bb*bpMg!l#lR`R2p|Ud_BN+@5x5Je1x^J<0zH6lZe`vB zxD8kVOb4<6C-C_#)HC2V;7ni|&=&~ZjNS-%6u25#1WW>Y0|NN?CS)UEEwB)n2&4fA zZe-0Ca6hmVm<$AfpKl=Tz`ejlz$w5mzzux(H^Kte0;dB<0e)cL_2dQc0I&wA07e6D z;LE>~Zs1Cw3>Xb00l!}76mJ6$0IPu#U?|`LKDpK@9t73^mB4VI2k`SXJOexmTo0@O zW&(LY6!6Q{*f#_kfQy0CfMGySpm`nN7q|(S2NVEa;PbVl54aP!5GVo006l>3u3`=f zxCy8L@&Oz0{$J300ZV{szyQDtG+&8bB;XF=1dV$A* z>wv|;5kLy?^QGvVfqLM4U^Y+)1b~B=@Eq_Muo{>P6ab09FBhX*05$`E0nPv>07<~F z7dge>fg6D{fvG@WAao&R1h^kq3FIEXtYYc1+?uk}bLTCnnZJBa?om~_nm zoY(GsRg_5`P{;mEWl3%s#~05pDO)sm*pQrM9lS@YN4Yog-w3P2Olb{lshY~c&{0K+ z(YtmNwmuN**bf7r@Lj6rX4S4!z_>~7qUbop)^y^l8y}Ty;pxK5GEQin!|X)YiIHpN zy7p1Iu&P@>gz_g|iDBV_MP;3o$JQ6ui$ynSDpT`b-G4w?v~!m(p4UZyh8O&G?8hi0 z)IeRC-mxD>xw-OG+|KV(h&ubA^5II3f9))nd9Y&XV(K>@*|Qgu#lTR7L}b*QMr6^dB@>U0%YmV?WV#}*_P1))GX^dl!}!#T~sMEt}g3} z=}B(l>pHR}%d2WS$sIG0vYM&|9S5RU$z?Um=Pc{uJLsMkR?X|q3mb+yFKuQZdBHAH zvV8HfvdT_gMh~EDPA6Hf-|hU%=(j7ElERK-*QeaNsNcqYV`8quVm3!wI>^OCWyR7? zqA+|&+_49GXF23RI+(MtJ3q^7Do4=sSB~g7sH$bT6)Uk>tp`;yw`}Q(&bn&lvkTDx zAIoaWYW{?eZsL)lbedcib9YiTiNCrGDWY@X1s|Myuwrg^FFJQYC!dA@WCOD7PsGvb z3+MrKdbe`H!iug#*L_r1E$d7|BaPBa$1yBBi>_(m!rZefbTv)Pn`QjRs>K$j@VUJWX-T$XE%6!>H%WEn+5#!rO z&~Y+k0&~x-Qz%$>O^ETOXS&#XZKJGi>hn7kb2Ev7ga1;RCQ*>pYvJ1aOt1$I2TFsPk8HQ0HyM% zv#d7LzpO%z#yb9Frk~D*P1A>Lo8?fV>u|!p7fPWHONkj^YvJOVT>dbg9SN{0DjMBcWzbeUYKjo|@9+tsDdE*lmzenq>^BE;rO1|3~{l3BiT z#IUYCar#1e#hkM8GrIP+0*zip2~9%R-n!6*nD3{mSJ&aFJng*CYYnZ8(Nou9&8?_x z*Hm=*krr3fNQtZDj6YFUl;5u7KUDI&_P2PB?6OKa@3+i%UL;3U-BgD~vV?RU-=gZW zc@>Nvs>(}-4e3;!*cxfI?zQuwc9_R`73F2+^E>GaOn;r!@{;l@8r4qJZRWF!Q0&d? zY^>bssrCK3&WFxr%hr(Ql{3ydvw}Fg4r&n|Yr3sVf5M9lXayp1w{;wki^`UEQ+f3| z-gU~CRV?a6-xQt+GD%&BLwZ(Jb(bFWQw;RF38)h5kew)$Ta#2?LGRGLukH)uqB&(t zmoDf`h0_{eS#?Qe*|Hka-%a9`$L@MMWHdd%!TH^Uw~V#l-FWFtnllqG6VA}5yO`#6 z)0(Q_^14Y)#Uj;%cH^&d!AiYd>Bifi@FUd+CEXX}g_U~s`!h|R^4fLM7RaqLU3-~d zwrqZPC7}zwvH1bfE;CusbyT{{-i;SVSzV}b%-H5u%vnB9DwnzrP50Kd7umj+EUv0V z5#P1PDzlsJ+FN<`^6on~JXJ0%n`f%GyX^7RD|b^fI@eU1Sys;Zk6kBy5#48}<1#at zMe{4VtIOr{s_0+4li8M?wFpIU*C~=Ab^DPQt(enoM`VoLC|P>H-gTs%4;0NjkUmfb zcA`x&ed!YzT}M^6u#-qP)yAD;RB6B$}lXs`TVxBmC_y5ILgpX#)KsK2B|2{RKU z^(PF`>8`s&cgz2^@wdcFTAaEnRrj}X#YRcR#(_Gmjd(CZ|9{UwJ=~vif6kTvy?&ox z(h1fHR!MKMZn65IkK(e94GsPM{q_4<{w$peU$TGD$cgwMEjrfs(&?Pq{~$7yyB;6B z>E1)R+tiKz>c6qtUH&mRGjGJ^tD4y`$5o``#

vlhOMBb;^E)8K3&w8lM@jnGP{t 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�W6IT{ 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

miq=zjE!iE?pHCL*%crorXi$th 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%0A5;`7GJ(^ZT?Oo_@}dGzgSYtBUCEKBVZwRx+#ARR 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�d4P0@c!45mD2yyC%^On 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

!X3b4rww~}iaFJm0;#V+$=Of++?fe%Fl3emh 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

m42B9 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 YQq0akLuXWrB~N{v1BQS;w_0I9AnIRF3v literal 0 HcmV?d00001 diff --git a/ciphers/rsaBig/rsa_cipher_big_test.go b/ciphers/rsaBig/rsa_cipher_big_test.go index 0625af846..5be07d694 100644 --- a/ciphers/rsaBig/rsa_cipher_big_test.go +++ b/ciphers/rsaBig/rsa_cipher_big_test.go @@ -1,4 +1,4 @@ -package main +package bigrsacipher import ( crypto "crypto/rand" @@ -49,11 +49,11 @@ func TestRSABigCipher(t *testing.T) { stringEncoded := stringEncode(ASCIIs) bigNum, _ := new(big.Int).SetString(stringEncoded, 0) - encrypted := encryptBig(bigNum, e, n) - decrypted := decryptBig(encrypted, d, n) + encrypted := EncryptBig(bigNum, e, n) + decrypted := DecryptBig(encrypted, d, n) decryptASCIIs := stringDecode(decrypted) - if actual := toRune(decryptASCIIs); actual != test.input { + if actual := ToRune(decryptASCIIs); actual != test.input { t.Logf("FAIL: %s", test.description) t.Fatalf("Expecting %s, actual %s", test.input, actual) } diff --git a/ciphers/xor/xorCipher.go b/ciphers/xor/xorCipher.go index b8500fe91..0296c97ce 100644 --- a/ciphers/xor/xorCipher.go +++ b/ciphers/xor/xorCipher.go @@ -2,21 +2,12 @@ // ref: https://en.wikipedia.org/wiki/XOR_cipher package xor -// Xor is struct for xor package -type Xor struct { -} - -// NewXor returns a pointer to object of Xor. -func NewXor() *Xor { - return &Xor{} -} - // Encrypt encrypts with Xor encryption after converting each character to byte // The returned value might not be readable because there is no guarantee // which is within the ASCII range // If using other type such as string, []int, or some other types, // add the statements for converting the type to []byte. -func (x Xor) Encrypt(key byte, plaintext []byte) []byte { +func Encrypt(key byte, plaintext []byte) []byte { cipherText := []byte{} for _, ch := range plaintext { cipherText = append(cipherText, key^ch) @@ -25,7 +16,7 @@ func (x Xor) Encrypt(key byte, plaintext []byte) []byte { } // Decrypt decrypts with Xor encryption -func (x Xor) Decrypt(key byte, cipherText []byte) []byte { +func Decrypt(key byte, cipherText []byte) []byte { plainText := []byte{} for _, ch := range cipherText { plainText = append(plainText, key^ch) diff --git a/ciphers/xor/xor_cipher_test.go b/ciphers/xor/xor_cipher_test.go index b9d6120af..999755188 100644 --- a/ciphers/xor/xor_cipher_test.go +++ b/ciphers/xor/xor_cipher_test.go @@ -1,23 +1,21 @@ -package xor_test +package xor import ( - "TheAlgorithms/Go/ciphers/xor" "fmt" "reflect" "testing" ) -func ExampleNewXor() { +func Example() { const ( seed = "Hello World" key = 97 ) - x := xor.NewXor() - encrypted := x.Encrypt(byte(key), []byte(seed)) + encrypted := Encrypt(byte(key), []byte(seed)) fmt.Printf("Encrypt=> key: %d, seed: %s, encryptedText: %v\n", key, seed, encrypted) - decrypted := x.Decrypt(byte(key), encrypted) + decrypted := Decrypt(byte(key), encrypted) fmt.Printf("Decrypt=> key: %d, encryptedText: %v, DecryptedText: %s\n", key, encrypted, string(decrypted)) // Output: @@ -81,12 +79,10 @@ var xorTestData = []struct { }, } -var x *xor.Xor = xor.NewXor() - func TestXorCipherEncrypt(t *testing.T) { for _, test := range xorTestData { t.Run(test.description, func(t *testing.T) { - encrypted := x.Encrypt(byte(test.key), []byte(test.input)) + encrypted := Encrypt(byte(test.key), []byte(test.input)) if !reflect.DeepEqual(string(encrypted), test.encrypted) { t.Logf("FAIL: %s", test.description) t.Fatalf("Expecting %s, actual %s", test.encrypted, string(encrypted)) @@ -98,7 +94,7 @@ func TestXorCipherEncrypt(t *testing.T) { func TestXorCipherDecrypt(t *testing.T) { for _, test := range xorTestData { t.Run(test.description, func(t *testing.T) { - decrypted := x.Decrypt(byte(test.key), []byte(test.encrypted)) + decrypted := Decrypt(byte(test.key), []byte(test.encrypted)) if !reflect.DeepEqual(string(decrypted), test.input) { t.Logf("FAIL: %s", test.description) diff --git a/datastructures/binary-tree/binarysearchtree.go b/datastructures/binary-tree/binarysearchtree.go index 7e1c691f3..f43893657 100644 --- a/datastructures/binary-tree/binarysearchtree.go +++ b/datastructures/binary-tree/binarysearchtree.go @@ -1,126 +1,38 @@ // Binary search tree // https://en.wikipedia.org/wiki/Binary_search_tree -package binarySearchTree - -// package main - -import "fmt" - -type node struct { - val int - left *node - right *node -} - -type btree struct { - root *node -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func newNode(val int) *node { - return &node{val, nil, nil} -} - -func inorder(n *node) { - if n != nil { - inorder(n.left) - fmt.Print(n.val, " ") - inorder(n.right) - } -} - -func insert(root *node, val int) *node { - if root == nil { - return newNode(val) - } - if val < root.val { - root.left = insert(root.left, val) - } else { - root.right = insert(root.right, val) - } - return root -} - -func inorderSuccessor(root *node) *node { - cur := root - for cur.left != nil { - cur = cur.left - } - return cur -} - -func bst_delete(root *node, val int) *node { - if root == nil { - return nil - } - if val < root.val { - root.left = bst_delete(root.left, val) - } else if val > root.val { - root.right = bst_delete(root.right, val) - } else { - // this is the node to delete - // node with one child - if root.left == nil { - return root.right - } else if root.right == nil { - return root.left - } else { - n := root.right - d := inorderSuccessor(n) - d.left = root.left - return root.right - } - } - return root -} - -// helper function for t.depth -func _calculate_depth(n *node, depth int) int { - if n == nil { - return depth - } - return max(_calculate_depth(n.left, depth+1), _calculate_depth(n.right, depth+1)) -} - -func (t *btree) depth() int { - return _calculate_depth(t.root, 0) -} - - -func main() { - t := &btree{nil} - inorder(t.root) - t.root = insert(t.root, 30) - - t.root = insert(t.root, 20) - t.root = insert(t.root, 15) - t.root = insert(t.root, 10) - t.root = insert(t.root, 12) - t.root = insert(t.root, 9) - t.root = insert(t.root, 11) - t.root = insert(t.root, 17) - fmt.Print(t.depth(), "\n") - inorder(t.root) - fmt.Print("\n") - t.root = bst_delete(t.root, 10) - inorder(t.root) - fmt.Print("\n") - t.root = bst_delete(t.root, 30) - inorder(t.root) - fmt.Print("\n") - t.root = bst_delete(t.root, 15) - inorder(t.root) - fmt.Print("\n") - t.root = bst_delete(t.root, 20) - inorder(t.root) - fmt.Print("\n") - fmt.Print(t.depth(), "\n") -} - +package binarytree + +// import ( +// "fmt" +// ) + +// func main() { +// t := &BTree{nil} +// InOrder(t.root) +// t.root = Insert(t.root, 30) + +// t.root = Insert(t.root, 20) +// t.root = Insert(t.root, 15) +// t.root = Insert(t.root, 10) +// t.root = Insert(t.root, 12) +// t.root = Insert(t.root, 9) +// t.root = Insert(t.root, 11) +// t.root = Insert(t.root, 17) +// fmt.Print(t.depth(), "\n") +// InOrder(t.root) +// fmt.Print("\n") +// t.root = BstDelete(t.root, 10) +// InOrder(t.root) +// fmt.Print("\n") +// t.root = BstDelete(t.root, 30) +// InOrder(t.root) +// fmt.Print("\n") +// t.root = BstDelete(t.root, 15) +// InOrder(t.root) +// fmt.Print("\n") +// t.root = BstDelete(t.root, 20) +// InOrder(t.root) +// fmt.Print("\n") +// fmt.Print(t.depth(), "\n") +// } diff --git a/datastructures/binary-tree/binarytree.go b/datastructures/binary-tree/binarytree.go index f85563c8f..6ee12ec9c 100644 --- a/datastructures/binary-tree/binarytree.go +++ b/datastructures/binary-tree/binarytree.go @@ -1,90 +1,14 @@ -// basic binary tree and related operations - +// Package binarytree basic binary tree and related operations package binarytree -// package main - -import "fmt" - -type node struct { - val int - left *node - right *node -} - -type btree struct { - root *node -} - -func max(a, b int) int { +// Max Function that returns max of two numbers - possibly already declared. +func Max(a, b int) int { if a > b { return a } return b } -func newNode(val int) *node { - n := &node{val, nil, nil} - return n -} - -func inorder(n *node) { - if n == nil { - return - } - inorder(n.left) - fmt.Print(n.val, " ") - inorder(n.right) -} - -func preorder(n *node) { - if n == nil { - return - } - fmt.Print(n.val, " ") - preorder(n.left) - preorder(n.right) -} - -func postorder(n *node) { - if n == nil { - return - } - postorder(n.left) - postorder(n.right) - fmt.Print(n.val, " ") -} - -func levelorder(root *node) { - var q []*node // queue - var n *node // temporary node - - q = append(q, root) - - for len(q) != 0 { - n, q = q[0], q[1:] - fmt.Print(n.val, " ") - if n.left != nil { - q = append(q, n.left) - } - if n.right != nil { - q = append(q, n.right) - } - } -} - -// helper function for t.depth -func _calculate_depth(n *node, depth int) int { - if n == nil { - return depth - } - return max(_calculate_depth(n.left, depth+1), _calculate_depth(n.right, depth+1)) -} - -func (t *btree) depth() int { - return _calculate_depth(t.root, 0) -} - /* func main() { t := btree{nil} diff --git a/datastructures/binary-tree/btree.go b/datastructures/binary-tree/btree.go new file mode 100644 index 000000000..0e0ad8224 --- /dev/null +++ b/datastructures/binary-tree/btree.go @@ -0,0 +1,117 @@ +package binarytree + +import "fmt" + +// BTree Returns a binary tree structure which contains only a root Node +type BTree struct { + Root *Node +} + +// calculateDepth helper function for BTree's depth() +func calculateDepth(n *Node, depth int) int { + if n == nil { + return depth + } + return Max(calculateDepth(n.left, depth+1), calculateDepth(n.right, depth+1)) +} + +// Insert a value in the BTree +func Insert(root *Node, val int) *Node { + if root == nil { + return NewNode(val) + } + if val < root.val { + root.left = Insert(root.left, val) + } else { + root.right = Insert(root.right, val) + } + return root +} + +// Depth returns the calculated depth of a binary tree +func (t *BTree) Depth() int { + return calculateDepth(t.Root, 0) +} + +// InOrder add's children to a node in order left first then right recursively +func InOrder(n *Node) { + if n != nil { + InOrder(n.left) + fmt.Print(n.val, " ") + InOrder(n.right) + } +} + +// InOrderSuccessor Goes to the left +func InOrderSuccessor(root *Node) *Node { + cur := root + for cur.left != nil { + cur = cur.left + } + return cur +} + +// BstDelete removes the node +func BstDelete(root *Node, val int) *Node { + if root == nil { + return nil + } + if val < root.val { + root.left = BstDelete(root.left, val) + } else if val > root.val { + root.right = BstDelete(root.right, val) + } else { + // this is the node to delete + // node with one child + if root.left == nil { + return root.right + } else if root.right == nil { + return root.left + } else { + n := root.right + d := InOrderSuccessor(n) + d.left = root.left + return root.right + } + } + return root +} + +// PreOrder Preorder +func PreOrder(n *Node) { + if n == nil { + return + } + fmt.Print(n.val, " ") + PreOrder(n.left) + PreOrder(n.right) +} + +// PostOrder PostOrder +func PostOrder(n *Node) { + if n == nil { + return + } + PostOrder(n.left) + PostOrder(n.right) + fmt.Print(n.val, " ") +} + +// LevelOrder LevelOrder +func LevelOrder(root *Node) { + var q []*Node // queue + var n *Node // temporary node + + q = append(q, root) + + for len(q) != 0 { + n, q = q[0], q[1:] + fmt.Print(n.val, " ") + if n.left != nil { + q = append(q, n.left) + } + if n.right != nil { + q = append(q, n.right) + } + } +} diff --git a/datastructures/binary-tree/node.go b/datastructures/binary-tree/node.go new file mode 100644 index 000000000..71d37ac8f --- /dev/null +++ b/datastructures/binary-tree/node.go @@ -0,0 +1,13 @@ +package binarytree + +// Node structure for Nodes +type Node struct { + val int + left *Node + right *Node +} + +// NewNode Returns a new pointer to an empty Node +func NewNode(val int) *Node { + return &Node{val, nil, nil} +} diff --git a/datastructures/dynamic-array/dynamicarray.go b/datastructures/dynamic-array/dynamicarray.go index 70b11b38e..30132a231 100644 --- a/datastructures/dynamic-array/dynamicarray.go +++ b/datastructures/dynamic-array/dynamicarray.go @@ -1,4 +1,4 @@ -package dynamic-array +package dynamicarray import ( "errors" @@ -6,14 +6,16 @@ import ( var defaultCapacity = 10 -type dynamicArray struct { +// DynamicArray structure +type DynamicArray struct { size int capacity int elementData []interface{} } -func (da *dynamicArray) put(index int, element interface{}) error { - err := da.checkRangeFromIndex(index) +// Put function +func (da *DynamicArray) Put(index int, element interface{}) error { + err := da.CheckRangeFromIndex(index) if err != nil { return err @@ -24,17 +26,19 @@ func (da *dynamicArray) put(index int, element interface{}) error { return nil } -func (da *dynamicArray) add(element interface{}) { +// Add function +func (da *DynamicArray) Add(element interface{}) { if da.size == da.capacity { - da.newCapacity() + da.NewCapacity() } da.elementData[da.size] = element da.size++ } -func (da *dynamicArray) remove(index int) error { - err := da.checkRangeFromIndex(index) +// Remove function +func (da *DynamicArray) Remove(index int) error { + err := da.CheckRangeFromIndex(index) if err != nil { return err @@ -48,8 +52,9 @@ func (da *dynamicArray) remove(index int) error { return nil } -func (da *dynamicArray) get(index int) (interface{}, error) { - err := da.checkRangeFromIndex(index) +// Get function +func (da *DynamicArray) Get(index int) (interface{}, error) { + err := da.CheckRangeFromIndex(index) if err != nil { return nil, err @@ -58,22 +63,26 @@ func (da *dynamicArray) get(index int) (interface{}, error) { return da.elementData[index], nil } -func (da *dynamicArray) isEmpty() bool { +// IsEmpty function +func (da *DynamicArray) IsEmpty() bool { return da.size == 0 } -func (da *dynamicArray) getData() []interface{} { +// GetData function +func (da *DynamicArray) GetData() []interface{} { return da.elementData[:da.size] } -func (da *dynamicArray) checkRangeFromIndex(index int) error { +// CheckRangeFromIndex function +func (da *DynamicArray) CheckRangeFromIndex(index int) error { if index >= da.size || index < 0 { return errors.New("index out of range") } return nil } -func (da *dynamicArray) newCapacity() { +// NewCapacity function +func (da *DynamicArray) NewCapacity() { if da.capacity == 0 { da.capacity = defaultCapacity } else { @@ -111,4 +120,3 @@ func (da *dynamicArray) newCapacity() { // numbers.put(0, 100) // fmt.Println(numbers.getData()) // } - diff --git a/datastructures/hashmap/hashmap_test.go b/datastructures/hashmap/hashmap_test.go index 8b65fc70f..1abe50f1a 100644 --- a/datastructures/hashmap/hashmap_test.go +++ b/datastructures/hashmap/hashmap_test.go @@ -1,28 +1,59 @@ -package hashmap_test +package hashmap import ( - "TheAlgorithms/Go/datastructures/hashmap" - "fmt" "testing" ) -func TestHashMap_Contains(t *testing.T) { - - mp := hashmap.New() - - mp.Put("test-1", 10) - fmt.Println(mp.Get("test-1")) - - mp.Put("test-1", 20) - mp.Put("test-2", 30) - mp.Put(1, 40) - - fmt.Println(mp.Get("test-1")) - fmt.Println(mp.Get("test-2")) - fmt.Println(mp.Get(1)) - - fmt.Println(mp.Contains(2)) - fmt.Println(mp.Contains(1)) - fmt.Println(mp.Contains("test-1")) +func TestHashMap(t *testing.T) { + + mp := New() + + t.Run("Test 1: Put(10) and checking if Get() is correct", func(t *testing.T) { + mp.Put("test", 10) + got := mp.Get("test") + if got != 10 { + t.Errorf("Put: %v, Got: %v", 10, got) + } + }) + + t.Run("Test 2: Reassiging the value and checking if its correct", func(t *testing.T) { + mp.Put("test", 20) + got := mp.Get("test") + if got != 20 { + t.Errorf("Put (reassign): %v, Got: %v", 20, got) + } + }) + + t.Run("Test 3: Adding new key when there is already some data", func(t *testing.T) { + mp.Put("test2", 30) + got := mp.Get("test2") + if got != 30 { + t.Errorf("Put: %v, Got: %v", got, 30) + } + }) + + t.Run("Test 4: Adding numeric key", func(t *testing.T) { + mp.Put(1, 40) + got := mp.Get(1) + if got != 40 { + t.Errorf("Put: %v, Got: %v", got, 40) + } + }) + + t.Run("Test 5: Checking the Contains function", func(t *testing.T) { + want := true + got := mp.Contains(1) + if want != got { + t.Errorf("Key '1' exists but couldn't be retrieved") + } + }) + + t.Run("Test 6: Checking if the key that doesnt exists returns false", func(t *testing.T) { + want := false + got := mp.Contains(2) + if got != want { + t.Errorf("Key '2' doesn't exists in the map but it says otherwise") + } + }) } diff --git a/datastructures/linkedlist/doublylinkedlist.go b/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go similarity index 53% rename from datastructures/linkedlist/doublylinkedlist.go rename to datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go index 9b05130ed..1f4f33cbc 100644 --- a/datastructures/linkedlist/doublylinkedlist.go +++ b/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go @@ -1,38 +1,39 @@ -// demonstration of doubly linked list in golang - -package linkedlist - -// package main +// Package doublylinkedlist demonstration of doubly linked list in golang +package doublylinkedlist import "fmt" -type node struct { +// Node structure for a Node in the linkedlist +type Node struct { val int - next *node - prev *node + next *Node + prev *Node } -type doublelinkedlist struct { - head *node +// DoubleLinkedList structure with just the head Node +type DoubleLinkedList struct { + head *Node } -// to avoid mistakes when using pointer vs struct for new node creation -func newNode(val int) *node { - n := &node{} +// NewNode to avoid mistakes when using pointer vs struct for new Node creation +func NewNode(val int) *Node { + n := &Node{} n.val = val n.next = nil n.prev = nil return n } -func (ll *doublelinkedlist) addAtBeg(val int) { - n := newNode(val) +// AddAtBeg Add a node to the beginning of the linkedlist +func (ll *DoubleLinkedList) AddAtBeg(val int) { + n := NewNode(val) n.next = ll.head ll.head = n } -func (ll *doublelinkedlist) addAtEnd(val int) { - n := newNode(val) +// AddAtEnd Add a node at the end of the linkedlist +func (ll *DoubleLinkedList) AddAtEnd(val int) { + n := NewNode(val) if ll.head == nil { ll.head = n @@ -46,7 +47,8 @@ func (ll *doublelinkedlist) addAtEnd(val int) { n.prev = cur } -func (ll *doublelinkedlist) delAtBeg() int { +// DelAtBeg Delete the node at the beginning of the linkedlist +func (ll *DoubleLinkedList) DelAtBeg() int { if ll.head == nil { return -1 } @@ -57,11 +59,11 @@ func (ll *doublelinkedlist) delAtBeg() int { if ll.head != nil { ll.head.prev = nil } - return cur.val } -func (ll *doublelinkedlist) delAtEnd() int { +// DetAtEnd Delete a node at the end of the linkedlist +func (ll *DoubleLinkedList) DelAtEnd() int { // no item if ll.head == nil { return -1 @@ -69,7 +71,7 @@ func (ll *doublelinkedlist) delAtEnd() int { // only one item if ll.head.next == nil { - return ll.delAtBeg() + return ll.DelAtBeg() } // more than one, go to second last @@ -82,7 +84,8 @@ func (ll *doublelinkedlist) delAtEnd() int { return retval } -func (ll *doublelinkedlist) count() int { +// Count Number of nodes in the linkedlist +func (ll *DoubleLinkedList) Count() int { var ctr int = 0 for cur := ll.head; cur != nil; cur = cur.next { @@ -92,8 +95,9 @@ func (ll *doublelinkedlist) count() int { return ctr } -func (ll *doublelinkedlist) reverse() { - var prev, next *node +// Reverse Reverse the order of the linkedlist +func (ll *DoubleLinkedList) Reverse() { + var prev, next *Node cur := ll.head for cur != nil { @@ -107,7 +111,8 @@ func (ll *doublelinkedlist) reverse() { ll.head = prev } -func (ll *doublelinkedlist) display() { +// Display diplay the linked list +func (ll *DoubleLinkedList) Display() { for cur := ll.head; cur != nil; cur = cur.next { fmt.Print(cur.val, " ") } @@ -115,11 +120,12 @@ func (ll *doublelinkedlist) display() { fmt.Print("\n") } -func (ll *doublelinkedlist) displayReverse() { +// DisplayReverse Display the linkedlist in reverse order +func (ll *DoubleLinkedList) DisplayReverse() { if ll.head == nil { return } - var cur *node + var cur *Node for cur = ll.head; cur.next != nil; cur = cur.next { } @@ -132,7 +138,7 @@ func (ll *doublelinkedlist) displayReverse() { /* func main() { - ll := doublelinkedlist{} + ll := DoubleLinkedList{} ll.addAtBeg(10) ll.addAtEnd(20) diff --git a/datastructures/linkedlist/singlelinkedlist/single-linkedlist.go b/datastructures/linkedlist/singlelinkedlist/single-linkedlist.go deleted file mode 100644 index e280aa7b0..000000000 --- a/datastructures/linkedlist/singlelinkedlist/single-linkedlist.go +++ /dev/null @@ -1,113 +0,0 @@ -package singlelinkedlist - -// demonstration of singly linked list in golang -import "fmt" - -type node struct { - Val interface{} - Next *node -} - -type singlelinkedlist struct { - length int - Head *node -} - -// CreateList returns a new instance of a linked list -func CreateList() *singlelinkedlist { - return &singlelinkedlist{} -} - -// to avoid mistakes when using pointer vs struct for new node creation -func newNode(val interface{}) *node { - return &node{val, nil} -} - -// AddAtBeg adds a new node with given value at the beginning of the list. -func (ll *singlelinkedlist) AddAtBeg(val interface{}) { - n := newNode(val) - n.Next = ll.Head - ll.Head = n - ll.length++ -} - -// AddAtEnd adds a new node with given value at the end of the list. -func (ll *singlelinkedlist) AddAtEnd(val int) { - n := newNode(val) - - if ll.Head == nil { - ll.Head = n - ll.length++ - return - } - - cur := ll.Head - for ; cur.Next != nil; cur = cur.Next { - } - cur.Next = n - ll.length++ -} - -// DelAtBeg deletes the node at the head(beginning) of the list and returns its value. Returns -1 if the list is empty. -func (ll *singlelinkedlist) DelAtBeg() interface{} { - if ll.Head == nil { - return -1 - } - - cur := ll.Head - ll.Head = cur.Next - ll.length-- - - return cur.Val -} - -// DelAtEnd deletes the node at the tail(end) of the list and returns its value. Returns -1 if the list is empty. -func (ll *singlelinkedlist) DelAtEnd() interface{} { - if ll.Head == nil { - return -1 - } - - if ll.Head.Next == nil { - return ll.DelAtBeg() - } - - cur := ll.Head - - for ; cur.Next.Next != nil; cur = cur.Next { - } - - retval := cur.Next.Val - cur.Next = nil - ll.length-- - return retval - -} - -// Count returns the current size of the list. -func (ll *singlelinkedlist) Count() int { - return ll.length -} - -// Reverse reverses the list. -func (ll *singlelinkedlist) Reverse() { - var prev, Next *node - cur := ll.Head - - for cur != nil { - Next = cur.Next - cur.Next = prev - prev = cur - cur = Next - } - - ll.Head = prev -} - -// Display prints out the elements of the list. -func (ll *singlelinkedlist) Display() { - for cur := ll.Head; cur != nil; cur = cur.Next { - fmt.Print(cur.Val, " ") - } - - fmt.Print("\n") -} diff --git a/datastructures/linkedlist/singlylinkedlist.go b/datastructures/linkedlist/singlylinkedlist.go deleted file mode 100644 index be23eb7a7..000000000 --- a/datastructures/linkedlist/singlylinkedlist.go +++ /dev/null @@ -1,102 +0,0 @@ -package linkedlist - -import "fmt" - -/* v is the value of node; next is the pointer to next node */ -type node struct { - v int - next *node -} - -/* first node, called head. It points from first node to last node */ -var head *node = nil - -func (l *node) pushFront(val int) *node { - /* if there's no nodes, head points to l (first node) */ - if head == nil { - l.v = val - l.next = nil - head = l - return l - } else { - /* create a new node equals to head */ - nnode := new(node) - nnode = head - /* create a second node with new value and `next -> nnode` - * is this way, nnode2 is before nnode - */ - nnode2 := &node{ - v: val, - next: nnode, - } - /* now head is equals nnode2 */ - head = nnode2 - return head - } -} - -func (l *node) pushBack(val int) *node { - /* if there's no nodes, head points to l (first node) */ - if head == nil { - l.v = val - l.next = nil - head = l - return l - } else { - /* read all list to last node */ - for l.next != nil { - l = l.next - } - /* allocate a new portion of memory */ - l.next = new(node) - l.next.v = val - l.next.next = nil - return l - } -} - -func (l *node) popFront() *node { - if head == nil { - return head - } - /* create a new node equals to first node pointed by head */ - cpnode := new(node) - cpnode = head.next - - /* now head is equals cpnode (second node) */ - head = cpnode - - return head -} - -func (l *node) popBack() *node { - if head == nil { - return head - } - /* create a new node equals to head */ - cpnode := new(node) - cpnode = head - - /* read list to the penultimate node */ - for cpnode.next.next != nil { - cpnode = cpnode.next - } - /* the penultimate node points to null. In this way the last node is deleted */ - cpnode.next = nil - return head -} - -func main() { - lista := new(node) - lista.pushBack(25).pushBack(24).pushBack(32) /* lista: 25 24 32 */ - lista.pushBack(56) /* lista: 25 24 32 56 */ - lista.pushFront(36) /* lista: 36 25 24 32 56 */ - lista.popFront() /* lista: 25 24 32 56 */ - lista.popBack() /* lista: 25 24 32 */ - - /* read the list until head is not nil */ - for head != nil { - fmt.Printf("%d ", head.v) - head = head.next /*head points to next node */ - } -} diff --git a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go b/datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go new file mode 100644 index 000000000..9f7094692 --- /dev/null +++ b/datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go @@ -0,0 +1,116 @@ +// Package singlelinkedlist Single Linked List +package singlylinkedlist + +// demonstration of singly linked list in golang +import "fmt" + +// TODO: This is not how it should be done but I don't see a way out of this +type snode struct { + Val interface{} + Next *snode +} + +// SingleLinkedList structure with length of the list and its head +type SingleLinkedList struct { + length int + Head *snode +} + +// CreateList returns a new instance of a linked list +func CreateList() *SingleLinkedList { + return &SingleLinkedList{} +} + +// to avoid mistakes when using pointer vs struct for new snode creation +func NewNode(val interface{}) *snode { + return &snode{val, nil} +} + +// AddAtBeg adds a new snode with given value at the beginning of the list. +func (ll *SingleLinkedList) AddAtBeg(val interface{}) { + n := NewNode(val) + n.Next = ll.Head + ll.Head = n + ll.length++ +} + +// AddAtEnd adds a new snode with given value at the end of the list. +func (ll *SingleLinkedList) AddAtEnd(val int) { + n := NewNode(val) + + if ll.Head == nil { + ll.Head = n + ll.length++ + return + } + + cur := ll.Head + for ; cur.Next != nil; cur = cur.Next { + } + cur.Next = n + ll.length++ +} + +// DelAtBeg deletes the snode at the head(beginning) of the list and returns its value. Returns -1 if the list is empty. +func (ll *SingleLinkedList) DelAtBeg() interface{} { + if ll.Head == nil { + return -1 + } + + cur := ll.Head + ll.Head = cur.Next + ll.length-- + + return cur.Val +} + +// DelAtEnd deletes the snode at the tail(end) of the list and returns its value. Returns -1 if the list is empty. +func (ll *SingleLinkedList) DelAtEnd() interface{} { + if ll.Head == nil { + return -1 + } + + if ll.Head.Next == nil { + return ll.DelAtBeg() + } + + cur := ll.Head + + for ; cur.Next.Next != nil; cur = cur.Next { + } + + retval := cur.Next.Val + cur.Next = nil + ll.length-- + return retval + +} + +// Count returns the current size of the list. +func (ll *SingleLinkedList) Count() int { + return ll.length +} + +// Reverse reverses the list. +func (ll *SingleLinkedList) Reverse() { + var prev, Next *snode + cur := ll.Head + + for cur != nil { + Next = cur.Next + cur.Next = prev + prev = cur + cur = Next + } + + ll.Head = prev +} + +// Display prints out the elements of the list. +func (ll *SingleLinkedList) Display() { + for cur := ll.Head; cur != nil; cur = cur.Next { + fmt.Print(cur.Val, " ") + } + + fmt.Print("\n") +} diff --git a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go b/datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go new file mode 100644 index 000000000..3ad07ddc1 --- /dev/null +++ b/datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go @@ -0,0 +1,104 @@ +package singlylinkedlist + +// TODO not needed because there is already an implementation of SingleLinkedList + +// import "fmt" + +// /* v is the value of node; next is the pointer to next node */ +// type node struct { +// v int +// next *node +// } + +// /* first node, called head. It points from first node to last node */ +// var head *node = nil + +// func (l *node) pushFront(val int) *node { +// /* if there's no nodes, head points to l (first node) */ +// if head == nil { +// l.v = val +// l.next = nil +// head = l +// return l +// } else { +// /* create a new node equals to head */ +// nnode := new(node) +// nnode = head +// /* create a second node with new value and `next -> nnode` +// * is this way, nnode2 is before nnode +// */ +// nnode2 := &node{ +// v: val, +// next: nnode, +// } +// /* now head is equals nnode2 */ +// head = nnode2 +// return head +// } +// } + +// func (l *node) pushBack(val int) *node { +// /* if there's no nodes, head points to l (first node) */ +// if head == nil { +// l.v = val +// l.next = nil +// head = l +// return l +// } else { +// /* read all list to last node */ +// for l.next != nil { +// l = l.next +// } +// /* allocate a new portion of memory */ +// l.next = new(node) +// l.next.v = val +// l.next.next = nil +// return l +// } +// } + +// func (l *node) popFront() *node { +// if head == nil { +// return head +// } +// /* create a new node equals to first node pointed by head */ +// cpnode := new(node) +// cpnode = head.next + +// /* now head is equals cpnode (second node) */ +// head = cpnode + +// return head +// } + +// func (l *node) popBack() *node { +// if head == nil { +// return head +// } +// /* create a new node equals to head */ +// cpnode := new(node) +// cpnode = head + +// /* read list to the penultimate node */ +// for cpnode.next.next != nil { +// cpnode = cpnode.next +// } +// /* the penultimate node points to null. In this way the last node is deleted */ +// cpnode.next = nil +// return head +// } + +// func main() { +// lista := new(node) +// lista.pushBack(25).pushBack(24).pushBack(32) /* lista: 25 24 32 */ +// lista.pushBack(56) /* lista: 25 24 32 56 */ +// lista.pushFront(36) /* lista: 36 25 24 32 56 */ +// lista.popFront() /* lista: 25 24 32 56 */ +// lista.popBack() /* lista: 25 24 32 */ + +// /* read the list until head is not nil */ +// for head != nil { +// fmt.Printf("%d ", head.v) +// head = head.next /*head points to next node */ +// } +// } diff --git a/datastructures/linkedlist/singlelinkedlist/single-linkedlist_test.go b/datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go similarity index 98% rename from datastructures/linkedlist/singlelinkedlist/single-linkedlist_test.go rename to datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go index c9eb951bb..0ba8b94a7 100644 --- a/datastructures/linkedlist/singlelinkedlist/single-linkedlist_test.go +++ b/datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go @@ -1,4 +1,4 @@ -package singlelinkedlist +package singlylinkedlist import ( "reflect" diff --git a/datastructures/trie/trie_test.go b/datastructures/trie/trie_test.go index 4c6c94901..1b73896e3 100644 --- a/datastructures/trie/trie_test.go +++ b/datastructures/trie/trie_test.go @@ -18,7 +18,7 @@ func TestTrie(t *testing.T) { } for _, w := range insertWords { - n.insert(w) + n.Insert(w) t.Logf( "added \"%s\" to the Trie.", w, @@ -26,7 +26,7 @@ func TestTrie(t *testing.T) { } for k, v := range checkWords { - ok := n.find(k) + ok := n.Find(k) if ok != v { t.Fatalf( "\"%s\" is supposed to be %sin the Trie.", @@ -46,12 +46,12 @@ func BenchmarkTrie(b *testing.B) { for i := 0; i < b.N; i++ { n := NewNode() - n.insert("nikola") - n.insert("tesla") + n.Insert("nikola") + n.Insert("tesla") - n.find("thomas") - n.find("edison") - n.find("nikola") + n.Find("thomas") + n.Find("edison") + n.Find("nikola") } } @@ -60,11 +60,11 @@ func ExampleNode() { node := NewNode() // adds words - node.insert("nikola") - node.insert("tesla") + node.Insert("nikola") + node.Insert("tesla") // finds words - node.find("thomas") // false - node.find("edison") // false - node.find("nikola") // true + node.Find("thomas") // false + node.Find("edison") // false + node.Find("nikola") // true } diff --git a/dynamicprogramming/binomialcoeffecient.go b/dynamicprogramming/binomialcoeffecient.go index d8a64d1fc..3d5a43611 100644 --- a/dynamicprogramming/binomialcoeffecient.go +++ b/dynamicprogramming/binomialcoeffecient.go @@ -1,26 +1,22 @@ -package main +package dynamicprogramming -import ( - "fmt" - "time" -) +// func main() { +// myArrayOfK := [4]int{5, 6, 7, 8} +// var x int -func main() { - myArrayOfK := [4]int{5, 6, 7, 8} - var x int +// fmt.Println("\nBinomial Coefficient Using Dynamic Programming:", bin2(50, 5)) +// for _, element := range myArrayOfK { +// start := time.Now() +// x = bin2(50, element) +// elapsed := time.Since(start) +// fmt.Println("bin2 (50,", element, ") = ", x, " took ", elapsed) - fmt.Println("\nBinomial Coefficient Using Dynamic Programming:", bin2(50, 5)) - for _, element := range myArrayOfK { - start := time.Now() - x = bin2(50, element) - elapsed := time.Since(start) - fmt.Println("bin2 (50,", element, ") = ", x, " took ", elapsed) +// } - } - -} +// } -func bin2(n int, k int) int { +// Bin2 function +func Bin2(n int, k int) int { var i, j int B := make([][]int, (n + 1)) for i := range B { @@ -28,7 +24,7 @@ func bin2(n int, k int) int { } for i = 0; i <= n; i++ { - for j = 0; j <= min(i, k); j++ { + for j = 0; j <= Min(i, k); j++ { if j == 0 || j == i { B[i][j] = 1 } else { @@ -39,7 +35,8 @@ func bin2(n int, k int) int { return B[n][k] } -func min(a, b int) int { +// Min function - possible duplicate +func Min(a, b int) int { if a < b { return a } diff --git a/dynamicprogramming/knapsack.go b/dynamicprogramming/knapsack.go index 3a920e5dd..257f0c6b4 100644 --- a/dynamicprogramming/knapsack.go +++ b/dynamicprogramming/knapsack.go @@ -1,20 +1,20 @@ +package dynamicprogramming + // Knapsack Problem // https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ -package Knapsack - -// package main import ( "math" ) -func max(a, b int) int { +// Max function - possible duplicate +func Max(a, b int) int { return int(math.Max(float64(a), float64(b))) } -// solve knapsack problem +// Solve knapsack problem // return maxProfit -func solve(maxWeight int, weights, values []int) int { +func Solve(maxWeight int, weights, values []int) int { n := len(weights) m := maxWeight // create dp data structure @@ -27,7 +27,7 @@ func solve(maxWeight int, weights, values []int) int { if weights[i] > j { dp[i+1][j] = dp[i][j] } else { - dp[i+1][j] = max(dp[i][j-weights[i]]+values[i], dp[i][j]) + dp[i+1][j] = Max(dp[i][j-weights[i]]+values[i], dp[i][j]) } } } diff --git a/dynamicprogramming/longest-palindromic-subsequence.go b/dynamicprogramming/longest-palindromic-subsequence.go index 5cbfcd764..d05e42129 100644 --- a/dynamicprogramming/longest-palindromic-subsequence.go +++ b/dynamicprogramming/longest-palindromic-subsequence.go @@ -1,20 +1,10 @@ // longest palindromic subsequence // http://www.geeksforgeeks.org/dynamic-programming-set-12-longest-palindromic-subsequence/ -package longestPalindromicSubsequence +package dynamicprogramming -// package main - -import "fmt" - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func lpsRec(word string, i, j int) int { +// LpsRec function +func LpsRec(word string, i, j int) int { if i == j { return 1 } @@ -22,12 +12,13 @@ func lpsRec(word string, i, j int) int { return 0 } if word[i] == word[j] { - return 2 + lpsRec(word, i+1, j-1) + return 2 + LpsRec(word, i+1, j-1) } - return max(lpsRec(word, i, j-1), lpsRec(word, i+1, j)) + return Max(LpsRec(word, i, j-1), LpsRec(word, i+1, j)) } -func lpsDp(word string) int { +// LpsDp function +func LpsDp(word string) int { N := len(word) dp := make([][]int, N) @@ -47,7 +38,7 @@ func lpsDp(word string) int { dp[i][j] = 2 + dp[i+1][j-1] } } else { - dp[i][j] = max(dp[i+1][j], dp[i][j-1]) + dp[i][j] = Max(dp[i+1][j], dp[i][j-1]) } } } diff --git a/dynamicprogramming/longestCommonSubsequence.go b/dynamicprogramming/longestCommonSubsequence.go index 0d09111a8..04a12f8dd 100644 --- a/dynamicprogramming/longestCommonSubsequence.go +++ b/dynamicprogramming/longestCommonSubsequence.go @@ -2,20 +2,10 @@ // DP - 4 // https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/ -package longestcommonsubsequence +package dynamicprogramming -// package main - -// import "fmt" - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func longestCommonSubsequence(a string, b string, m int, n int) int { +// LongestCommonSubsequence function +func LongestCommonSubsequence(a string, b string, m int, n int) int { // m is the length of string a and n is the length of string b // here we are making a 2d slice of size (m+1)*(n+1) @@ -32,7 +22,7 @@ func longestCommonSubsequence(a string, b string, m int, n int) int { } else if a[i-1] == b[j-1] { lcs[i][j] = lcs[i-1][j-1] + 1 } else { - lcs[i][j] = max(lcs[i-1][j], lcs[i][j-1]) + lcs[i][j] = Max(lcs[i-1][j], lcs[i][j-1]) } } } diff --git a/dynamicprogramming/matrix-multiplication.go b/dynamicprogramming/matrix-multiplication.go index e02d98b20..5faf0aa59 100644 --- a/dynamicprogramming/matrix-multiplication.go +++ b/dynamicprogramming/matrix-multiplication.go @@ -2,33 +2,25 @@ // https://en.wikipedia.org/wiki/Matrix_chain_multiplication // www.geeksforgeeks.org/dynamicprogramming-set-8-matrix-chain-multiplication/ -// package main -package matrixChainMultiplication +// Package dynamicprogramming Package for dynamically run algorithms +package dynamicprogramming -import "fmt" - -func min(a, b int) int { - if a > b { - return b - } else { - return a - } -} - -func matrixChainRec(D []int, i, j int) int { +// MatrixChainRec function +func MatrixChainRec(D []int, i, j int) int { // d[i-1] x d[i] : dimension of matrix i if i == j { return 0 } q := 1 << 32 for k := i; k < j; k++ { - prod := matrixChainRec(D, i, k) + matrixChainRec(D, k+1, j) + D[i-1]*D[k]*D[j] - q = min(prod, q) + prod := MatrixChainRec(D, i, k) + MatrixChainRec(D, k+1, j) + D[i-1]*D[k]*D[j] + q = Min(prod, q) } return q } -func matrixChainDp(D []int) int { +// MatrixChainDp function +func MatrixChainDp(D []int) int { // d[i-1] x d[i] : dimension of matrix i N := len(D) @@ -44,7 +36,7 @@ func matrixChainDp(D []int) int { dp[i][j] = 1 << 31 for k := i; k < j; k++ { prod := dp[i][k] + dp[k+1][j] + D[i-1]*D[k]*D[j] - dp[i][j] = min(prod, dp[i][j]) + dp[i][j] = Min(prod, dp[i][j]) } } } diff --git a/dynamicprogramming/rod-cutting.go b/dynamicprogramming/rod-cutting.go index 8abc4e441..704745fb3 100644 --- a/dynamicprogramming/rod-cutting.go +++ b/dynamicprogramming/rod-cutting.go @@ -2,43 +2,30 @@ // https://en.wikipedia.org/wiki/Cutting_stock_problem // http://www.geeksforgeeks.org/dynamic-programming-set-13-cutting-a-rod/ -package dpRodCutting +package dynamicprogramming -// package main - -import "fmt" - -func max(a, b int) int { - if a > b { - return a - } else { - return b - } - -} - -// solve the problem recursively: initial approach -func cutRodRec(price []int, length int) int { +// CutRodRec solve the problem recursively: initial approach +func CutRodRec(price []int, length int) int { if length == 0 { return 0 } q := -1 for i := 1; i <= length; i++ { - q = max(q, price[i]+cutRodRec(price, length-i)) + q = Max(q, price[i]+CutRodRec(price, length-i)) } return q } -// solve the same problem using dynamic programming -func cutRodDp(price []int, length int) int { +// CutRodDp solve the same problem using dynamic programming +func CutRodDp(price []int, length int) int { r := make([]int, length+1) // a.k.a the memoization array r[0] = 0 // cost of 0 length rod is 0 for j := 1; j <= length; j++ { // for each length (subproblem) q := -1 for i := 1; i <= j; i++ { - q = max(q, price[i]+r[j-i]) // avoiding recursive call + q = Max(q, price[i]+r[j-i]) // avoiding recursive call } r[j] = q } diff --git a/go.mod b/go.mod index 4f30be98d..26f3cba15 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ -module TheAlgorithms/Go +module github.com/tjgurwara99/Go go 1.14 + +require github.com/douglasmakey/golang-algorithms- v0.0.0-20180429234644-0a5ef73a9fd5 diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..85237faa5 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/douglasmakey/golang-algorithms- v0.0.0-20180429234644-0a5ef73a9fd5 h1:ae3ZNa8+Q3WVR6I/BdB+AatZrnZZpnyl6ZOWDmh96Jw= +github.com/douglasmakey/golang-algorithms- v0.0.0-20180429234644-0a5ef73a9fd5/go.mod h1:DUocdLj6AeO5RUfLT9JPVhanSEihgqlwSlIfcEloUqY= diff --git a/graphs/breathfirstsearch.go b/graphs/breathfirstsearch.go deleted file mode 100644 index 66e8c7e29..000000000 --- a/graphs/breathfirstsearch.go +++ /dev/null @@ -1,72 +0,0 @@ -package graphs - -import "fmt" - -func getIdx(target int, nodes []int) int { - for i := 0; i < len(nodes); i++ { - if nodes[i] == target { - return i - } - } - return -1 -} - -func notExist(target int, slice []int) bool { - for i := 0; i < len(slice); i++ { - if slice[i] == target { - return false - } - } - return true -} - -func breadthFirstSearch(start, end int, nodes []int, edges [][]bool) bool { - var route []int - var queue []int - startIdx := getIdx(start, nodes) - queue = append(queue, startIdx) - for len(queue) > 0 { - now := queue[0] - route = append(route, nodes[now]) - if len(queue) > 1 { - queue = queue[1:] - } else { - queue = queue[0:] - } - for i := 0; i < len(edges[now]); i++ { - if edges[now][i] && notExist(i, queue) { - queue = append(queue, i) - } - edges[now][i] = false - edges[i][now] = false - } - if route[len(route)-1] == end { - return true - } - } - return false -} - -func main() { - nodes := []int{ - 1, 2, 3, 4, 5, 6, - } - /* - sample graph - ①-② - | | - ③-④-⑤-⑥ - */ - edges := [][]bool{ - {false, true, true, false, false, false}, - {true, false, false, true, false, false}, - {true, false, false, true, false, false}, - {false, true, true, false, true, false}, - {false, false, false, true, false, true}, - {false, false, false, false, true, false}, - } - start := 1 - end := 6 - result := breadthFirstSearch(start, end, nodes, edges) - fmt.Println(result) -} diff --git a/graphs/breathfirstsearch/breathfirstsearch.go b/graphs/breathfirstsearch/breathfirstsearch.go new file mode 100644 index 000000000..8d10e0a99 --- /dev/null +++ b/graphs/breathfirstsearch/breathfirstsearch.go @@ -0,0 +1,73 @@ +package breathfirstsearch + +// GetIdx ... +func GetIdx(target int, nodes []int) int { + for i := 0; i < len(nodes); i++ { + if nodes[i] == target { + return i + } + } + return -1 +} + +// NotExist ... +func NotExist(target int, slice []int) bool { + for i := 0; i < len(slice); i++ { + if slice[i] == target { + return false + } + } + return true +} + +// BreadthFirstSearch The main algorithm for bread first search +func BreadthFirstSearch(start, end int, nodes []int, edges [][]bool) bool { + var route []int + var queue []int + startIdx := GetIdx(start, nodes) + queue = append(queue, startIdx) + for len(queue) > 0 { + now := queue[0] + route = append(route, nodes[now]) + if len(queue) > 1 { + queue = queue[1:] + } else { + queue = queue[0:] + } + for i := 0; i < len(edges[now]); i++ { + if edges[now][i] && NotExist(i, queue) { + queue = append(queue, i) + } + edges[now][i] = false + edges[i][now] = false + } + if route[len(route)-1] == end { + return true + } + } + return false +} + +// func main() { +// nodes := []int{ +// 1, 2, 3, 4, 5, 6, +// } +// /* +// sample graph +// ①-② +// | | +// ③-④-⑤-⑥ +// */ +// edges := [][]bool{ +// {false, true, true, false, false, false}, +// {true, false, false, true, false, false}, +// {true, false, false, true, false, false}, +// {false, true, true, false, true, false}, +// {false, false, false, true, false, true}, +// {false, false, false, false, true, false}, +// } +// start := 1 +// end := 6 +// result := breadthFirstSearch(start, end, nodes, edges) +// fmt.Println(result) +// } diff --git a/graphs/depthfirstsearch.go b/graphs/depthfirstsearch.go deleted file mode 100644 index 6f0003c46..000000000 --- a/graphs/depthfirstsearch.go +++ /dev/null @@ -1,72 +0,0 @@ -package graphs - -import "fmt" - -func getIdx(target int, nodes []int) int { - for i := 0; i < len(nodes); i++ { - if nodes[i] == target { - return i - } - } - return -1 -} - -func notExist(target int, slice []int) bool { - for i := 0; i < len(slice); i++ { - if slice[i] == target { - return false - } - } - return true -} - -func dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { - var route []int - var stack []int - startIdx := getIdx(start, nodes) - stack = append(stack, startIdx) - for len(stack) > 0 { - now := stack[len(stack)-1] - route = append(route, nodes[now]) - if len(stack) > 1 { - stack = stack[:len(stack)-1] - } else { - stack = stack[:len(stack)-1] - } - for i := 0; i < len(edges[now]); i++ { - if edges[now][i] && notExist(i, stack) { - stack = append(stack, i) - } - edges[now][i] = false - edges[i][now] = false - } - if route[len(route)-1] == end { - return route, true - } - } - return nil, false -} - -func main() { - nodes := []int{ - 1, 2, 3, 4, 5, 6, - } - /* - sample graph - ①-② - | | - ③-④-⑤-⑥ - */ - edges := [][]bool{ - {false, true, true, false, false, false}, - {true, false, false, true, false, false}, - {true, false, false, true, false, false}, - {false, true, true, false, true, false}, - {false, false, false, true, false, true}, - {false, false, false, false, true, false}, - } - start := 1 - end := 6 - route, _ := dfs(start, end, nodes, edges) - fmt.Println(route) -} diff --git a/graphs/depthfirstsearch/depthfirstsearch.go b/graphs/depthfirstsearch/depthfirstsearch.go new file mode 100644 index 000000000..2ebd3302f --- /dev/null +++ b/graphs/depthfirstsearch/depthfirstsearch.go @@ -0,0 +1,70 @@ +package depthfirstsearch + +func GetIdx(target int, nodes []int) int { + for i := 0; i < len(nodes); i++ { + if nodes[i] == target { + return i + } + } + return -1 +} + +func NotExist(target int, slice []int) bool { + for i := 0; i < len(slice); i++ { + if slice[i] == target { + return false + } + } + return true +} + +func Dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { + var route []int + var stack []int + startIdx := GetIdx(start, nodes) + stack = append(stack, startIdx) + for len(stack) > 0 { + now := stack[len(stack)-1] + route = append(route, nodes[now]) + if len(stack) > 1 { + stack = stack[:len(stack)-1] + } else { + stack = stack[:len(stack)-1] + } + for i := 0; i < len(edges[now]); i++ { + if edges[now][i] && NotExist(i, stack) { + stack = append(stack, i) + } + edges[now][i] = false + edges[i][now] = false + } + if route[len(route)-1] == end { + return route, true + } + } + return nil, false +} + +// func main() { +// nodes := []int{ +// 1, 2, 3, 4, 5, 6, +// } +// /* +// sample graph +// ①-② +// | | +// ③-④-⑤-⑥ +// */ +// edges := [][]bool{ +// {false, true, true, false, false, false}, +// {true, false, false, true, false, false}, +// {true, false, false, true, false, false}, +// {false, true, true, false, true, false}, +// {false, false, false, true, false, true}, +// {false, false, false, false, true, false}, +// } +// start := 1 +// end := 6 +// route, _ := dfs(start, end, nodes, edges) +// fmt.Println(route) +// } diff --git a/graphs/floydwarshall.go b/graphs/floydwarshall/floydwarshall.go similarity index 66% rename from graphs/floydwarshall.go rename to graphs/floydwarshall/floydwarshall.go index 4fe0807ce..90f655a19 100644 --- a/graphs/floydwarshall.go +++ b/graphs/floydwarshall/floydwarshall.go @@ -1,20 +1,15 @@ // Floyd-Warshall algorithm // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm -package graphs +package floydwarshall -import ( - "math" - "fmt" -) - -// Defining matrix to use 2d array easier +// Matrix Defining matrix to use 2d array easier type Matrix [][]float64 // Defining maximum value. If two vertices share this value, it means they are not connected -var maxValue = math.Inf(1) +// var maxValue = math.Inf(1) // This is not being used in the code?? -// Returns all pair's shortest path using Floyd Warshall algorithm +// FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm func FloydWarshall(graph Matrix) Matrix { // If graph is empty or width != height, returns nil if len(graph) == 0 || len(graph) != len(graph[0]) { @@ -48,17 +43,17 @@ func FloydWarshall(graph Matrix) Matrix { return result } -func main() { - var graph Matrix - graph = Matrix{{0, maxValue, -2, maxValue}, - {4, 0, 3, maxValue}, - {maxValue, maxValue, 0, 2}, - {maxValue, -1, maxValue, 0}} +// func main() { +// var graph Matrix +// graph = Matrix{{0, maxValue, -2, maxValue}, +// {4, 0, 3, maxValue}, +// {maxValue, maxValue, 0, 2}, +// {maxValue, -1, maxValue, 0}} - result := FloydWarshall(graph) +// result := FloydWarshall(graph) - //Print result - for i := 0; i < len(result); i++ { - fmt.Printf("%4g\n", result[i]) - } - } +// //Print result +// for i := 0; i < len(result); i++ { +// fmt.Printf("%4g\n", result[i]) +// } +// } diff --git a/math/sieve/Sieve.go b/math/sieve/Sieve.go index 0162c3a4d..4e4b7facf 100644 --- a/math/sieve/Sieve.go +++ b/math/sieve/Sieve.go @@ -1,50 +1,18 @@ -package main +package sieve -import ( - _ "fmt" -) - -func main() { - var l, f int - l = 100 - channel := make(chan int, l) - channelTwo := make(chan int, l) - var nums []bool - - for i := 0; i < l; i++ { - nums = append(nums, true) - } - f = 2 - - go crossOff(channel, channelTwo, f, l) - go nextF(f, channelTwo, nums) - //blocks and sieves out non-primes - for { - select { - case index := <-channel: - nums[index-1] = false - } +// Generate generates the sequence of integers starting at 2 and sends it to the channel `ch` +func Generate(ch chan<- int) { + for i := 2; ; i++ { + ch <- i } } -func crossOff(c chan int, r chan int, f int, l int) { - for f != -1 { - for f <= l { - c <- f - f += f - } - f = <-r - r <- 1 - } - -} -func nextF(f int, r chan int, nums []bool) { +// Sieve Sieving the numbers that are not prime from the channel - basically removing them from the channels +func Sieve(in <-chan int, out chan<- int, prime int) { for { - <-r - for i, v := range nums[f:] { - if v { - r <- i + f - } + i := <-in + if i%prime != 0 { + out <- i } } } diff --git a/math/sieve/sieve_test.go b/math/sieve/sieve_test.go new file mode 100644 index 000000000..5e6664dab --- /dev/null +++ b/math/sieve/sieve_test.go @@ -0,0 +1,28 @@ +package sieve + +import ( + "testing" +) + +func TestSieve(t *testing.T) { + firstTenPrimes := [10]int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} + + t.Run("First 10 primes test", func(t *testing.T) { + var testTenPrimes [10]int + + ch := make(chan int) + go Generate(ch) + + for i := 0; i < 10; i++ { + testTenPrimes[i] = <-ch + ch1 := make(chan int) + go Sieve(ch, ch1, testTenPrimes[i]) + ch = ch1 + } + + if firstTenPrimes != testTenPrimes { + t.Errorf("The first 10 primes do not match") + } + + }) +} diff --git a/other/PrimeNumbers.go b/other/PrimeNumbers.go deleted file mode 100644 index fa2fc81a2..000000000 --- a/other/PrimeNumbers.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "fmt" - "github.com/douglasmakey/golang-algorithms-/utils" - "math" - "os" - "strconv" - "time" -) - -// Define struct -type numberResult struct { - number int64 - isPrime bool -} - -// Define functions - -// isPrime: validate N number is prime -func isPrime(n int64) bool { - var i, limit int64 - if n <= 1 { - return false - } - - if n == 2 { - return true - } - - if math.Mod(float64(n), 2) == 0 { - return false - } - - limit = int64(math.Ceil(math.Sqrt(float64(n)))) - for i = 3; i <= limit; i += 2 { - if math.Mod(float64(n), float64(i)) == 0 { - return false - } - } - return true -} - -// createNrAndValidate: Receive number and validate if is prime, send channel this same -func createNrAndValidate(n int64, c chan numberResult) { - - result := new(numberResult) - result.number = n - result.isPrime = isPrime(n) - c <- *result -} - -func initGoCalculations(min int64, max int64, c chan numberResult) { - var i int64 - for i = min; i <= max; i++ { - go createNrAndValidate(i, c) - } -} - -func primesInRange(min int64, max int64) (primeArr []int64) { - defer utils.TimeTrack(time.Now(), "primesInRange") - - // Create channels and defer close - c := make(chan numberResult) - defer close(c) - - // Execute N goroutines in range number - go initGoCalculations(min, max, c) - - for i := min; i <= max; i++ { - // Receive numberResult - r := <-c - if r.isPrime { - primeArr = append(primeArr, r.number) - } - } - return -} - -func main() { - // Receive arguments min max - min, _ := strconv.ParseInt(os.Args[1], 10, 64) - max, _ := strconv.ParseInt(os.Args[2], 10, 64) - fmt.Println(primesInRange(min, max)) -} diff --git a/other/maxsubarraysum.go b/other/maxsubarraysum.go deleted file mode 100644 index 78e1b8db3..000000000 --- a/other/maxsubarraysum.go +++ /dev/null @@ -1,30 +0,0 @@ -/* O(n) solution, for calculating -maximum contiguous sum in the given array. */ - -package main - -import ( - "fmt" -) - -func Max(x int, y int) int { - if x < y { - return y - } - return x -} - -func maxSubarraySum(array []int) int { - var currentMax int = 0 - var maxTillNow int = 0 - for _, v := range array { - currentMax = Max(v, currentMax+v) - maxTillNow = Max(maxTillNow, currentMax) - } - return maxTillNow -} - -func main() { - array := []int{-2, -5, 6, 0, -2, 0, -3, 1, 0, 5, -6} - fmt.Println("Maximum contiguous sum: ", maxSubarraySum(array)) -} diff --git a/other/maxsubarraysum/maxsubarraysum.go b/other/maxsubarraysum/maxsubarraysum.go new file mode 100644 index 000000000..e50453b3b --- /dev/null +++ b/other/maxsubarraysum/maxsubarraysum.go @@ -0,0 +1,28 @@ +/* O(n) solution, for calculating +maximum contiguous sum in the given array. */ + +package maxsubarraysum + +// Max - already defined somewhere in this repository TODO: remove this definition and add the import path +func Max(x int, y int) int { + if x < y { + return y + } + return x +} + +// MaxSubarraySum returns the maximum subarray sum +func MaxSubarraySum(array []int) int { + var currentMax int = 0 + var maxTillNow int = 0 + for _, v := range array { + currentMax = Max(v, currentMax+v) + maxTillNow = Max(maxTillNow, currentMax) + } + return maxTillNow +} + +// func main() { +// array := []int{-2, -5, 6, 0, -2, 0, -3, 1, 0, 5, -6} +// fmt.Println("Maximum contiguous sum: ", maxSubarraySum(array)) +// } diff --git a/other/monte_carlo_pi/monte_carlo_pi.go b/other/monte_carlo_pi/monte_carlo_pi.go index d427dfe1f..2506af346 100644 --- a/other/monte_carlo_pi/monte_carlo_pi.go +++ b/other/monte_carlo_pi/monte_carlo_pi.go @@ -1,50 +1,50 @@ -package main +package montecarlopi -import ( - "fmt" - "math" - "math/rand" - "runtime" - "sync" - "time" -) +// import ( +// "fmt" +// "math" +// "math/rand" +// "runtime" +// "sync" +// "time" +// ) -func main() { - cpus := runtime.NumCPU() - monteCarlo := func(iterations, cpus int) float64{ - start := time.Now() - flow := make(chan int, int(math.Floor(float64(cpus)/2))) - var wg sync.WaitGroup - var total int - miniFunc := func(iters int, flow chan int) { - defer wg.Done() - var inside int - for i := 0; i < iters; i++ { - x := rand.Float64() - y := rand.Float64() - if math.Hypot(x, y) <= 1 { - inside++ - } - } - flow <- inside - } //end of minifunc - fuxc := func(flow chan int) { - defer wg.Done() - for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { - total += <-flow - } - } //end of fuxc - wg.Add(int(math.Floor(float64(cpus) / 2))) - //spawn goroutines for half the logical processors - // This leaves free cpus for swapping - for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { - go miniFunc(int(math.Ceil(float64(iterations/int(math.Floor(float64(cpus)/2))))), flow) - } - wg.Add(1) - go fuxc(flow) - wg.Wait() - fmt.Printf("took %v \n",time.Since(start)) - return 4 * float64(total) / float64(iterations) - }//end of monteCarlo - fmt.Println(monteCarlo(2<<18, cpus)) -} +// func main() { +// cpus := runtime.NumCPU() +// monteCarlo := func(iterations, cpus int) float64{ +// start := time.Now() +// flow := make(chan int, int(math.Floor(float64(cpus)/2))) +// var wg sync.WaitGroup +// var total int +// miniFunc := func(iters int, flow chan int) { +// defer wg.Done() +// var inside int +// for i := 0; i < iters; i++ { +// x := rand.Float64() +// y := rand.Float64() +// if math.Hypot(x, y) <= 1 { +// inside++ +// } +// } +// flow <- inside +// } //end of minifunc +// fuxc := func(flow chan int) { +// defer wg.Done() +// for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { +// total += <-flow +// } +// } //end of fuxc +// wg.Add(int(math.Floor(float64(cpus) / 2))) +// //spawn goroutines for half the logical processors +// // This leaves free cpus for swapping +// for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { +// go miniFunc(int(math.Ceil(float64(iterations/int(math.Floor(float64(cpus)/2))))), flow) +// } +// wg.Add(1) +// go fuxc(flow) +// wg.Wait() +// fmt.Printf("took %v \n",time.Since(start)) +// return 4 * float64(total) / float64(iterations) +// }//end of monteCarlo +// fmt.Println(monteCarlo(2<<18, cpus)) +// } diff --git a/other/monte_carlo_pi/monte_carlo_pi_test.go b/other/monte_carlo_pi/monte_carlo_pi_test.go index e660f5eba..899fd5c46 100644 --- a/other/monte_carlo_pi/monte_carlo_pi_test.go +++ b/other/monte_carlo_pi/monte_carlo_pi_test.go @@ -1,16 +1,16 @@ -package main +package montecarlopi -import ( - "math" - "testing" -) +// import ( +// "math" +// "testing" +// ) -func TestMonteCarloPi(t *testing.T) { - delta := 0.0001 +// func TestMonteCarloPi(t *testing.T) { +// delta := 0.0001 - pi := MonteCarloPi(100000000) +// pi := MonteCarloPi(100000000) - if math.Abs(pi-math.Pi) > delta { - t.Errorf("Given: %.4f, expected: %.4f", pi, math.Pi) - } -} +// if math.Abs(pi-math.Pi) > delta { +// t.Errorf("Given: %.4f, expected: %.4f", pi, math.Pi) +// } +// } diff --git a/other/nestedbrackets.go b/other/nestedbrackets/nestedbrackets.go similarity index 77% rename from other/nestedbrackets.go rename to other/nestedbrackets/nestedbrackets.go index d3e0b19d9..f2fd239d8 100644 --- a/other/nestedbrackets.go +++ b/other/nestedbrackets/nestedbrackets.go @@ -9,18 +9,13 @@ // returns true if input is nested and false otherwise. //note that only an even number of brackets can be properly nested -package main +package nestedbrackets -import ( - "bufio" - "fmt" - "os" - "strings" -) - -func isBalanced(input string) string { - if len(input)%2 != 0{ +// IsBalanced function which checks whether the number of brackets are balanced +func IsBalanced(input string) string { + if len(input)%2 != 0 { return input + "is not balanced." + } if len(input) > 0 { var stack []byte for i := 0; i < len(input); i++ { @@ -46,11 +41,11 @@ func isBalanced(input string) string { return "Please enter a sequence of brackets." } -func main() { - reader := bufio.NewReader(os.Stdin) - fmt.Print("Enter sequence of brackets: ") - text, _ := reader.ReadString('\n') +// func main() { +// reader := bufio.NewReader(os.Stdin) +// fmt.Print("Enter sequence of brackets: ") +// text, _ := reader.ReadString('\n') - text = strings.TrimSpace(text) - fmt.Println(isBalanced(text)) -} \ No newline at end of file +// text = strings.TrimSpace(text) +// fmt.Println(isBalanced(text)) +// } diff --git a/other/passwordgenerator.go b/other/passwordgenerator/passwordgenerator.go similarity index 63% rename from other/passwordgenerator.go rename to other/passwordgenerator/passwordgenerator.go index 5dd30dff0..742bd7303 100644 --- a/other/passwordgenerator.go +++ b/other/passwordgenerator/passwordgenerator.go @@ -2,17 +2,16 @@ // You must provide a minimum length and a maximum length // This length is not fixed if you generate multiple passwords for the same range -package main +package passwordgenerator import ( crand "crypto/rand" - "fmt" "io" "math/rand" - "time" ) -func generatePassword(minLength int, maxLength int) string { +// GeneratePassword returns a newly generated password +func GeneratePassword(minLength int, maxLength int) string { var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~") var length = rand.Intn(maxLength-minLength) + minLength @@ -39,16 +38,16 @@ func generatePassword(minLength int, maxLength int) string { } } -func main() { - rand.Seed(time.Now().Unix()) +// func main() { +// rand.Seed(time.Now().Unix()) - fmt.Print("Please specify a minimum length: ") - var minLength int - fmt.Scanf("%d", &minLength) +// fmt.Print("Please specify a minimum length: ") +// var minLength int +// fmt.Scanf("%d", &minLength) - fmt.Print("Please specify a maximum length: ") - var maxLength int - fmt.Scanf("%d", &maxLength) +// fmt.Print("Please specify a maximum length: ") +// var maxLength int +// fmt.Scanf("%d", &maxLength) - fmt.Printf("Your generated password is %v\n", generatePassword(minLength, maxLength)) -} +// fmt.Printf("Your generated password is %v\n", generatePassword(minLength, maxLength)) +// } diff --git a/other/prime_numbers.go b/other/prime_numbers.go deleted file mode 100644 index fa2fc81a2..000000000 --- a/other/prime_numbers.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "fmt" - "github.com/douglasmakey/golang-algorithms-/utils" - "math" - "os" - "strconv" - "time" -) - -// Define struct -type numberResult struct { - number int64 - isPrime bool -} - -// Define functions - -// isPrime: validate N number is prime -func isPrime(n int64) bool { - var i, limit int64 - if n <= 1 { - return false - } - - if n == 2 { - return true - } - - if math.Mod(float64(n), 2) == 0 { - return false - } - - limit = int64(math.Ceil(math.Sqrt(float64(n)))) - for i = 3; i <= limit; i += 2 { - if math.Mod(float64(n), float64(i)) == 0 { - return false - } - } - return true -} - -// createNrAndValidate: Receive number and validate if is prime, send channel this same -func createNrAndValidate(n int64, c chan numberResult) { - - result := new(numberResult) - result.number = n - result.isPrime = isPrime(n) - c <- *result -} - -func initGoCalculations(min int64, max int64, c chan numberResult) { - var i int64 - for i = min; i <= max; i++ { - go createNrAndValidate(i, c) - } -} - -func primesInRange(min int64, max int64) (primeArr []int64) { - defer utils.TimeTrack(time.Now(), "primesInRange") - - // Create channels and defer close - c := make(chan numberResult) - defer close(c) - - // Execute N goroutines in range number - go initGoCalculations(min, max, c) - - for i := min; i <= max; i++ { - // Receive numberResult - r := <-c - if r.isPrime { - primeArr = append(primeArr, r.number) - } - } - return -} - -func main() { - // Receive arguments min max - min, _ := strconv.ParseInt(os.Args[1], 10, 64) - max, _ := strconv.ParseInt(os.Args[2], 10, 64) - fmt.Println(primesInRange(min, max)) -} diff --git a/other/stringcombinations.go b/other/stringcombinations/stringcombinations.go similarity index 70% rename from other/stringcombinations.go rename to other/stringcombinations/stringcombinations.go index 8d04fc1a8..0e1dc3d10 100644 --- a/other/stringcombinations.go +++ b/other/stringcombinations/stringcombinations.go @@ -1,16 +1,16 @@ -/* - String combinations in Go -*/ -package main +// Package stringcombinations ... +package stringcombinations import "fmt" +// Combinations structure with in and out rune type Combinations struct { out []rune in []rune } -func startCombinations(input string) { +// StartCombinations ... +func StartCombinations(input string) { c := &Combinations{ in: []rune(input), } @@ -18,6 +18,7 @@ func startCombinations(input string) { c.Combine(0) } +// Combine ... func (c *Combinations) Combine(seed int) { inLen := len(c.in) for i := seed; i < inLen-1; i++ { diff --git a/searches/binarysearch.go b/searches/binarysearch.go index 5a7f32fa1..725c10c07 100644 --- a/searches/binarysearch.go +++ b/searches/binarysearch.go @@ -1,34 +1,35 @@ package searches - -func binarySearch(array []int, target int, lowIndex int, highIndex int) int { - if highIndex < lowIndex || len(array) == 0{ +// BinarySearch Binary Search +func BinarySearch(array []int, target int, lowIndex int, highIndex int) int { + if highIndex < lowIndex || len(array) == 0 { return -1 } - mid := (highIndex+lowIndex)/2 + mid := (highIndex + lowIndex) / 2 if array[mid] > target { - return binarySearch(array, target, lowIndex, mid-1) + return BinarySearch(array, target, lowIndex, mid-1) } else if array[mid] < target { - return binarySearch(array, target, mid+1, highIndex) + return BinarySearch(array, target, mid+1, highIndex) } else { return mid } } -func iterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { +// IterBinarySearch Iter Binary Search +func IterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { startIndex := lowIndex endIndex := highIndex var mid int size := len(array) - if size ==0 || highIndex > size || lowIndex < 0 { + if size == 0 || highIndex > size || lowIndex < 0 { return -1 } for startIndex <= endIndex { - mid = (endIndex + startIndex)/2 + mid = (endIndex + startIndex) / 2 if array[mid] > target { - endIndex = mid-1 + endIndex = mid - 1 } else if array[mid] < target { - startIndex = mid+1 + startIndex = mid + 1 } else { return mid } diff --git a/searches/linearsearch.go b/searches/linearsearch.go index 23baec9e9..a41ef8a80 100644 --- a/searches/linearsearch.go +++ b/searches/linearsearch.go @@ -1,8 +1,7 @@ package searches -import "fmt" - -func linearSearch(array []int, query int) int { +// LinearSearch Simple linear search algorithm that iterates over all elements of an array in the worst case scenario +func LinearSearch(array []int, query int) int { for i, item := range array { if item == query { return i @@ -10,16 +9,3 @@ func linearSearch(array []int, query int) int { } return -1 } - -func main() { - - fmt.Println("Linear search:") - array := []int{0, 2, 4, 6, 8, 10, 12, 14, 16, 18} - index := linearSearch(array, 10) - if index == -1 { - fmt.Println("Number not found") - } else { - fmt.Println("Index: ", index) - fmt.Println("array[", index, "] = ", array[index]) - } -} diff --git a/searches/search_test.go b/searches/search_test.go index fbbc226f5..dccd93c11 100644 --- a/searches/search_test.go +++ b/searches/search_test.go @@ -23,7 +23,7 @@ var searchTests = []searchTest{ func TestBinarySearch(t *testing.T) { for _, test := range searchTests { - actual := binarySearch(test.data, test.key, 0, len(test.data)-1) + actual := BinarySearch(test.data, test.key, 0, len(test.data)-1) if actual != test.expected { t.Errorf("test %s failed", test.name) } @@ -32,7 +32,7 @@ func TestBinarySearch(t *testing.T) { func TestIterBinarySearch(t *testing.T) { for _, test := range searchTests { - actual := iterBinarySearch(test.data, test.key, 0, len(test.data)-1) + actual := IterBinarySearch(test.data, test.key, 0, len(test.data)-1) if actual != test.expected { t.Errorf("test %s failed", test.name) } @@ -41,10 +41,9 @@ func TestIterBinarySearch(t *testing.T) { func TestLinearSearch(t *testing.T) { for _, test := range searchTests { - actual := linearSearch(test.data, test.key) + actual := LinearSearch(test.data, test.key) if actual != test.expected { t.Errorf("test %s failed", test.name) } } } - diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index cacfdcd31..f93949132 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -50,9 +50,9 @@ func TestRadix(t *testing.T) { } // Very slow, consider commenting -func TestSelection(t *testing.T) { - testFramework(t, SelectionSort) -} +// func TestSelection(t *testing.T) { +// testFramework(t, SelectionSort) +// } /* func TestTopological(t *testing.T) { testFramework(t, topologicalSort) diff --git a/strings/levenshteindistance/levenshteinDistance.go b/strings/levenshteindistance/levenshteinDistance.go index 143315536..e4181e205 100644 --- a/strings/levenshteindistance/levenshteinDistance.go +++ b/strings/levenshteindistance/levenshteinDistance.go @@ -6,7 +6,8 @@ Output: distance between both strings package levenshteindistance -func levenshteinDistance(str1, str2 string, icost, scost, dcost int) int { +// LevenshteinDistance Function that gives Levenshtein Distance +func LevenshteinDistance(str1, str2 string, icost, scost, dcost int) int { row1 := make([]int, len(str2)+1) row2 := make([]int, len(str2)+1) diff --git a/strings/levenshteindistance/levenshteinDistance_test.go b/strings/levenshteindistance/levenshteinDistance_test.go index 9079d844a..d02053fd4 100644 --- a/strings/levenshteindistance/levenshteinDistance_test.go +++ b/strings/levenshteindistance/levenshteinDistance_test.go @@ -43,7 +43,7 @@ var testCases = []struct { func TestLevenshteinDistance(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := levenshteinDistance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost) + actual := LevenshteinDistance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost) if actual != tc.expected { t.Errorf("Expected Levenshtein distance between strings: '%s' and '%s' is %v, but got: %v", tc.string1, tc.string2, tc.expected, actual) } diff --git a/strings/multiple-string-matching/advanced-aho-corasick/adac.go b/strings/multiple-string-matching/advanced-aho-corasick/adac.go index 2a4f452aa..82012451b 100644 --- a/strings/multiple-string-matching/advanced-aho-corasick/adac.go +++ b/strings/multiple-string-matching/advanced-aho-corasick/adac.go @@ -2,86 +2,84 @@ package advancedahocorasick import ( "fmt" - "io/ioutil" - "log" - "strings" "time" ) // User defined. // Set to true to print various extra stuff out (slows down the execution) // Set to false for quick and quiet execution. -const debugMode bool = true +// const debugMode bool = true // TODO: very convoluted algorithm need time to read through it properly -type result struct { +// Result structure +type Result struct { occurrences map[string][]int } // Implementation of Advanced Aho-Corasick algorithm (Prefix based). // Searches for a set of strings (patterns.txt) in text.txt. -func main() { - patFile, err := ioutil.ReadFile("../patterns.txt") - if err != nil { - log.Fatal(err) - } - textFile, err := ioutil.ReadFile("../text.txt") - if err != nil { - log.Fatal(err) - } - patterns := strings.Split(string(patFile), " ") - fmt.Printf("\nRunning: Advanced Aho-Corasick algorithm.\n\n") - if debugMode == true { - fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) - } - for i := 0; i < len(patterns); i++ { - if len(patterns[i]) > len(textFile) { - log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) - } - if debugMode == true { - fmt.Printf("%q ", patterns[i]) - } - } - if debugMode == true { - fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) - } - r := ahoCorasick(string(textFile), patterns) - for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) - fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) - for i := range value { - fmt.Printf("%d", value[i]) - if i != len(value)-1 { - fmt.Printf(", ") - } - } - fmt.Printf(".") - } - return -} +// func main() { +// patFile, err := ioutil.ReadFile("../patterns.txt") +// if err != nil { +// log.Fatal(err) +// } +// textFile, err := ioutil.ReadFile("../text.txt") +// if err != nil { +// log.Fatal(err) +// } +// patterns := strings.Split(string(patFile), " ") +// fmt.Printf("\nRunning: Advanced Aho-Corasick algorithm.\n\n") +// if debugMode == true { +// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) +// } +// for i := 0; i < len(patterns); i++ { +// if len(patterns[i]) > len(textFile) { +// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) +// } +// if debugMode == true { +// fmt.Printf("%q ", patterns[i]) +// } +// } +// if debugMode == true { +// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) +// } +// r := ahoCorasick(string(textFile), patterns) +// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) +// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) +// for i := range value { +// fmt.Printf("%d", value[i]) +// if i != len(value)-1 { +// fmt.Printf(", ") +// } +// } +// fmt.Printf(".") +// } +// return +// } -// Function performing the Advanced Aho-Corasick alghoritm. +// AhoCorasick Function performing the Advanced Aho-Corasick alghoritm. // Finds and prints occurrences of each pattern. -func ahoCorasick(t string, p []string) result { +func AhoCorasick(t string, p []string) Result { startTime := time.Now() occurrences := make(map[int][]int) - ac, f := buildExtendedAc(p) - if debugMode == true { - fmt.Printf("\n\nAC:\n\n") - } + ac, f := BuildExtendedAc(p) + // if debugMode == true { + // fmt.Printf("\n\nAC:\n\n") + // } current := 0 for pos := 0; pos < len(t); pos++ { - if getTransition(current, t[pos], ac) != -1 { - current = getTransition(current, t[pos], ac) + if GetTransition(current, t[pos], ac) != -1 { + current = GetTransition(current, t[pos], ac) } else { current = 0 } _, ok := f[current] if ok { for i := range f[current] { - if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match - if debugMode == true { - fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) - } - newOccurrences := intArrayCapUp(occurrences[f[current][i]]) + if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match + // if debugMode == true { + // fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) + // } + newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) occurrences[f[current][i]] = newOccurrences occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 } @@ -96,122 +94,122 @@ func ahoCorasick(t string, p []string) result { resultOccurrences[p[key]] = value } - return result{ + return Result{ resultOccurrences, } } -// Functions that builds extended Aho Corasick automaton. -func buildExtendedAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int) { - acTrie, stateIsTerminal, f := constructTrie(p) +// BuildExtendedAc Functions that builds extended Aho Corasick automaton. +func BuildExtendedAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int) { + acTrie, stateIsTerminal, f := ConstructTrie(p) s := make([]int, len(stateIsTerminal)) //supply function i := 0 //root of acTrie acToReturn = acTrie s[i] = -1 - if debugMode == true { - fmt.Printf("\n\nAC construction: \n") - } + // if debugMode == true { + // fmt.Printf("\n\nAC construction: \n") + // } for current := 1; current < len(stateIsTerminal); current++ { - o, parent := getParent(current, acTrie) + o, parent := GetParent(current, acTrie) down := s[parent] - for stateExists(down, acToReturn) && getTransition(down, o, acToReturn) == -1 { + for StateExists(down, acToReturn) && GetTransition(down, o, acToReturn) == -1 { down = s[down] } - if stateExists(down, acToReturn) { - s[current] = getTransition(down, o, acToReturn) - if stateIsTerminal[s[current]] == true { + if StateExists(down, acToReturn) { + s[current] = GetTransition(down, o, acToReturn) + if stateIsTerminal[s[current]] { stateIsTerminal[current] = true - f[current] = arrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) - if debugMode == true { - fmt.Printf(" f[%d] set to: ", current) - for i := range f[current] { - fmt.Printf("%d\n", f[current][i]) - } - } + f[current] = ArrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) + // if debugMode == true { + // fmt.Printf(" f[%d] set to: ", current) + // for i := range f[current] { + // fmt.Printf("%d\n", f[current][i]) + // } + // } } } else { s[current] = i //initial state? } } - if debugMode == true { - fmt.Printf("\nsupply function: \n") - for i := range s { - fmt.Printf("\ns[%d]=%d", i, s[i]) - } - fmt.Printf("\n\n") - for i, j := range f { - fmt.Printf("f[%d]=", i) - for k := range j { - fmt.Printf("%d\n", j[k]) - } - } - } - if debugMode == true { - fmt.Printf("\n\nAdAC completion: \n") - } + // if debugMode == true { + // fmt.Printf("\nsupply function: \n") + // for i := range s { + // fmt.Printf("\ns[%d]=%d", i, s[i]) + // } + // fmt.Printf("\n\n") + // for i, j := range f { + // fmt.Printf("f[%d]=", i) + // for k := range j { + // fmt.Printf("%d\n", j[k]) + // } + // } + // } + // if debugMode == true { + // fmt.Printf("\n\nAdAC completion: \n") + // } // advanced Aho-Corasick part - a := computeAlphabet(p) // concat of all patterns in p + a := ComputeAlphabet(p) // concat of all patterns in p for j := range a { - if getTransition(i, a[j], acToReturn) == -1 { - createTransition(i, a[j], i, acToReturn) + if GetTransition(i, a[j], acToReturn) == -1 { + CreateTransition(i, a[j], i, acToReturn) } } for current := 1; current < len(stateIsTerminal); current++ { for j := range a { - if getTransition(current, a[j], acToReturn) == -1 { - createTransition(current, a[j], getTransition(s[current], a[j], acToReturn), acToReturn) + if GetTransition(current, a[j], acToReturn) == -1 { + CreateTransition(current, a[j], GetTransition(s[current], a[j], acToReturn), acToReturn) } } } return acToReturn, f } -// Function that constructs Trie as an automaton for a set of reversed & trimmed strings. -func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { +// ConstructTrie Function that constructs Trie as an automaton for a set of reversed & trimmed strings. +func ConstructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { trie = make(map[int]map[uint8]int) stateIsTerminal = make([]bool, 1) f = make(map[int][]int) state := 1 - if debugMode == true { - fmt.Printf("\n\nTrie construction: \n") - } - createNewState(0, trie) + // if debugMode == true { + // fmt.Printf("\n\nTrie construction: \n") + // } + CreateNewState(0, trie) for i := 0; i < len(p); i++ { current := 0 j := 0 - for j < len(p[i]) && getTransition(current, p[i][j], trie) != -1 { - current = getTransition(current, p[i][j], trie) + for j < len(p[i]) && GetTransition(current, p[i][j], trie) != -1 { + current = GetTransition(current, p[i][j], trie) j++ } for j < len(p[i]) { - stateIsTerminal = boolArrayCapUp(stateIsTerminal) - createNewState(state, trie) + stateIsTerminal = BoolArrayCapUp(stateIsTerminal) + CreateNewState(state, trie) stateIsTerminal[state] = false - createTransition(current, p[i][j], state, trie) + CreateTransition(current, p[i][j], state, trie) current = state j++ state++ } if stateIsTerminal[current] { - newArray := intArrayCapUp(f[current]) + newArray := IntArrayCapUp(f[current]) newArray[len(newArray)-1] = i f[current] = newArray // F(Current) <- F(Current) union {i} - if debugMode == true { - fmt.Printf(" and %d", i) - } + // if debugMode == true { + // fmt.Printf(" and %d", i) + // } } else { stateIsTerminal[current] = true f[current] = []int{i} // F(Current) <- {i} - if debugMode == true { - fmt.Printf("\n%d is terminal for word number %d", current, i) - } + // if debugMode == true { + // fmt.Printf("\n%d is terminal for word number %d", current, i) + // } } } return trie, stateIsTerminal, f } -// Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. -func contains(s []int, e int) bool { +// Contains Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. +func Contains(s []int, e int) bool { for _, a := range s { if a == e { return true @@ -220,8 +218,8 @@ func contains(s []int, e int) bool { return false } -// Function that returns word found in text 't' at position range 'begin' to 'end'. -func getWord(begin, end int, t string) string { +// GetWord Function that returns word found in text 't' at position range 'begin' to 'end'. +func GetWord(begin, end int, t string) string { for end >= len(t) { return "" } @@ -232,8 +230,8 @@ func getWord(begin, end int, t string) string { return string(d) } -// Function that returns string of all the possible characters in given patterns. -func computeAlphabet(p []string) (s string) { +// ComputeAlphabet Function that returns string of all the possible characters in given patterns. +func ComputeAlphabet(p []string) (s string) { s = p[0] for i := 1; i < len(p); i++ { s = s + p[i] @@ -241,37 +239,37 @@ func computeAlphabet(p []string) (s string) { return s } -// Dynamically increases an array size of int's by 1. -func intArrayCapUp(old []int) (new []int) { +// IntArrayCapUp Dynamically increases an array size of int's by 1. +func IntArrayCapUp(old []int) (new []int) { new = make([]int, cap(old)+1) copy(new, old) //copy(dst,src) - old = new + // old = new return new } -// Dynamically increases an array size of bool's by 1. -func boolArrayCapUp(old []bool) (new []bool) { +// BoolArrayCapUp Dynamically increases an array size of bool's by 1. +func BoolArrayCapUp(old []bool) (new []bool) { new = make([]bool, cap(old)+1) copy(new, old) - old = new + // old = new return new } -// Concats two arrays of int's into one. -func arrayUnion(to, from []int) (concat []int) { +// ArrayUnion Concats two arrays of int's into one. +func ArrayUnion(to, from []int) (concat []int) { concat = to for i := range from { - if !contains(concat, from[i]) { - concat = intArrayCapUp(concat) + if !Contains(concat, from[i]) { + concat = IntArrayCapUp(concat) concat[len(concat)-1] = from[i] } } return concat } -// Function that finds the first previous state of a state and returns it. +// GetParent Function that finds the first previous state of a state and returns it. // Used for trie where there is only one parent. -func getParent(state int, at map[int]map[uint8]int) (uint8, int) { +func GetParent(state int, at map[int]map[uint8]int) (uint8, int) { for beginState, transitions := range at { for c, endState := range transitions { if endState == state { @@ -282,36 +280,36 @@ func getParent(state int, at map[int]map[uint8]int) (uint8, int) { return 0, 0 //unreachable } -// Automaton function for creating a new state 'state'. -func createNewState(state int, at map[int]map[uint8]int) { +// CreateNewState Automaton function for creating a new state 'state'. +func CreateNewState(state int, at map[int]map[uint8]int) { at[state] = make(map[uint8]int) - if debugMode == true { - fmt.Printf("\ncreated state %d", state) - } + // if debugMode == true { + // fmt.Printf("\ncreated state %d", state) + // } } -// Creates a transition for function σ(state,letter) = end. -func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { +// CreateTransition Creates a transition for function σ(state,letter) = end. +func CreateTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { at[fromState][overChar] = toState - if debugMode == true { - fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - } + // if debugMode == true { + // fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) + // } } -// Returns ending state for transition σ(fromState,overChar), '-1' if there is none. -func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { - if !stateExists(fromState, at) { +// GetTransition Returns ending state for transition σ(fromState,overChar), '-1' if there is none. +func GetTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { + if !StateExists(fromState, at) { return -1 } toState, ok := at[fromState][overChar] - if ok == false { + if !ok { return -1 } return toState } -// Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. -func stateExists(state int, at map[int]map[uint8]int) bool { +// StateExists Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. +func StateExists(state int, at map[int]map[uint8]int) bool { _, ok := at[state] if !ok || state == -1 || at[state] == nil { return false diff --git a/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go b/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go index d05047231..a7861858b 100644 --- a/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go +++ b/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go @@ -3,6 +3,7 @@ package advancedahocorasick import ( "fmt" "reflect" + "strings" "testing" ) @@ -10,14 +11,14 @@ var testCases = []struct { name string words []string text string - expected result + expected Result }{ { "String comparison on all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conferenceannounce_announce_annually_announce", - result{ + Result{ map[string][]int{ "annual": {4, 39}, "announce": {21, 30, 48}, @@ -29,7 +30,7 @@ var testCases = []struct { "String comparison on not all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conference_announce", - result{ + Result{ map[string][]int{ "annual": {4}, "announce": {22}, @@ -40,7 +41,7 @@ var testCases = []struct { "String comparison on not all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conference_announce", - result{ + Result{ map[string][]int{ "annual": {4}, "announce": {22}, @@ -52,7 +53,7 @@ var testCases = []struct { func TestAhoCorasick(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := ahoCorasick(tc.text, tc.words) + actual := AhoCorasick(tc.text, tc.words) if !reflect.DeepEqual(actual, tc.expected) { actualString := convertToString(actual) expectedString := convertToString(tc.expected) @@ -63,17 +64,20 @@ func TestAhoCorasick(t *testing.T) { } } -func convertToString(res result) string { - var r string +func convertToString(res Result) string { + // var r string + var r strings.Builder for key, val := range res.occurrences { - r = r + fmt.Sprintf("Word: '%s' at positions: ", key) + r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) for i := range val { - r = r + fmt.Sprintf("%d", val[i]) + r.WriteString(fmt.Sprintf("%d", val[i])) if i != len(val)-1 { - r = r + fmt.Sprintf(", ") + // r = r + fmt.Sprintf(", ") + r.WriteString(", ") } } - r = r + fmt.Sprintf(". ") + // r = r + fmt.Sprintf(". ") + r.WriteString(". ") } - return r + return r.String() } diff --git a/strings/multiple-string-matching/aho-corasick/ac.go b/strings/multiple-string-matching/aho-corasick/ac.go index 2e68c7ac3..d6abb0922 100644 --- a/strings/multiple-string-matching/aho-corasick/ac.go +++ b/strings/multiple-string-matching/aho-corasick/ac.go @@ -2,75 +2,72 @@ package ahocorasick import ( "fmt" - "io/ioutil" - "log" - "strings" "time" ) // User defined. // Set to true to print various extra stuff out (slows down the execution) // Set to false for quick and quiet execution. -const debugMode bool = true +// const debugMode bool = true -type result struct { +type Result struct { occurrences map[string][]int } // Implementation of Basic Aho-Corasick algorithm (Prefix based). // Searches for a set of strings (patterns.txt) in text.txt. -func main() { - patFile, err := ioutil.ReadFile("../patterns.txt") - if err != nil { - log.Fatal(err) - } - textFile, err := ioutil.ReadFile("../text.txt") - if err != nil { - log.Fatal(err) - } - patterns := strings.Split(string(patFile), " ") - fmt.Printf("\nRunning: Basic Aho-Corasick algorithm.\n\n") - if debugMode == true { - fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) - } - for i := 0; i < len(patterns); i++ { - if len(patterns[i]) > len(textFile) { - log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) - } - if debugMode == true { - fmt.Printf("%q ", patterns[i]) - } - } - if debugMode == true { - fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) - } - r := ahoCorasick(string(textFile), patterns) - for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) - fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) - for i := range value { - fmt.Printf("%d", value[i]) - if i != len(value)-1 { - fmt.Printf(", ") - } - } - fmt.Printf(".") - } -} +// func main() { +// patFile, err := ioutil.ReadFile("../patterns.txt") +// if err != nil { +// log.Fatal(err) +// } +// textFile, err := ioutil.ReadFile("../text.txt") +// if err != nil { +// log.Fatal(err) +// } +// patterns := strings.Split(string(patFile), " ") +// fmt.Printf("\nRunning: Basic Aho-Corasick algorithm.\n\n") +// if debugMode == true { +// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) +// } +// for i := 0; i < len(patterns); i++ { +// if len(patterns[i]) > len(textFile) { +// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) +// } +// if debugMode == true { +// fmt.Printf("%q ", patterns[i]) +// } +// } +// if debugMode == true { +// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) +// } +// r := ahoCorasick(string(textFile), patterns) +// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) +// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) +// for i := range value { +// fmt.Printf("%d", value[i]) +// if i != len(value)-1 { +// fmt.Printf(", ") +// } +// } +// fmt.Printf(".") +// } +// } -// Function performing the Basic Aho-Corasick algorithm. +// AhoCorasick Function performing the Basic Aho-Corasick algorithm. // Finds and prints occurrences of each pattern. -func ahoCorasick(t string, p []string) result { +func AhoCorasick(t string, p []string) Result { startTime := time.Now() occurrences := make(map[int][]int) ac, f, s := buildAc(p) - if debugMode == true { - fmt.Printf("\n\nAC:\n\n") - } + // if debugMode == true { + // fmt.Printf("\n\nAC:\n\n") + // } current := 0 for pos := 0; pos < len(t); pos++ { - if debugMode == true { - fmt.Printf("Position: %d, we read: %c", pos, t[pos]) - } + // if debugMode == true { + // fmt.Printf("Position: %d, we read: %c", pos, t[pos]) + // } for getTransition(current, t[pos], ac) == -1 && s[current] != -1 { current = s[current] } @@ -79,17 +76,17 @@ func ahoCorasick(t string, p []string) result { fmt.Printf(" (Continue) \n") } else { current = 0 - if debugMode == true { - fmt.Printf(" (FAIL) \n") - } + // if debugMode == true { + // fmt.Printf(" (FAIL) \n") + // } } _, ok := f[current] if ok { for i := range f[current] { if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match - if debugMode == true { - fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) - } + // if debugMode == true { + // fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) + // } newOccurrences := intArrayCapUp(occurrences[f[current][i]]) occurrences[f[current][i]] = newOccurrences occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 @@ -104,7 +101,7 @@ func ahoCorasick(t string, p []string) result { resultOccurrences[p[key]] = value } - return result{ + return Result{ resultOccurrences, } } @@ -116,9 +113,9 @@ func buildAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int, s [ i := 0 //root of acTrie acToReturn = acTrie s[i] = -1 - if debugMode == true { - fmt.Printf("\n\nAC construction: \n") - } + // if debugMode == true { + // fmt.Printf("\n\nAC construction: \n") + // } for current := 1; current < len(stateIsTerminal); current++ { o, parent := getParent(current, acTrie) down := s[parent] @@ -127,33 +124,33 @@ func buildAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int, s [ } if stateExists(down, acToReturn) { s[current] = getTransition(down, o, acToReturn) - if stateIsTerminal[s[current]] == true { + if stateIsTerminal[s[current]] { stateIsTerminal[current] = true f[current] = arrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) - if debugMode == true { - fmt.Printf(" f[%d] set to: ", current) - for i := range f[current] { - fmt.Printf("%d\n", f[current][i]) - } - } + // if debugMode == true { + // fmt.Printf(" f[%d] set to: ", current) + // for i := range f[current] { + // fmt.Printf("%d\n", f[current][i]) + // } + // } } } else { s[current] = i //initial state? } } - if debugMode == true { - fmt.Printf("\nsupply function: \n") - for i := range s { - fmt.Printf("\ns[%d]=%d", i, s[i]) - } - fmt.Printf("\n\n") - for i, j := range f { - fmt.Printf("f[%d]=", i) - for k := range j { - fmt.Printf("%d\n", j[k]) - } - } - } + // if debugMode == true { + // fmt.Printf("\nsupply function: \n") + // for i := range s { + // fmt.Printf("\ns[%d]=%d", i, s[i]) + // } + // fmt.Printf("\n\n") + // for i, j := range f { + // fmt.Printf("f[%d]=", i) + // for k := range j { + // fmt.Printf("%d\n", j[k]) + // } + // } + // } return acToReturn, f, s } @@ -163,9 +160,9 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo stateIsTerminal = make([]bool, 1) f = make(map[int][]int) state := 1 - if debugMode == true { - fmt.Printf("\n\nTrie construction: \n") - } + // if debugMode == true { + // fmt.Printf("\n\nTrie construction: \n") + // } createNewState(0, trie) for i := 0; i < len(p); i++ { current := 0 @@ -187,15 +184,15 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo newArray := intArrayCapUp(f[current]) newArray[len(newArray)-1] = i f[current] = newArray //F(Current) <- F(Current) union {i} - if debugMode == true { - fmt.Printf(" and %d", i) - } + // if debugMode == true { + // fmt.Printf(" and %d", i) + // } } else { stateIsTerminal[current] = true f[current] = []int{i} //F(Current) <- {i} - if debugMode == true { - fmt.Printf("\n%d is terminal for word number %d", current, i) - } + // if debugMode == true { + // fmt.Printf("\n%d is terminal for word number %d", current, i) + // } } } return trie, stateIsTerminal, f @@ -231,7 +228,7 @@ func getWord(begin, end int, t string) string { func intArrayCapUp(old []int) (new []int) { new = make([]int, cap(old)+1) copy(new, old) //copy(dst,src) - old = new + // old = new return new } @@ -239,7 +236,7 @@ func intArrayCapUp(old []int) (new []int) { func boolArrayCapUp(old []bool) (new []bool) { new = make([]bool, cap(old)+1) copy(new, old) - old = new + // old = new return new } @@ -271,17 +268,17 @@ func getParent(state int, at map[int]map[uint8]int) (uint8, int) { // Automaton function for creating a new state 'state'. func createNewState(state int, at map[int]map[uint8]int) { at[state] = make(map[uint8]int) - if debugMode == true { - fmt.Printf("\ncreated state %d", state) - } + // if debugMode == true { + // fmt.Printf("\ncreated state %d", state) + // } } // Creates a transition for function σ(state,letter) = end. func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { at[fromState][overChar] = toState - if debugMode == true { - fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - } + // if debugMode == true { + // fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) + // } } // Returns ending state for transition σ(fromState,overChar), '-1' if there is none. @@ -290,7 +287,7 @@ func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toS return -1 } toState, ok := at[fromState][overChar] - if ok == false { + if !ok { return -1 } return toState diff --git a/strings/multiple-string-matching/aho-corasick/ac_test.go b/strings/multiple-string-matching/aho-corasick/ac_test.go index d6638b77c..2f3241702 100644 --- a/strings/multiple-string-matching/aho-corasick/ac_test.go +++ b/strings/multiple-string-matching/aho-corasick/ac_test.go @@ -3,6 +3,7 @@ package ahocorasick import ( "fmt" "reflect" + "strings" "testing" ) @@ -10,17 +11,17 @@ var testCases = []struct { name string words []string text string - expected result + expected Result }{ { "String comparison on all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conferenceannounce_announce_annually_announce", - result{ + Result{ map[string][]int{ "annual": {4, 39}, - "announce": {21,30,48}, + "announce": {21, 30, 48}, "annually": {39}, }, }, @@ -29,7 +30,7 @@ var testCases = []struct { "String comparison on not all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conference_announce", - result{ + Result{ map[string][]int{ "annual": {4}, "announce": {22}, @@ -40,7 +41,7 @@ var testCases = []struct { "String comparison on not all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conference_announce", - result{ + Result{ map[string][]int{ "annual": {4}, "announce": {22}, @@ -52,7 +53,7 @@ var testCases = []struct { func TestAhoCorasick(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := ahoCorasick(tc.text, tc.words) + actual := AhoCorasick(tc.text, tc.words) if !reflect.DeepEqual(actual, tc.expected) { actualString := convertToString(actual) expectedString := convertToString(tc.expected) @@ -63,17 +64,17 @@ func TestAhoCorasick(t *testing.T) { } } -func convertToString(res result) string { - var r string +func convertToString(res Result) string { + var r strings.Builder for key, val := range res.occurrences { - r = r + fmt.Sprintf("Word: '%s' at positions: ", key) + r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) for i := range val { - r = r + fmt.Sprintf("%d", val[i]) + r.WriteString(fmt.Sprintf("%d", val[i])) if i != len(val)-1 { - r = r + fmt.Sprintf(", ") + r.WriteString(", ") } } - r = r + fmt.Sprintf(". ") + r.WriteString(". ") } - return r + return r.String() } diff --git a/strings/multiple-string-matching/sbom/sbom.go b/strings/multiple-string-matching/sbom/sbom.go index b0cd2a7b4..022ec1577 100644 --- a/strings/multiple-string-matching/sbom/sbom.go +++ b/strings/multiple-string-matching/sbom/sbom.go @@ -2,8 +2,6 @@ package sbom import ( "fmt" - "io/ioutil" - "log" "strings" "time" ) @@ -13,74 +11,74 @@ import ( // Set to false for quick and quiet execution. const debugMode bool = true -type result struct { +type Result struct { occurrences map[string][]int } // Implementation of Set Backward Oracle Matching algorithm (Factor based). // Searches for a set of strings (in 'patterns.txt') in text.txt. -func main() { - patFile, err := ioutil.ReadFile("../patterns.txt") - if err != nil { - log.Fatal(err) - } - textFile, err := ioutil.ReadFile("../text.txt") - if err != nil { - log.Fatal(err) - } - patterns := strings.Split(string(patFile), " ") - fmt.Printf("\nRunning: Set Backward Oracle Matching algorithm.\n\n") - if debugMode == true { - fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) - } - for i := 0; i < len(patterns); i++ { - if len(patterns[i]) > len(textFile) { - log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) - } - if debugMode == true { - fmt.Printf("%q ", patterns[i]) - } - } - if debugMode == true { - fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) - } - r := sbom(string(textFile), patterns) - for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) - fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) - for i := range value { - fmt.Printf("%d", value[i]) - if i != len(value)-1 { - fmt.Printf(", ") - } - } - fmt.Printf(".") - } +// func main() { +// patFile, err := ioutil.ReadFile("../patterns.txt") +// if err != nil { +// log.Fatal(err) +// } +// textFile, err := ioutil.ReadFile("../text.txt") +// if err != nil { +// log.Fatal(err) +// } +// patterns := strings.Split(string(patFile), " ") +// fmt.Printf("\nRunning: Set Backward Oracle Matching algorithm.\n\n") +// if debugMode { +// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) +// } +// for i := 0; i < len(patterns); i++ { +// if len(patterns[i]) > len(textFile) { +// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) +// } +// if debugMode { +// fmt.Printf("%q ", patterns[i]) +// } +// } +// if debugMode { +// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) +// } +// r := sbom(string(textFile), patterns) +// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) +// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) +// for i := range value { +// fmt.Printf("%d", value[i]) +// if i != len(value)-1 { +// fmt.Printf(", ") +// } +// } +// fmt.Printf(".") +// } -} +// } -// Function sbom performing the Set Backward Oracle Matching algorithm. +// Sbom Function sbom performing the Set Backward Oracle Matching algorithm. // Finds and prints occurrences of each pattern. -func sbom(t string, p []string) result { +func Sbom(t string, p []string) Result { startTime := time.Now() occurrences := make(map[int][]int) lmin := computeMinLength(p) or, f := buildOracleMultiple(reverseAll(trimToLength(p, lmin))) - if debugMode == true { + if debugMode { fmt.Printf("\n\nSBOM:\n\n") } pos := 0 for pos <= len(t)-lmin { current := 0 j := lmin - if debugMode == true { + if debugMode { fmt.Printf("Position: %d, we read: ", pos) } for j >= 1 && stateExists(current, or) { - if debugMode == true { + if debugMode { fmt.Printf("%c", t[pos+j-1]) } current = getTransition(current, t[pos+j-1], or) - if debugMode == true { + if debugMode { if current == -1 { fmt.Printf(" (FAIL) ") } else { @@ -89,14 +87,14 @@ func sbom(t string, p []string) result { } j-- } - if debugMode == true { + if debugMode { fmt.Printf("in the factor oracle. \n") } word := getWord(pos, pos+lmin-1, t) if stateExists(current, or) && j == 0 && strings.HasPrefix(word, getCommonPrefix(p, f[current], lmin)) { //check for prefix match for i := range f[current] { if p[f[current][i]] == getWord(pos, pos-1+len(p[f[current][i]]), t) { //check for word match - if debugMode == true { + if debugMode { fmt.Printf("- Occurence, %q = %q\n", p[f[current][i]], word) } newOccurences := intArrayCapUp(occurrences[f[current][i]]) @@ -115,7 +113,7 @@ func sbom(t string, p []string) result { resultOccurrences[p[key]] = value } - return result{ + return Result{ resultOccurrences, } } @@ -127,7 +125,7 @@ func buildOracleMultiple(p []string) (orToReturn map[int]map[uint8]int, f map[in i := 0 //root of trie orToReturn = orTrie s[i] = -1 - if debugMode == true { + if debugMode { fmt.Printf("\n\nOracle construction: \n") } for current := 1; current < len(stateIsTerminal); current++ { @@ -152,7 +150,7 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo stateIsTerminal = make([]bool, 1) f = make(map[int][]int) state := 1 - if debugMode == true { + if debugMode { fmt.Printf("\n\nTrie construction: \n") } createNewState(0, trie) @@ -176,13 +174,13 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo newArray := intArrayCapUp(f[current]) newArray[len(newArray)-1] = i f[current] = newArray //F(Current) <- F(Current) union {i} - if debugMode == true { + if debugMode { fmt.Printf(" and %d", i) } } else { stateIsTerminal[current] = true f[current] = []int{i} //F(Current) <- {i} - if debugMode == true { + if debugMode { fmt.Printf("\n%d is terminal for word number %d", current, i) } } @@ -194,7 +192,7 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo func intArrayCapUp(old []int) (new []int) { new = make([]int, cap(old)+1) copy(new, old) //copy(dst,src) - old = new + // old = new return new } @@ -202,7 +200,7 @@ func intArrayCapUp(old []int) (new []int) { func boolArrayCapUp(old []bool) (new []bool) { new = make([]bool, cap(old)+1) copy(new, old) - old = new + // old = new return new } @@ -292,7 +290,7 @@ func getParent(state int, at map[int]map[uint8]int) (uint8, int) { // Automaton function for creating a new state 'state'. func createNewState(state int, at map[int]map[uint8]int) { at[state] = make(map[uint8]int) - if debugMode == true { + if debugMode { fmt.Printf("\ncreated state %d", state) } } @@ -300,7 +298,7 @@ func createNewState(state int, at map[int]map[uint8]int) { // Creates a transition for function σ(state,letter) = end. func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { at[fromState][overChar] = toState - if debugMode == true { + if debugMode { fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) } } @@ -311,7 +309,7 @@ func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toS return -1 } toState, ok := at[fromState][overChar] - if ok == false { + if ok { return -1 } return toState diff --git a/strings/multiple-string-matching/sbom/sbom_test.go b/strings/multiple-string-matching/sbom/sbom_test.go index aa9d1e140..786c1c16a 100644 --- a/strings/multiple-string-matching/sbom/sbom_test.go +++ b/strings/multiple-string-matching/sbom/sbom_test.go @@ -3,6 +3,7 @@ package sbom import ( "fmt" "reflect" + "strings" "testing" ) @@ -10,14 +11,14 @@ var testCases = []struct { name string words []string text string - expected result + expected Result }{ { "String comparison on all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conferenceannounce_announce_annually_announce", - result{ + Result{ map[string][]int{ "annual": {4, 39}, "announce": {21, 30, 48}, @@ -29,7 +30,7 @@ var testCases = []struct { "String comparison on not all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conference_announce", - result{ + Result{ map[string][]int{ "annual": {4}, "announce": {22}, @@ -40,7 +41,7 @@ var testCases = []struct { "String comparison on not all patterns found", []string{"announce", "annual", "annually"}, "CPM_annual_conference_announce", - result{ + Result{ map[string][]int{ "annual": {4}, "announce": {22}, @@ -52,7 +53,7 @@ var testCases = []struct { func TestAhoCorasick(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := sbom(tc.text, tc.words) + actual := Sbom(tc.text, tc.words) if !reflect.DeepEqual(actual, tc.expected) { actualString := convertToString(actual) expectedString := convertToString(tc.expected) @@ -63,17 +64,22 @@ func TestAhoCorasick(t *testing.T) { } } -func convertToString(res result) string { - var r string +func convertToString(res Result) string { + // var r string + var r strings.Builder for key, val := range res.occurrences { - r = r + fmt.Sprintf("Word: '%s' at positions: ", key) + // r = r + fmt.Sprintf("Word: '%s' at positions: ", key) + r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) for i := range val { - r = r + fmt.Sprintf("%d", val[i]) + // r = r + fmt.Sprintf("%d", val[i]) + r.WriteString(fmt.Sprintf("%d", val[i])) if i != len(val)-1 { - r = r + fmt.Sprintf(", ") + // r = r + fmt.Sprintf(", ") + r.WriteString(", ") } } - r = r + fmt.Sprintf(". ") + // r = r + fmt.Sprintf(". ") + r.WriteString(". ") } - return r + return r.String() } diff --git a/strings/single-string-matching/bom.go b/strings/single-string-matching/bom.go deleted file mode 100644 index 46d1f8359..000000000 --- a/strings/single-string-matching/bom.go +++ /dev/null @@ -1,236 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "time" -) - -// User defined. -// Set to true to print various extra stuff out (slows down the execution) -// Set to false for quick and quiet execution. -const debugMode bool = false - -// User defined. -// Set to true to read input from two command line arguments -// Set to false to read input from two files "pattern.txt" and "text.txt" -const commandLineInput bool = false - -// Implementation of Backward Oracle Matching algorithm (Factor based approach). -// Requires either a two command line arguments separated by a single space, -// or two files in the same folder: "pattern.txt" containing the string to -// be searched for, "text.txt" containing the text to be searched in. -func main() { - if commandLineInput == true { // case of command line input - args := os.Args - if len(args) <= 2 { - log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") - } - pattern := args[1] - s := args[2] - for i := 3; i < len(args); i++ { - s = s + " " + args[i] - } - if len(args[1]) > len(s) { - log.Fatal("Pattern is longer than text!") - } - if debugMode == true { - fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") - fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) - fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) - } else { - fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") - } - bom(s, pattern) - } else if commandLineInput == false { // case of file line input - patFile, err := ioutil.ReadFile("pattern.txt") - if err != nil { - log.Fatal(err) - } - textFile, err := ioutil.ReadFile("text.txt") - if err != nil { - log.Fatal(err) - } - if len(patFile) > len(textFile) { - log.Fatal("Pattern is longer than text!") - } - if debugMode == true { - fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") - fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) - fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) - } else { - fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") - } - bom(string(textFile), string(patFile)) - } -} - -// Function bom performing the Backward Oracle Matching algorithm. -// Prints whether the word/pattern was found + positions of possible multiple occurrences -// or that the word was not found. -func bom(t, p string) { - startTime := time.Now() - n, m := len(t), len(p) - var current, j, pos int - oracle := oracleOnLine(reverse(p)) - occurences := make([]int, len(t)) - currentOcc := 0 - pos = 0 - if debugMode == true { - fmt.Printf("\n\nWe are reading backwards in %q, searching for %q\n\nat position %d:\n", t, p, pos+m-1) - } - for pos <= n-m { - current = 0 //initial state of the oracle - j = m - for j > 0 && stateExists(current, oracle) { - if debugMode == true { - prettyPrint(current, j, n, pos, t, oracle) - } - current = getTransition(current, t[pos+j-1], oracle) - j-- - } - if stateExists(current, oracle) { - if debugMode == true { - fmt.Printf(" We got an occurence!") - } - occurences[currentOcc] = pos - currentOcc++ - } - pos = pos + j + 1 - if pos+m-1 < len(t) { - if debugMode == true { - fmt.Printf("\n\nposition %d:\n", pos+m-1) - } - } - } - elapsed := time.Since(startTime) - fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - fmt.Printf("\n\n") - if currentOcc > 0 { - fmt.Printf("Word %q was found %d times at positions: ", p, currentOcc) - for k := 0; k < currentOcc-1; k++ { - fmt.Printf("%d, ", occurences[k]) - } - fmt.Printf("%d", occurences[currentOcc-1]) - fmt.Printf(".\n") - } - if currentOcc == 0 { - fmt.Printf("\nWord was not found.\n") - } - return -} - -// Construction of the factor oracle automaton for a word p. -func oracleOnLine(p string) (oracle map[int]map[uint8]int) { - if debugMode == true { - fmt.Printf("Oracle construction: \n") - } - oracle = make(map[int]map[uint8]int) - supply := make([]int, len(p)+2) // supply function - createNewState(0, oracle) - supply[0] = -1 - var orP string - for j := 0; j < len(p); j++ { - oracle, orP = oracleAddLetter(oracle, supply, orP, p[j]) - } - return oracle -} - -// Adds one letter to the oracle. -func oracleAddLetter(oracle map[int]map[uint8]int, supply []int, orP string, o uint8) (oracleToReturn map[int]map[uint8]int, orPToReturn string) { - m := len(orP) - var s int - createNewState(m+1, oracle) - createTransition(m, o, m+1, oracle) - k := supply[m] - for k > -1 && getTransition(k, o, oracle) == -1 { - createTransition(k, o, m+1, oracle) - k = supply[k] - } - if k == -1 { - s = 0 - } else { - s = getTransition(k, o, oracle) - } - supply[m+1] = s - return oracle, orP + string(o) -} - -// Function that takes a single string and reverses it. -// @author 'Walter' http://stackoverflow.com/a/10043083 -func reverse(s string) string { - l := len(s) - m := make([]rune, l) - for _, c := range s { - l-- - m[l] = c - } - return string(m) -} - -// Automaton function for creating a new state. -func createNewState(state int, at map[int]map[uint8]int) { - at[state] = make(map[uint8]int) - if debugMode == true { - fmt.Printf("\ncreated state %d", state) - } -} - -// Creates a transition for function σ(state,letter) = end. -func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { - at[fromState][overChar] = toState - if debugMode == true { - fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - } -} - -// Returns ending state for transition σ(fromState,overChar), -1 if there is none. -func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { - if !stateExists(fromState, at) { - return -1 - } - toState, ok := at[fromState][overChar] - if ok == false { - return -1 - } - return toState -} - -// Checks if state exists. Returns true if it does, false otherwise. -func stateExists(state int, at map[int]map[uint8]int) bool { - _, ok := at[state] - if !ok || state == -1 || at[state] == nil { - return false - } - return true -} - -// Just some printing of extra information about what the algorithm does. -func prettyPrint(current int, j int, n int, pos int, t string, oracle map[int]map[uint8]int) { - if current == 0 && !(getTransition(current, t[pos+j-1], oracle) == -1) { - fmt.Printf("\n -->(%d)---(%c)--->(%d)", current, t[pos+j-1], getTransition(current, t[pos+j-1], oracle)) - } else if getTransition(current, t[pos+j-1], oracle) == -1 && current != 0 { - fmt.Printf("\n (%d)---(%c) ", current, t[pos+j-1]) - } else if getTransition(current, t[pos+j-1], oracle) == -1 && current == 0 { - fmt.Printf("\n -->(%d)---(%c) ", current, t[pos+j-1]) - } else { - fmt.Printf("\n (%d)---(%c)--->(%d)", current, t[pos+j-1], getTransition(current, t[pos+j-1], oracle)) - } - fmt.Printf(" ") - for a := 0; a < pos+j-1; a++ { - fmt.Printf("%c", t[a]) - } - if getTransition(current, t[pos+j-1], oracle) == -1 { - fmt.Printf("[%c]", t[pos+j-1]) - } else { - fmt.Printf("[%c]", t[pos+j-1]) - } - for a := pos + j; a < n; a++ { - fmt.Printf("%c", t[a]) - } - if getTransition(current, t[pos+j-1], oracle) == -1 { - fmt.Printf(" FAIL on the character[%c]", t[pos+j-1]) - } -} diff --git a/strings/single-string-matching/bom/bom.go b/strings/single-string-matching/bom/bom.go new file mode 100644 index 000000000..2d0fd01f4 --- /dev/null +++ b/strings/single-string-matching/bom/bom.go @@ -0,0 +1,228 @@ +package bom + +// User defined. +// Set to true to print various extra stuff out (slows down the execution) +// Set to false for quick and quiet execution. +// const debugMode bool = false + +// User defined. +// Set to true to read input from two command line arguments +// Set to false to read input from two files "pattern.txt" and "text.txt" +// const commandLineInput bool = false + +// Implementation of Backward Oracle Matching algorithm (Factor based approach). +// Requires either a two command line arguments separated by a single space, +// or two files in the same folder: "pattern.txt" containing the string to +// be searched for, "text.txt" containing the text to be searched in. +// func main() { +// if commandLineInput == true { // case of command line input +// args := os.Args +// if len(args) <= 2 { +// log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") +// } +// pattern := args[1] +// s := args[2] +// for i := 3; i < len(args); i++ { +// s = s + " " + args[i] +// } +// if len(args[1]) > len(s) { +// log.Fatal("Pattern is longer than text!") +// } +// if debugMode == true { +// fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") +// fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) +// fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) +// } else { +// fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") +// } +// bom(s, pattern) +// } else if commandLineInput == false { // case of file line input +// patFile, err := ioutil.ReadFile("pattern.txt") +// if err != nil { +// log.Fatal(err) +// } +// textFile, err := ioutil.ReadFile("text.txt") +// if err != nil { +// log.Fatal(err) +// } +// if len(patFile) > len(textFile) { +// log.Fatal("Pattern is longer than text!") +// } +// if debugMode == true { +// fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") +// fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) +// fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) +// } else { +// fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") +// } +// bom(string(textFile), string(patFile)) +// } +// } + +// // Function bom performing the Backward Oracle Matching algorithm. +// // Prints whether the word/pattern was found + positions of possible multiple occurrences +// // or that the word was not found. +// func bom(t, p string) { +// startTime := time.Now() +// n, m := len(t), len(p) +// var current, j, pos int +// oracle := oracleOnLine(reverse(p)) +// occurences := make([]int, len(t)) +// currentOcc := 0 +// pos = 0 +// if debugMode == true { +// fmt.Printf("\n\nWe are reading backwards in %q, searching for %q\n\nat position %d:\n", t, p, pos+m-1) +// } +// for pos <= n-m { +// current = 0 //initial state of the oracle +// j = m +// for j > 0 && stateExists(current, oracle) { +// if debugMode == true { +// prettyPrint(current, j, n, pos, t, oracle) +// } +// current = getTransition(current, t[pos+j-1], oracle) +// j-- +// } +// if stateExists(current, oracle) { +// if debugMode == true { +// fmt.Printf(" We got an occurence!") +// } +// occurences[currentOcc] = pos +// currentOcc++ +// } +// pos = pos + j + 1 +// if pos+m-1 < len(t) { +// if debugMode == true { +// fmt.Printf("\n\nposition %d:\n", pos+m-1) +// } +// } +// } +// elapsed := time.Since(startTime) +// fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) +// fmt.Printf("\n\n") +// if currentOcc > 0 { +// fmt.Printf("Word %q was found %d times at positions: ", p, currentOcc) +// for k := 0; k < currentOcc-1; k++ { +// fmt.Printf("%d, ", occurences[k]) +// } +// fmt.Printf("%d", occurences[currentOcc-1]) +// fmt.Printf(".\n") +// } +// if currentOcc == 0 { +// fmt.Printf("\nWord was not found.\n") +// } +// return +// } + +// // Construction of the factor oracle automaton for a word p. +// func oracleOnLine(p string) (oracle map[int]map[uint8]int) { +// if debugMode == true { +// fmt.Printf("Oracle construction: \n") +// } +// oracle = make(map[int]map[uint8]int) +// supply := make([]int, len(p)+2) // supply function +// createNewState(0, oracle) +// supply[0] = -1 +// var orP string +// for j := 0; j < len(p); j++ { +// oracle, orP = oracleAddLetter(oracle, supply, orP, p[j]) +// } +// return oracle +// } + +// // Adds one letter to the oracle. +// func oracleAddLetter(oracle map[int]map[uint8]int, supply []int, orP string, o uint8) (oracleToReturn map[int]map[uint8]int, orPToReturn string) { +// m := len(orP) +// var s int +// createNewState(m+1, oracle) +// createTransition(m, o, m+1, oracle) +// k := supply[m] +// for k > -1 && getTransition(k, o, oracle) == -1 { +// createTransition(k, o, m+1, oracle) +// k = supply[k] +// } +// if k == -1 { +// s = 0 +// } else { +// s = getTransition(k, o, oracle) +// } +// supply[m+1] = s +// return oracle, orP + string(o) +// } + +// // Function that takes a single string and reverses it. +// // @author 'Walter' http://stackoverflow.com/a/10043083 +// func reverse(s string) string { +// l := len(s) +// m := make([]rune, l) +// for _, c := range s { +// l-- +// m[l] = c +// } +// return string(m) +// } + +// // Automaton function for creating a new state. +// func createNewState(state int, at map[int]map[uint8]int) { +// at[state] = make(map[uint8]int) +// if debugMode == true { +// fmt.Printf("\ncreated state %d", state) +// } +// } + +// // Creates a transition for function σ(state,letter) = end. +// func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { +// at[fromState][overChar] = toState +// if debugMode == true { +// fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) +// } +// } + +// // Returns ending state for transition σ(fromState,overChar), -1 if there is none. +// func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { +// if !stateExists(fromState, at) { +// return -1 +// } +// toState, ok := at[fromState][overChar] +// if ok == false { +// return -1 +// } +// return toState +// } + +// // Checks if state exists. Returns true if it does, false otherwise. +// func stateExists(state int, at map[int]map[uint8]int) bool { +// _, ok := at[state] +// if !ok || state == -1 || at[state] == nil { +// return false +// } +// return true +// } + +// // Just some printing of extra information about what the algorithm does. +// func prettyPrint(current int, j int, n int, pos int, t string, oracle map[int]map[uint8]int) { +// if current == 0 && !(getTransition(current, t[pos+j-1], oracle) == -1) { +// fmt.Printf("\n -->(%d)---(%c)--->(%d)", current, t[pos+j-1], getTransition(current, t[pos+j-1], oracle)) +// } else if getTransition(current, t[pos+j-1], oracle) == -1 && current != 0 { +// fmt.Printf("\n (%d)---(%c) ", current, t[pos+j-1]) +// } else if getTransition(current, t[pos+j-1], oracle) == -1 && current == 0 { +// fmt.Printf("\n -->(%d)---(%c) ", current, t[pos+j-1]) +// } else { +// fmt.Printf("\n (%d)---(%c)--->(%d)", current, t[pos+j-1], getTransition(current, t[pos+j-1], oracle)) +// } +// fmt.Printf(" ") +// for a := 0; a < pos+j-1; a++ { +// fmt.Printf("%c", t[a]) +// } +// if getTransition(current, t[pos+j-1], oracle) == -1 { +// fmt.Printf("[%c]", t[pos+j-1]) +// } else { +// fmt.Printf("[%c]", t[pos+j-1]) +// } +// for a := pos + j; a < n; a++ { +// fmt.Printf("%c", t[a]) +// } +// if getTransition(current, t[pos+j-1], oracle) == -1 { +// fmt.Printf(" FAIL on the character[%c]", t[pos+j-1]) +// } +// } diff --git a/strings/single-string-matching/horspool.go b/strings/single-string-matching/horspool.go deleted file mode 100644 index 7d659a5de..000000000 --- a/strings/single-string-matching/horspool.go +++ /dev/null @@ -1,102 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "log" - "os" -) - -// User defined. -// Set to true to read input from two command line arguments -// Set to false to read input from two files "pattern.txt" and "text.txt" -const commandLineInput bool = false - -// Implementation of Boyer-Moore-Horspool algorithm (Suffix based approach). -// Requires either a two command line arguments separated by a single space, -// or two files in the same folder: "pattern.txt" containing the string to -// be searched for, "text.txt" containing the text to be searched in. -func main() { - if commandLineInput == true { // case of command line input - args := os.Args - if len(args) <= 2 { - log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") - } - pattern := args[1] - s := args[2] - for i := 3; i < len(args); i++ { - s = s + " " + args[i] - } - if len(args[1]) > len(s) { - log.Fatal("Pattern is longer than text!") - } - fmt.Printf("\nRunning: Horspool algorithm.\n\n") - fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) - fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) - horspool(s, pattern) - } else if commandLineInput == false { // case of file line input - patFile, err := ioutil.ReadFile("pattern.txt") - if err != nil { - log.Fatal(err) - } - textFile, err := ioutil.ReadFile("text.txt") - if err != nil { - log.Fatal(err) - } - if len(patFile) > len(textFile) { - log.Fatal("Pattern is longer than text!") - } - fmt.Printf("\nRunning: Horspool algorithm.\n\n") - fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) - fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) - horspool(string(textFile), string(patFile)) - } -} - -// Function horspool performing the Horspool algorithm. -// Prints whether the word/pattern was found and on what position in the text or not. -func horspool(t, p string) { - m, n, c, pos := len(p), len(t), 0, 0 - //Perprocessing - d := preprocess(t, p) - //Map output - fmt.Printf("Precomputed shifts per symbol: ") - for key, value := range d { - fmt.Printf("%c:%d; ", key, value) - } - fmt.Println() - //Searching - for pos <= n-m { - j := m - if t[pos+j-1] != p[j-1] { - fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) - c++ - } - for j > 0 && t[pos+j-1] == p[j-1] { - fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) - c++ - fmt.Printf(" - match") - j-- - } - if j == 0 { - fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", p, pos, t, c) - return - } - pos = pos + d[t[pos+m]] - } - fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", c) - return -} - -// Function that pre-computes map with Key: uint8 (char) Value: int. -// Values determine safe shifting of search window. -func preprocess(t, p string) (d map[uint8]int) { - d = make(map[uint8]int) - for i := 0; i < len(t); i++ { - d[t[i]] = len(p) - } - for i := 0; i < len(p); i++ { - d[p[i]] = len(p) - i - } - return d -} diff --git a/strings/single-string-matching/horspool/horspool.go b/strings/single-string-matching/horspool/horspool.go new file mode 100644 index 000000000..f210f9187 --- /dev/null +++ b/strings/single-string-matching/horspool/horspool.go @@ -0,0 +1,95 @@ +package horspool + +// User defined. +// Set to true to read input from two command line arguments +// Set to false to read input from two files "pattern.txt" and "text.txt" +// const commandLineInput bool = false + +// Implementation of Boyer-Moore-Horspool algorithm (Suffix based approach). +// Requires either a two command line arguments separated by a single space, +// or two files in the same folder: "pattern.txt" containing the string to +// be searched for, "text.txt" containing the text to be searched in. +// func main() { +// if commandLineInput == true { // case of command line input +// args := os.Args +// if len(args) <= 2 { +// log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") +// } +// pattern := args[1] +// s := args[2] +// for i := 3; i < len(args); i++ { +// s = s + " " + args[i] +// } +// if len(args[1]) > len(s) { +// log.Fatal("Pattern is longer than text!") +// } +// fmt.Printf("\nRunning: Horspool algorithm.\n\n") +// fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) +// fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) +// horspool(s, pattern) +// } else if commandLineInput == false { // case of file line input +// patFile, err := ioutil.ReadFile("pattern.txt") +// if err != nil { +// log.Fatal(err) +// } +// textFile, err := ioutil.ReadFile("text.txt") +// if err != nil { +// log.Fatal(err) +// } +// if len(patFile) > len(textFile) { +// log.Fatal("Pattern is longer than text!") +// } +// fmt.Printf("\nRunning: Horspool algorithm.\n\n") +// fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) +// fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) +// horspool(string(textFile), string(patFile)) +// } +// } + +// // Function horspool performing the Horspool algorithm. +// // Prints whether the word/pattern was found and on what position in the text or not. +// func horspool(t, p string) { +// m, n, c, pos := len(p), len(t), 0, 0 +// //Perprocessing +// d := preprocess(t, p) +// //Map output +// fmt.Printf("Precomputed shifts per symbol: ") +// for key, value := range d { +// fmt.Printf("%c:%d; ", key, value) +// } +// fmt.Println() +// //Searching +// for pos <= n-m { +// j := m +// if t[pos+j-1] != p[j-1] { +// fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) +// c++ +// } +// for j > 0 && t[pos+j-1] == p[j-1] { +// fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) +// c++ +// fmt.Printf(" - match") +// j-- +// } +// if j == 0 { +// fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", p, pos, t, c) +// return +// } +// pos = pos + d[t[pos+m]] +// } +// fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", c) +// return +// } + +// // Function that pre-computes map with Key: uint8 (char) Value: int. +// // Values determine safe shifting of search window. +// func preprocess(t, p string) (d map[uint8]int) { +// d = make(map[uint8]int) +// for i := 0; i < len(t); i++ { +// d[t[i]] = len(p) +// } +// for i := 0; i < len(p); i++ { +// d[p[i]] = len(p) - i +// } +// return d +// } diff --git a/strings/single-string-matching/kmp/kmp.go b/strings/single-string-matching/kmp/kmp.go index 0ce14a8dc..425c52a51 100644 --- a/strings/single-string-matching/kmp/kmp.go +++ b/strings/single-string-matching/kmp/kmp.go @@ -2,18 +2,17 @@ package kmp import ( "fmt" - "io/ioutil" - "log" - "os" ) // User defined. // Set to true to read input from two command line arguments // Set to false to read input from two files "pattern.txt" and "text.txt" -const isTakingInputFromCommandLine bool = true + +// const isTakingInputFromCommandLine bool = true + const notFoundPosition int = -1 -type result struct { +type Result struct { resultPosition int numberOfComparison int } @@ -22,62 +21,62 @@ type result struct { // Requires either a two command line arguments separated by a single space, // or two files in the same folder: "pattern.txt" containing the string to // be searched for, "text.txt" containing the text to be searched in. -func main() { - var text string - var word string +// func main() { +// var text string +// var word string - if isTakingInputFromCommandLine { // case of command line input - args := os.Args - if len(args) <= 2 { - log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") - } - word = args[1] - text = args[2] - for i := 3; i < len(args); i++ { - text = text + " " + args[i] - } - } else { // case of file input - patFile, err := ioutil.ReadFile("../pattern.txt") - if err != nil { - log.Fatal(err) - } - textFile, err := ioutil.ReadFile("../text.txt") - if err != nil { - log.Fatal(err) - } - text = string(textFile) - word = string(patFile) - } +// if isTakingInputFromCommandLine { // case of command line input +// args := os.Args +// if len(args) <= 2 { +// log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") +// } +// word = args[1] +// text = args[2] +// for i := 3; i < len(args); i++ { +// text = text + " " + args[i] +// } +// } else { // case of file input +// patFile, err := ioutil.ReadFile("../pattern.txt") +// if err != nil { +// log.Fatal(err) +// } +// textFile, err := ioutil.ReadFile("../text.txt") +// if err != nil { +// log.Fatal(err) +// } +// text = string(textFile) +// word = string(patFile) +// } - if len(word) > len(text) { - log.Fatal("Pattern is longer than text!") - } - fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") - fmt.Printf("Search word (%d chars long): %q.\n", len(word), word) - fmt.Printf("Text (%d chars long): %q.\n\n", len(text), text) +// if len(word) > len(text) { +// log.Fatal("Pattern is longer than text!") +// } +// fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") +// fmt.Printf("Search word (%d chars long): %q.\n", len(word), word) +// fmt.Printf("Text (%d chars long): %q.\n\n", len(text), text) - r := kmp(text, word) - if r.resultPosition == notFoundPosition { - fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", r.numberOfComparison) - } else { - fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word, - r.resultPosition, text, r.numberOfComparison) - } -} +// r := kmp(text, word) +// if r.resultPosition == notFoundPosition { +// fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", r.numberOfComparison) +// } else { +// fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word, +// r.resultPosition, text, r.numberOfComparison) +// } +// } -// Function kmp performing the Knuth-Morris-Pratt algorithm. +// Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. // Prints whether the word/pattern was found and on what position in the text or not. // m - current match in text, i - current character in w, c - amount of comparisons. -func kmp(text string, word string) result { +func Kmp(text string, word string) Result { m, i, c := 0, 0, 0 - t := kmp_table(word) + t := kmpTable(word) for m+i < len(text) { fmt.Printf("\n comparing characters %c %c at positions %d %d", text[m+i], word[i], m+i, i) c++ if word[i] == text[m+i] { fmt.Printf(" - match") if i == len(word)-1 { - return result{ + return Result{ m, c, } } @@ -91,14 +90,14 @@ func kmp(text string, word string) result { } } } - return result{notFoundPosition, + return Result{notFoundPosition, c, } } // Table building alghoritm. // Takes word to be analyzed and table to be filled. -func kmp_table(word string) (t []int) { +func kmpTable(word string) (t []int) { t = make([]int, len(word)) pos, cnd := 2, 0 t[0], t[1] = -1, 0 diff --git a/strings/single-string-matching/kmp/kmp_test.go b/strings/single-string-matching/kmp/kmp_test.go index 6233053ac..f25c68a07 100644 --- a/strings/single-string-matching/kmp/kmp_test.go +++ b/strings/single-string-matching/kmp/kmp_test.go @@ -9,13 +9,13 @@ var testCases = []struct { name string word string text string - expected result + expected Result }{ { "String comparison on single pattern match", "announce", "CPM_annual_conference_announce", - result{ + Result{ 22, 32, }, @@ -24,7 +24,7 @@ var testCases = []struct { "String comparison on multiple pattern match", "AABA", "AABAACAADAABAABA", - result{ + Result{ 0, 4, }, @@ -33,7 +33,7 @@ var testCases = []struct { "String comparison with not found pattern", "AABC", "AABAACAADAABAABA", - result{ + Result{ -1, 23, }, @@ -43,7 +43,7 @@ var testCases = []struct { func TestKMP(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := kmp(tc.text, tc.word) + actual := Kmp(tc.text, tc.word) if !reflect.DeepEqual(actual, tc.expected) { t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v steps at position %v, but actual matches are: %v steps at position %v", tc.word, tc.text, tc.expected.numberOfComparison, tc.expected.resultPosition, actual.numberOfComparison, actual.resultPosition) From 4af3545a3a018f8935e191780a6c9d5e0a9fcc19 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 18 Feb 2021 11:49:22 +0100 Subject: [PATCH 162/488] Run golangci-lint on the entire codebase (#267) * DRAFT: Run golangci-lint on the entire codebase * shopt -s globstar && golangci-lint run --no-config **/*.go * || true * Upgrade to golangci-lint v2.4 * Upgrade golangci-lint to v1.37 * Remove all the clutter * golang_lint_and_test in a single GitHub Action * Delete golangci-lint.yml --- .github/workflows/golang_lint_and_test.yml | 17 +++++++++ .github/workflows/golangci-lint.yml | 40 ---------------------- .github/workflows/golangtests.yml | 13 ------- 3 files changed, 17 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/golang_lint_and_test.yml delete mode 100644 .github/workflows/golangci-lint.yml delete mode 100644 .github/workflows/golangtests.yml diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml new file mode 100644 index 000000000..b5171a5b0 --- /dev/null +++ b/.github/workflows/golang_lint_and_test.yml @@ -0,0 +1,17 @@ +# https://github.com/golangci/golangci-lint +name: golang_lint_and_test +on: [push, pull_request] +jobs: + golang_lint_and_test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + - run: go version + - uses: golangci/golangci-lint-action@v2 + with: + # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. + version: v1.37 + - run: go test $(go list ./... | grep -v /sbom | grep -v /rsa) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml deleted file mode 100644 index 27e280a89..000000000 --- a/.github/workflows/golangci-lint.yml +++ /dev/null @@ -1,40 +0,0 @@ -# https://github.com/golangci/golangci-lint -name: golangci-lint -on: [push, pull_request] -jobs: - golangci-lint: - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - - uses: golangci/golangci-lint-action@v2 - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.31 - args: --issues-exit-code=0 # Hopefully someday we can remove this... - working-directory: sorts # Hopefully someday we can remove this... and enable only-new-issues - # only-new-issues: true # Let's focus on this PR first - - run: echo "/home/runner/golangci-lint-1.31.0-linux-amd64" >> $GITHUB_PATH - - run: go version ; golangci-lint --version # Fix the following and remove || true - - run: golangci-lint run --no-config ciphers/... - # - run: golangci-lint run --no-config datastructures/binary-tree || true - # - run: golangci-lint run --no-config datastructures/dynamic-array || true - # - run: golangci-lint run --no-config datastructures/hashmap - # - run: golangci-lint run --no-config datastructures/linkedlist || true - # - run: golangci-lint run --no-config datastructures/trie || true - - run: golangci-lint run --no-config dynamicprogramming/... - - run: golangci-lint run --no-config other/... - - run: golangci-lint run --no-config searches/... - - run: golangci-lint run --no-config sorts/... - - run: golangci-lint run --no-config strings/... - # - run: golangci-lint run --no-config "strings/multiple-string-matching" || true - # - run: golangci-lint run --no-config "strings/single string matching" || true - # - run: golangci-lint run --no-config strings/levenshteindistance - # - run: golangci-lint run --no-config strings/naivesearch - - run: golangci-lint run --no-config math/... - # - run: golangci-lint run --no-config math/gcd - # - run: golangci-lint run --no-config math/power - # - run: golangci-lint run --no-config math/primecheck - # - run: golangci-lint run --no-config math/sieve || true diff --git a/.github/workflows/golangtests.yml b/.github/workflows/golangtests.yml deleted file mode 100644 index ed3341b96..000000000 --- a/.github/workflows/golangtests.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: golang-tests -on: [push, pull_request] -jobs: - golang-tests: - runs-on: ubuntu-latest - strategy: - fail-fast: false - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - - run: go version - - name: Tests - run: go test $(go list ./... | grep -v /sbom | grep -v /rsa) From c74c9b1d40964f596275c96168c284b8f730ec28 Mon Sep 17 00:00:00 2001 From: Taj Date: Thu, 18 Feb 2021 13:32:59 +0000 Subject: [PATCH 163/488] Fix: Tests work on the TheAlgorithms/Go repository (#273) * fix: the algorithm handle for go get command * fix: changed the required import from my repo (tjgurwara99/Go) to the algorithms repo (TheAlgorithms/Go) * fix: typo --- ciphers/rot13/rot13.go | 2 +- go.mod | 6 ++---- go.sum | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/ciphers/rot13/rot13.go b/ciphers/rot13/rot13.go index 1882c9201..83090129c 100644 --- a/ciphers/rot13/rot13.go +++ b/ciphers/rot13/rot13.go @@ -3,7 +3,7 @@ package rot13 import ( - "github.com/tjgurwara99/Go/ciphers/caesar" + "github.com/TheAlgorithms/Go/ciphers/caesar" ) // rot13 is a special case, which is fixed the shift of 13, of the Caesar cipher diff --git a/go.mod b/go.mod index 26f3cba15..d2d3ee496 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,3 @@ -module github.com/tjgurwara99/Go +module github.com/TheAlgorithms/Go -go 1.14 - -require github.com/douglasmakey/golang-algorithms- v0.0.0-20180429234644-0a5ef73a9fd5 +go 1.15 diff --git a/go.sum b/go.sum index 85237faa5..e69de29bb 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +0,0 @@ -github.com/douglasmakey/golang-algorithms- v0.0.0-20180429234644-0a5ef73a9fd5 h1:ae3ZNa8+Q3WVR6I/BdB+AatZrnZZpnyl6ZOWDmh96Jw= -github.com/douglasmakey/golang-algorithms- v0.0.0-20180429234644-0a5ef73a9fd5/go.mod h1:DUocdLj6AeO5RUfLT9JPVhanSEihgqlwSlIfcEloUqY= From 21381acd88723f6e39c337be5a9d0885b6bcd586 Mon Sep 17 00:00:00 2001 From: Taj Date: Mon, 22 Feb 2021 02:27:14 +0000 Subject: [PATCH 164/488] feat: Added a proper Modular Exponentiation algorithm (#275) * fix: the algorithm handle for go get command * fix: changed the required import from my repo (tjgurwara99/Go) to the algorithms repo (TheAlgorithms/Go) * fix: typo * feat: Global Modular Exponentiation for uses in other files * fix: updated comment * updating DIRECTORY.md * fix: changed the benchmarking for a proper test * fix: better error handling * fix: removed unused type struct Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 3 + .../modularexponentiation.go | 49 +++++++++++ .../modularexponentiation_test.go | 84 +++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 math/modulararithmetic/modularexponentiation.go create mode 100644 math/modulararithmetic/modularexponentiation_test.go diff --git a/DIRECTORY.md b/DIRECTORY.md index bcc55ce8d..56b1925d8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -69,6 +69,9 @@ * Gcd * [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go) * [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go) + * Modulararithmetic + * [Modularexponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation.go) + * [Modularexponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation_test.go) * Power * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent.go) * [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent_test.go) diff --git a/math/modulararithmetic/modularexponentiation.go b/math/modulararithmetic/modularexponentiation.go new file mode 100644 index 000000000..1480096b8 --- /dev/null +++ b/math/modulararithmetic/modularexponentiation.go @@ -0,0 +1,49 @@ +package modulararithmetic + +import ( + "errors" + "math" +) + +// ErrorIntOverflow For asserting that the values do not overflow in Int64 +var ErrorIntOverflow = errors.New("Integer Overflow") + +// ErrorNegativeExponent for asserting that the exponent we receive is positive +var ErrorNegativeExponent = errors.New("Negative Exponent Provided") + +// ModularExponentiation returns base^exponent % mod +func ModularExponentiation(base, exponent, mod int64) (int64, error) { + if mod == 1 { + return 0, nil + } + + if exponent < 0 { + return -1, ErrorNegativeExponent + } + _, err := Multiply64BitInt(mod-1, mod-1) + + if err != nil { + return -1, err + } + + var result int64 = 1 + + base = base % mod + + for exponent > 0 { + if exponent%2 == 1 { + result = (result * base) % mod + } + exponent = exponent >> 1 + base = (base * base) % mod + } + return result, nil +} + +// Multiply64BitInt Checking if the integer multiplication overflows +func Multiply64BitInt(left, right int64) (int64, error) { + if math.Abs(float64(left)) > float64(math.MaxInt64)/math.Abs(float64(right)) { + return 0, ErrorIntOverflow + } + return left * right, nil +} diff --git a/math/modulararithmetic/modularexponentiation_test.go b/math/modulararithmetic/modularexponentiation_test.go new file mode 100644 index 000000000..531e4045f --- /dev/null +++ b/math/modulararithmetic/modularexponentiation_test.go @@ -0,0 +1,84 @@ +package modulararithmetic + +import "testing" + +type cases struct { + name string + description string + base int64 + exponent int64 + mod int64 + expected int64 + expectedError error +} + +var testCases = []cases{ + { + name: "Test 1", + description: "Test 1: 3^6 % 3 == 0", + base: 3, + exponent: 6, + mod: 3, + expected: 0, + expectedError: nil, + }, + { + name: "Test 2", + description: "Test 2: 33^60 % 25 == 1", + base: 33, + exponent: 60, + mod: 25, + expected: 1, + expectedError: nil, + }, + { + name: "Test 3", + description: "Test 3: 17^60 % 23 == 2", + base: 17, + exponent: 60, + mod: 23, + expected: 2, + expectedError: nil, + }, + { + name: "Test 4", + description: "Test 4: 17^60 % 1 == 0", // handling result when we get mod = 1 + base: 17, + exponent: 60, + mod: 1, + expected: 0, + expectedError: nil, + }, + { + name: "Error test 1", + description: "Testing whether we receive the expected errors gracefully", + base: 50, + exponent: -1, + mod: 2, + expected: -1, + expectedError: ErrorNegativeExponent, + }, +} + +func TestModularExponentiation(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result, err := ModularExponentiation(test.base, test.exponent, test.mod) + if err != test.expectedError { + t.Logf("Test Failed for %s", test.name) + t.Logf("Unexpected error occured") + t.Errorf("Expected error: %v, Recieved error: %v", test.expectedError, err) + } + if result != test.expected { + t.Logf("Test Failed for %s", test.description) + t.Fatalf("Expected: %d, Recieved: %d", test.expected, result) + } + }) + } +} + +func BenchmarkModularExponentiation(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = ModularExponentiation(17, 60, 23) + } +} From 46af4158ad262c4c0360f60a52ab6d98f6644f43 Mon Sep 17 00:00:00 2001 From: Mertcan Davulcu <54983926+mertcandav@users.noreply.github.com> Date: Tue, 23 Feb 2021 21:14:20 +0300 Subject: [PATCH 165/488] Update fastexponent.go --- math/power/fastexponent.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/math/power/fastexponent.go b/math/power/fastexponent.go index 61e4660b4..c7626b045 100644 --- a/math/power/fastexponent.go +++ b/math/power/fastexponent.go @@ -4,13 +4,12 @@ package power func IterativePower(n uint, power uint) uint { var res uint = 1 for power > 0 { - if (power & 1) != 0 { res = res * n } power = power >> 1 - n = n * n + n *= n } return res } From 2887895628e8cd7b67430c7c256fff66f0920010 Mon Sep 17 00:00:00 2001 From: Pritam Singh <43764373+Zzocker@users.noreply.github.com> Date: Thu, 25 Feb 2021 16:26:00 +0530 Subject: [PATCH 166/488] resolving missing cipher test from issue #272 (#283) * resolving missing cipher test from issue #272 Signed-off-by: Zzocker * coorecting test file name Signed-off-by: Zzocker --- ciphers/diffieHellmanKeyExchange.go | 69 ------------------- .../diffieHellmanKeyExchange.go | 41 +++++++++++ .../diffieHellmanKeyExchange_test.go | 41 +++++++++++ 3 files changed, 82 insertions(+), 69 deletions(-) delete mode 100644 ciphers/diffieHellmanKeyExchange.go create mode 100644 ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go create mode 100644 ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go diff --git a/ciphers/diffieHellmanKeyExchange.go b/ciphers/diffieHellmanKeyExchange.go deleted file mode 100644 index 526604f81..000000000 --- a/ciphers/diffieHellmanKeyExchange.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - "fmt" - "math/rand" -) - -func main() { - bit := 30 - /* - p and g are pre-agreed constants - that can be communicated over an insecure channel - p should ideally be a large prime number but any integer works - g should be a small integer, 2,3 works fine - PS: Note that the secret keys are never send over - the network - */ - - p := 2 + rand.Intn(1< 0 { - if e%2 == 1 { - r = (r * b) % mod - } - e = e >> 1 - b = (b * b) % mod - } - return r -} diff --git a/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go b/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go new file mode 100644 index 000000000..11e8183d1 --- /dev/null +++ b/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go @@ -0,0 +1,41 @@ +// Package diffiehelkeyexchange implements Deffie Hellman Key Exchange Algorithm +// for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI +package diffiehelkeyexchange + +const ( + generator = 3 + primeNumber int64 = 6700417 // prime number discovered by Leonhard Euler +) + +// GenerateShareKey : generates a key using client private key , generator and primeNumber +// this key can be made public +// shareKey = (g^key)%primeNumber +func GenerateShareKey(prvKey int64) int64 { + return modularExponentiation(generator, prvKey, primeNumber) +} + +// GenerateMutualKey : generates a mutual key that can be used by only alice and bob +// mutualKey = (shareKey^prvKey)%primeNumber +func GenerateMutualKey(prvKey, shareKey int64) int64 { + return modularExponentiation(shareKey, prvKey, primeNumber) +} + +// r = (b^e)%mod +func modularExponentiation(b, e, mod int64) int64 { + + //runs in O(log(n)) where n = e + //uses exponentiation by squaring to speed up the process + if mod == 1 { + return 0 + } + var r int64 = 1 + b = b % mod + for e > 0 { + if e&1 == 1 { + r = (r * b) % mod + } + e = e >> 1 + b = (b * b) % mod + } + return r +} diff --git a/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go b/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go new file mode 100644 index 000000000..2b923920c --- /dev/null +++ b/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go @@ -0,0 +1,41 @@ +package diffiehelkeyexchange + +import ( + "crypto/rand" + "crypto/rsa" + "testing" +) + +func TestDiffieHellmanKeyExchange(t *testing.T) { + t.Run("Test 1: modularExponentiation", func(t *testing.T) { + var want int64 = 9 // (3^5)mod13 = 243mod13 = 9 + var prvKey int64 = 5 + var generator int64 = 3 + var primeNumber int64 = 13 + got := modularExponentiation(generator, prvKey, primeNumber) + if got != want { + t.Errorf(`with privateKey=%d, generator=%d and primeNumber=%d + modularExponentiation should result=%d, but resulted=%d`, prvKey, generator, primeNumber, want, got) + } + }) + + t.Run("Test 2: Key Exchange", func(t *testing.T) { + // generating a small sized rsa key for testing + alicePrvKey, _ := rsa.GenerateKey(rand.Reader, 31) + bobPrvKey, _ := rsa.GenerateKey(rand.Reader, 31) + + // alice and bob generates their respective share key with their privateKey + shareKeyByAlice := GenerateShareKey(alicePrvKey.D.Int64()) + shareKeyByBob := GenerateShareKey(bobPrvKey.D.Int64()) + + // generated share key now can be exchanged even via insecure channel + + // mutualKey can be computed using shared key + mutualKeyComputedByAlice := GenerateMutualKey(alicePrvKey.D.Int64(), shareKeyByBob) + mutualKeyComputedByBob := GenerateMutualKey(bobPrvKey.D.Int64(), shareKeyByAlice) + + if mutualKeyComputedByAlice != mutualKeyComputedByBob { + t.Errorf("mutual key computed by alice and bob should be same, but got un-equal") + } + }) +} From 04f4572ef969ee8ffa2f5447b10ae49b683ea70d Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 25 Feb 2021 10:56:15 +0000 Subject: [PATCH 167/488] updating DIRECTORY.md --- DIRECTORY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 56b1925d8..30a4bbe03 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,7 +3,9 @@ * Caesar * [Caesar Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_test.go) * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/CaesarCipher.go) - * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffieHellmanKeyExchange.go) + * Diffiehelkeyexchange + * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go) + * [Diffiehellmankeyexchange Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go) * Polybius * [Polybius](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius.go) * [Polybius Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius_test.go) From d5c5780e8cfbe952b73b08c648367aec40ccce73 Mon Sep 17 00:00:00 2001 From: Kaveh Fazaeli Date: Thu, 25 Feb 2021 19:39:48 +0330 Subject: [PATCH 168/488] Correct BFS algorithm and tests (#279) * Revise BFS algorithm implementation. * Test for BFS * Fix: Edit package name and structure Fix: Improve documenting * Fix: rename function and file name (Breadthfirstsearch -> BFS) * Fix: revert renaming function and file name (BFS -> BreadthFirstSearch) --- graphs/breathfirstsearch/breathfirstsearch.go | 73 ----------------- graphs/search/breadthFirstSearch.go | 33 ++++++++ graphs/search/breadthFirstSearch_test.go | 78 +++++++++++++++++++ 3 files changed, 111 insertions(+), 73 deletions(-) delete mode 100644 graphs/breathfirstsearch/breathfirstsearch.go create mode 100644 graphs/search/breadthFirstSearch.go create mode 100644 graphs/search/breadthFirstSearch_test.go diff --git a/graphs/breathfirstsearch/breathfirstsearch.go b/graphs/breathfirstsearch/breathfirstsearch.go deleted file mode 100644 index 8d10e0a99..000000000 --- a/graphs/breathfirstsearch/breathfirstsearch.go +++ /dev/null @@ -1,73 +0,0 @@ -package breathfirstsearch - -// GetIdx ... -func GetIdx(target int, nodes []int) int { - for i := 0; i < len(nodes); i++ { - if nodes[i] == target { - return i - } - } - return -1 -} - -// NotExist ... -func NotExist(target int, slice []int) bool { - for i := 0; i < len(slice); i++ { - if slice[i] == target { - return false - } - } - return true -} - -// BreadthFirstSearch The main algorithm for bread first search -func BreadthFirstSearch(start, end int, nodes []int, edges [][]bool) bool { - var route []int - var queue []int - startIdx := GetIdx(start, nodes) - queue = append(queue, startIdx) - for len(queue) > 0 { - now := queue[0] - route = append(route, nodes[now]) - if len(queue) > 1 { - queue = queue[1:] - } else { - queue = queue[0:] - } - for i := 0; i < len(edges[now]); i++ { - if edges[now][i] && NotExist(i, queue) { - queue = append(queue, i) - } - edges[now][i] = false - edges[i][now] = false - } - if route[len(route)-1] == end { - return true - } - } - return false -} - -// func main() { -// nodes := []int{ -// 1, 2, 3, 4, 5, 6, -// } -// /* -// sample graph -// ①-② -// | | -// ③-④-⑤-⑥ -// */ -// edges := [][]bool{ -// {false, true, true, false, false, false}, -// {true, false, false, true, false, false}, -// {true, false, false, true, false, false}, -// {false, true, true, false, true, false}, -// {false, false, false, true, false, true}, -// {false, false, false, false, true, false}, -// } -// start := 1 -// end := 6 -// result := breadthFirstSearch(start, end, nodes, edges) -// fmt.Println(result) -// } diff --git a/graphs/search/breadthFirstSearch.go b/graphs/search/breadthFirstSearch.go new file mode 100644 index 000000000..6781be597 --- /dev/null +++ b/graphs/search/breadthFirstSearch.go @@ -0,0 +1,33 @@ +// Package search Graph search algorithms +// reference: https://en.wikipedia.org/wiki/Tree_traversal +package search + +/*BreadthFirstSearch is an algorithm for traversing and searching graph data structures. + It starts at an arbitrary node of a graph, and explores all of the neighbor nodes + at the present depth prior to moving on to the nodes at the next depth level. + Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) + Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) +reference: https://en.wikipedia.org/wiki/Breadth-first_search +*/ +func BreadthFirstSearch(start, end, nodes int, edges [][]int) (isConnected bool, distance int) { + queue := make([]int, 0) + discovered := make([]int, nodes) + discovered[start] = 1 + queue = append(queue, start) + for len(queue) > 0 { + v := queue[0] + if len(queue) > 0 { + queue = queue[1:] + } + for i := 0; i < len(edges[v]); i++ { + if discovered[i] == 0 && edges[v][i] > 0 { + if i == end { + return true, discovered[v] + } + discovered[i] = discovered[v] + 1 + queue = append(queue, i) + } + } + } + return false, 0 +} diff --git a/graphs/search/breadthFirstSearch_test.go b/graphs/search/breadthFirstSearch_test.go new file mode 100644 index 000000000..d476c3bc1 --- /dev/null +++ b/graphs/search/breadthFirstSearch_test.go @@ -0,0 +1,78 @@ +package search + +import ( + "testing" +) + +func TestBreadthFirstSearch(t *testing.T) { + var bfsTestData = []struct { + description string + start int + end int + nodes int + edges [][]int + expected1 bool + expected2 int + }{ + { + "test 1 connected with distance 2", + 0, + 5, + 6, + [][]int{ + {0, 1, 1, 0, 0, 0}, + {1, 0, 0, 1, 0, 1}, + {1, 0, 0, 1, 0, 0}, + {0, 1, 1, 0, 1, 0}, + {0, 0, 0, 1, 0, 0}, + {0, 1, 0, 0, 0, 0}, + }, + true, + 2, + }, + { + "test 2 connected with distance 4", + 0, + 5, + 6, + [][]int{ + {0, 1, 1, 0, 0, 0}, + {1, 0, 0, 1, 0, 0}, + {1, 0, 0, 1, 0, 0}, + {0, 1, 1, 0, 1, 0}, + {0, 0, 0, 1, 0, 1}, + {0, 0, 0, 0, 1, 0}, + }, + true, + 4, + }, + { + "test 2 not connected", + 0, + 5, + 6, + [][]int{ + {0, 1, 1, 0, 0, 0}, + {1, 0, 0, 1, 0, 0}, + {1, 0, 0, 1, 0, 0}, + {0, 1, 1, 0, 1, 0}, + {0, 0, 0, 1, 0, 0}, + {0, 0, 0, 0, 0, 0}, + }, + false, + 0, + }, + } + for _, test := range bfsTestData { + t.Run(test.description, func(t *testing.T) { + r1, r2 := BreadthFirstSearch(test.start, test.end, + test.nodes, test.edges) + if r1 != test.expected1 || r2 != test.expected2 { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Nodes '%v' and Edges '%v' start from '%d' and end in '%d' "+ + "was expecting '%v' with distance '%d' but result was '%v','%d'", + test.nodes, test.edges, test.start, test.end, test.expected1, test.expected2, r1, r2) + } + }) + } +} From e0e5eaa5e5b20266862a583a8f294af96afff48c Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 25 Feb 2021 16:10:05 +0000 Subject: [PATCH 169/488] updating DIRECTORY.md --- DIRECTORY.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 30a4bbe03..5c803cae6 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -60,12 +60,13 @@ * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/rod-cutting.go) ## Graphs - * Breathfirstsearch - * [Breathfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/breathfirstsearch/breathfirstsearch.go) * Depthfirstsearch * [Depthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/depthfirstsearch/depthfirstsearch.go) * Floydwarshall * [Floydwarshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floydwarshall/floydwarshall.go) + * Search + * [Breadthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadthFirstSearch.go) + * [Breadthfirstsearch Test](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadthFirstSearch_test.go) ## Math * Gcd From 12da49702971d1fb46e384dceb709e6c4ce6d2a7 Mon Sep 17 00:00:00 2001 From: Mohamed Date: Sat, 27 Feb 2021 22:00:30 +0200 Subject: [PATCH 170/488] feat: added abstract factory to design patterns --- .../abstractfactory/abstractfactory_test.go | 52 +++++++++++++++++++ designpatterns/abstractfactory/adidas.go | 23 ++++++++ designpatterns/abstractfactory/adidasshirt.go | 6 +++ designpatterns/abstractfactory/adidasshoe.go | 6 +++ designpatterns/abstractfactory/ishirt.go | 31 +++++++++++ designpatterns/abstractfactory/ishoe.go | 30 +++++++++++ .../abstractfactory/isportsFactory.go | 21 ++++++++ designpatterns/abstractfactory/nike.go | 23 ++++++++ designpatterns/abstractfactory/nikeshirt.go | 6 +++ designpatterns/abstractfactory/nikeshoe.go | 7 +++ 10 files changed, 205 insertions(+) create mode 100644 designpatterns/abstractfactory/abstractfactory_test.go create mode 100644 designpatterns/abstractfactory/adidas.go create mode 100644 designpatterns/abstractfactory/adidasshirt.go create mode 100644 designpatterns/abstractfactory/adidasshoe.go create mode 100644 designpatterns/abstractfactory/ishirt.go create mode 100644 designpatterns/abstractfactory/ishoe.go create mode 100644 designpatterns/abstractfactory/isportsFactory.go create mode 100644 designpatterns/abstractfactory/nike.go create mode 100644 designpatterns/abstractfactory/nikeshirt.go create mode 100644 designpatterns/abstractfactory/nikeshoe.go diff --git a/designpatterns/abstractfactory/abstractfactory_test.go b/designpatterns/abstractfactory/abstractfactory_test.go new file mode 100644 index 000000000..7505be461 --- /dev/null +++ b/designpatterns/abstractfactory/abstractfactory_test.go @@ -0,0 +1,52 @@ +package abstractfactorry + +import ( + "reflect" + "testing" +) + +// test client code and how to use the factory + +func TestAbstractFactory(t *testing.T) { + + t.Run("Test Nike Factory", func(t *testing.T) { + nikeFactory, _ := getSportsFactory("nike") + nikeShoe := nikeFactory.makeShoe() + nikeShirt := nikeFactory.makeShirt() + if !reflect.DeepEqual(nikeShoe.getLogo(), "nike") { + t.Errorf("got: %v, want: %v", nikeShoe.getLogo(), "nike") + } + if !reflect.DeepEqual(nikeShoe.getSize(), 14) { + t.Errorf("got: %v, want: %v", nikeShoe.getSize(), 14) + } + if !reflect.DeepEqual(nikeShirt.getLogo(), "nike") { + t.Errorf("got: %v, want: %v", nikeShirt.getLogo(), "nike") + } + if !reflect.DeepEqual(nikeShirt.getSize(), 14) { + t.Errorf("got: %v, want: %v", nikeShirt.getLogo(), 14) + } + }) + + t.Run("Test Adidas Factory", func(t *testing.T) { + adidasFactory, _ := getSportsFactory("adidas") + adidasShoe := adidasFactory.makeShoe() + adidasShirt := adidasFactory.makeShirt() + + if !reflect.DeepEqual(adidasShoe.getLogo(), "adidas") { + t.Errorf("got: %v, want: %v", adidasShoe.getLogo(), "adidas") + } + if !reflect.DeepEqual(adidasShoe.getSize(), 14) { + t.Errorf("got: %v, want: %v", adidasShoe.getSize(), 14) + } + if !reflect.DeepEqual(adidasShirt.getLogo(), "adidas") { + t.Errorf("got: %v, want: %v", adidasShirt.getLogo(), "adidas") + } + if !reflect.DeepEqual(adidasShirt.getSize(), 14) { + t.Errorf("got: %v, want: %v", adidasShirt.getLogo(), 14) + } + }) + +} + + + diff --git a/designpatterns/abstractfactory/adidas.go b/designpatterns/abstractfactory/adidas.go new file mode 100644 index 000000000..d5285068d --- /dev/null +++ b/designpatterns/abstractfactory/adidas.go @@ -0,0 +1,23 @@ +package abstractfactorry + +// Concrete factory +type adidas struct { +} + +func (a *adidas) makeShoe() iShoe { + return &adidasShoe{ + shoe: shoe{ + logo: "adidas", + size: 14, + }, + } +} + +func (a *adidas) makeShirt() iShirt { + return &adidasShirt{ + shirt: shirt{ + logo: "adidas", + size: 14, + }, + } +} \ No newline at end of file diff --git a/designpatterns/abstractfactory/adidasshirt.go b/designpatterns/abstractfactory/adidasshirt.go new file mode 100644 index 000000000..0b6fd8d1d --- /dev/null +++ b/designpatterns/abstractfactory/adidasshirt.go @@ -0,0 +1,6 @@ +package abstractfactorry + +// Concrete product +type adidasShirt struct { + shirt +} \ No newline at end of file diff --git a/designpatterns/abstractfactory/adidasshoe.go b/designpatterns/abstractfactory/adidasshoe.go new file mode 100644 index 000000000..79528f04f --- /dev/null +++ b/designpatterns/abstractfactory/adidasshoe.go @@ -0,0 +1,6 @@ +package abstractfactorry + +// Concrete product +type adidasShoe struct { + shoe +} \ No newline at end of file diff --git a/designpatterns/abstractfactory/ishirt.go b/designpatterns/abstractfactory/ishirt.go new file mode 100644 index 000000000..9378f08a7 --- /dev/null +++ b/designpatterns/abstractfactory/ishirt.go @@ -0,0 +1,31 @@ +package abstractfactorry + +// Abstract product + +type iShirt interface { + setLogo(logo string) + setSize(size int) + getLogo() string + getSize() int +} + +type shirt struct { + logo string + size int +} + +func (s *shirt) setLogo(logo string) { + s.logo = logo +} + +func (s *shirt) getLogo() string { + return s.logo +} + +func (s *shirt) setSize(size int) { + s.size = size +} + +func (s *shirt) getSize() int { + return s.size +} diff --git a/designpatterns/abstractfactory/ishoe.go b/designpatterns/abstractfactory/ishoe.go new file mode 100644 index 000000000..ca25ff8c7 --- /dev/null +++ b/designpatterns/abstractfactory/ishoe.go @@ -0,0 +1,30 @@ +package abstractfactorry + +// Abstract product +type iShoe interface { + setLogo(logo string) + setSize(size int) + getLogo() string + getSize() int +} + +type shoe struct { + logo string + size int +} + +func (s *shoe) setLogo(logo string) { + s.logo = logo +} + +func (s *shoe) getLogo() string { + return s.logo +} + +func (s *shoe) setSize(size int) { + s.size = size +} + +func (s *shoe) getSize() int { + return s.size +} \ No newline at end of file diff --git a/designpatterns/abstractfactory/isportsFactory.go b/designpatterns/abstractfactory/isportsFactory.go new file mode 100644 index 000000000..991c8de24 --- /dev/null +++ b/designpatterns/abstractfactory/isportsFactory.go @@ -0,0 +1,21 @@ +package abstractfactorry + +import "fmt" + +// Abstract factory interface +type iSportsFactory interface { + makeShoe() iShoe + makeShirt() iShirt +} + +func getSportsFactory(brand string) (iSportsFactory, error) { + if brand == "adidas" { + return &adidas{}, nil + } + + if brand == "nike" { + return &nike{}, nil + } + + return nil, fmt.Errorf("Wrong brand type passed") +} \ No newline at end of file diff --git a/designpatterns/abstractfactory/nike.go b/designpatterns/abstractfactory/nike.go new file mode 100644 index 000000000..8b4f4346f --- /dev/null +++ b/designpatterns/abstractfactory/nike.go @@ -0,0 +1,23 @@ +package abstractfactorry + +// Concrete factory +type nike struct { +} + +func (n *nike) makeShoe() iShoe { + return &nikeShoe{ + shoe: shoe{ + logo: "nike", + size: 14, + }, + } +} + +func (n *nike) makeShirt() iShirt { + return &nikeShirt{ + shirt: shirt{ + logo: "nike", + size: 14, + }, + } +} diff --git a/designpatterns/abstractfactory/nikeshirt.go b/designpatterns/abstractfactory/nikeshirt.go new file mode 100644 index 000000000..530f822d1 --- /dev/null +++ b/designpatterns/abstractfactory/nikeshirt.go @@ -0,0 +1,6 @@ +package abstractfactorry + +// Concrete product +type nikeShirt struct { + shirt +} \ No newline at end of file diff --git a/designpatterns/abstractfactory/nikeshoe.go b/designpatterns/abstractfactory/nikeshoe.go new file mode 100644 index 000000000..b2bc2c7cf --- /dev/null +++ b/designpatterns/abstractfactory/nikeshoe.go @@ -0,0 +1,7 @@ +package abstractfactorry + +// Concrete product + +type nikeShoe struct { + shoe +} \ No newline at end of file From ae2d6744ca12e5243607263fafe0f2efbf1db530 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sat, 27 Feb 2021 20:05:01 +0000 Subject: [PATCH 171/488] updating DIRECTORY.md --- DIRECTORY.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 5c803cae6..e3a5592e9 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -49,6 +49,19 @@ * [Trie](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie.go) * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie_test.go) +## Designpatterns + * Abstractfactory + * [Abstractfactory Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/abstractfactory_test.go) + * [Adidas](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/adidas.go) + * [Adidasshirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/adidasshirt.go) + * [Adidasshoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/adidasshoe.go) + * [Ishirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/ishirt.go) + * [Ishoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/ishoe.go) + * [Isportsfactory](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/isportsFactory.go) + * [Nike](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nike.go) + * [Nikeshirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshirt.go) + * [Nikeshoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshoe.go) + ## Dynamicprogramming * [Binomialcoeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/binomialcoeffecient.go) * [Fibonacc Test](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/fibonacc_test.go) From 8cf5f6314c8648a2a9dae7e92fe0ca39e30cbb6b Mon Sep 17 00:00:00 2001 From: Mohamed Date: Sun, 28 Feb 2021 15:28:22 +0200 Subject: [PATCH 172/488] feat:factory method pattern added to designpatterns --- .../factorymethod/accountingDepartment.go | 14 ++++++ designpatterns/factorymethod/department.go | 23 ++++++++++ .../factorymethod/departmentFactory.go | 13 ++++++ .../factorymethod/factorymethod_test.go | 43 +++++++++++++++++++ .../factorymethod/financeDepartment.go | 14 ++++++ designpatterns/factorymethod/idepartment.go | 8 ++++ 6 files changed, 115 insertions(+) create mode 100644 designpatterns/factorymethod/accountingDepartment.go create mode 100644 designpatterns/factorymethod/department.go create mode 100644 designpatterns/factorymethod/departmentFactory.go create mode 100644 designpatterns/factorymethod/factorymethod_test.go create mode 100644 designpatterns/factorymethod/financeDepartment.go create mode 100644 designpatterns/factorymethod/idepartment.go diff --git a/designpatterns/factorymethod/accountingDepartment.go b/designpatterns/factorymethod/accountingDepartment.go new file mode 100644 index 000000000..d6757922b --- /dev/null +++ b/designpatterns/factorymethod/accountingDepartment.go @@ -0,0 +1,14 @@ +package factorymethod + +type accounting struct { + department +} + +func newAccounting() iDepartment { + return &accounting{ + department: department{ + name: "Accounting Department", + employees: 1, + }, + } +} \ No newline at end of file diff --git a/designpatterns/factorymethod/department.go b/designpatterns/factorymethod/department.go new file mode 100644 index 000000000..114159acc --- /dev/null +++ b/designpatterns/factorymethod/department.go @@ -0,0 +1,23 @@ +package factorymethod + +type department struct { + name string + employees int +} + + +func (g *department) setName(name string) { + g.name = name +} + +func (g *department) getName() string { + return g.name +} + +func (g *department) setEmployees(employees int) { + g.employees = employees +} + +func (g *department) getEmployees() int { + return g.employees +} \ No newline at end of file diff --git a/designpatterns/factorymethod/departmentFactory.go b/designpatterns/factorymethod/departmentFactory.go new file mode 100644 index 000000000..e1e8dfca8 --- /dev/null +++ b/designpatterns/factorymethod/departmentFactory.go @@ -0,0 +1,13 @@ +package factorymethod + +import "fmt" + +func getDepartment(departmentType string) (iDepartment, error) { + if departmentType == "accounting" { + return newAccounting(), nil + } + if departmentType == "finance" { + return newFinance(), nil + } + return nil, fmt.Errorf("wrong department type passed") +} diff --git a/designpatterns/factorymethod/factorymethod_test.go b/designpatterns/factorymethod/factorymethod_test.go new file mode 100644 index 000000000..df8304b68 --- /dev/null +++ b/designpatterns/factorymethod/factorymethod_test.go @@ -0,0 +1,43 @@ +package factorymethod + +import ( + "reflect" + "testing" +) + +// test client code and how to use the factory +func TestFactoryMethod(t *testing.T) { + t.Run("Test Accounting Department", func(t *testing.T) { + accounting, _ := getDepartment("accounting") + if !reflect.DeepEqual(accounting.getName(), "Accounting Department") { + t.Errorf("got: %v, want: %v", accounting.getName(), "Accounting Department") + } + if !reflect.DeepEqual(accounting.getEmployees(), 1) { + t.Errorf("got: %v, want: %v", accounting.getName(), 1) + } + }) + + + t.Run("Test Finance Department", func(t *testing.T) { + finance, _ := getDepartment("finance") + if !reflect.DeepEqual(finance.getName(), "Finance Department") { + t.Errorf("got: %v, want: %v", finance.getName(), "Finance Department") + } + if !reflect.DeepEqual(finance.getEmployees(), 2) { + t.Errorf("got: %v, want: %v", finance.getEmployees(), 2) + } + }) + + t.Run("Test not existing department", func(t *testing.T) { + random, _ := getDepartment("test") + + if !reflect.DeepEqual(random, nil) { + t.Errorf("should return empty nil for non existing department") + } + + }) +} + + + + diff --git a/designpatterns/factorymethod/financeDepartment.go b/designpatterns/factorymethod/financeDepartment.go new file mode 100644 index 000000000..b6f2194fa --- /dev/null +++ b/designpatterns/factorymethod/financeDepartment.go @@ -0,0 +1,14 @@ +package factorymethod + +type finance struct { + department +} + +func newFinance() iDepartment { + return &finance{ + department: department{ + name: "Finance Department", + employees: 2, + }, + } +} \ No newline at end of file diff --git a/designpatterns/factorymethod/idepartment.go b/designpatterns/factorymethod/idepartment.go new file mode 100644 index 000000000..e5c7b7148 --- /dev/null +++ b/designpatterns/factorymethod/idepartment.go @@ -0,0 +1,8 @@ +package factorymethod + +type iDepartment interface { + setName(name string) + setEmployees(employees int) + getName() string + getEmployees() int +} \ No newline at end of file From 10a89dfa5f743188d8ba927907f9d88185caa933 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 7 Mar 2021 09:17:20 +0000 Subject: [PATCH 173/488] updating DIRECTORY.md --- DIRECTORY.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index e3a5592e9..18dd7690e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -61,6 +61,13 @@ * [Nike](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nike.go) * [Nikeshirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshirt.go) * [Nikeshoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshoe.go) + * Factorymethod + * [Accountingdepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/accountingDepartment.go) + * [Department](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/department.go) + * [Departmentfactory](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/departmentFactory.go) + * [Factorymethod Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/factorymethod_test.go) + * [Financedepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/financeDepartment.go) + * [Idepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/idepartment.go) ## Dynamicprogramming * [Binomialcoeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/binomialcoeffecient.go) From 1d57dc1fdc1129e3272b3f27bdd2870d65e1a323 Mon Sep 17 00:00:00 2001 From: Mohamed Date: Sun, 7 Mar 2021 14:19:53 +0200 Subject: [PATCH 174/488] feat:builder pattern added to design patterns --- designpatterns/builder/builderinterface.go | 19 +++++++++ designpatterns/builder/builderpattern_test.go | 39 +++++++++++++++++++ designpatterns/builder/director.go | 22 +++++++++++ designpatterns/builder/house.go | 7 ++++ designpatterns/builder/igloobuilder.go | 31 +++++++++++++++ designpatterns/builder/normalbuilder.go | 31 +++++++++++++++ 6 files changed, 149 insertions(+) create mode 100644 designpatterns/builder/builderinterface.go create mode 100644 designpatterns/builder/builderpattern_test.go create mode 100644 designpatterns/builder/director.go create mode 100644 designpatterns/builder/house.go create mode 100644 designpatterns/builder/igloobuilder.go create mode 100644 designpatterns/builder/normalbuilder.go diff --git a/designpatterns/builder/builderinterface.go b/designpatterns/builder/builderinterface.go new file mode 100644 index 000000000..a6ab01dec --- /dev/null +++ b/designpatterns/builder/builderinterface.go @@ -0,0 +1,19 @@ +package builder + +type iBuilder interface { + setWindowType() + setDoorType() + setNumFloor() + getHouse() house +} + +func getBuilder(builderType string) iBuilder { + if builderType == "normal" { + return &normalBuilder{} + } + + if builderType == "igloo" { + return &iglooBuilder{} + } + return nil +} diff --git a/designpatterns/builder/builderpattern_test.go b/designpatterns/builder/builderpattern_test.go new file mode 100644 index 000000000..09177c73b --- /dev/null +++ b/designpatterns/builder/builderpattern_test.go @@ -0,0 +1,39 @@ +package builder +import ( + "reflect" + "testing" +) + +func TestBuilderPatter(t *testing.T){ + t.Run("Test Normal Builder", func(t *testing.T) { + normalBuilder := getBuilder("normal") + director := newDirector(normalBuilder) + normalHouse := director.buildHouse() + if !reflect.DeepEqual(normalHouse.doorType, "Wooden Door") { + t.Errorf("got: %v, want: %v", normalHouse.doorType, "Wooden Door") + } + if !reflect.DeepEqual(normalHouse.windowType, "Wooden Window") { + t.Errorf("got: %v, want: %v", normalHouse.windowType, "Wooden Window") + } + if !reflect.DeepEqual(normalHouse.floor, 2) { + t.Errorf("got: %v, want: %v", normalHouse.floor, 2) + } + }) + t.Run("Test Igloo Builder", func(t *testing.T) { + iglooBuilder := getBuilder("igloo") + director := newDirector(iglooBuilder) + iglooHouse := director.buildHouse() + if !reflect.DeepEqual(iglooHouse.doorType, "Snow Door") { + t.Errorf("got: %v, want: %v", iglooHouse.doorType, "Snow Door") + } + if !reflect.DeepEqual(iglooHouse.windowType, "Snow Window") { + t.Errorf("got: %v, want: %v", iglooHouse.windowType, "Snow Window") + } + if !reflect.DeepEqual(iglooHouse.floor, 1) { + t.Errorf("got: %v, want: %v", iglooHouse.floor, 1) + } + }) + +} + + diff --git a/designpatterns/builder/director.go b/designpatterns/builder/director.go new file mode 100644 index 000000000..fe2eec2b7 --- /dev/null +++ b/designpatterns/builder/director.go @@ -0,0 +1,22 @@ +package builder + +type director struct { + builder iBuilder +} + +func newDirector(b iBuilder) *director { + return &director{ + builder: b, + } +} + +func (d *director) setBuilder(b iBuilder) { + d.builder = b +} + +func (d *director) buildHouse() house { + d.builder.setDoorType() + d.builder.setWindowType() + d.builder.setNumFloor() + return d.builder.getHouse() +} \ No newline at end of file diff --git a/designpatterns/builder/house.go b/designpatterns/builder/house.go new file mode 100644 index 000000000..f7e9954e9 --- /dev/null +++ b/designpatterns/builder/house.go @@ -0,0 +1,7 @@ +package builder + +type house struct { + windowType string + doorType string + floor int +} \ No newline at end of file diff --git a/designpatterns/builder/igloobuilder.go b/designpatterns/builder/igloobuilder.go new file mode 100644 index 000000000..f7803199c --- /dev/null +++ b/designpatterns/builder/igloobuilder.go @@ -0,0 +1,31 @@ +package builder + +type iglooBuilder struct { + windowType string + doorType string + floor int +} + +func newIglooBuilder() *iglooBuilder { + return &iglooBuilder{} +} + +func (b *iglooBuilder) setWindowType() { + b.windowType = "Snow Window" +} + +func (b *iglooBuilder) setDoorType() { + b.doorType = "Snow Door" +} + +func (b *iglooBuilder) setNumFloor() { + b.floor = 1 +} + +func (b *iglooBuilder) getHouse() house { + return house{ + doorType: b.doorType, + windowType: b.windowType, + floor: b.floor, + } +} \ No newline at end of file diff --git a/designpatterns/builder/normalbuilder.go b/designpatterns/builder/normalbuilder.go new file mode 100644 index 000000000..9b389b718 --- /dev/null +++ b/designpatterns/builder/normalbuilder.go @@ -0,0 +1,31 @@ +package builder + +type normalBuilder struct { + windowType string + doorType string + floor int +} + +func newNormalBuilder() *normalBuilder { + return &normalBuilder{} +} + +func (b *normalBuilder) setWindowType() { + b.windowType = "Wooden Window" +} + +func (b *normalBuilder) setDoorType() { + b.doorType = "Wooden Door" +} + +func (b *normalBuilder) setNumFloor() { + b.floor = 2 +} + +func (b *normalBuilder) getHouse() house { + return house{ + doorType: b.doorType, + windowType: b.windowType, + floor: b.floor, + } +} \ No newline at end of file From 74af3ef51c144ded516790454acbba70976afb57 Mon Sep 17 00:00:00 2001 From: Mohamed Date: Sun, 7 Mar 2021 14:26:19 +0200 Subject: [PATCH 175/488] fix:refactor unused functions in concrete builder --- designpatterns/builder/builderinterface.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/designpatterns/builder/builderinterface.go b/designpatterns/builder/builderinterface.go index a6ab01dec..b1cf6ad5c 100644 --- a/designpatterns/builder/builderinterface.go +++ b/designpatterns/builder/builderinterface.go @@ -9,11 +9,11 @@ type iBuilder interface { func getBuilder(builderType string) iBuilder { if builderType == "normal" { - return &normalBuilder{} + return newNormalBuilder() } if builderType == "igloo" { - return &iglooBuilder{} + return newIglooBuilder() } return nil } From 050ac927bd08194c69f8cd55cb46e81cc7902a2c Mon Sep 17 00:00:00 2001 From: Mohamed Date: Sun, 7 Mar 2021 15:19:17 +0200 Subject: [PATCH 176/488] fix:refactor unused functions in concrete builder --- designpatterns/builder/builderpattern_test.go | 13 +++++++++++++ designpatterns/builder/director.go | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/designpatterns/builder/builderpattern_test.go b/designpatterns/builder/builderpattern_test.go index 09177c73b..18965feee 100644 --- a/designpatterns/builder/builderpattern_test.go +++ b/designpatterns/builder/builderpattern_test.go @@ -1,5 +1,6 @@ package builder import ( + "fmt" "reflect" "testing" ) @@ -34,6 +35,18 @@ func TestBuilderPatter(t *testing.T){ } }) + t.Run("Test set builder ", func(t *testing.T) { + iglooBuilder := getBuilder("igloo") + director := director{} + director.setBuilder(iglooBuilder) + iglooHouse := director.buildHouse() + fmt.Println(iglooHouse) + if !reflect.DeepEqual(iglooHouse.floor, 1) { + t.Errorf("got: %v, want: %v", iglooHouse.floor, 1) + } + + }) + } diff --git a/designpatterns/builder/director.go b/designpatterns/builder/director.go index fe2eec2b7..9ca220454 100644 --- a/designpatterns/builder/director.go +++ b/designpatterns/builder/director.go @@ -9,7 +9,6 @@ func newDirector(b iBuilder) *director { builder: b, } } - func (d *director) setBuilder(b iBuilder) { d.builder = b } From bca6e3ff91445f52011a7bbc7d8590cc90f899d5 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 7 Mar 2021 13:24:17 +0000 Subject: [PATCH 177/488] updating DIRECTORY.md --- DIRECTORY.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 18dd7690e..212bda771 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -61,6 +61,13 @@ * [Nike](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nike.go) * [Nikeshirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshirt.go) * [Nikeshoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshoe.go) + * Builder + * [Builderinterface](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/builderinterface.go) + * [Builderpattern Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/builderpattern_test.go) + * [Director](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/director.go) + * [House](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/house.go) + * [Igloobuilder](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/igloobuilder.go) + * [Normalbuilder](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/normalbuilder.go) * Factorymethod * [Accountingdepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/accountingDepartment.go) * [Department](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/department.go) From 959228fb9b09d6ec69b4f54b0263f16b548689db Mon Sep 17 00:00:00 2001 From: Mohamed Abdelrhman Date: Sun, 7 Mar 2021 19:37:57 +0200 Subject: [PATCH 178/488] feat: prototype pattern added --- designpatterns/prototype/file.go | 15 +++++++++ designpatterns/prototype/folder.go | 27 ++++++++++++++++ designpatterns/prototype/nodeInterface.go | 5 +++ designpatterns/prototype/prototype_test.go | 36 ++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 designpatterns/prototype/file.go create mode 100644 designpatterns/prototype/folder.go create mode 100644 designpatterns/prototype/nodeInterface.go create mode 100644 designpatterns/prototype/prototype_test.go diff --git a/designpatterns/prototype/file.go b/designpatterns/prototype/file.go new file mode 100644 index 000000000..67c7cc9cc --- /dev/null +++ b/designpatterns/prototype/file.go @@ -0,0 +1,15 @@ +package prototype + +import "fmt" + +type file struct { + name string +} + +func (f *file) print(indentation string) { + fmt.Println(indentation + f.name) +} + +func (f *file) clone() nodeInterface { + return &file{name: f.name + "_clone"} +} diff --git a/designpatterns/prototype/folder.go b/designpatterns/prototype/folder.go new file mode 100644 index 000000000..a6700b3ae --- /dev/null +++ b/designpatterns/prototype/folder.go @@ -0,0 +1,27 @@ +package prototype + +import "fmt" + +type folder struct { + children []nodeInterface + name string +} + +func (f *folder) print(indentation string) { + fmt.Println(indentation + f.name) + for _, i := range f.children { + i.print(indentation + indentation) + } +} + +func (f *folder) clone() nodeInterface { + cloneFolder := &folder{name: f.name + "_clone"} + var tempChildren []nodeInterface + for _, i := range f.children { + copy := i.clone() + tempChildren = append(tempChildren, copy) + } + cloneFolder.children = tempChildren + return cloneFolder +} + diff --git a/designpatterns/prototype/nodeInterface.go b/designpatterns/prototype/nodeInterface.go new file mode 100644 index 000000000..ca25dcc79 --- /dev/null +++ b/designpatterns/prototype/nodeInterface.go @@ -0,0 +1,5 @@ +package prototype +type nodeInterface interface { + print(string) + clone() nodeInterface +} diff --git a/designpatterns/prototype/prototype_test.go b/designpatterns/prototype/prototype_test.go new file mode 100644 index 000000000..baf874f61 --- /dev/null +++ b/designpatterns/prototype/prototype_test.go @@ -0,0 +1,36 @@ +package prototype + +import ( + "fmt" + "testing" +) + +// test client code and how to use the factory +func TestProtoType(t *testing.T) { + t.Run("Test File And Folder Hierarchy", func(t *testing.T) { + file1 := &file{name: "File1"} + file2 := &file{name: "File2"} + file3 := &file{name: "File3"} + + folder1 := &folder{ + children: []nodeInterface{file1}, + name: "Folder1", + } + + folder2 := &folder{ + children: []nodeInterface{folder1, file2, file3}, + name: "Folder2", + } + fmt.Println("\nPrinting hierarchy for Folder2") + folder2.print(" ") + + cloneFolder := folder2.clone() + fmt.Println("\nPrinting hierarchy for clone Folder") + cloneFolder.print(" ") + }) +} + + + + + From e70140700d78b6fb10a56f0b7b7624b9bcc87f02 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 7 Mar 2021 17:48:40 +0000 Subject: [PATCH 179/488] updating DIRECTORY.md --- DIRECTORY.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 212bda771..7c5e8ea61 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -75,6 +75,11 @@ * [Factorymethod Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/factorymethod_test.go) * [Financedepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/financeDepartment.go) * [Idepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/idepartment.go) + * Prototype + * [File](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/file.go) + * [Folder](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/folder.go) + * [Nodeinterface](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/nodeInterface.go) + * [Prototype Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/prototype_test.go) ## Dynamicprogramming * [Binomialcoeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/binomialcoeffecient.go) From 8bc4e86f2fa69111bb961861796735c2562d3441 Mon Sep 17 00:00:00 2001 From: Taj Date: Mon, 8 Mar 2021 08:19:57 +0000 Subject: [PATCH 180/488] feat: added a few algorithms that will be used for rewriting RSA algorithm that currently fails the tests (#288) * feat: added a few algorithms that will be used for rsa algorithm * fix: renamed the directory for better import string organisation * fix: rename of a file * updating DIRECTORY.md * fix: corrected the mistakes in the documetation comments of some code * fix: missplelling * fix: spelling errors * fix: reduced cyclomatic complexity Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 10 ++- ciphers/polybius/polybius_test.go | 2 +- math/gcd/gcd.go | 6 +- math/gcd/gcd_test.go | 32 ++++++-- math/gcd/gcditerative.go | 9 +++ math/lcm/lcm.go | 12 +++ .../modularexponentiation_test.go | 6 +- math/prime/millerrabinprimalitytest.go | 73 +++++++++++++++++++ .../prime_test.go} | 29 +++++++- math/{primecheck => prime}/primecheck.go | 2 +- .../advanced-aho-corasick/adac.go | 4 +- .../aho-corasick/ac.go | 4 +- strings/multiple-string-matching/sbom/sbom.go | 53 +------------- strings/single-string-matching/bom/bom.go | 10 +-- 14 files changed, 175 insertions(+), 77 deletions(-) create mode 100644 math/gcd/gcditerative.go create mode 100644 math/lcm/lcm.go create mode 100644 math/prime/millerrabinprimalitytest.go rename math/{primecheck/primecheck_test.go => prime/prime_test.go} (63%) rename math/{primecheck => prime}/primecheck.go (97%) diff --git a/DIRECTORY.md b/DIRECTORY.md index 7c5e8ea61..b242a201d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -104,15 +104,19 @@ * Gcd * [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go) * [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go) + * [Gcditerative](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcditerative.go) + * Lcm + * [Lcm](https://github.com/TheAlgorithms/Go/blob/master/math/lcm/lcm.go) * Modulararithmetic * [Modularexponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation.go) * [Modularexponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation_test.go) * Power * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent.go) * [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent_test.go) - * Primecheck - * [Primecheck](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/primecheck.go) - * [Primecheck Test](https://github.com/TheAlgorithms/Go/blob/master/math/primecheck/primecheck_test.go) + * Prime + * [Millerrabinprimalitytest](https://github.com/TheAlgorithms/Go/blob/master/math/prime/millerrabinprimalitytest.go) + * [Prime Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_test.go) + * [Primecheck](https://github.com/TheAlgorithms/Go/blob/master/math/prime/primecheck.go) * Pythagoras * [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras.go) * [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go) diff --git a/ciphers/polybius/polybius_test.go b/ciphers/polybius/polybius_test.go index d75b4ebb3..d607884e3 100644 --- a/ciphers/polybius/polybius_test.go +++ b/ciphers/polybius/polybius_test.go @@ -45,7 +45,7 @@ func TestNewPolybius(t *testing.T) { wantErr string }{ { - name: "correct initalization", size: 5, characters: "HogeF", key: "abcdefghijklmnopqrstuvwxy", wantErr: "", + name: "correct initialization", size: 5, characters: "HogeF", key: "abcdefghijklmnopqrstuvwxy", wantErr: "", }, { name: "truncate characters", size: 5, characters: "HogeFuga", key: "abcdefghijklmnopqrstuvwxy", wantErr: "", diff --git a/math/gcd/gcd.go b/math/gcd/gcd.go index ef22b1589..e76e8396f 100644 --- a/math/gcd/gcd.go +++ b/math/gcd/gcd.go @@ -1,9 +1,9 @@ package gcd -// Gcd finds and returns the greatest common divisor of a given integer. -func Gcd(a, b int) int { +// Recursive finds and returns the greatest common divisor of a given integer. +func Recursive(a, b int64) int64 { if b == 0 { return a } - return Gcd(b, a%b) + return Recursive(b, a%b) } diff --git a/math/gcd/gcd_test.go b/math/gcd/gcd_test.go index ef589fabe..78b5b3155 100644 --- a/math/gcd/gcd_test.go +++ b/math/gcd/gcd_test.go @@ -2,21 +2,23 @@ package gcd import "testing" +type testFunction func(int64, int64) int64 + var testCases = []struct { name string - a int - b int - output int + a int64 + b int64 + output int64 }{ {"gcd of 10 and 0", 10, 0, 10}, {"gcd of 98 and 56", 98, 56, 14}, {"gcd of 0 and 10", 0, 10, 10}, } -func TestGCD(t *testing.T) { +func TemplateTestGCD(t *testing.T, f testFunction) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := Gcd(tc.a, tc.b) + actual := f(tc.a, tc.b) if actual != tc.output { t.Errorf("Expected GCD of %d and %d to be: %v, but got: %d", tc.a, tc.b, tc.output, actual) } @@ -24,8 +26,24 @@ func TestGCD(t *testing.T) { } } -func BenchmarkGCD(b *testing.B) { +func TestGCDRecursive(t *testing.T) { + TemplateTestGCD(t, Recursive) +} + +func TestGCDIterative(t *testing.T) { + TemplateTestGCD(t, Iterative) +} + +func TemplateBenchmarkGCD(b *testing.B, f testFunction) { for i := 0; i < b.N; i++ { - Gcd(98, 56) + f(98, 56) } } + +func BenchmarkGCDRecursive(b *testing.B) { + TemplateBenchmarkGCD(b, Recursive) +} + +func BenchmarkGCDIterative(b *testing.B) { + TemplateBenchmarkGCD(b, Iterative) +} diff --git a/math/gcd/gcditerative.go b/math/gcd/gcditerative.go new file mode 100644 index 000000000..e87dfce6f --- /dev/null +++ b/math/gcd/gcditerative.go @@ -0,0 +1,9 @@ +package gcd + +// Iterative Faster iterative version of GcdRecursive without holding up too much of the stack +func Iterative(a, b int64) int64 { + for b != 0 { + a, b = b, a%b + } + return a +} diff --git a/math/lcm/lcm.go b/math/lcm/lcm.go new file mode 100644 index 000000000..e1de23e17 --- /dev/null +++ b/math/lcm/lcm.go @@ -0,0 +1,12 @@ +package lcm + +import ( + "math" + + "github.com/TheAlgorithms/Go/math/gcd" +) + +// Lcm returns the lcm of two numbers using the fact that lcm(a,b) * gcd(a,b) = | a * b | +func Lcm(a, b int64) int64 { + return int64(math.Abs(float64(a*b)) / float64(gcd.Iterative(a, b))) +} diff --git a/math/modulararithmetic/modularexponentiation_test.go b/math/modulararithmetic/modularexponentiation_test.go index 531e4045f..9af4d7461 100644 --- a/math/modulararithmetic/modularexponentiation_test.go +++ b/math/modulararithmetic/modularexponentiation_test.go @@ -66,12 +66,12 @@ func TestModularExponentiation(t *testing.T) { result, err := ModularExponentiation(test.base, test.exponent, test.mod) if err != test.expectedError { t.Logf("Test Failed for %s", test.name) - t.Logf("Unexpected error occured") - t.Errorf("Expected error: %v, Recieved error: %v", test.expectedError, err) + t.Logf("Unexpected error occurred") + t.Errorf("Expected error: %v, Received error: %v", test.expectedError, err) } if result != test.expected { t.Logf("Test Failed for %s", test.description) - t.Fatalf("Expected: %d, Recieved: %d", test.expected, result) + t.Fatalf("Expected: %d, Received: %d", test.expected, result) } }) } diff --git a/math/prime/millerrabinprimalitytest.go b/math/prime/millerrabinprimalitytest.go new file mode 100644 index 000000000..f38da3dfa --- /dev/null +++ b/math/prime/millerrabinprimalitytest.go @@ -0,0 +1,73 @@ +package prime + +import ( + "math/rand" + + "github.com/TheAlgorithms/Go/math/modulararithmetic" +) + +// findD accepts a number and returns the +// odd number d such that num = 2^r * d - 1 +func findRD(num int64) (int64, int64) { + r := int64(0) + d := num - 1 + for num%2 == 0 { + d /= 2 + r++ + } + return d, r +} + +// MillerTest This is the intermediate step that repeats within the +// miller rabin primality test for better probabilitic chances of +// receiving the correct result. +func MillerTest(d, num int64) (bool, error) { + random := rand.Int63n(num-1) + 2 + + res, err := modulararithmetic.ModularExponentiation(random, d, num) + + if err != nil { + return false, err + } + // miller conditions checks + if res == 1 || res == num-1 { + return true, nil + } + + for d != num-1 { + res = (res * res) % num + d *= 2 + if res == 1 { + return false, nil + } + if res == num-1 { + return true, nil + } + } + return false, nil +} + +// MillerRabinTest Probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin. +func MillerRabinTest(num, rounds int64) (bool, error) { + if num <= 4 { + if num == 2 || num == 3 { + return true, nil + } + return false, nil + } + if num%2 == 0 { + return false, nil + } + d, _ := findRD(num) + + for i := int64(0); i < rounds; i++ { + val, err := MillerTest(d, num) + if err != nil { + return false, err + } + if !val { + return false, nil + } + } + return true, nil +} diff --git a/math/primecheck/primecheck_test.go b/math/prime/prime_test.go similarity index 63% rename from math/primecheck/primecheck_test.go rename to math/prime/prime_test.go index 62c8105e0..a8b835f5e 100644 --- a/math/primecheck/primecheck_test.go +++ b/math/prime/prime_test.go @@ -1,4 +1,4 @@ -package primecheck +package prime import ( "testing" @@ -49,6 +49,33 @@ func TestTablePairApproach(t *testing.T) { } +func TestMillerRabinTest(t *testing.T) { + var tests = []struct { + name string + input int64 + expected bool + rounds int64 + err error + }{ + {"smallest prime", 2, true, 5, nil}, + {"random prime", 3, true, 5, nil}, + {"neither prime nor composite", 1, false, 5, nil}, + {"random non-prime", 10, false, 5, nil}, + {"another random prime", 23, true, 5, nil}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + output, err := MillerRabinTest(test.input, test.rounds) + if err != test.err { + t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err) + } + if output != test.expected { + t.Errorf("For input: %d, expected: %v", test.input, output) + } + }) + } +} + func BenchmarkNaiveApproach(b *testing.B) { for i := 0; i < b.N; i++ { NaiveApproach(23) diff --git a/math/primecheck/primecheck.go b/math/prime/primecheck.go similarity index 97% rename from math/primecheck/primecheck.go rename to math/prime/primecheck.go index 6f03a5918..e6b4f96c2 100644 --- a/math/primecheck/primecheck.go +++ b/math/prime/primecheck.go @@ -1,4 +1,4 @@ -package primecheck +package prime // A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography. //Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number is prime or not. diff --git a/strings/multiple-string-matching/advanced-aho-corasick/adac.go b/strings/multiple-string-matching/advanced-aho-corasick/adac.go index 82012451b..dfbb6ae67 100644 --- a/strings/multiple-string-matching/advanced-aho-corasick/adac.go +++ b/strings/multiple-string-matching/advanced-aho-corasick/adac.go @@ -44,7 +44,7 @@ type Result struct { // } // r := ahoCorasick(string(textFile), patterns) // for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) +// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) // for i := range value { // fmt.Printf("%d", value[i]) // if i != len(value)-1 { @@ -77,7 +77,7 @@ func AhoCorasick(t string, p []string) Result { for i := range f[current] { if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match // if debugMode == true { - // fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) + // fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) // } newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) occurrences[f[current][i]] = newOccurrences diff --git a/strings/multiple-string-matching/aho-corasick/ac.go b/strings/multiple-string-matching/aho-corasick/ac.go index d6abb0922..903f693fc 100644 --- a/strings/multiple-string-matching/aho-corasick/ac.go +++ b/strings/multiple-string-matching/aho-corasick/ac.go @@ -43,7 +43,7 @@ type Result struct { // } // r := ahoCorasick(string(textFile), patterns) // for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) +// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) // for i := range value { // fmt.Printf("%d", value[i]) // if i != len(value)-1 { @@ -85,7 +85,7 @@ func AhoCorasick(t string, p []string) Result { for i := range f[current] { if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match // if debugMode == true { - // fmt.Printf("Occurence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) + // fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) // } newOccurrences := intArrayCapUp(occurrences[f[current][i]]) occurrences[f[current][i]] = newOccurrences diff --git a/strings/multiple-string-matching/sbom/sbom.go b/strings/multiple-string-matching/sbom/sbom.go index 022ec1577..1c0c8904f 100644 --- a/strings/multiple-string-matching/sbom/sbom.go +++ b/strings/multiple-string-matching/sbom/sbom.go @@ -6,11 +6,6 @@ import ( "time" ) -// User defined. -// Set to true to print various extra stuff out (slows down the execution) -// Set to false for quick and quiet execution. -const debugMode bool = true - type Result struct { occurrences map[string][]int } @@ -44,7 +39,7 @@ type Result struct { // } // r := sbom(string(textFile), patterns) // for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurences for word: %q at positions: ", len(value), key) +// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) // for i := range value { // fmt.Printf("%d", value[i]) // if i != len(value)-1 { @@ -63,43 +58,21 @@ func Sbom(t string, p []string) Result { occurrences := make(map[int][]int) lmin := computeMinLength(p) or, f := buildOracleMultiple(reverseAll(trimToLength(p, lmin))) - if debugMode { - fmt.Printf("\n\nSBOM:\n\n") - } pos := 0 for pos <= len(t)-lmin { current := 0 j := lmin - if debugMode { - fmt.Printf("Position: %d, we read: ", pos) - } for j >= 1 && stateExists(current, or) { - if debugMode { - fmt.Printf("%c", t[pos+j-1]) - } current = getTransition(current, t[pos+j-1], or) - if debugMode { - if current == -1 { - fmt.Printf(" (FAIL) ") - } else { - fmt.Printf(", ") - } - } j-- } - if debugMode { - fmt.Printf("in the factor oracle. \n") - } word := getWord(pos, pos+lmin-1, t) if stateExists(current, or) && j == 0 && strings.HasPrefix(word, getCommonPrefix(p, f[current], lmin)) { //check for prefix match for i := range f[current] { if p[f[current][i]] == getWord(pos, pos-1+len(p[f[current][i]]), t) { //check for word match - if debugMode { - fmt.Printf("- Occurence, %q = %q\n", p[f[current][i]], word) - } - newOccurences := intArrayCapUp(occurrences[f[current][i]]) - occurrences[f[current][i]] = newOccurences - occurrences[f[current][i]][len(newOccurences)-1] = pos + newOccurrences := intArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurrences + occurrences[f[current][i]][len(newOccurrences)-1] = pos } } j = 0 @@ -125,9 +98,6 @@ func buildOracleMultiple(p []string) (orToReturn map[int]map[uint8]int, f map[in i := 0 //root of trie orToReturn = orTrie s[i] = -1 - if debugMode { - fmt.Printf("\n\nOracle construction: \n") - } for current := 1; current < len(stateIsTerminal); current++ { o, parent := getParent(current, orTrie) down := s[parent] @@ -150,9 +120,6 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo stateIsTerminal = make([]bool, 1) f = make(map[int][]int) state := 1 - if debugMode { - fmt.Printf("\n\nTrie construction: \n") - } createNewState(0, trie) for i := 0; i < len(p); i++ { current := 0 @@ -174,15 +141,9 @@ func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo newArray := intArrayCapUp(f[current]) newArray[len(newArray)-1] = i f[current] = newArray //F(Current) <- F(Current) union {i} - if debugMode { - fmt.Printf(" and %d", i) - } } else { stateIsTerminal[current] = true f[current] = []int{i} //F(Current) <- {i} - if debugMode { - fmt.Printf("\n%d is terminal for word number %d", current, i) - } } } return trie, stateIsTerminal, f @@ -290,17 +251,11 @@ func getParent(state int, at map[int]map[uint8]int) (uint8, int) { // Automaton function for creating a new state 'state'. func createNewState(state int, at map[int]map[uint8]int) { at[state] = make(map[uint8]int) - if debugMode { - fmt.Printf("\ncreated state %d", state) - } } // Creates a transition for function σ(state,letter) = end. func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { at[fromState][overChar] = toState - if debugMode { - fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - } } // Returns ending state for transition σ(fromState,overChar), '-1' if there is none. diff --git a/strings/single-string-matching/bom/bom.go b/strings/single-string-matching/bom/bom.go index 2d0fd01f4..b237eb05b 100644 --- a/strings/single-string-matching/bom/bom.go +++ b/strings/single-string-matching/bom/bom.go @@ -67,7 +67,7 @@ package bom // n, m := len(t), len(p) // var current, j, pos int // oracle := oracleOnLine(reverse(p)) -// occurences := make([]int, len(t)) +// occurrences := make([]int, len(t)) // currentOcc := 0 // pos = 0 // if debugMode == true { @@ -85,9 +85,9 @@ package bom // } // if stateExists(current, oracle) { // if debugMode == true { -// fmt.Printf(" We got an occurence!") +// fmt.Printf(" We got an occurrence!") // } -// occurences[currentOcc] = pos +// occurrences[currentOcc] = pos // currentOcc++ // } // pos = pos + j + 1 @@ -103,9 +103,9 @@ package bom // if currentOcc > 0 { // fmt.Printf("Word %q was found %d times at positions: ", p, currentOcc) // for k := 0; k < currentOcc-1; k++ { -// fmt.Printf("%d, ", occurences[k]) +// fmt.Printf("%d, ", occurrences[k]) // } -// fmt.Printf("%d", occurences[currentOcc-1]) +// fmt.Printf("%d", occurrences[currentOcc-1]) // fmt.Printf(".\n") // } // if currentOcc == 0 { From 0eb6ade11b76bb37b3471bfd8a169a4989179ce5 Mon Sep 17 00:00:00 2001 From: Kevin Burchfield Date: Mon, 29 Mar 2021 21:44:03 -0400 Subject: [PATCH 181/488] Heap's Algorithm --- DIRECTORY.md | 3 +++ math/permutation/heaps.go | 43 ++++++++++++++++++++++++++++++++++ math/permutation/heaps_test.go | 31 ++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 math/permutation/heaps.go create mode 100644 math/permutation/heaps_test.go diff --git a/DIRECTORY.md b/DIRECTORY.md index b242a201d..aa0b5ee76 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -123,6 +123,9 @@ * Sieve * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/Sieve.go) * [Sieve Test](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve_test.go) + * Permutation + * [Heap's Algorithm](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps.go) + * [Heap's Algorithm Test](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps_test.go) ## Other * Maxsubarraysum diff --git a/math/permutation/heaps.go b/math/permutation/heaps.go new file mode 100644 index 000000000..19abc4635 --- /dev/null +++ b/math/permutation/heaps.go @@ -0,0 +1,43 @@ +package permutation + +import ( + "strings" +) + +// Heap's Algorithm for generating all permutations of n objects +func Heaps(out chan []string, n int) { + elementSetCh := make(chan []string) + go GenerateElementSet(elementSetCh, n) + elementSet := <-elementSetCh + + var recursiveGenerate func([]string, int, []string) + var permutations []string + recursiveGenerate = func(previousIteration []string, n int, elements []string) { + if n == 1 { + permutations = append(permutations, strings.Join(elements, "")) + } else { + for i := 0; i < n; i++ { + recursiveGenerate(previousIteration, n - 1, elements) + if n % 2 == 1 { + tmp := elements[i] + elements[i] = elements[n - 1] + elements[n - 1] = tmp + } else { + tmp := elements[0] + elements[0] = elements[n - 1] + elements[n - 1] = tmp + } + } + } + } + recursiveGenerate(permutations, n, elementSet) + out <- permutations +} + +func GenerateElementSet(out chan []string, n int) { + elementSet := make([]string, n) + for i, _ := range elementSet { + elementSet[i] = string(i + 49) // Adjust this if you want to change your charset + } + out <- elementSet +} diff --git a/math/permutation/heaps_test.go b/math/permutation/heaps_test.go new file mode 100644 index 000000000..d65069d1f --- /dev/null +++ b/math/permutation/heaps_test.go @@ -0,0 +1,31 @@ +package permutation + +import ( + "reflect" + "sort" + "testing" +) + +func TestHeaps(t *testing.T) { + t.Run("Should generate permutations for various size sets", func (t *testing.T) { + expectedValues := [][]string { + {"1"}, + {"12", "21"}, + {"123", "213", "321", "231", "312", "132"}, + {"1234", "1243", "1324", "1342", "1423", "1432", "2134", "2143", "2314", "2341", "2413", "2431", "3124", "3142", "3214", "3241", "3412", "3421", "4123", "4132", "4213", "4231", "4312", "4321"}, + {"12345", "12354", "12435", "12453", "12534", "12543", "13245", "13254", "13425", "13452", "13524", "13542", "14235", "14253", "14325", "14352", "14523", "14532", "15234", "15243", "15324", "15342", "15423", "15432", "21345", "21354", "21435", "21453", "21534", "21543", "23145", "23154", "23415", "23451", "23514", "23541", "24135", "24153", "24315", "24351", "24513", "24531", "25134", "25143", "25314", "25341", "25413", "25431", "31245", "31254", "31425", "31452", "31524", "31542", "32145", "32154", "32415", "32451", "32514", "32541", "34125", "34152", "34215", "34251", "34512", "34521", "35124", "35142", "35214", "35241", "35412", "35421", "41235", "41253", "41325", "41352", "41523", "41532", "42135", "42153", "42315", "42351", "42513", "42531", "43125", "43152", "43215", "43251", "43512", "43521", "45123", "45132", "45213", "45231", "45312", "45321", "51234", "51243", "51324", "51342", "51423", "51432", "52134", "52143", "52314", "52341", "52413", "52431", "53124", "53142", "53214", "53241", "53412", "53421", "54123", "54132", "54213", "54231", "54312", "54321"}, + } + permutationsCh := make(chan []string) + var value []string + + for i := 1; i <= 5; i++ { + go Heaps(permutationsCh, i) + value = <- permutationsCh + sort.Strings(value) + sort.Strings(expectedValues[i - 1]) + if !reflect.DeepEqual(value, expectedValues[i - 1]) { + t.Errorf("Permutation set is incorrect for element size of %v. Expected (%v) and received (%v)", i, expectedValues[i - 1], value) + } + } + }) +} From ac5590df6e12864d54d849d319978ecb40ac37e6 Mon Sep 17 00:00:00 2001 From: Kevin Burchfield Date: Mon, 29 Mar 2021 22:15:05 -0400 Subject: [PATCH 182/488] Fix lint --- math/permutation/heaps.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/permutation/heaps.go b/math/permutation/heaps.go index 19abc4635..aea82eb88 100644 --- a/math/permutation/heaps.go +++ b/math/permutation/heaps.go @@ -36,7 +36,7 @@ func Heaps(out chan []string, n int) { func GenerateElementSet(out chan []string, n int) { elementSet := make([]string, n) - for i, _ := range elementSet { + for i := range elementSet { elementSet[i] = string(i + 49) // Adjust this if you want to change your charset } out <- elementSet From a42da304ef7f743a20f8aeb2d5094f23cab903ce Mon Sep 17 00:00:00 2001 From: Kevin Burchfield Date: Mon, 29 Mar 2021 22:23:35 -0400 Subject: [PATCH 183/488] Converting int to rune --- math/permutation/heaps.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/permutation/heaps.go b/math/permutation/heaps.go index aea82eb88..81b0a15d6 100644 --- a/math/permutation/heaps.go +++ b/math/permutation/heaps.go @@ -37,7 +37,7 @@ func Heaps(out chan []string, n int) { func GenerateElementSet(out chan []string, n int) { elementSet := make([]string, n) for i := range elementSet { - elementSet[i] = string(i + 49) // Adjust this if you want to change your charset + elementSet[i] = string(rune(i + 49)) // Adjust this if you want to change your charset } out <- elementSet } From b6b7905ec6632a537abd79fa564c4691703cd29f Mon Sep 17 00:00:00 2001 From: Brayo Date: Mon, 5 Apr 2021 22:49:44 +0300 Subject: [PATCH 184/488] Quicksort sorts in-place --- sorts/quicksort.go | 47 +++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/sorts/quicksort.go b/sorts/quicksort.go index 52274e98c..04cb60b73 100644 --- a/sorts/quicksort.go +++ b/sorts/quicksort.go @@ -1,38 +1,25 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -import ( - "math/rand" -) - -func QuickSort(arr []int) []int { - - if len(arr) <= 1 { - return arr +func Quicksort(array []int) { + if len(array) <= 1 { + return } + q := partition(array) + Quicksort(array[:q]) + Quicksort(array[q+1:]) +} - median := arr[rand.Intn(len(arr))] - - lowPart := make([]int, 0, len(arr)) - highPart := make([]int, 0, len(arr)) - middlePart := make([]int, 0, len(arr)) - - for _, item := range arr { - switch { - case item < median: - lowPart = append(lowPart, item) - case item == median: - middlePart = append(middlePart, item) - case item > median: - highPart = append(highPart, item) +func partition(array []int) int { + r := len(array) - 1 + x := array[r] // last element of slice + i := -1 + for j := 0; j < r; j++ { + if array[j] <= x { + i++ + array[i], array[j] = array[j], array[i] } } - - lowPart = QuickSort(lowPart) - highPart = QuickSort(highPart) - - lowPart = append(lowPart, middlePart...) - lowPart = append(lowPart, highPart...) - - return lowPart + array[i+1], array[r] = array[r], array[i+1] + return i + 1 } From a26459b90495fc836ec9ec5c9f2dac6b87956e0e Mon Sep 17 00:00:00 2001 From: Brayo Date: Tue, 6 Apr 2021 12:21:27 +0300 Subject: [PATCH 185/488] naming update --- sorts/quicksort.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sorts/quicksort.go b/sorts/quicksort.go index 04cb60b73..1ed1b3bc1 100644 --- a/sorts/quicksort.go +++ b/sorts/quicksort.go @@ -1,13 +1,14 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -func Quicksort(array []int) { +func QuickSort(array []int)[]int { if len(array) <= 1 { - return + return array } q := partition(array) - Quicksort(array[:q]) - Quicksort(array[q+1:]) + QuickSort(array[:q]) + QuickSort(array[q+1:]) + return array } func partition(array []int) int { From ff74b11878dc12a4fb948f87d5f6d92d6d7ed215 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 8 Apr 2021 15:16:52 +0000 Subject: [PATCH 186/488] updating DIRECTORY.md --- DIRECTORY.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index aa0b5ee76..46f4abeff 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -110,6 +110,9 @@ * Modulararithmetic * [Modularexponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation.go) * [Modularexponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation_test.go) + * Permutation + * [Heaps](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps.go) + * [Heaps Test](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps_test.go) * Power * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent.go) * [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent_test.go) @@ -123,9 +126,6 @@ * Sieve * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/Sieve.go) * [Sieve Test](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve_test.go) - * Permutation - * [Heap's Algorithm](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps.go) - * [Heap's Algorithm Test](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps_test.go) ## Other * Maxsubarraysum From 7bd5ff1c631ed1d38e89e7702666dc41070bca2d Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 10 Apr 2021 17:09:31 +0200 Subject: [PATCH 187/488] Upgrade gloangci to v1.39 (#304) --- .github/workflows/golang_lint_and_test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index b5171a5b0..286e18367 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -12,6 +12,8 @@ jobs: - run: go version - uses: golangci/golangci-lint-action@v2 with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.37 + # Required: the version of golangci-lint is required and must be + # specified without patch version: we always use the latest patch version. + # https://github.com/golangci/golangci-lint/releases + version: v1.39 - run: go test $(go list ./... | grep -v /sbom | grep -v /rsa) From 3d47bf8b18412a7b71056123738b43a11b12b2eb Mon Sep 17 00:00:00 2001 From: Stepfen Shawn Date: Sat, 22 May 2021 23:48:25 -0500 Subject: [PATCH 188/488] Update LICENSE Update Copyright year. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 3b7951527..f6bcf04e7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 The Algorithms +Copyright (c) 2021 The Algorithms Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 100e8df906a10ba2280350f7505fc4f8a18ea46b Mon Sep 17 00:00:00 2001 From: David Leal Date: Mon, 7 Jun 2021 18:22:09 -0500 Subject: [PATCH 189/488] Add Discord badge in `README.md` --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6070b354e..ff2f00c0e 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ![golangci-lint](https://github.com/TheAlgorithms/Go/workflows/golangci-lint/badge.svg) ![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  ![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) +[![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square)](https://discord.gg/c7MnfGFGa6)  ### Algorithms implemented in Go (for education) From 0a282fa7834f443b4f4811649b57b8c9d8653a61 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 21 Jun 2021 15:55:43 +0000 Subject: [PATCH 190/488] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 46f4abeff..cfc3f607d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -91,6 +91,9 @@ * [Matrix-Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/matrix-multiplication.go) * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/rod-cutting.go) +## Genetic-Algorithm + * [Genetic Algo](https://github.com/TheAlgorithms/Go/blob/master/genetic-algorithm/genetic_algo.go) + ## Graphs * Depthfirstsearch * [Depthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/depthfirstsearch/depthfirstsearch.go) From 7b431d7a2f202238ea3308f07a566b736181fe3e Mon Sep 17 00:00:00 2001 From: miraddo Date: Tue, 13 Jul 2021 14:24:59 +0430 Subject: [PATCH 191/488] fixed double linked list and create test for it --- .../doublylinkedlist/doublylinkedlist.go | 6 ++ .../doublylinkedlist/doublylinkedlist_test.go | 88 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go diff --git a/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go b/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go index 1f4f33cbc..eb0a1f08a 100644 --- a/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go +++ b/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go @@ -28,7 +28,13 @@ func NewNode(val int) *Node { func (ll *DoubleLinkedList) AddAtBeg(val int) { n := NewNode(val) n.next = ll.head + + if ll.head != nil{ + ll.head.prev = n + } + ll.head = n + } // AddAtEnd Add a node at the end of the linkedlist diff --git a/datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go b/datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go new file mode 100644 index 000000000..5f13b040c --- /dev/null +++ b/datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go @@ -0,0 +1,88 @@ +package doublylinkedlist + +import ( + "reflect" + "testing" +) + +func TestDoubleLinkedList(t *testing.T) { + newList := DoubleLinkedList{} + + newList.AddAtBeg(1) + newList.AddAtBeg(2) + newList.AddAtBeg(3) + + t.Run("Test AddAtBeg", func(t *testing.T) { + wantNext := []int{3, 2, 1} + wantPrev := []int{1, 2, 3} + got := []int{} + + // check from next address + current := newList.head + + got = append(got, current.val) + + for current.next != nil { + current = current.next + got = append(got, current.val) + } + + if !reflect.DeepEqual(got, wantNext) { + t.Errorf("got: %v, want: %v", got, wantNext) + } + + // check from prev address + got = []int{} + got = append(got, current.val) + + for current.prev != nil { + current = current.prev + got = append(got, current.val) + } + + if !reflect.DeepEqual(got, wantPrev) { + t.Errorf("got: %v, want: %v", got, wantPrev) + } + }) + + newList.AddAtEnd(4) + + t.Run("Test AddAtEnd", func(t *testing.T) { + want := []int{3, 2, 1, 4} + got := []int{} + current := newList.head + got = append(got, current.val) + for current.next != nil { + current = current.next + got = append(got, current.val) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + t.Run("Test DelAtBeg", func(t *testing.T) { + want := 3 + got := newList.DelAtBeg() + if got != want { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + t.Run("Test DelAtEnd", func(t *testing.T) { + want := 4 + got := newList.DelAtEnd() + if got != want { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + t.Run("Test Count", func(t *testing.T) { + want := 2 + got := newList.Count() + if got != want { + t.Errorf("got: %v, want: %v", got, want) + } + }) + +} From 4589cdaaa0fbb931a412bb4b870b2d620912a3ea Mon Sep 17 00:00:00 2001 From: Milad Date: Wed, 14 Jul 2021 13:42:46 -0700 Subject: [PATCH 192/488] added pull request --- .github/PULL_REQUEST_TEMPLATE/pull_request.md | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request.md b/.github/PULL_REQUEST_TEMPLATE/pull_request.md index 5fd421062..69a8f4f8d 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request.md @@ -1,10 +1,21 @@ - +#### Description of Change + + +#### Checklist + + +- [ ] Added description of change +- [ ] Added file name matches [File name guidelines](https://github.com/TheAlgorithms/Go/blob/master/CONTRIBUTING.md#New-File-Name-guidelines) +- [ ] Added tests and example, test must pass +- [ ] Added documentation so that the program is self-explanatory and educational - [GoDoc guidelines](https://blog.golang.org/godoc) +- [ ] Relevant documentation/comments is changed or added +- [ ] PR title follows semantic [commit guidelines](https://github.com/TheAlgorithms/Go/blob/master/CONTRIBUTING.md#Commit-Guidelines) +- [ ] Search previous suggestions before making a new one, as yours may be a duplicate. +- [ ] I acknowledge that all my contributions will be made under the project's license. + +Notes: \ No newline at end of file From 3484eb0c3671fed596055246d11a52391f49c98c Mon Sep 17 00:00:00 2001 From: Milad Date: Wed, 14 Jul 2021 13:43:55 -0700 Subject: [PATCH 193/488] fixed contributing.md --- CONTRIBUTING.md | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e69de29bb..5c617ec5c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -0,0 +1,180 @@ +# CONTRIBUTION GUIDELINES + +## Before contributing + +Welcome to [TheAlgorithms/Go](https://github.com/TheAlgorithms/Go)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/Go/issues/new/choose) or ask in our [Discord server](https://discord.gg/c7MnfGFGa6) / [Gitter](https://gitter.im/TheAlgorithms), and clearly state your concerns. + +## Contributing + +### Maintainer/reviewer + +**Please check the [reviewer code](https://github.com/TheAlgorithms/Go/blob/master/DIRECTORY.md) file for maintainers and reviewers.** + +### Contributor + +Being a contributor at The Algorithms, we request you to follow the points mentioned below: + +- You did your own work. + - No plagiarism allowed. Any plagiarized work will not be merged. +- Your work will be distributed under the [MIT License](https://github.com/TheAlgoritms/Go/blob/master/LICENSE) once your pull request has been merged. +- Please follow the repository guidelines and standards mentioned below. + +**New implementation** New implementations are welcome! + +You can add new algorithms or data structures which are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs or in any other resonable sense) + +**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers. + +### Making Changes + +#### Code + +- Please use the directory structure of the repository. +- Make sure the file extensions should be `*.go`. +- Use meaning variable names. +- Use standard library inside your code and avoid to import packages from other repositories +- If an implementation of the algorithm already exists, please refer to the [file-name section below](#new-file-name-guidelines). +- You can suggest reasonable changes to existing algorithms. +- Strictly use snake_case (underscore_separated) in filenames. +- If you have added or modified code, please make sure the code compiles before submitting. +- Our automated testing runs [LGTM](https://lgtm.com/projects/g/TheAlgorithms/Go/) on all the pull requests, so please be sure that your code passes before submitting. +- Please conform to [GoDoc](https://blog.golang.org/godoc) standard and document the code as much as possible. This not only facilitates the readers but also generates the correct info on the website. +- **Be consistent in the use of these guidelines.** + +#### Documentation + +- Make sure you put useful comments in your code. Do not comment on obvious things. +- Please avoid creating new directories if at all possible. Try to fit your work into the existing directory structure. If you want to create a new directory, then please check if a similar category has been recently suggested or created by other pull requests. +- If you have modified/added documentation, please ensure that your language is concise and must not contain grammatical errors. +- Do not update [`README.md`](https://github.com/TheAlgorithms/Go/blob/master/README.md) along with other changes. First, create an issue and then link to that issue in your pull request to suggest specific changes required to [`README.md`](https://github.com/TheAlgorithms/Go/blob/master/README.md). +- The repository follows [GoDoc](https://blog.golang.org/godoc) standards and auto-generates the [repository website](https://thealgorithms.github.io/). Please ensure the code is documented in this structure. A sample implementation is given below. + +#### Test + +- Make sure to add examples and test cases in your `filename_test.go` file. +- If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes. +- Please try to add one or more `Test` functions that will invoke the algorithm implementation on random test data with the expected output. + +#### Typical structure of a program + +```go + +// filename +// description: Add one line description here +// details: +// This is a multi-line +// description containing links, references, +// math equations, etc. +// author(s) [Name](https://github.com/handle), [Name](https://github.com/handle) +// see related_file.go, another_file.go, file_test.go + + +// Package sort provides primitives for sorting slices and user-defined +// collections. +package sort + +// Reasons why you used those packages +// name package : Add one line description here +// name2 package : Add one line description here +// ... +import ( + ... +) + + +// Fprint formats using the default formats for its operands and writes to w. +// Spaces are added between operands when neither is a string. +// It returns the number of bytes written and any write error encountered. +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + ... +} + + +``` + +#### New File Name guidelines + +- Use lowercase words with ``"_"`` as a separator +- For instance + +```markdown +MyNewGoFile.GO is incorrect +my_new_go_file.go is correct format +``` + +- It will be used to dynamically create a directory of files and implementation. +- File name validation will run on Docker to ensure validity. +- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example: if `binary_search.go` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `binary_search2.go` and for a third implementation, `binary_search3.go`. + +#### New Directory guidelines + +- We recommend adding files to existing directories as much as possible. +- Use lowercase words with ``"_"`` as separator ( no spaces or ```"-"``` allowed ) +- For instance + +```markdown +SomeNew Fancy-Category is incorrect +some_new_fancy_category is correct +``` + +- Filepaths will be used to dynamically create a directory of our algorithms. +- Filepath validation will run on GitHub Actions to ensure compliance. + +#### Commit Guidelines + +- It is recommended to keep your changes grouped logically within individual commits. Maintainers find it easier to understand changes that are logically spilled across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected. + +```bash +git add file_xyz.go +git commit -m "your message" +``` + +Examples of commit messages with semantic prefixes: + +```markdown +fix: xyz algorithm bug +feat: add xyx algorithm +test: add test for xyz algorithm +docs: add comments and explanation to xyz algorithm +``` + +Common prefixes: + +- fix: A bug fix +- feat: A new feature +- docs: Documentation changes +- test: Correct existing tests or add new ones + +### Pull Requests + +- Checkout our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.go + ) + +#### Building Locally + +Before submitting a pull request, +build the code locally or using the convenient [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/Go) service. + +```bash +go build . +``` + +#### Code Formatter + +- Installation (only needs to be installed once.) + - Mac (using home-brew): `brew install go` + - Windows (MSYS2 64-bit): `choco install golang` [Chocolatey Package Manager](https://chocolatey.org/) + - Linux (Debian): `sudo apt-get install golang` +- Running (all platforms): `go run main.go` or `go build main.go` + +#### GitHub Actions + +- Enable GitHub Actions on your fork of the repository. + After enabling, it will execute `golang_lint_and_test` after every push (not a commit). +- The result can create another commit if the actions made any changes on your behalf. +- Hence, it is better to wait and check the results of GitHub Actions after every push. +- Run `git pull` in your local clone if these actions made many changes to avoid merge conflicts. + +Most importantly, + +- Happy coding! From 3eb77fef21d9cb36d56957db6ef610409fb9107a Mon Sep 17 00:00:00 2001 From: Milad Date: Wed, 14 Jul 2021 14:45:29 -0700 Subject: [PATCH 194/488] fixed name files and folders based on contribution guidelines --- .github/workflows/golang_lint_and_test.yml | 2 +- DIRECTORY.md | 256 +++++++++--------- .../{CaesarCipher.go => caesar_cipher.go} | 0 .../diffie_hellman_key_exchange.go} | 4 +- .../diffie_hellman_key_exchange_test.go} | 4 +- ciphers/rsaBig/rsaBig | Bin 2514312 -> 0 bytes .../RSAcipher.go => rsa_cipher/rsa_cipher.go} | 0 .../{rsa => rsa_cipher}/rsa_cipher_test.go | 2 +- .../rsa_cipher_big.go} | 0 .../rsa_cipher_big_test.go | 2 +- .../xorCipher.go => xor_cipher/xor_cipher.go} | 4 +- .../{xor => xor_cipher}/xor_cipher_test.go | 2 +- .../roman_to_integer.go | 0 .../roman_to_integer_test.go | 0 .../binary_tree/binary_search_tree.go | 0 .../binary_tree/binary_tree.go | 0 .../binary_tree}/btree.go | 0 .../binary_tree}/node.go | 0 .../dynamic-array/dynamic_array.go | 0 .../hashmap/hashmap.go | 0 .../hashmap/hashmap_test.go | 0 .../doubly_linkedlist/doubly_linkedlist.go | 4 +- .../doubly_linkedlist_test.go | 2 +- .../singly_linkedlist/singly_linkedlist.go | 2 +- .../singly_linkedlist/singly_linkedlist2.go | 2 +- .../singly_linkedlist_test.go | 2 +- .../trie/trie.go | 0 .../trie/trie_test.go | 0 .../abstract_factory/abstract_factory_test.go | 0 .../abstract_factory}/adidas.go | 0 .../abstract_factory/adidas_shoe.go | 0 .../abstract_factory}/adidasshirt.go | 0 .../abstract_factory/i_shirt.go | 0 .../abstract_factory/i_shoe.go | 0 .../abstract_factory/i_sports_factory.go | 0 .../abstract_factory}/nike.go | 0 .../abstract_factory/nike_shirt.go | 0 .../abstract_factory/nike_shoe.go | 0 .../builder/builder_interface.go | 0 .../builder/builder_pattern_test.go | 0 .../builder/director.go | 0 .../builder/house.go | 0 .../builder/igloo_builder.go | 0 .../builder/normal_builder.go | 0 .../factory_method/accounting_department.go | 2 +- .../factory_method}/department.go | 2 +- .../factory_method/department_factory.go | 2 +- .../factory_method/factory_method_test.go | 2 +- .../factory_method/finance_department.go | 2 +- .../factory_method/i_department.go | 2 +- .../prototype/file.go | 0 .../prototype/folder.go | 0 .../prototype/node_interface.go | 0 .../prototype/prototype_test.go | 0 .../binomial_coefficient.go | 2 +- .../fibonacci.go | 2 +- .../fibonacci_test.go | 2 +- .../knapsack.go | 2 +- .../longest_common_subsequence.go | 2 +- .../longest_palindromic_subsequence.go | 2 +- .../matrix_multiplication.go | 6 +- .../rod_cutting.go | 2 +- .../genetic_algo.go | 0 .../depth_first_search.go} | 2 +- .../floyd_warshall.go} | 2 +- ...FirstSearch.go => breadth_first_search.go} | 0 ...h_test.go => breadth_first_search_test.go} | 0 .../gcd/{gcditerative.go => gcd_iterative.go} | 0 .../modular_exponentiation.go} | 2 +- .../modular_exponentiation_test.go} | 2 +- .../{fastexponent.go => fast_exponent.go} | 0 ...exponent_test.go => fast_exponent_test.go} | 0 ...test.go => miller_rabin_primality_test.go} | 4 +- math/prime/{primecheck.go => prime_check.go} | 0 math/sieve/{Sieve.go => sieve.go} | 0 .../max_subarray_sum.go} | 2 +- .../nested_brackets.go} | 2 +- .../password_generator.go} | 2 +- .../string_combinations.go} | 4 +- .../{binarysearch.go => binary_search.go} | 0 .../{linearsearch.go => linear_search.go} | 0 sorts/{bubblesort.go => bubble_sort.go} | 0 sorts/{heapsort.go => heap_sort.go} | 0 sorts/{insertionsort.go => insertion_sort.go} | 0 sorts/{mergesort.go => merge_sort.go} | 0 sorts/{quicksort.go => quick_sort.go} | 0 sorts/{radixsort.go => radix_sort.go} | 0 sorts/{selectionsort.go => selection_sort.go} | 0 sorts/{shellsort.go => shell_sort.go} | 0 .../levenshtein_distance.go} | 2 +- .../levenshtein_distance_test.go} | 2 +- .../advanced_aho_corasick.go} | 0 .../advanced_aho_corasick_test.go} | 0 .../aho_corasick/aho_corasick.go} | 0 .../aho_corasick/aho_corasick_test.go} | 0 .../patterns.txt | 0 .../sbom/sbom.go | 0 .../sbom/sbom_test.go | 0 .../text.txt | 0 .../naive_string_search.go} | 2 +- .../naive_string_search_test.go} | 2 +- .../bom/bom.go | 0 .../horspool/horspool.go | 0 .../kmp/kmp.go | 0 .../kmp/kmp_test.go | 0 .../pattern.txt | 0 .../text.txt | 0 107 files changed, 175 insertions(+), 175 deletions(-) rename ciphers/caesar/{CaesarCipher.go => caesar_cipher.go} (100%) rename ciphers/{diffiehelkeyexchange/diffieHellmanKeyExchange.go => diffie_hellman_key_exchange/diffie_hellman_key_exchange.go} (89%) rename ciphers/{diffiehelkeyexchange/diffieHellmanKeyExchange_test.go => diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go} (93%) delete mode 100755 ciphers/rsaBig/rsaBig rename ciphers/{rsa/RSAcipher.go => rsa_cipher/rsa_cipher.go} (100%) rename ciphers/{rsa => rsa_cipher}/rsa_cipher_test.go (96%) rename ciphers/{rsaBig/RSAcipher(Big).go => rsa_cipher_big/rsa_cipher_big.go} (100%) rename ciphers/{rsaBig => rsa_cipher_big}/rsa_cipher_big_test.go (95%) rename ciphers/{xor/xorCipher.go => xor_cipher/xor_cipher.go} (86%) rename ciphers/{xor => xor_cipher}/xor_cipher_test.go (99%) rename conversions/{roman-to-integer => roman_to_integer}/roman_to_integer.go (100%) rename conversions/{roman-to-integer => roman_to_integer}/roman_to_integer_test.go (100%) rename datastructures/binary-tree/binarysearchtree.go => data_structures/binary_tree/binary_search_tree.go (100%) rename datastructures/binary-tree/binarytree.go => data_structures/binary_tree/binary_tree.go (100%) rename {datastructures/binary-tree => data_structures/binary_tree}/btree.go (100%) rename {datastructures/binary-tree => data_structures/binary_tree}/node.go (100%) rename datastructures/dynamic-array/dynamicarray.go => data_structures/dynamic-array/dynamic_array.go (100%) rename {datastructures => data_structures}/hashmap/hashmap.go (100%) rename {datastructures => data_structures}/hashmap/hashmap_test.go (100%) rename datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go => data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go (96%) rename datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go => data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go (98%) rename datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go => data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go (98%) rename datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go => data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go (98%) rename datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go => data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go (98%) rename {datastructures => data_structures}/trie/trie.go (100%) rename {datastructures => data_structures}/trie/trie_test.go (100%) rename designpatterns/abstractfactory/abstractfactory_test.go => design_patterns/abstract_factory/abstract_factory_test.go (100%) rename {designpatterns/abstractfactory => design_patterns/abstract_factory}/adidas.go (100%) rename designpatterns/abstractfactory/adidasshoe.go => design_patterns/abstract_factory/adidas_shoe.go (100%) rename {designpatterns/abstractfactory => design_patterns/abstract_factory}/adidasshirt.go (100%) rename designpatterns/abstractfactory/ishirt.go => design_patterns/abstract_factory/i_shirt.go (100%) rename designpatterns/abstractfactory/ishoe.go => design_patterns/abstract_factory/i_shoe.go (100%) rename designpatterns/abstractfactory/isportsFactory.go => design_patterns/abstract_factory/i_sports_factory.go (100%) rename {designpatterns/abstractfactory => design_patterns/abstract_factory}/nike.go (100%) rename designpatterns/abstractfactory/nikeshirt.go => design_patterns/abstract_factory/nike_shirt.go (100%) rename designpatterns/abstractfactory/nikeshoe.go => design_patterns/abstract_factory/nike_shoe.go (100%) rename designpatterns/builder/builderinterface.go => design_patterns/builder/builder_interface.go (100%) rename designpatterns/builder/builderpattern_test.go => design_patterns/builder/builder_pattern_test.go (100%) rename {designpatterns => design_patterns}/builder/director.go (100%) rename {designpatterns => design_patterns}/builder/house.go (100%) rename designpatterns/builder/igloobuilder.go => design_patterns/builder/igloo_builder.go (100%) rename designpatterns/builder/normalbuilder.go => design_patterns/builder/normal_builder.go (100%) rename designpatterns/factorymethod/accountingDepartment.go => design_patterns/factory_method/accounting_department.go (88%) rename {designpatterns/factorymethod => design_patterns/factory_method}/department.go (93%) rename designpatterns/factorymethod/departmentFactory.go => design_patterns/factory_method/department_factory.go (92%) rename designpatterns/factorymethod/factorymethod_test.go => design_patterns/factory_method/factory_method_test.go (97%) rename designpatterns/factorymethod/financeDepartment.go => design_patterns/factory_method/finance_department.go (88%) rename designpatterns/factorymethod/idepartment.go => design_patterns/factory_method/i_department.go (83%) rename {designpatterns => design_patterns}/prototype/file.go (100%) rename {designpatterns => design_patterns}/prototype/folder.go (100%) rename designpatterns/prototype/nodeInterface.go => design_patterns/prototype/node_interface.go (100%) rename {designpatterns => design_patterns}/prototype/prototype_test.go (100%) rename dynamicprogramming/binomialcoeffecient.go => dynamic_programming/binomial_coefficient.go (96%) rename {dynamicprogramming => dynamic_programming}/fibonacci.go (92%) rename dynamicprogramming/fibonacc_test.go => dynamic_programming/fibonacci_test.go (96%) rename {dynamicprogramming => dynamic_programming}/knapsack.go (96%) rename dynamicprogramming/longestCommonSubsequence.go => dynamic_programming/longest_common_subsequence.go (97%) rename dynamicprogramming/longest-palindromic-subsequence.go => dynamic_programming/longest_palindromic_subsequence.go (97%) rename dynamicprogramming/matrix-multiplication.go => dynamic_programming/matrix_multiplication.go (85%) rename dynamicprogramming/rod-cutting.go => dynamic_programming/rod_cutting.go (97%) rename {genetic-algorithm => genetic_algorithm}/genetic_algo.go (100%) rename graphs/{depthfirstsearch/depthfirstsearch.go => depth_first_search/depth_first_search.go} (98%) rename graphs/{floydwarshall/floydwarshall.go => floyd_warshall/floyd_warshall.go} (98%) rename graphs/search/{breadthFirstSearch.go => breadth_first_search.go} (100%) rename graphs/search/{breadthFirstSearch_test.go => breadth_first_search_test.go} (100%) rename math/gcd/{gcditerative.go => gcd_iterative.go} (100%) rename math/{modulararithmetic/modularexponentiation.go => modular_arithmetic/modular_exponentiation.go} (97%) rename math/{modulararithmetic/modularexponentiation_test.go => modular_arithmetic/modular_exponentiation_test.go} (98%) rename math/power/{fastexponent.go => fast_exponent.go} (100%) rename math/power/{fastexponent_test.go => fast_exponent_test.go} (100%) rename math/prime/{millerrabinprimalitytest.go => miller_rabin_primality_test.go} (91%) rename math/prime/{primecheck.go => prime_check.go} (100%) rename math/sieve/{Sieve.go => sieve.go} (100%) rename other/{maxsubarraysum/maxsubarraysum.go => max_subarray_sum/max_subarray_sum.go} (96%) rename other/{nestedbrackets/nestedbrackets.go => nested_brackets/nested_brackets.go} (98%) rename other/{passwordgenerator/passwordgenerator.go => password_generator/password_generator.go} (98%) rename other/{stringcombinations/stringcombinations.go => string_combinations/string_combinations.go} (90%) rename searches/{binarysearch.go => binary_search.go} (100%) rename searches/{linearsearch.go => linear_search.go} (100%) rename sorts/{bubblesort.go => bubble_sort.go} (100%) rename sorts/{heapsort.go => heap_sort.go} (100%) rename sorts/{insertionsort.go => insertion_sort.go} (100%) rename sorts/{mergesort.go => merge_sort.go} (100%) rename sorts/{quicksort.go => quick_sort.go} (100%) rename sorts/{radixsort.go => radix_sort.go} (100%) rename sorts/{selectionsort.go => selection_sort.go} (100%) rename sorts/{shellsort.go => shell_sort.go} (100%) rename strings/{levenshteindistance/levenshteinDistance.go => levenshtein_distance/levenshtein_distance.go} (96%) rename strings/{levenshteindistance/levenshteinDistance_test.go => levenshtein_distance/levenshtein_distance_test.go} (96%) rename strings/{multiple-string-matching/advanced-aho-corasick/adac.go => multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick.go} (100%) rename strings/{multiple-string-matching/advanced-aho-corasick/adac_test.go => multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick_test.go} (100%) rename strings/{multiple-string-matching/aho-corasick/ac.go => multiple_string_matching/aho_corasick/aho_corasick.go} (100%) rename strings/{multiple-string-matching/aho-corasick/ac_test.go => multiple_string_matching/aho_corasick/aho_corasick_test.go} (100%) rename strings/{multiple-string-matching => multiple_string_matching}/patterns.txt (100%) rename strings/{multiple-string-matching => multiple_string_matching}/sbom/sbom.go (100%) rename strings/{multiple-string-matching => multiple_string_matching}/sbom/sbom_test.go (100%) rename strings/{multiple-string-matching => multiple_string_matching}/text.txt (100%) rename strings/{naivesearch/naiveStringSearch.go => naive_string_search/naive_string_search.go} (95%) rename strings/{naivesearch/naiveStringSearch_test.go => naive_string_search/naive_string_search_test.go} (96%) rename strings/{single-string-matching => single_string_matching}/bom/bom.go (100%) rename strings/{single-string-matching => single_string_matching}/horspool/horspool.go (100%) rename strings/{single-string-matching => single_string_matching}/kmp/kmp.go (100%) rename strings/{single-string-matching => single_string_matching}/kmp/kmp_test.go (100%) rename strings/{single-string-matching => single_string_matching}/pattern.txt (100%) rename strings/{single-string-matching => single_string_matching}/text.txt (100%) diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index 286e18367..63bafe8c5 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -16,4 +16,4 @@ jobs: # specified without patch version: we always use the latest patch version. # https://github.com/golangci/golangci-lint/releases version: v1.39 - - run: go test $(go list ./... | grep -v /sbom | grep -v /rsa) + - run: go test $(go list ./... | grep -v /sbom | grep -v /rsa_cipher) diff --git a/DIRECTORY.md b/DIRECTORY.md index cfc3f607d..2d57c08ca 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -2,186 +2,186 @@ ## Ciphers * Caesar * [Caesar Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_test.go) - * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/CaesarCipher.go) - * Diffiehelkeyexchange - * [Diffiehellmankeyexchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go) - * [Diffiehellmankeyexchange Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go) + * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_cipher.go) + * Diffie Hellman Key Exchange + * [Diffie Hellman Key Exchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go) + * [Diffie Hellman Key Exchange Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go) * Polybius * [Polybius](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius.go) * [Polybius Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius_test.go) * Rot13 * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13.go) * [Rot13 Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13_test.go) - * Rsa - * [Rsa Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa/rsa_cipher_test.go) - * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa/RSAcipher.go) - * Rsabig - * [Rsa Cipher Big Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsaBig/rsa_cipher_big_test.go) - * [Rsacipher(Big)](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsaBig/RSAcipher(Big).go) - * Xor - * [Xor Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xor_cipher_test.go) - * [Xorcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor/xorCipher.go) + * RSA Cipher + * [Rsa Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/rsa_cipher_test.go) + * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/rsa_cipher.go) + * RSA Cipher Big + * [RSA Cipher Big Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big_test.go) + * [RSA Cipher Big](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big.go) + * XOR Cipher + * [XOR Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher_test.go) + * [XOR Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher.go) ## Conversions - * Roman-To-Integer - * [Roman To Integer](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman-to-integer/roman_to_integer.go) - * [Roman To Integer Test](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman-to-integer/roman_to_integer_test.go) + * Roman To Integer + * [Roman To Integer](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman_to_integer/roman_to_integer.go) + * [Roman To Integer Test](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman_to_integer/roman_to_integer_test.go) -## Datastructures - * Binary-Tree - * [Binarysearchtree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/binarysearchtree.go) - * [Binarytree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/binarytree.go) - * [Btree](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/btree.go) - * [Node](https://github.com/TheAlgorithms/Go/blob/master/datastructures/binary-tree/node.go) - * Dynamic-Array - * [Dynamicarray](https://github.com/TheAlgorithms/Go/blob/master/datastructures/dynamic-array/dynamicarray.go) +## Data Structures + * Binary Tree + * [Binary Search Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_search_tree.go) + * [Binary Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_tree.go) + * [B Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/btree.go) + * [Node](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/node.go) + * Dynamic Array + * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array.go) * Hashmap - * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/datastructures/hashmap/hashmap.go) - * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/hashmap/hashmap_test.go) - * Linkedlist - * Doublylinkedlist - * [Doublylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go) - * Singlylinkedlist - * [Singlylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go) - * [Singlylinkedlist2](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go) - * [Singlylinkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go) + * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap.go) + * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap_test.go) + * Linked-List + * Doubly Linked-List + * [Doublylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go) + * Singly Linked-List + * [Singlylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go) + * [Singlylinkedlist2](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go) + * [Singlylinkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go) * Trie - * [Trie](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie.go) - * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/datastructures/trie/trie_test.go) + * [Trie](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/trie.go) + * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/trie_test.go) -## Designpatterns - * Abstractfactory - * [Abstractfactory Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/abstractfactory_test.go) - * [Adidas](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/adidas.go) - * [Adidasshirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/adidasshirt.go) - * [Adidasshoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/adidasshoe.go) - * [Ishirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/ishirt.go) - * [Ishoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/ishoe.go) - * [Isportsfactory](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/isportsFactory.go) - * [Nike](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nike.go) - * [Nikeshirt](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshirt.go) - * [Nikeshoe](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/abstractfactory/nikeshoe.go) +## Design Patterns + * Abstract Factory + * [Abstract Factory Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/abstract_factory_test.go) + * [Adidas](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas.go) + * [Adidas Shirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas_shirt.go) + * [Adidas Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas_shoe.go) + * [I Shirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_shirt.go) + * [I Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_shoe.go) + * [I Sports Factory](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_sports_factory.go) + * [Nike](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/nike.go) + * [Nike Shirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/nike_shirt.go) + * [Nike Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/nike_shoe.go) * Builder - * [Builderinterface](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/builderinterface.go) - * [Builderpattern Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/builderpattern_test.go) - * [Director](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/director.go) - * [House](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/house.go) - * [Igloobuilder](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/igloobuilder.go) - * [Normalbuilder](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/builder/normalbuilder.go) - * Factorymethod - * [Accountingdepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/accountingDepartment.go) - * [Department](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/department.go) - * [Departmentfactory](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/departmentFactory.go) - * [Factorymethod Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/factorymethod_test.go) - * [Financedepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/financeDepartment.go) - * [Idepartment](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/factorymethod/idepartment.go) + * [Builder Interface](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/builder_interface.go) + * [Builder Pattern Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/builder_pattern_test.go) + * [Director](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/director.go) + * [House](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/house.go) + * [Igloo Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/iglooـbuilder.go) + * [Normal Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/normalـbuilder.go) + * Factory Method + * [Accounting Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/accounting_department.go) + * [Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/department.go) + * [Department Factory](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/department_factory.go) + * [Factory Method Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/factory_method_test.go) + * [Finance Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/finance_department.go) + * [I Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/i_department.go) * Prototype - * [File](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/file.go) - * [Folder](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/folder.go) - * [Nodeinterface](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/nodeInterface.go) - * [Prototype Test](https://github.com/TheAlgorithms/Go/blob/master/designpatterns/prototype/prototype_test.go) + * [File](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/file.go) + * [Folder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/folder.go) + * [Node Interface](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/node_interface.go) + * [Prototype Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/prototype_test.go) -## Dynamicprogramming - * [Binomialcoeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/binomialcoeffecient.go) - * [Fibonacc Test](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/fibonacc_test.go) - * [Fibonacci](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/fibonacci.go) - * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/knapsack.go) - * [Longest-Palindromic-Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/longest-palindromic-subsequence.go) - * [Longestcommonsubsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/longestCommonSubsequence.go) - * [Matrix-Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/matrix-multiplication.go) - * [Rod-Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamicprogramming/rod-cutting.go) +## Dynamic Programming + * [Binomial Coeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/binomial_coeffecient.go) + * [Fibonacci Test](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci_test.go) + * [Fibonacci](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci.go) + * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/knapsack.go) + * [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longest_palindromic_subsequence.go) + * [Longest Common Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longest_common_subsequence.go) + * [Matrix Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/matrix_multiplication.go) + * [Rod Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/rod_cutting.go) -## Genetic-Algorithm - * [Genetic Algo](https://github.com/TheAlgorithms/Go/blob/master/genetic-algorithm/genetic_algo.go) +## Genetic Algorithm + * [Genetic Algo](https://github.com/TheAlgorithms/Go/blob/master/genetic_algorithm/genetic_algo.go) ## Graphs - * Depthfirstsearch - * [Depthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/depthfirstsearch/depthfirstsearch.go) - * Floydwarshall - * [Floydwarshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floydwarshall/floydwarshall.go) + * Depth First Search + * [Depth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/depth_first_search/depth_first_search.go) + * Floyd Warshall + * [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall/floyd_warshall.go) * Search - * [Breadthfirstsearch](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadthFirstSearch.go) - * [Breadthfirstsearch Test](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadthFirstSearch_test.go) + * [Breadth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadth_first_search.go) + * [Breadth First Search Test](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadth_first_search_test.go) ## Math * Gcd * [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go) * [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go) - * [Gcditerative](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcditerative.go) + * [Gcd Iterative](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_iterative.go) * Lcm * [Lcm](https://github.com/TheAlgorithms/Go/blob/master/math/lcm/lcm.go) - * Modulararithmetic - * [Modularexponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation.go) - * [Modularexponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modulararithmetic/modularexponentiation_test.go) + * Modular Arithmetic + * [Modular Exponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modular_arithmetic/modular_exponentiation.go) + * [Modular Exponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modular_arithmetic/modular_exponentiation_test.go) * Permutation * [Heaps](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps.go) * [Heaps Test](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps_test.go) * Power - * [Fastexponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent.go) - * [Fastexponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fastexponent_test.go) + * [Fast Exponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fast_exponent.go) + * [Fast Exponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fast_exponent_test.go) * Prime - * [Millerrabinprimalitytest](https://github.com/TheAlgorithms/Go/blob/master/math/prime/millerrabinprimalitytest.go) + * [Millerrabinprimalitytest](https://github.com/TheAlgorithms/Go/blob/master/math/prime/miller_rabin_primality_test.go) * [Prime Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_test.go) - * [Primecheck](https://github.com/TheAlgorithms/Go/blob/master/math/prime/primecheck.go) + * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_check.go) * Pythagoras * [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras.go) * [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go) * Sieve - * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/Sieve.go) + * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve.go) * [Sieve Test](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve_test.go) ## Other - * Maxsubarraysum - * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/maxsubarraysum/maxsubarraysum.go) + * Max SubArray Sum + * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/max_subarray_sum/max_subarray_sum.go) * Monte Carlo Pi * [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi.go) * [Monte Carlo Pi Test](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi_test.go) - * Nestedbrackets - * [Nestedbrackets](https://github.com/TheAlgorithms/Go/blob/master/other/nestedbrackets/nestedbrackets.go) - * Passwordgenerator - * [Passwordgenerator](https://github.com/TheAlgorithms/Go/blob/master/other/passwordgenerator/passwordgenerator.go) - * Stringcombinations - * [Stringcombinations](https://github.com/TheAlgorithms/Go/blob/master/other/stringcombinations/stringcombinations.go) + * Nested Brackets + * [Nested Brackets](https://github.com/TheAlgorithms/Go/blob/master/other/nested_brackets/nested_brackets.go) + * Password Generator + * [Password Generator](https://github.com/TheAlgorithms/Go/blob/master/other/password_generator/password_generator.go) + * String Combinations + * [String Combinations](https://github.com/TheAlgorithms/Go/blob/master/other/string_combinations/string_combinations.go) ## Searches - * [Binarysearch](https://github.com/TheAlgorithms/Go/blob/master/searches/binarysearch.go) - * [Linearsearch](https://github.com/TheAlgorithms/Go/blob/master/searches/linearsearch.go) + * [Binary Search](https://github.com/TheAlgorithms/Go/blob/master/searches/binary_search.go) + * [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search.go) * [Search Test](https://github.com/TheAlgorithms/Go/blob/master/searches/search_test.go) ## Sorts - * [Bubblesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubblesort.go) - * [Heapsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heapsort.go) - * [Insertionsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertionsort.go) - * [Mergesort](https://github.com/TheAlgorithms/Go/blob/master/sorts/mergesort.go) - * [Quicksort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quicksort.go) - * [Radixsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radixsort.go) - * [Selectionsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selectionsort.go) - * [Shellsort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shellsort.go) + * [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubble_sort.go) + * [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heap_sort.go) + * [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertion_sort.go) + * [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/merge_sort.go) + * [Quick Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quick_sort.go) + * [Radix Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radix_sort.go) + * [Selection Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selection_sort.go) + * [Shell Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shell_sort.go) * [Sorts Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_test.go) * [Sorts Testcases](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_testcases.go) ## Strings - * Levenshteindistance - * [Levenshteindistance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteindistance/levenshteinDistance.go) - * [Levenshteindistance Test](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshteindistance/levenshteinDistance_test.go) - * Multiple-String-Matching - * Advanced-Aho-Corasick - * [Adac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/advanced-aho-corasick/adac.go) - * [Adac Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go) - * Aho-Corasick - * [Ac](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/aho-corasick/ac.go) - * [Ac Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/aho-corasick/ac_test.go) + * Levenshtein Distance + * [Levenshtein Distance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshtein_distance/levenshtein_distance.go) + * [Levenshtein Distance Test](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshtein_distance/levenshtein_distance_test.go) + * Multiple String Matching + * Advanced Aho Corasick + * [Advanced Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasic.go) + * [Advanced Aho Corasick Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasic_test.go) + * Aho Corasick + * [Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/aho_corasick.go) + * [Aho Corasick Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/aho_corasick_test.go) * Sbom - * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/sbom/sbom.go) - * [Sbom Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple-string-matching/sbom/sbom_test.go) - * Naivesearch - * [Naivestringsearch](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch.go) - * [Naivestringsearch Test](https://github.com/TheAlgorithms/Go/blob/master/strings/naivesearch/naiveStringSearch_test.go) - * Single-String-Matching + * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/sbom/sbom.go) + * [Sbom Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/sbom/sbom_test.go) + * Naive String Search + * [Naive String Search](https://github.com/TheAlgorithms/Go/blob/master/strings/naive_string_search/naive_string_search.go) + * [Naive String Search Test](https://github.com/TheAlgorithms/Go/blob/master/strings/naive_string_search/naive_string_search_test.go) + * Single String Matching * Bom - * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/bom/bom.go) + * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/bom/bom.go) * Horspool - * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/horspool/horspool.go) + * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/horspool/horspool.go) * Kmp - * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/kmp/kmp.go) - * [Kmp Test](https://github.com/TheAlgorithms/Go/blob/master/strings/single-string-matching/kmp/kmp_test.go) + * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/kmp/kmp.go) + * [Kmp Test](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/kmp/kmp_test.go) diff --git a/ciphers/caesar/CaesarCipher.go b/ciphers/caesar/caesar_cipher.go similarity index 100% rename from ciphers/caesar/CaesarCipher.go rename to ciphers/caesar/caesar_cipher.go diff --git a/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go b/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go similarity index 89% rename from ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go rename to ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go index 11e8183d1..8d82b100f 100644 --- a/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange.go +++ b/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go @@ -1,6 +1,6 @@ -// Package diffiehelkeyexchange implements Deffie Hellman Key Exchange Algorithm +// Package diffie_hellman_key_exchange implements Deffie Hellman Key Exchange Algorithm // for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI -package diffiehelkeyexchange +package diffie_hellman_key_exchange const ( generator = 3 diff --git a/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go b/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go similarity index 93% rename from ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go rename to ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go index 2b923920c..6865f6c63 100644 --- a/ciphers/diffiehelkeyexchange/diffieHellmanKeyExchange_test.go +++ b/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go @@ -1,4 +1,4 @@ -package diffiehelkeyexchange +package diffie_hellman_key_exchange import ( "crypto/rand" @@ -20,7 +20,7 @@ func TestDiffieHellmanKeyExchange(t *testing.T) { }) t.Run("Test 2: Key Exchange", func(t *testing.T) { - // generating a small sized rsa key for testing + // generating a small sized rsa_cipher key for testing alicePrvKey, _ := rsa.GenerateKey(rand.Reader, 31) bobPrvKey, _ := rsa.GenerateKey(rand.Reader, 31) diff --git a/ciphers/rsaBig/rsaBig b/ciphers/rsaBig/rsaBig deleted file mode 100755 index 9caf7ba306c976ec6f84cb44357eaa19ba88d0dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2514312 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

^-)`GY=&Tbc0r`~? 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

owmRgeAFb$2+LAjeg#PnJ$7D@IAg$ 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

vlhOMBb;^E)8K3&w8lM@jnGP{t z6B8$DqV<2u6e>`0%DF~0;vgVRj5z(!{l=7^x${R#$h@DNLIQdvr<=*>v5Gw3ocL>^ z5n>(IYIXsw;q#)?f!6={8x6Gnw`(F3F#k8P%wKM~F#n4|IfFD295fp&uOMG&GGN{x z7rZ{GiCcrWgY~OEyIvEy^|@eq)smK5!qUSgBXK5RKHt2nkfO)^xrHR`C^M5ICzYsA0H%9EIj2(;!86{2By73Q~_lrsU*O2{Ix0DC@GDpFX}ar0292_ z(Z~eObTPtDT9l-T>ZBU5ylNYsYtY1p4WEMLrA3a4)I?F_DPaAoyYg;Lth;+VSigwt zsId5iNax*GiQ82U5Eq;T<7&?RF_$;UJph*1u7f`u)I~aP6BbfZ7AI7LmnJMz zrRLE6VD`LhO;lx9gI8s*0=K<_VkCJvPD})siOSY|HGMrUF0<~kEQnh|{(O-1fhvXO zT_G+>yp->o7|034i<^VDn61ho59|cj#K(@PhYrTt-eP=6s&;$SFBy;n4RblZ1io7GT2=F3QEq2kTw zcb%?@?*Vzg8TzZ@&HF*x;&RmSJJ3<0FuFz7_Zo6n1eVGY#ZhNbXXo=#@`=#W^Qk5qwp{v^EPZ9r*S8gXlOWNJ9rSv`v$na%5AtCJTFbJTDxeo$3 zRzT+g;rDA3KBi1JC42*JPS_{;q)>P%jMYR8AfJhY7AW3K|7QMwtK6EQ``X?2lcOU6 z`FtT%LU{a*ZcTgzNVk7Me^a~}zW7=b&ja%Qi_muz-+G^ZWW4I{ilHYd-n?Jy)WmIo ze0~EIQ@w5CuT9#-+ip&J8N5rcf1f0M8utF5RncydXKTj^u>^YHp|;NpTCWV%e`Z5- z6>r90$N#@8x0j%Ax4XaDrir%znZEa+2NZ8UU(5enm0KOOzTJI6ex|5AO@~U5VVPHL z3}ph4Zo8nLD!%o8Pfa`u$oo$~KUTbXe;4KHYgMM2q5BkX-WL%*B#Wqs$>6CG)4`>f zQahA_TE52<>YFq|UvBq(8tIpQ1mqJTsDwjL(;xTH#EXD*+Xa1J@n-zB{iZ`FHqjmjB$$ufJgz)E69g+T@lA`nYFPHG) z-!Co^6(Z6f#hw19RIYpZnD=Qi-;cOAf2WBDUFOq5#>1x~Ml!&d#AN$iCpZJ@I|8xJB;Og~D z^)ZD%c{b8XY4W+?Rmqow*CpQwu1mfTEX2{;GRFY>im0=qEaI+&yQ%-D`>S|9D`P;0 zyg%Jq5)&O+8uLiPagIk5D*T(BbMxv#V_t6#?G4HMC8E&ZlwRaN&fh}}ZW)3UGPPwo zxG+?x-+x*p`Ddr6`A7NFgf+*WV-fBgUyfCzH`)}Si12V%2?x3iLU2Xp0UYl#g&)e~C z7@_uC{Wibd@9;}lC7(ibINPl%u@g}8h7jiRn0?^&_ zO|%t1sW$l+=&y=D01YX=HL?yEZ8M|42aR}&p)(YZJsoLNr`z}i($g@qTBfrIdc5LG zq4N~qLA0$-)kvIc0r~tj&<%>Ohd!qGR?i(Ub+p%yt2TQJbf@CqgoYH~!DEM<=$|G7 zGXCk%%M`yBdb{EedG3Hq*U^e?0Oa!x(03ItCE+g>-_`Si{@^6lC!7L34Ujs9+0YW@-qrK9jAb7J zWc-cLpA^3z8d7|h&m)grtz$JdA=xeJR|GI$mhY2COyszNFY!Zq7Md>O2R8pSqAL&mPmK=;h30IDnUMe-m zulG`&hj4iRW%U1D_hMn;eWQsffS!KnNs6BhEm3@!?@n1WmrQE*KkG7S;QqvA>g7zY zP2-b|=YoowH#(taBqpsLW<2LVx$F4V#QP|JWf^;t=K5=@{N?Nqsj2WUu2|upKGR<_ zUv3w{#6`zfq;gjFI!wDAhtZCo=Bx;HBUVvN`{xwIv{)n9cSx=2<3lN2@e zpKYHy^sln4rfi{KUt}}N&(aCMTst8b&-&+7um`20)vdD}uw9J&cbP30nXxu?H9gM2 zw3TU7MN@Vt8(DGv?MQ(+ExD$4=upIpyCb+ih<-2_0ypP{@)!l>x8(B`2hSRetQ)GL z{w@jK+G#C*L3>rR($TI?zdr5q^tI`lxFP*^@W%89z+2K^OOFP~xzl_QW?cq9_eq7|_Hefz{xMU?7+*dIz(3 zqY=ST;IG#IKrVEAIf4=R2!#0-Lmr)q?`c2W4&JwDKeF`x_rV=s;qt$f^_qGLU5foT zTLHb#k};U^nDwWzz^F&1v%0QFX8kpvZ&LE7`F!y>w|T40i%@v<%cW?f3Mg99SVied zJH9A!P9^8Kp~DnE0y;tQ#n6R{KP(X1-5VKc=)w0v(*{Vs8d{_HTIi8|m7jJ2)J4A# z%?L4i2S*FYoHwAYx&q$c%$N4h3v|mC9nj4}(*YS)Ei|O~X7s_Ks6#s8HerO7_Q?HFl=GPV zar-Tz$Nu#F9ue4|0pDkT=6TO5kt6qrh(9XCQ_IQOU$KV3AB* z*mbr2MOv<1_HV&I*na`19T>*Qcf^4);DQ512P|UTfg{1=4@?9fbzr(NE>>YYuWi>X z;zjLc@GIJD;2*W0!L{j^(dMj6{~Ne2eFOO6^uN;<{haOb2*A3e*gX>9|MW8pT}2}XQkx=P2fimLXYjbHw>kKe5SX8fh9 zJt&&QpsIt*bTq>;$Io>$jdmw`ib1Pqv}=b5&aTF3PADg*>us3_I#jt2hmKJE7-%72 z#v`_%aR6le)zEVlUkhEW_;t`56@Lr#cE#(j(WD6nAfIy zpFdnbZl_1EwDt(2Wx)-rBkg;H+E`6o3ds0ZL)QSZ$-Dyk7v;VddaL4Zht?}z#xKsG zodo3b#n6)!e+slr@#WAJia!s!R`K%jt*&=nNut0r%abIwdfo*;=Y887C*JWE_~wgQ zzMa06;#1$yloNbje@?J>bZ+prP}R=cL$`-yj6xJJ?=TCH^2%l!`DXwh`~&C#E8buX z`?L^?p-Tbzgr7ELm12qhFQN4SlyOSd0T$mqj z?a(mZ*5)$fHPdg(0qx(ze5if;&F4)$nfbigE(8x6?Z5?*7cz3YIPy{ihsz?@z+V}8 z7x=BCjQ%Qg&iXd5cH*LOxZ>I*;Q%AsjR982;sT zQXL;Vo<*1ax$`Y8GSTBd7~%CxjqU(l?_27h3ty>gM?)?9Li@%3(1C8l7g~3hMUy|y znvq~59TAveXPT9xud(3gjxfJW=kFlznBU*bPxJek-{0&H%yFIhJ=dMkaevf4w!^|# z<=70TNYx879vu!km;TWov--Qp;sw>9rS9&UkklK@paI8#kWuIq5uCu z`>>Zb1o_9z(?ek%;)-aCk5ujPwN;07Zc;BJ=Z@sFUqFW={~fnPh!IdzMwH`zbL@X8 z#J1dpzKf7LFY#RuzRC9>_+j7E;Aeb|KC5`vw;lc!T6w$J<=YMaj_*C6MZE9(6#gsU z58$7CzkoZvyk4|ik=|%~f%_*_@G-c8QIYy+epxxS?Y&_g7D0zem`i~fXduICA#KMU98H4^rx zD*RHyUZukCP1r|v6Mp#mi}3m1I%JT$lpL~*zVU3;KgzWpvX7K9aR3_LS9X*~&%VQI z6CjzJ2cSLQHTa>>>58v{Uat6h=-(CJyob3npsW0;^xyri^e2sS_xWW4{_)+hZ z;4R+g!P~trfnV|N0Ke^h2mFb*$!igxdB1@F%KHQON3Yb39)5M!KF{=@OSI5alW`q+{0V0wR;@riWYq>(@(CSUCfrcesupP_IU~;Ct5yCsPn(zyu-iE zkF>e*kAu%2zo5kyx|zj$pV3PHBlK05ZME5vn(t`#duBUowsVa~7;?DTuA1$f@VAu* z+UJxRt{IQn4>w-JkcX@I6yr0l!(gxczZpa1lGg4wXk82g!Y(eeeOAMDVW!uN$4saB zK4Q4>9>wPy{rI}m+sXARu3Fbc%iB#Hi8>mo52sc9&_24zjzXUi|cvt zi>{Zzuex3bzw7$QWfvd2K6N2;xxT>VD_0A+?R99q)c>q67VpW`nVt2>7q~A%@o|a! zFW|NAtHIa0H-a17o52sc9|k|_eiFRJ{Q~$!_sif{-8;a$+)eIi@tOMz_^;eQg7>*Y z;5JuGCv6gFE^6%NcejIIefI#kF0_@>_+02k z@GGI6;5S3>fQcN1I!y7Spkn}8cE>^s6<-8B3Xo|lhMuJO@bEQ{)x!wX;{``~qQP;V{@?+gAUNMM z7(CP?S00V=j0Yd(nFOBVnF>CEQ4{NdJg0$6Jmug@&kAt(bsBlTow3jY689qXB|!SP zf$DR_8I+@9q4)o?zrPhxP4@Y+znAYaCakX?{|&t<&^B}-F7#YPjF))UfUokb17G9$ zEBHpwP2gKRw|Ok$cF$cNo4DJv5nS(S!2N#Dli;nM=fK-NFM(h2>;Ug#1Q;Q{^6ZB< zuE$yZnq+yyQsk(z?vI!ld5mLwq&soE>&V0n$#X5kQqM`9And`s;2@D797-9!HFz8N zk6;V9XPtNb@AjSbU)3jw>V}US7Kxu5erZ4-8mewrO3hWmhwCqEO*ygMcuLGP+Mo9F zs3|`-<{A}Eb6a6J{0SW8jt0lM`-2C#gW!DkVDM1)Fz^WXNbneUf!iVq-ABM5<(>qd z;+_gV)_szjQ^MV+!q0YB!q0P`2`>N{gUl~G)S-AUG*0n7p$Uplf(}*u2XV)N}V&uKq@&s)}qvcs}ljTeB1nb$>p<+;)l%rRs-JF&oZb{n) zzr?@FA1T)PZ}IaT1FHg*nLgj3Up#lvd4ni#>u+6;`-Z(6R*QWbPTf>)J#ACTCbKN5 zBGr~ucRc4P*GwH+EA@X@2A2skr$@}Rn&r;apPA*#?6+%GKW>i8TlIZP&u8|NW@QrEv_$~+1LSSR%|1N(sUuQrtn>u)7@FuXazSrN9efT_%!$zDAhX?F) zB!g2Oeh2z1M*Xl-$f&63 z=$M#Tt~jn9Ts^tsxe~Y%xste&)s>>IRCT4Pt5>@#z1?+KfoSWHMGrYdoF_&{ZH*io zbxV9n#60&|V@=S}^p83zrfcPf!2l$J#ZpdO3m-Qj|U{*#> zKU?3NtQ=;ggE8nPdj?a$y>zWw!NJ6q55zEZYZfu7<>Z!FacawKcvom_XoxrsJ)8MO z+NSH!KPT;nT!>U8ibbiY7PVrXs1ut-qu7O&|7MzWzgDD`YPB5e-KaIuwG~-vEsYjo zt+fhUtxec#?ZP1<*eK$vbqjB;x7J6HaZIfy)+W^^ixh(Ii(t{eb^y@~<@l!}F{ySk z(H$>JYfsmsJd~Vv+-%Z>9!Wev1doU(giSnWd4cxrP0Od?f9R{vzqkCr8IjGF5H8ED z7h9vmCDv!sN2G2`e>R=fkLf$XAE$o`{yzN&@WJ#Juv$&MA%24<{2Kz`%Qvh6pR(zp z1G9=B*6Tn)s3>F+UxdC0>4mOc+QR>u^Tn;Xt@<}}9AVan#<51Z7pnacs(&=wA+x@; zuNP*0s8#a-<~d*HIi=>gnBi%Xd_d$1DajRqPZ6`hrQ#eu$+?WGG;xR60Io-WYZ3SI z%`M_VG`V)MO}xt~q`!-3e^PpkKhw|JLw^ByoPQ?xc>iqhxF-W+);RNLW@J2*fOzAi(#a+KdBl_ibh3kiyRYmGxa0c-^}$E3~lKphPNC^{Wz-SBQp0D_5ylFK+UsvH zZhZEuF?4+8COL&C#Fw7qERueG<|KV@K=eJkzn1^&mQG8Q6O%<}NB=A*`f9h|eg0o$ zB+pj;bZG{3&1owqloQF^4G%xo#1z8Um)kO4TqBU5t$>W(4)rQN3L35WIB0*x4}b<0 zpAQ|Z_@U5|iXQ_VulS>&lN3J%I#uz-P&uz551^AWe7SP3gf3KkHMBqh5yC1kDh(0K2m7*{Dh>v(tAF-krREh(X&{L+ zNUHW<@2K&gwQU{B7Xi#-SU{QgHYyR9lxJpDeeo0H19=54?&N(k?Ew zuC`jl<<>R0Txq=uey#Nm_`9s1ft#%%aKE$xX^imF%D|PnB)Kh3q>t0I^q#bziRo!z zfBFRQr1Yua;`CYIlhRAlEuu92Jowu5N5GGzKM&rX{ucP1^bf%w>+SGQ>A%4LrnkoZ z0u`GI*BqYyam*?+6DH0E8?tVrcnAJH@f&!rkaDjf@rty*q;pW(so*(jQm1@I+6wSl zX32Y2Ao-skm=;K7{fJySQaWfAGH~w=m(dGcv0)qdxeeRFzi$YEgPTr9 z5g7asm&E3PD=zb=8 zXiO90$z`#Z$6ghCTdXZED=sf?NZhEnlY5-n!^OU)jj0i7?zGWq1!O1yd(_*7Z%=sp*thFGh-m8F)VImD$G<0I zPyaoG_l(#xYR{xSllL66r+ClIJtyutdC#ePX74H8Q@-bnJ+iyRzQ_znA?9Sli^_Tevnwf@3ztgZ-QOf%|XD0k`l~7WPnu0O=kOIl?Cj#pU+N_Fj&3WcS_3T7!fZ!O>b`U&L@{ zff(r=>$Hgi=Ui7mt->`q`X7!d(R1Pwtn=dLldFs4hbFuzh9y`NcL-PF_@vR=grtqh zE@SY#Q z#{7e!pRV*(`Eb`~Jc=VvilmI_bBz9|EL!5C=%b@4q0u*jjlE9BD(8v%E{a`A@3Zc- zHf(o9amq>L$L5qL!A1Js!s67E$Q%FqEZ%;Xu{*WiRS&Q4Ol+>-2XE{zGjSOZlXkg5C>O0FGq}3Y6=MMIL6gmDW{^9tF_x>f~SKfPnM6%N_`Z)XZMVGiHM!s#^ z9{ES~Fw46MM&e5;j+}vO=FTeE~+wiE+9v$CY8J# zx3>Rpy32cVRNLMC_WsT12{GUGGUHI+eGvk$U%MrO?e9okHgwy5rczuyk(J`@c zJ$l9`Bqk-Nq^9*UibvmmnUsrxgR*mSDFTCs3>`Ln#K=*j$BZo~EE;#jk>e*!JZjR> zlcyXrb=vgeV`t1f?)VdCop{p8r<{7)?2^*5IpvsRoi~5M>1Qllw79Bz$x>{1ow;J= zS!bVf?s@00s=eUCi!Q$8(#uv~zUGQ6|8mvZbyr_=?R9^>{%<$jc+<_d+|X1Vbi_$-T%Pm2OoO)kw+hU{D~)@dV0$-h6BK+wZ*l-uoYX_|eCoeA@Kc=U;sJkFWmu^*7)C>$~sw{LuX4Pe1?i>uNtbOdM>ki*e|T|h{r}&KUQG75vZs|)_OjvsWltOazx{pL z`*wA|yXR$({hvJlpT^((|M~jyKfWwoUU9N;n^%U_I)q|AJ}l0GVvLAk_NajGAaxE> z&+s4`hIi2}_{DElha=h&;c(LbjrY$$Gkv!ITtBPm{8xe#14V)UVq9Q6viX$2y1)c+ zb>KSqn*uk3>jLWoR&jse^?+aO47>@yJMatquYpi+dg_co1~F#bjOO5$jECVr%J>ZY zc;9FHy2akUp}y=->erZgtoCf?^O?;1W&Q))oEZX(tP8Wyyk@-%{wV7JxFstzfDypJ z@dJ^G1|9>>IxweYq;+mfC31}?lp2Z=X`x=onWu(kBVm3X`UY9?+t7C%jtR`JA)Kx| zc-8W^o?2g+829r2-^w2={PL_1t~~L|#=-dh0)*UH_e>) zap5kpr{lmV)mJuXpxaRA~RcaN)0on{IsR`@&_X&v|(J z>OFk*YD+d?5>Rk`IKH)sq zEO(xJhY>& zKkdZylhaR4pPl|_`U~kFrT?0~)}K45WKh5C4cQN5Kc2lU`^D^?+3#k5ntfAF5rWU! zy!8A~{_FLj`piwan}#14d!X>Z5eFt5nAtL~WqHd#Lx<;#;S#c09C>+! z%Fo}?W|($@!uMMKN?r~p59J7J1av$gb<;O2Hr7o?Ok}My=v3uC4LTi=aUBbt zq4?vVvj7?XNzgJthBF5`SMl?prvviYh0vvnuYs;m{8`X*6@Nao7Legw0KHtfUje;Y z@pnM)Qv5y8dc|*oKCSqU)>{R{Al6Uhpkeo-=P5+KIp2Dj)x~)I?{?fADUK-7cHHic z;EP1;jrfkyd(b&tkm_kmfZ>OfImpEB=#59L_77)ndkzKPny7pc4OEG|1>qiFQoi*Ho_m5b4-p$ zOv{;`L*520LHa%2l9{h{%#U`m&6xki`WwVc^)J_>$I-|9pEfi%#E2go{lf~17f(Y2I?=IS$3v&Am!QtKPmH?4BNOS3ga{Am5fY8Ag)u=9v_KcPF{;R;d{2zfo^Z$eSg0KAl^4rCC{vU9$1R?@<;SR(h zCG-p=1#BWYkOto;&>uc4FbG*8JCGZ&h+rTO_rZY?;4y(h@Pxq8;J*fL1m6<49ehXN zPVn76e;oKS5F!2%aAss^ zt_%>9kBFIC!s20kL_wubKv zL?fT4b)$_pG(^UZLqjwF?`Vr?pgO$d=xML6p={Q5lT9I;XA{kt9Gx_VZ0;RAWp`}? z+dLEzWw42>rz=H1rTg(1etdUGKfar#yY5rhsx~>jRk*lx z{~jaW$Y*ikxO?eS_wUhT*EO$=9%mZv5x(Klk6q3eId%U&-G4;nROuceQ=)5UYhl8! z|787f@^0E5fDa?4L61|soM)V;_zR&oEB-O)lZt;D`V1iZG&%qHcjf*9bf@CKg<9V> z!tVtguJ{?yGZcR*^mfHR1$|5Ld!P|&p0PJ{wBk>IRw;fB^d7}O2mL_tA3;A;{2$OB z?;2@{ho&fg7<8KAi=oFWz8bn(@oS)K72g1TPVvt}Usn99P`QqK7J^v@wEcQ+X%A=@ zAj_7tza{M>y#yaF7d9gw{;FieQ6A)DKz@^Odk*boN7H7?e=0jlnNh|iN`<;Qvakuu~9fOP*)!J0EZ-Cwl$Z+n5KC1X#&~FrPqdwRH=_dl}R=f||L-Fy@RK<^g zj#T_;Xo2F3pyL%k5jq)=JA9@@wJznwE(90FS z5!$Hu&!PJjpGut>qUz5H(8Y>h2i>UnSD=FWG>m$sK|9-rA=f7VgSunKfS|PF)|*+F zF=TcI)U=B?k$$}xka_nc((F@etTmW%)DS?rFM~D$vbB8$`kHbdO1&7S>c}@x)7G3^ z10d)6NuKCzPXCA=thohb{yqo&J0RoQ)|0pZ$rr{W!vQPcABRf&Nj2~zk)lVbacmP3 z#t`buakxucpVEHT4EZeeIG%sR2bOIp5{2R3SbjF9g%#YAt0O=m2UJO%pB-}oa zT+?l?$>Hh^I?Dt|2xLUKLC>7_4OfJdEsl1C-E&O1JaLvN#nCz7v04N z45QJ?eYD{$OuF|MGJ~s0BCaMKGmbpT2#1wl`u*$W1f9Iv{cjAAd0Zosm|Ej1QZ)K9 zr#yPdi6ADor-V7eB*!9XoDJwIJ8ctc7fskqihhkOgd?~ z;cnXNFsb3||2{U;`M)2NvGS{w&vFhcy)@Q(JqdoAHC|{UbS>y24so$hJ#kZ;7QET?3{tW&#^>^_8RN;46HNVHt-YK=mvKqcdAL-TV zBfUC(SC0tvMN-cUWPt~%k=s=G>1rj-74Yi<{phWV`b-9w_A#`%%LX!T9r#!94FipJ zYI20zY}nup+8F0Lf=*V6xzw7q;kb+m7J`j6f_1?I!Bbchzb@}OadqD9d9)sRUx5Ak zTAWq+JM&o;F*r0B_o<<&d`W#Z;c9&~VQ}Nfjm)6e@2tOrm4yWdzc{w=V06nHBBmv& z1&y*ABTFsv{FXDop%xAOu_feZgf^PhhpZaYZ77*@tWBYD;xm0O)7POr+}#&C*gBT$ zsO&^&$e4gEU(2B@6~6|0h2lTsyB`3gA3u$mY0vUR(j%K)>ws^{e zX^T?YGJ6J){u`kk*)=PozcAO#p9gVuAj9;bL|^R5Dr;eSRG@CzXMQS<|&0m*+$88&T1o=k}~ZJ9{hmAe7y zCw#wtEwaz`fOKzqlhqP{o1ms{ z_BQx%ncB2{Bkco9xmx-U*V#%tr&7LNf^hO@%tbhQqG^mJfYw@Za*$arv;iM!QCc0#_03!_lr|z|&mQ!58ZLLbtkP+ivdp zd=36xm(@K;6u4#Eevx~td$ic*ZiIi?{VMyiUUOSK!-UmS;2AB7JV&utZIWk-$109t zC!UA>Y};sAo^7+M?KNE9^=RG!!s4}hS!b#5OTW;25&TwfBfFHJ)%P&JsP-_wio3Cg z*`ix^D)1HgsIkhL(=qU~d>8r#ii_AYe++x(-@xTPeYgBizMtU>q6+C5Rz(erzE=#2 z&WpB-5z(Wgtzt~{3DL=7R`i@`k0_6xOKUbSdJ*`d=!?OZMPCVC8+{XZZ;rkN{;`Cu z2~M#s;RX7T7ZY9rXC(Eb4ariLeDmN3CyfBh9Vm?7l4m7bL|JkzibWKpj6+C1GG#pY!jwBw(#86e4e$*q|4bPxzD@ZKeox9zDK_zQN}tp` z(KmG8|zu&*AQ$V%?(4qQyb1{$Pwo?{HtNH*wgR>F26Q>v1yO^a?@9+ zCI7kU8}PTAz5}mE=46&$-&=5@?JstZc9lKSQ7fVxpE!1kZyX05Jw%J+w}`!BzpL7F zruMUEFJFAWXO;I7G2M5TZ-CIEtbCEUsGe9Tj*m)!PmW3l4~ZIq%hsqD;9peM;&#Hn zt;?df>303s>FY`t#TO;LW%)$6YhIReI=NJ1oG%j40*u}Q4zM%e0`~~Sqq|QC^g?T& z9>~C@FVdz(MB?~MN7ff?t3&&#+8{7A-!;LkG-Nwc@;`}Bl9Pw<33Pw-sd-=(rw*Zx=cn}^>2 zy3B20VVp}dFn1th(t#7fQwO$}f&Ve++d=4v4?7*ekcw@=*kGiHLmu{tVL>Sm7wGcv zy1c9NkZrQ|d-; zT+vWqS=n$FrRd_)y7)HRC)I<^a;n}Hno2cZuEvd?=Q z`h?;KAwx_6q`f0~R=|b882E>wj{?&FHmKA^NPZA9Mh+nPeCS}sOT9!BAa(AaK|fdS z7IYHkeg|n=sSuFQj)Qi$XF={)m;*@txZJNW6q)5s_+ilDN~S4-j#K;u=w{#y{5%MK zNVz`=eHxH?vIV+Txjze)cAfU%z8U%;Ak!x8zCW$_tWUG^>N`=FxVE^ah#jsm z?kX|Wy#>6(eb5~gExJX6G3 zd&$${p0mu3E1{gfobVPU<>Q2rNvCR~bQ|}}mA(4S$$8?z#(HZ#@#i`dikgiCfnvQNsXVyPlUn&~w|54vpoYQa~E#5Z$yrJJ3PT5q!-V(Xj`aAusnqCL| zEf#A)x7=#%LNql1Uxdbol}2NKjJYS~6Iph(9L*x~wPE0q+EL)i+DherDPewM{dVFrs>cRJF_k$nM9t1z6 zJ&Az3p(NbNbb}wzB zj_tI*#|n%Otb1_(#riw*c>ApTaX)CyrM{K2XO*|MHG-f0KkU5+TogUmK0Nde3l^Hf zq9{mFK(J6`t=L7ei;BG~*bwU~*codal&fO}&{Z6R;fs5r#9dH59S49j=_kFoJ016ee*)TZ(fd^Gh{|?+4*Ii7Q*K!& zHz!@e-N^^NkXQ(qU~WWZbu7Z8vxm0O#iJ`~XAh5lp!<77f*$BG#6w3I?I8y}&f`A# z&pckhf9oMjY#dV~u`l%F$rBgDFO^h233Vf>Km3@aQSe76O@Kc&X*&G)q}lN2C#Aw) zo3sJL-L#~w@V6)J2j@`I5%@=w$c`v+&l9PJ;?AsX!d<})bHU=CEC@XdT3QwGj4NtY zhVQRc7k&e+X!ygmM#CSYCC9Um)fx|alGZfTo7r0Pv~=)QSPcF$trehGX|2K0WUcjD zdN5+M6>+v}?E-(F)&cO3LhmO^5PCnMQw4fIp(|MH7WlWdUcrA09iVvcwZ7o294$xG zq0-tF;Rk95YwHLy?HZs%w41;W)ozY@)>69_{5IO{zzNrm(1v`9b~n)7wR^(vrQH`t z2WUru9;iJ8DU8AnXdPjkb}aZ4wWq$zL9Aj1Jp2y zYVV%Z(FL@ZV`ca<)egR<*t-XL62~6kM5^}gr8#Z_z27n2(Mq`BnCWOC+;e>Bs4Fyf zigT(&E#P(X=;om-boc0s+BV2zC~DzYj|ZTid%T4I&O`9Tn!K9!-Rg<`Pz%Q2z}beqc-Tjl6t*^AN3qkf=i2|8)^4Zc z9@Lu?j;G=0Z`*Rf5oNPXoXnh17oDu&=aC2bm`?<(KOq>(QitN!FyvdNiR|0t>P(T@cxif3ikRWJ3PcHEJS5!el?x*O_@a z5Vq#b%Ym@73twr;4AZ%Tlmjfa4AEXS=0hzq;A30XBOf<={s#j4bp)|^`jNk&_ z4I^i5=!@{j2vn41l?manXh5_?=nLD09f)%P@~sE7C+f7-%g}14*AZW%$$Cn?%EDp2 zW3XNIPNl)yNZ%M^6H|RN`1bk^`Z|K6esBE-LLdEp;IRFx#BSIpgD>z!>z_;lHqyvM z_+~WJI0kDE(WVo%;!NM0MQSxMZ)1q}N>Pwnne32uG zDAG;)?M2jLr_V~8rT?POe#vuigsibc8M5qB&#fBwY87HSVOco8&Kje=~>aD zXhwwl&=auuzWE5 z>g8)f=S3|lwM%qw1Yx~$e?HmWL5ZUiO@y~9`^AIRBzQk3f5q4&H@SR@4|ec&Oz{#9 zs_bowmNrF8iFZ`CP}y!?$@enNEWa1WN~P_0ukY4EZIxD!dfyv@qb~8=@p~t5dVcTy zU0cAqX5M_PY3k%*J^=ckAw7egz}kWZE!0lq)# zCgxQHab26}pX-Q~?Gn(jvqEr2OYLT!!qi@gG)RZ(cOiAPHm$22K&wky z8>(cNMVoLvp{?k5(#F54;bOfNWy?hkF_x&SMO9jiyu5-i(-~=ON~)WP4g_^+vVBAccd%wL7;>4+M%wthrSr}n15s8Nb~rJ zjEt(NMn?7ic4RbNYc@te^RyOWEVEcEL5m+Br6QfR7$s@v8zt@5+K0a9evFkcAA|9c zPQLNcYmAQ|V^7CNWMt&4T@|C4UyYCEfIm-rBmAGoHSs#@bV>;83ox$9)$!8x6}&6lfYZ zMR^RuSZOduPZ%?LjKG&c97AP!JohjZUcxdm=1~834CR&Njj>Y2q$rG%1||&yoqs$v z1N>P@bKuWSnunv}sA^-aoJ6Q}n^0TLDh(&1Ey};fTt* z>e@e%FR6}k%dhO6sPAd}zb=EKz9+As@+kjg-=4b6N@4f#F?koVhmXm-sN3$*w1-b! z4n}}X1G815X>Z>@m6cKN+iThjs4h>VzAx}UDqDjW!C7#}Zi_(G{$_D4K-}fL5-XqR zL#ib1)?xh=M`0P3C-!rQU7%J?5lF{ODjebC0zz53o>vao zmD0U|eJLFajHC24U<#!-0JAAAT*N2~PIWDykU`{UvCsl+38%W&HOxO;7wO73FiL?V z{C>c}lpYFow7DiS&W)a3mcs;2cUTfEy^i33!0g z2Z84)eF6A^(vmm0UpSHuv5UEm(vN`JZ$-WY7(i(mur8%TflVnL0qjO;;T_g);7FQS z&=D?w6zNRhb4tGkex)>)dxSx7B)%MYjnbLGXOtE`WAqD0;z)oYlnw>9p>zarBBkSj z>nSaK!MSkcTr*%4r3V3rQhGRWC8gH@Qz^Xxc#6_zfni_8bRvMn{vSy*5;%y`!+^sn zEeDRHbUbh#rE!YtHxzxG;cz4kE!1mGx~45~jKp!qsw>+!!DJfHM8M1CwE>SrqpLN8%G%1|p+CXdR8)RdJ2%pC=fo8Q&6{sNaPg=Uz3e!Z;WROq7T118TTNann0o(pX_Z>mwDiA zNJQ>|&`k!2@()BlL|y)Y>`9poN8&6)dn#l?9;GzuEl?kh@C|`BlrD&k zwU8%h>)&7>6)KZAupS&qCluI=(xgqAOlcg-_xqptzWi_frX0NTuiJ(pcBKpRJ<7X} z)n7a)@?A=UBlV1Yn}`mCL*Ns;GvqsksjUC?->E;}CPDbsw~4%HwRO_;`e<+ZN$%(< z>~d-g5|u{z2KvPKY#aTK@FVrF=yw;cs&vWU)6W9uv3@rE7y6b4&X7k6Hqa78d8Fco z*67dK8H~Jn-4?AVz1-Oh63CEYcKjj3%-j7EC7Hd=ea&?Q zKXZR`$Z?r(GVdyEHQxn#kNIBsXU(H5Rtp0y#^ME@u4Z@HT~Z0X3?}nj4RlLM8~7b0 z5%4>!Nj^tO27@y$pG?oE8Otp~y1u9AWtZ!-a3;1nCFZM5J- zWub`_w6&c*zML)WI>7H_HyFNPuZxuzKl_^S<@V#?udq*nzs`O={Kxih;5(Nf-`K|` z-{UK{T_qnY+Pxl}I3f}Aq$=yz+Q}x#MndUimt>@qJQn^|m9+EGHcU05GS4GbQd?=Mn^U!gEvZ{^bVuq=`1>IX z?I}FZCky>_Eyk)j4mr3NjXx=LqOE|e$Z)Ls$LX}xYoj+sZ#v#RViA|v!_|id83%nc z0|_Mk8X0UdP#SzS_-5c~=w;Z>u!CW5Lj|liWEf5}BDR_47!i9+yCCUz#E85p#0t|@ z{BObblFITDtf&whDn(!^B@pilv5!Kmqcp|8jWMx`GSql1Y$5H1^`mtBGx25+yGLJ) zO-+bxog%QKL#*f!8#=^-4zZsTj(37s%^3#^HZx$kW|0Z8Rzqynq?!;bHN-~EG1#U_ z$Nwt+#5Rop3v)rRDc1tFj|Kw_R(S zW_!{$-S!6NO6=_%Al*0y+GgYJ7TGDV%1Eq)2=)!^Lm`zew|{4!YhSrU0JP3Ff<1R4 zeYUT}@e=7JuurmNF-IbAMs#iyDYH<>>Buo7eFfUI-$IMF1S^nUSYeEmMnTuf5-FKW zA+|&Wr>Rb4UnJQT8R0z0o$Q5N=>E>*iwCiZ?dj>|*~4>yXQbyC=wDWNHYqPJ|E|1H z;c^9)EV$QvuSKv9ujjqno9udg?Y*s$veB#Mf@0cgBFmk=+C5Q*bwvU5$V6NArzH1e zvgc8TRYrO8(d2W`m7AFyhPB0!DRSt_y^~TYRhHT)mFUV1hwS6c)Q_n|gEP_JOtd#k zG5Z_|2}q(vm)OlBRAE!Q-t={icpT8h;7i`Yr9@a$IzDct8 zir9T3@4C8ez`vW1=zc+rPv#?-{lJ3EN2u>9By$mL4k7|H+g~VL`hP?2Jh@p__{+Xmli>~x?O zmc$-!pb_culAUx-f9mV*HQH~aEgZ;aPw^~bUNsVXyx*bQNVJQl+1eT3@7;^Nct|r} z@0Zv(WW8Tv*HG;J24Z&}EU4w{1OH_$Pjerb*q^(KZ#(G&>!LTCzYqME1zGhz@LtpX zrpT2BE2Qc@VR1h~H8b`8a3jo>wK7xh51%p%5zhZ)2lwaxaEN(h^no{-Z$%Gzo2oy2 zLS>iw=Y0)PYWo`0`^m?!L$Dim2>vTQ@T%S22-;Rm>Kl;yP-vnmGRQo1aFPik9AEBQ?`p=coe`fZ{{<2Ia?x9e(OeWeS z6L&_8@yzt>B;51N^CVWvh~-PsO4)$Kf#`J)R_%`v``)h;-+-f?te>nam?W1@wh^53 z^}~;%H=e25ACZ?_HpNA7N%2JAJ4Ce)QS6OxQSCka=e_X*=#w8rpWN+7pB()R;lWzc zCuch>gzxvYwZ2wM|kx^6FU~QJK z71?VPARJV+A7{~K6vHT4Y%{d+mIoSFH`WtK?_Uqv7aAC2_bs)MsNQCbL(IL#2NCBG zZ8ONK%vt06#z@WhtFg6^quM#7g%JT{1x>1>&8VSjGsw8WNMP-R(xe*p6$z#l1zpo> zrv5^(sSIty&vvC*tFYG;JBCe7J zcirBurCk8_$&t}>gk5LsA?{|^7xbWftpeFcCD`lWz4x`Rg#E;o?fpRq+Sjnx|ItE> z1!txG8u-bo(e_%^X#0_UHsU|Ae}TQluT&#%j}jHpa)^7dSo`sN`-b^7b`mRxziLtb zvU@lnad4uZFhpaEQYP6>D4TpFd6{q&qYQhx*D8No(iAO@%BZDo~=YAO!RD#b)ssRz%K)2>qY8%w)nN9I;g=US7U%={fN+H zuPoEW#jhPPy#Z43ecg%ZBqM3^>rO;sneYp{?!-c%E5P6e{Pw*0yi(Sb&; ztG@0;bfW!A7g|Bqqn7T)d>$N0lkC&|SM{aUxQKcMN74~)pap{?bO5j~rH26H;E1KX z1mJSYUjf`mX|gt^4@b`Zr)y$fSnn^0&bA+V+O#y;?iPgqR{Nrbwu7um6RoLLf$Htc zScFNrYyobkw7T9uzO8YmZHFh2wL5%UvmM9$kme5Hei~oBt*L-E#T$-Xm#kwGoq=S1 zlV8hz06tmE$^xplL0YukQE!7};E^_^EaGcwQ>vit2!Zrwe+zIY z*J*DBJEap@Ew4TwEZdtEJJA*AZynupk1pBNAjbtBk>a2GWGTJ zo3xEnwRLvbF^c%=>*=J8s{%*TQD0Bz+qjlAP8*e6l_R2`-~#_^C!|@X1<@uCN2^HAGY1IcRFQWpo?#U88&OUmLxFpKGLNYy{2Q z#^~{pl^bG{-W9%^u@`(FrJpUWVQ+Z7PCF@$=Z{Sa1iTHXjRO;Fn{D@UJ<^` zyf*x?=HuYUnNKi>UIp_hpr@Iyg1^Q*37ll}G|-#Px4^H*SZT}Fy zP@**2_C_U|z;9b38vc`fI!Ql*^R&w#JM`WoJP?>zW|@3uzp8^2l(Ur|({B^1YM8{U!C zpWq8?OfaV=Npytomgo+@f1)DMM_7^g5cEu}!1WYzlC&_hrjx7(-yqo-zG-qP__E|d z@W&-@f&Vu76a1XyZ^_!i_hjP~Q^6#qObYHdr4IZEtkgE__b0Sz>i2B06!{qDE#56qf?=&BXuL_O{v>JZ%^Hosw3=9-3N{mtA5(T z&D2|ND%ak}QL-Y4Cyq5iXnnw{AUIeTM18=@Ao?*mjyc+b zG{-duC6iMLewCa+_|^a43iuk-g_FZ=hEu|kF9gvaOXgG9z8$t_hX}g4zdC>&9(P3BREZc}1|i|CvcFdiXuByu>S&y?6wCgT&f zr-#gw5Zmd@ZaT4SVit?yapv_K#ONArj24cm9%!deQzsVRN6prXqRl7&GJxfIHljvbxR2t_yqg>$Ra5c*y>;;`= zzQ9^|Zgqe?Q73!jeSqr)$Lt`agMI<`8twy}&T@-d8x% zzbAUfNFRSWTqYcm9}pt3D}Ewy63S}|Fby(9n~)w{Gq|pBJ>VkYayH}mUg%qci-a2q zCx@E^7Z0}xj_iwA4#(sW*q#WoA7UUJ88>9Zkv$Hz;h1cJkRi$yL;#6Q0g)#l`YMR7 z3Z}0j5j3%(Kx`opI|y~)h&=wS*&Z$KkHP5gP>!;6mYuEw~PFMAz*P8Gsi^ z7mnzJaE5b%BeuziT{7ZA;F!&^uAqCs5u0Gd9vHFv#cX~NSy!?bgYCm$doalU3$o9G z$pkQYfXFxEK8r^{vd2OKNA_2+y%nLL$-WAB4ZU&Xx+Y@Y+$;~)p0>~CQ5qZq{tSD?K| zz;06C9om8nuH;T_K?=9x9QGi?Wj@34&)|Or(zz=QA4gao5`Sc`0r}~R@B_&_3HfP4 zGPWka!XlX$A;14=WcS7L&tD%UsQPI_7GKlx-|_kD{w_X$ys+12&zmm?K40uQnvl;| zLBsrYG@XYxT=nCT<%gZeAJ@cZ@%Z~@=`m#IYeGIAOP3)#kA->sZ{I)v-m~&x$nvKN z+5P{k$kJu!v+^n^{;TJ)^!fW_=`m#SG$9|4f4=NIp3lMsy?+*;$HHF!&-*X7EBtfd z%auJx9{G6u^I`FMJ`3~LW$}4r@p=4LuTPs(0MU0W&eIe7ePt=_3iPLRATWs1!9X&e zCi!4vYC^MdwTjjj$IOIg<7PsWF|#8ap~<*eM(G;BdXy&PXriZAl@4$zr4>Ljt|ojk zwmwhkP+f6+tx6x`W-^v0G#gK=_;f5yXf~cEG#gW^;uwnKYC@B-wJ{ud1|~p1IKr%NXGPpX5)Ajjd44%JEo#7V2cfo&}`gp1lk+C+LX`6@Fb3o1nXLG zgpLJnq%<4HtKwLqe!>yD7LbhPiEZVkz=4!c#`dvrL`EVGxS8?~0*_Go2JjY~>K(I! zR4E)uvk1_g(qtZB0;MMbr@)c;Q-RYde%v%`35!x77p3*YlKsX=p2LZ`khAKYhD)iw9Z3r}?v-2X(5*#kTA#&99RF@@yC9wOc8?Bn{8PskAGiJ6Jd!U(IT{-!eCU{sVKz#IJWupYFl&V;8sZb`5WuQHSGiJDIqC=DMh* zojCsKsV_@Mms;|41jp|eHcU3F-kA;aIex2i+uO%j1&-Uq@hi8?X;f*hmb1GWKHNK+6}6-f4?C zzDGCP`>m~aT-d_##nwQ!uEVO4|2Ixq&s zEyWB@jyShKS%u?AhCdx~&S&&YB2%RP>nVS-c6F7Dm;0$RLDw#|*t)DsljV~*zDv%L zOWrHHyjaQclh>b^R;AmWw0#`^X1BF=GYpT%UgP+SOGefBQnLM#w;aFqWBWvpUX5m> zTb%Frbb6#6=DTmWaQynwuNE&_)o*1Djz7N7sI4Q08NChX_|Z1EV^(A}-x|&F4;@Wt zH+w?639~tVQ2Y5Oj)wW2SjX|VC>DGT-|9B+ILCj`QL$*>@;Z0$SGp*`P-$My& zayfqZ@`bAgEI+&b=`=e-XG3Gb)lg<=BUCT2q*~M;NwxncB-QGeYyFFo zYR8~ap}27S-z=}DkXQ*TBu6Ef3xa+IeQMbxSMon0!6sVw5$&h^yQJB!THmtP6No+t z%v2OwjxEVf&%T48{|}_uMwP&Ip)~^Qwa^;@S;G`D zjMQ9+hgJ&AuQ(Yv=?TWrldReL2hpF5nI3BWqaNtSPO(mYLLBTNVLnl13B=2zg9m0p zJhI?FgT)!l7(iPx?nq5rvM9Ybz*FvNDUAJ>WcVtS*YmofrSIkK3JPQhlO4-?!Ds?Hbd>{PKLV#QxxnNn8qFp_1yePI63w zmB^$?@TWr42BgrSYXe`Lf2*9|`IO8QOW~eM+V9bCr2U4b;+t3?IltS8$>jXrgC^QO zG|TyUt!;~=;Zz6p?`8goJ`l`GLLz|NUQH-w@Q+H<;`o>2fpq zK|(VbLPGyp_Ymj6{wLQxm<%H+e^{NkVW5LG#-uZIwM%)5WqMpUw) z|BbZ~8P-K=(zOvy>m)>GbPSy8UFOzI<{(@Xb$c$5$d8gZM27SprI{=#(PR5xTUWXC z|Ar1K~LtClu5pfJ!;}kqr>5*({%M_jRryV4J}t0! ze|Ku`)md5_Jsvpw`t%NVFRJA@`%H~vJ>~D3ET2$ng|zBM7t2+f*34geXy2FB2JI%4 z8Cx!Jfm`o;&4z!vS#fpmWhbWu^mm#YJ91IGrbkocH+y|L{qEJFj{;q!cK0w+d=Hi*Ar>mM3W&2{|ow`(Rns2H7{ZoAIp`2K;f z?LSBMDkDrtZt}6{lnb944!X2;*q8pRXC%3Jw|Y}ySmLvU%f|N3LWOou9NW}8dZVgm z!%1(y&g<0P_f^_H_a!YI?oSJ?8Zp&m&qcrHkwc5U`gHBh2jln-B`aSVGs?y@-XZ2$ z=FE{JN{v~#=b2V#^O!18_e#aAn=!VQEaOJ#(JQU>7tbGfX70`dar??`c~HIS_@p|I zcW-K0Y|D~*1A2bZjaLNrnix8|U(rz0$dhg7GS^C>sp0%DA(9< z&-x~dd&f^b*`?OU-iD#ya3{c`^c_tso`v}cJ z-R0VQt2DN**7#2Ix)!bf!V@{!+F(cBWrk)9Lug6OK!!4|Sxu|E>`FS99Wwv< zolg5l+0;lH8fZSOo@{!wyhv8xLv?CJ%{GaAY^!V+(#^WxwTP0#49zp6K3slcVX?eb z|49`ObnYMWXlvtUd8Sd*)-0;BY)#8-=fyU$t)`A#-n^)wt-mD9aAA+;O*g-6le@EM z;-a{zc{AUYY8K@G*gf$>mAVbxW5-Pmz4N(3&*RG_A54RfhQC=~BBN~UJ~AV{fd{|N z-z#YrB|OQQlTpd^1uGdX3495=&o+&v^NoGl()Js3n#P5kvP#y;ni9HtxliSlqsgzqb)A3Qwrjhq z%dXD;wl2H%<`YgmoxGpa8Ik87^rW}@j@)VE(<=3_%zL~%u)~Hmhe}kPclf>A(4o%; z7<@bOXwc&q-Z|S|g>J~b*`}iNn0_}c%zb5#=S0oEeQfn0#}6~RrSkA^ zwFmZA&epTC-B zzrWXfaE-5JKAOu)7Fl*q(tW=Eq8n!pUiEELyOebHjU82MRDaa6h0DiT@yoaFo8sCv zsL!l%iUIn^SEM&vzT)+?oW9-Ny2h^Wl2&rz(rNWaZ*Sdc<=rlK4?TZY>3iV0yslwu z+@ED_zhE70w#@qCfSVzuD(zSqwJYGLHH{;CC!!;Z3xI245%iWF(*D3v)A5C3nFmvzeDw0WQ9S7~+-?zoKnr|;He;nYo zyl9sp&QXpv@1%ZgaOm{*R%4ProXRi;qKJ{s@x1G)o3)(of)ybtj$M~n%RP<}Me_x5vBu~L=Q^K@b{n~Bye%t+2 z_ij2_m3Q2K(sbF*^F0$vG@n=}@?_<5?N_4PW>W9kB)YqQg zB<9=uQ4fpV?fE)h&qz6a?fQl5v-DTb9XoDQi|WCH^Den~)j3z&@Oe+m()t-y4=X3s zTd1|6t@*;1l@@k7W2YCi(Q5P7?ZfZ&jjaDBHB#n(XWq%vA$}cOWO*4c$v6`tNStC}`REE)Of5o*cV!SJro{c{@#4#_luS(kX4$mD5Jc*S-6^ zyXvH!M=reBqI0*s(Tj1XkIXImF(M;j;x3(I>8-lgkbk<-di+|SWu5JBjyZ9!!i3_N ztHfLtp0{zC-_rlV_4o$X6;9aeO$fhu>RJ1MwKx3|Zm0Jdnmn=Sso3phJJtyMI8-5X z4{Yyy<@3NPPr44SKCJQ6YPYp3L=S6LBYVsOS?7}OvoG1b&MEh_@l>}Z^G<1336rcC zd8*g-5zei;)T`9TXLC|`SA&sbM)Y`Kye9bA&TAo6BL{!mp@_+xc1y9zv2=9*lRIiu z++N&8{^+VvO4YNspP#aA*VCnFqaCwmTC-tq_KIXcO&xHF|Gin!KdOmP}QiZfL%SPNw z+Tl3vP`T^p9Npc`yt{U&9N+fZzEPzti}$X0`fTLq-5<*I>e3-9u0fgf%$gyyouY>v zH8+g9p3~YQtAq8uz3bamIx{S2o=<%2P{q8suz=oGGnA8OCQiCGsYG%@m$6CV(MzUp z44&hLXOge9i5ODnvsr1( ztPZ&cN&(+rS(3~y)i>M@&U84L+^qQ+^V6maS~vIZ zG}Haj z`M^KcuE)+b6Q)0$`OI}vM2z)gr&h~PyX)L3KKj-}=ZjYJE@d_yH}z4uRfeYxhtyZP zms#plH_`9&_+;DX3qCD!X(V~^cBpc_e=X}CS<&}L`AzP-G;sR{gP4te?QZI3_BrQr z?M=JuuG$9@x@@^uX2d=34P|zXnzyXRlhS2+jt*Sg(R^OTHp>r0ReI{?A@QkN^VP-8 z2TzPS?r?FmSxDy@@8wn@Pb!X`gHI?V?2{%*;98 zZiCLw9V-oG-ahFLDJL?jJ@2tofvuhoZ_i2la`0o;uvnA5&-)n8IG#H|xuEHgWuJB5 z`o7fb;oPun@yp|e%sw7iq|T7lBkpavzcn@7-ZFSqhcY#b7M~Hca>>~AT3cM-)NLeP zTQ#TDg}$kkW|lr6DHpywp<||G-G=y6Zdn#-+nX;veb!=lm98_hjVgs`b(FR};(21{ z_8BjF9$#1bTTQdsW!`p;89Sxz`h8{Aw$CYD+GxaOSV*K_u259-{< zdC}RIleBdLJ?*_3ls@p>+o-)!r@)1^vcm2^%{eHUbg^px%byb>UB(ab>7f0p-{v*P z0=#$iX&>MgA!Ig(OnRc3`+jjSe$R~}JzMGv7Tb&;}_)7NOqIawek`D&yWp(SU zcec*_()ZhcAK&i9N#Rt{d0vlvmHVFfJx$pZzNX=Mo1*L5w~qZ<^6~KPj}9DLSS)Uy zy!V|K8HSw_2g^gI9nmUV&o$?Ly`AeGcU$b>*tg@VRhiPahii>CE52@lON}GNJl0#b zy}UnV`nqO!JofJ^XPQ%`czXZ3D_e)IoO#>v$%xSNHcs_V>i2tCZ+q^px3>GWAHTYt zE?LztvghM5wpX?;?eZ+{Qokq3D~h-IJnmbNd}W=6U9Z+Mw)5|t+HBiYn=*Em`=rNg z)>iwv=&9s(<0cm?_B~UnTbZi;s${Ql&sjEPbVO7{-;qIk9A;POHDRVI>8gXXLJ>cNVU#^1WWJvLhDYV6cFGtK{j_~Ge*?qdjZyteriTnO|DKw2WaC)Jv$B)J430(Z zcXpcJTlenvLnY7mwU{@j@!WI+*(wL!9>?z=8`@2J@{4`5rX8ZLx)1L&p?am5X@Nr) z4A1ITf0*sM8_k}58Z^?xGQ(g;xg&dnUHT*%Hy_gWgr`^WJ6SD_BQsV!?a zGO5giHTp01ul4WU<#X9?Q-)NLKFYo^e7~0Q`y=g+@85dz@WJKA=Xwpl)iw2|ap3si zFWWCyozZP)-TmWF8@!uzreZVQtU5hfPJ2IgwxwmY3hs{|U9MPjMEms*`geFx>wxj+ zX8|6S=a>5$)WoMrxs15Wf>GiL>&y&;1zXNne%sR6=t5vd&Gr!wj}O21)wb4p^8pg& ziTx37BXpAYOdi!D(JFA^qFznAEGkT3EPKj z$1NH?{==K;mWO=heT&Gp4;}Qi!kxt{8>S~M9Q`=DQCiXE{Z@p$n5w%zsDZan$vIgM zmo+pFdRKGJv-i8pULQ0_vC%)qXYrOt7K!~AKI+t^dlO&B2dC>PYu(yk;;l~e4$l+~&yRp0)~ibD0qFY1J;<(FUeET|3QeVO?_h(MQU<-a}$)UJH2j_G0wn z0r#{fPT$$Td(R23zULkfY+-O^R`X5crax=G|CwD2yeLJMygcdR3UA|B6 zobV<1Qq^ibN|pLB?RY=K(OtSP8NIywgUToyt{Up4@g;^u7%{w*5KWyZgo0}#K`jpe%YTw}tb#`}O+|w>{oAaiq zD-9YcH!L&$R@0+Jw|iOE-bGuNURT#@&(YSgM~xrI_eFn9ojK<9YL|hFazpQ>EopzI zZgTa6tTcxxy#QF>sePS zK5wqm@

RN1y!Man8r<-J2dsDN%FgN}Uf$&n5et9$uBv^vQhJ;_}Rx56-UAc2%Bi zduVzrtxbK0-8lxEQ_HpPb|<-fm8r+4>)yF{_3rR9^V^0E4tU*RP{N8oT8kf zlA_>3&!ecMD7cDzp$R>ohUFBM?07kPoT9+4&%$o>I76b28$Wqlij=RUD7cG!WqW!a z4a+IYSUzc3@SyP+()`L9Qoi6x(`ENV!*a%_D3qt^QIt~@Lh1P|T!F@;D5ofRQ9eaE zMI}YSn;xeqr>LYT_|W4FL&dP1hLtodG^Oz<$|)+@c|-*iDQAjGico#5;w#ztG%RO) ziZDE+iYKEer>JE7N;G}?oaHpEqzL88;`tQi6qOW(Dl{MT`6yZWv3xcYj|((C8I3Pz z=TVde(0Enp^(e|IDk%y?)iZuFigFgNM)}o6R8qb`)0I98Q$0-WoB45eE^f}5XU&hX(d^trS zgr-MP&XA=?QD{%|L(@^xctTxzK1Df2B}IYO8yTxV6ovZqJc@FPN{T`QdYq!1qLN*o zhJ}VS9z{7tB}IYOOBsDWa#l}iSV_Y|V=)~i<;!ST#_pSj_x+sR*2^hq3N;s5-$F0DJ|z}bSK4hn*JSARk^*MN{`K(!sN%EhfV4H&qKC5SJW7|R)^6^+Z_7k7JAGFwis`o6uoG8-AkF{qE zmBf4oeq@g|`7snjfBCZVVmzkDh2dW@{+`m5e`z@}T~=NU`P4$`eX`>W`FNVb&z;2U z@Z}Uy!1B|Se^~+Z|6arOHRYG*M;7w_GwX}@&+08h{yLh%n(kkv)Ep9~m3 zXZ4%mPw_M`G+kd=!1pJ&kmWBgWclm<=KG`Jwtuh{@5J)!K`SsrX|Bj;`y?4MeM2mP z_(JAiQ~4_j`Tj%{@cq$reR%=TSI~H@elld`^E;Flvi>SYiqEMjy%0m?j$iZn=O-)V z^);2Bj2I=rkCg{QzC1LYF9eI{v+n^z{(L#@A2B^>4EcDP!kVt1R>1lvT_)yp7`*^P zL1ltj5K2)#L%tl8g{(iC@~pAP6G5qa`G{S3|PuA~XC@*CB3(jJ_^5;t<#CWds z07IdU$Y<>hL;ie4TQMGyvnD@=g15+L-*bjytiODPhW_(kG5(&?bpNv21qh3tQ5y1uM{ z&tDcK=9B0qBR_^>==Z*az9;Pd7|IKJeL4@pUrAcP@{^wx^AD9HLTSo*(fa>VL=!czs1(v7Fhw2gAQg z=}5fY+C5sDFQd)xVBvDt{$ym)Q4+;a_Kpl#=F?^-CD?@ic`sT|cvc_pdV4 zhs0U^WT@$SJYUoG1$XheviF%Gf4)#tj7Rj;ksm`b^m{*o7}dg$eYY5DI+O3m$_rWl zBmP74C(1&$f64;3KSc}q{gBTQ%fAmTaE7vIk?&0T4EcV9ruySm*#1)i>z}6U%L;k@ z&;p*XEM)&R;y=`W$qHG1Dut7H_Uw5xhXz9X7sU7+=Wz z3&g-Cm4&Q-n#x~M!1B{{zN~=vpBX3KX9T@5hVscGpRIE;{OSH_ zK3TtqAslc)t8U)c=zf^8V8cn14;>ms!a3Ul;IvIsMMF zc@u{GbJi5rlz&+v%P*pU=Vu-e>*-dSL5A`ZBEJ{qGvx0>WBv>H{m^v2P)58yo3CJ4 z(CbSIc)o)huR-`0iU17^79qTkM)}vvio2trRBu#iy=GyJM=2# z`LaTuA6m%sHI<*DkmVmi^Tp~dL%uwfk>YczK@Tt#R*3v+l+Td=j%v!kvXJ?g6|nw9 z(0O`dhk^VUMi%h?HRWGk$n!G`dH?YRyuO0QWA6<^u{3_~`xdhO5In_t!s-RX-(Ojb zkygn3XBM{q-%-qe8Jb~+^4=n!$u%xq^RFmm|0lhW*Vk14rS!S7`oxfbuCm5r zIWf6IhO&a5uVMW`UcmQXsp0+S^QkEuSjhUHS=jQgDwZFcpJAvezd!L^#q-(smElkE zG%z$h|A@jqzXF~w*Kq%`0*>Em74rFMx_?Ch^RMZAWdYBBUD*1g;r$V4zmm0A4Ebsx z{fG63uV0z;K3TiZkiU+`a6Pg9vUMwl8sl>Zlp5MkX#wwFm?mDIjV~AqF(RLR4;b?I zuh7u`Wi}GeXYVsZF8hL#wsUOWjUgY8h574eQaJ}EAJ0%RTD*QadLl#qe8EqQ$F9qe zU5`h;9(mDnX5R;f{CS$f4Ga1HDmAnpLR0a+jOc|K^7&|9$m`4gVfpdbmuV?~iPNcz!UAz)(70##6if5Hp-{gBTP%da=R07Ger$YJiluppI_fXp06xq{*@ZaKU2f=rD#wX@_T6U4+81^|GTKhsQU*hIoJaoth1KG9M$w22Bi4)j5XxuBf1e^W zjDMu`yUN-d9$CI3T8P(S`(+uXYiR%Y_Cwl3Jl~xr$WT^SR&5CyMbp(eoJ! zNg}@n(>o?=-lOs(K3lHGZ zf5p|u4_x>f_xwrSQ2!0*>X*_>)SIGPQLHEIyLf`~?{n|#5z4>7UH1&-H|5evr~GYP zy}v~Hl{x(?*C_uSm(N?2KZbignUw#QdoEd&|AxD6Hsw2U&*eGg8+(f7z}lnNlpn&i z3-2j^8F#;*DPO|9r@53LURz9`wLgNlSpHME_gt6q)t{X@9nHO`?0q}YSxleJn=}3n zt{r9VMH<&$#nFp+bQIHJ`cW9aa~+Y-`adk4zTER--!H$>Vti+s?j(x!BSpTHh8e8l z^26dMa`|Wc4*kS**!Q1ZHX7<<_6$Yta*YW5oEZ zpThFLkITQP4Mz}8g^KZ6JIwg&xaT#Nraxn_7~hE|%;Im0J7Z@6}t(53?sdmgeh9ul#&=-7N0D7(Yxd#xFz9XX(G^)1k+$xa(5(Pr%ZtLHjQ( z%y1y(v+)|^XLJ1>cKn$J{&?CxvwFtjucYk>dmmW+Nz%a2qwPBTZn5|g^n1nnkL)@< zH1Icb{U;Vbo3>+Y9K`riuAOB0b<@Ci^%0*J`!2Bf7kouN>sPV+xUGR7z`YkNer^>p z9oAoA_ifCzCycMdwUdl*z_o{rZ^pG7tX+4|z;9Ml%nxgyS^U?u-Dd3`D_0$^J!Jfk z^~7{od&2mm8i{6ivwpuYQjE{@PmU7#&RqQRTsz6q zSv5|KUzWyaPZHn5g>oaKL2V=>I$uaDgO6I@+9&dO~A_x{f3 z(tF3{rz@u)a66aYA+Ejj=kn8#ws)-l+Hw8Il3aRUhKTufq9td^mB&-AoovPRr}gN2 z!}>e@XuHIolXf35efC|CAmF2r+1VXUrO)KI#>*| z`tCL`|M8jJ^T_Eg9%uJAsjnDj_tTuyx0uA0&qD70`!*BLXZ^HsTsV@pi>!V+arM`x zNB;Z_nIncP(EH2e>f;oyfAcOtjL+)38+ZMSTsx9FNQ}?QZv)rPx97@hbSE)BYo{C1 z?*)7RjJfBrfwpt3{sq+)&u8^VpL<`XbMbAs;|IC=a-4e}6+`l;U!Q(=+54^F>Qfyq z{yVPz_2u#t$9?zbap5Lhd*H;SH?OUjKlc2Sx%<1rmH&M1{k_PIC*rvCrQH3D=gMo# z6!H439c~#ThS_&0ko!LOqu)C=KDy7fN4vS}H|D~o^t;ab0cW}M6S(ra<|F2Z^&^bA z`wi#bw@F-oOP8x(-?;lP%02&aT>5rH#p|>B`iZMwKJ@)#--nId^#s`Qp}d{Ehd*;6mddDX<4!DnRJjdah$I+hUgJSBxd~m$z z_wf=^mXKHaZQK)om9h769qaB=#c__&dC=53fG50XzD zY?0o6ORCB751CF=y}mAaS^H`YifLc)4Yxu`OL2gzZjj zV5JvgV=#B+xYEgr``YD`ce-c#m{%$9`qKU7gG%=&7`wfCJYu=8-f`Q{-#P}*{}{7u z&yo=@_x0HGc*%%yo3B6Lp3tvSLZ{q?mv45rnQ+h`;cVqKyUO|ROWcsyseV|a4>k#B zyW8Kmb;o?|5iFqgTLxEyZx?F<9YIHE~6?qEOOQwd&AYiyNH#8XO}V_ zU#u#v7&-1-_{lAgR}7z-d99mvY3I_;9^0(u*R!g$K=*9Mao>|QjHb3Z=how)@!JKB z=E`r!W_(igT%@>DK`Y1f%#G3~+LWD?v!=Fo=f*Vxf`_H=4oUB0>;KKlYu0D0$W<9y zhdo^l>$N^3uX1$s^YW8TXD_VPHF{Pp-Lt#y&uv@%n0~L>llGR@$}#GBv-FAZsc{{5 z-*x_I_`Hwa+3!&g;(O-kp6%B&ui5VOMXOBrCcfGEeUk6W;7Xe(cP%$>EHcl)S^Df~X_JiL zPWLW3WZhxz1aCubCLG8m{ELpsw*A%}s<@}R|-bgPueNeNlu4WBdUD z?{QndK?zA`X7nr`7Vsi7U`y(^j@8$#U%O%Qn(kla4O8tMTdv7V+Hmbi^{Y#^JATR< zeeKr&2VFp-zr9E@A=%_Pf04K{&>&nVzcsi{N)Bq>r`J0H;-cuD<0*5LYK?sb$P2?$5y!pd-Gid!J)&v`qxmG%ayM`9m7hlpzB!f`bj4TgWg~KtKWyb zUVaJYd%eK|zR53iO>|A<_PI)LpRYAJnE3yO7Hd`g0x4w!(?eI>srkX+c;cmwcsZ}< zkAC;GfzuPfhmY%u6@ z9pf#i8tNVF8XV-8g5WUMP!9WFde|@MVW0T_Hf+7Zxio$`^qqs!L(j?%1~mzs!;$sP zOMf^rJLvU}_ZAHGo*XP3J$kgOV6>}H!#%hh_WmxH>sXhyGQ6(*{Cw9jlf2&ie3vWV zbxirBU~s&blj+KL@wcn|7`=8lu7B%sJ@SKLv)c~O`G2H_-2{Ki?Eg*x(`7U-h}1{* zZuzhDp}Y9B>CuBJGi}Q3*#}#0>Xd1-4yx>onu94gV@lnDTVqr8O$RaD=$!i6*)<1O zaCS}Xz&+PDpF4ZX^u~iOm|C3wjc%vsrM|hoA$sn?lxwP;HtWFsSJzB!KJe<%r4DMc zb;;S$gKTnkbb2Iu?tzC>U2|?@q@BC4jYB~l-4tUd5l)ig9j4?OWTF{*(F z#QV8Z8k=TEr@IfjVAGVTv;Vso(mn0x&W=uLI$)bKrZmp@9~x(OV>4=|)K@ppsXt(Q zwdYQmc3{|MpWE1UFk3rSE;4Gw)Y=1&Wp;GhtVm;VCYHb&~Abl8-%wLCr~be!Bvp=Zw$|2FM_UiPIO-c}>kg*jgWxw@v4kqdf=j#UFl%U4L{g|2WGMjt#g{24no>) zteIUi?ZESPP~t>m?ew}Svky|rOck~y(*ursztaD=9-8Y8LXvH)oqllJoWyO~>?w_n z2SG0zXV)Ht5ZD+!w@C}B2O$p~94~EbYN)L{@H*xSKJdQQr4AP3P0dp^ahqLR*L-00 zp|NdF)06{mqQpdWFE!BpOnfeCrX|KC2yrnQg%$^5vlo}c;smb$aZNIbFnh8UN_oz za2leQ_igkq;$fqi|ERT?|qBX^*<+2 z#Dq(na*9_1YK~w-vP3+}E_mMN=DD_g*mvR)`%s>|2LxCvwPG*Zix|(uFV;<-=SVj> z&&bZ|Y0_$ORdKGLB2PcNKjVcJT~fmhoV^&xhia6Xcw7 zBJk zMevm2rf&q=b0i{jBp^*{Hnto6B_d9%#BB+OpxJ>#%FaTwADM17TkwKWr0lpUQOSpw z4IkUw(diJ5?=iz|qN7-l5mOO7NRI_h&_jk#JjmEB=4LNNH}kRY4d zVT9O*;F^SkE)$1@I94?JEp(XltC%UyK{9NT^+wFG-G59F=da^*vucPkp)A`m&_w z%g)r7zgl0`_k8&}^<|;;Wn0geUHl@JdTMTmsLGq=Gn8g>%tG#mmNJ{F0iL))wf(V7b*ka#kmK{iqoJh=q^$&0V$U} z$z#zA=-Q);Ztf|%=)V^ILKhu2BHe12Jw@gwc*V($zci6+ZTy`^QK1CnJI*I!%OxPK zsi{nGDnHRJjT@P6X?0Iasiw~FZt8q{Q9-(?HZ~PYH5F%5uj!_$Mx~p2kxgCA(_Q}j z5mF>!`7~HnRaJ#p6j}XG=QEo8h)0!y8+83)o>YBg;jrwhq*jd)?6ECV5L}R)%%>l1 z8(j3YNhsjF4AkoBTfa}`qq0{@SO!Z#s_M084;Mg{E@t!g^xKVap_@w#%-2)xSz<0A=cVeUe%Hx3&7lKgUMK+>Dgn~c+ma3ms7!3Lxn+n1Bv4;ZP}b^3 zZT_A{Kd@zAB@uaFoXDRih!l&*K`dTnFC!LD5s%6g{44Gtvmrv4DL3DI+(BG6Nmymz za#g`spLDbp@ma7$Rfv*Gp=W*t~d0u;jDQ3^>aypl^#e| zS`)rDHQ}p`MUqEq!XK9^#NEjpm5FC;ZapxM6o?1yxn!H2#UYvKmDSDARl2!+sAIbP6f zkvQdK@tCuQ$PlkMrAVB@Hjylr{xV5L(4|}c!tjZ1IgyKAK0%8kwdtcx9C=6OSQ)Q- z84Dv8QV}dkRH{t8Z%~-<3ug38P%?@>8W)&bq6}=%=-4qng$`58*BTush*K^SkEU!c zDK*hnBj_8_t1rNfB&JtIur`^iOu>sbpTNFM$l}71=aqo?NKq0|8ASm#C_@CDxuaaL zSJUCJK3DJ?x_mw(0Se#W%W*8;woW3NT#gqk%P7Lf?ZuA_MP@Z(4nZsF91I5O?YI6pkGY##Ox<|GNeEv(kc-YRtwG| zx@svE#l%CwQD9#s5uChO@R%(|;_3Im7i@*wLUdl0ccfrdXARzl8<(^ACva;L?a{^WXYt43mNB@lvlwr{ zjVoB{BbK5!@;!Wd1a84~oqkspxfZ!s9$rHT8#^7C=|Idc5Vu5vtS`8>v(hh!7YpqA z<*mtLty5)mRRe~OC?hSPkEBp@WWkJn4!(y;^oG_>`&al)wyh)JO)PXd?7EXf-$$D_`# z41BG{q9rG%8@`KTAq+M=leMPupDMIPm4Pj~@PJd&g*UVCH4?Cja$%ZPmbmqxF1o&_ z=vD$u$~Q+mQcGANvD0UxPmwwiZx{6EW>%90x1X7#OuTO6g0!|nP@E^pMDfT(4$j3* zbcF;iJzjDpAdho-N?^+I134_g5f$o0JpGI21Uq$m91IY?5w@OZi%3?MsP$-dyVJGByq}Eau|D= zMBuI#Oiq&y$c7ZQpjJslnsG&Z-*t*t;gg8wBP;)7t*QuCcJARAUL%co_7ZGL`UOwz zLwwBN{&(tQ23_Ly%4wt?q(KSXXQZgl{fSDb(1f7i0pmZZ&&GsBeI`gCO?$}eEPwaB zM3u~}lsOW)1+{*`@2m|OD3{|0NZ^C9W5*!s7xZ;otNDH-BzPcEjK3Rh+(EVZ8Dn2U z^LWB9xZl{1&}>T7V6)-IJuJS}usW~^%~lrQV35!}nkdG@h8y>@)DtX4Lh}Tl?jRF> zG~pknSw^NNAJ>p6@34^u-fx8POv0g!4tPA_kTE1;Rir2}hm7qZIwXhXay$uyQ&Kde zl@x2}>8&B=?~rt)wEa z>!mjAjP8Yq8&pcMJD>dUh&l<#t^-h$0fL$9D1pHq!egELEwVcl*)X@NNuJDolRt&j z5`XWg;rhB$g~YS1UN9$D8F*2PX*=fVs`lYo$fo8m4@p4g z5f|A6kVf7C7`B`24#6A=D+ASf{>r9y*Th?#Khrf+YNbg6GM;_Ic!L5N8(3kYh45ab zr=;(+RJ|N!7l^pNZI)z8_rBxi_{D3=LToN$9sg#H^5M*`R z%Ix`To4kGLzkGSxHv)e7Tq+x2%vRDU}B}f|)W*ewJDx z$G1mzNyPldK6a12XxBNH%g+)NBr69g1E1?fzioCJge$n{S^OkP>bAl#>f{osHOtL& z?vOk!MWT(m{3IzQ4VOvck(rVkq@vX6x99%Y1XLqYNi%DrQl@&vc~Vf9N~w~RLrG0( zFm78NWa$nXq(cM6BQHw;9X&5qC?pYCL(^=_Cd6ydJ0xhT6!a=Wq75CD(s-mY@SZh} zXnGtQQ{xbO2m^O>tDas-yr8I>tNsj}vqx^1-%CI?2?iG7oW){47DsU_;M_fefgzmJ zrax4Qi9>dhE;oE+ylZ{Y~)IM@)* zNrRA&-n!AI?k2=O5V?G1qN>uWz9|K-Nn3hA(7sQzhiL%n(}*#lDFYJS?WO9DCy6<6 zoHFpRo~fO!>6!Z6NNr}Z5By=DkjhiULlaE!9P{0C%tvLSb>!gD@njTePZ3YkIbuG~ zecAT2IM<7PrLl)|9G1Y(GM7DayCRu>`IL<9e!Ca?K;>c$O<89Onj>(RwQj; zsHwOpSwcc^%r1$jBgDjaHi~s-lSI^1yB7e%CF{JA4@f$cf$MeY&E2K@!Idqg%D~B*E^q68e>8rREn#^; z0zB&Y&>m7pW!iLM{f0I~Q`z!L*h_oj8M)#l0AJfT zsH3qi1=$HcOe~g0@p|F)p`=*Z@tp4U_P9fil71NF!-;(RtbTh(>g@<0N{f;06Q`83 zw*DPZ5d?FrKIW;TaYL$)u|AATjp!BK%1x~dwt zb@u)eP)FnSc&^OixsYzXuMbg;hg4J6?|?FJqea@+_cZj1EnC@fg}p+z^HJO(Gj$u{ zL))*nah27^fO#okj>XX_k$0^G$Sz^8$d_7aR=zkOyD14W z@)_ByB!Kb~!4O>u&_@)1G0;X~9nq+SDT{=~e1(4r4hix6jEbxM=v|V>H9As&P&svL zttfhAyo?jH`I|<{P;tVD(PH)6B81-*bT9z8i#lW#+2i^@r$_M?*`HuzvV>&lQ5z>D zh|DsV3?WOR{V$m#9**QSn~!4fU~y^=_&Y5zUuNN@?}h0WzqVMk@mZ)(W5cvtg|$9Hg`+{sD9{Frg_>ViEl4-N(xAwG8k;yj$$f*p zHm#rGPz&e=M?V$8rwP9W_2mYaI1dG!QsnZYgM!sd7D4D~^?r*)MRe$KP#?V0aNwn} z@QH+j!@u8f%cT-Vdx?tRnM9>J7WW#}!Jte-2Fq#&p=P7gua1?Wa=bY8rambsGu7ubbw z!w@L<__LAi7R+^^xl(uJS)#dqc1TcNsb=FiQdEyR7Uh2S3dcObS+pxetc96eEVc4V zPuGw#vKpEUWhdGyk(e*`0Y6EEFePXsNmVpLQhTj^I1by5dcWY%B8|3yn3%PgGR5zF zvQV6uwFez-ZF8jyZA7_c!me7Bp2#mKUagcc4?30`bzCew=r~sJ0gsJm%FG!O7oF; zzl807gnc(H?q*kiW#D^VerHelduf@1on|a;!g`uIfr(ZQ>2Y27yi3xJKgYr=#p9I< z2}nJe9mx}t#Z*3Z>76~LU$;sJg8P=Hs!Ds>DqXsMNxJP1ezo*_#|x6nm4RiteBZ8g z`7f-2mgeu*x_R>Pg2a5HPFGmpQ(-qdNR5;dt~pH4X&Xm+zAij&X}a}=&{8#R%z7VF zYe}I-J868aEd<+oD%^mSlLqm}pI1o<4rdD;+r=r@Qjgb_>Mu?A^7nl!(Gtu>)|tba zeYL^NDM+&R3(CMfy7qv}(zRdeu1&JZ(@Y9X+a)aa6ZUdYYjlO3Jr&;Ru0Z%$fg%yl zMc8eU>SuRfSL&*(E>HLMWj8+Tg}bCdOs>6)bfIC((uH=j(A5&=d3vej2gNy%mbCg7 z84#t-UzcCiUA{klo8mADl`A-;zrg;6I8}eaZ0`697pd_|L3>o?;?NN6A%2@fiekUS zprVyJYM4QqZ@VG|M}I+nwgg?`WV0x;noL&qbIDPnX-qOlllIdr_M5H;58+{@M!!Bb z@vyB7lGnT@35wmJ`=o(rg6{EesU8R5Sk~kz?bVVer%0a39Y?b1kvf4{f!3|p2o9we z%S!Q}tr+5#oAln9ohw$F4+kGl7N-wMhftd4;Su_9rxgg=7Nfz>;|CmGp@MkJC{hCi zmnY_1uj#IW%+OeYT9kf60C--|ii|Qe>a!Xi{e&(3_#BR5$Cc?Zyh6UVQf3i#R6hfP zUK>*9YArOTpmmctDXby3Nzf}Kb>iphAxov@kpx)!wnUrg(%W_EN#e|>$I(#n z$P{r3&HT;ckyFa0OCQneYeSs&x6Kq^3RPN$x)7aRvXNwIj7=KGt+{*y>ch zf%qFq3at-xwJ6|j^T-YfYtep=l*+04$0KtjESF2E6eT4hzZZ|Tf}6}S6Q+1q%SjgV z7{RecLKYvUcq!DpUUP9mYTNklN%N_P57XPwn*9AA%J=lF$IeaSJV{{C72tM?6E{d$?-UOoUXd`4o`;#0 zv>Oqm1!{zt_$EO;Y@pyBTeXB~R_dr!#|buea3`6idSBc>_>&(m*+Qbv32=cCI!Cl*C0#rq4NI5sWO6D0N)a2h=;cO@CJ1{-m~F}4 zV6Dw{`f&V;4o!S-Nw2~M!gNN)DuTGC-LD4XwG5y2ur)Os`rSPFi#iV1w>#88yqQrZ zfyII&Leh^b_s{x}VW40)){0Y~;Zu8BDNa(3>%N;Sm`O2rJE>I1R{FZN5sb3i(qOzm zFi4fm@u@v|souN+>7sCPqts52#*_}v+(9T;0zxNrP~b3v9Q4fwonfbm zQ-+IYrO@GEwBTdgA|(8HJy9%p)8>{^j4eV9Pv-qpUBZIQGAdiD3_rB**X0EnWNW8N zSm;$?YSI9DuF;fzlLVAg@VLz!3f9=;*@7eTLpinMropXotQXxlbj*uXA)@>pvWuE z)5sQTC4k;O^m8NZ;0fRmAHt5~F)0_H+vZ^z&koyosvD31>@jS!h0rH70VRH{NLFHa znPr&p$OAlJ<5I=7MzuJtY+6lz33JD6Z>M|aK*6mUzMyDth3DE!#K~8;XZUa=*(^=f zCRvtQFi4HSo{k)?A3I32?l636ApWe}f(H|C?lX@>FgKr<^YIAh5#J>If=lQ*h3&R7 z7-d+Kti%hXEVt5E3$NI=AnHe_f8UW@ZG-2y zx?jRrXzZPP$y~v`N!oBy4nL>py-xOeq2AQv9!PKMPt5GBr+HL)r#NNwDA>7?%>sfI z(Yylf8k0}9m#BewG{a}PoW0OCS;EBd`?exgh%1xDDTlj8RftCtljU-nJA@*XXS5oK z6;h$aK%U-wL!Y(nZMmGqn`N0M%oatawAs~4nz!x2G=vxSN~wD0qsqXy`q*gLL+Q_d z-S6{G{dq~x=gWIh^w+*u0mpE0NuIoxGB_i#ouvC8LQfTK?Dimup)$k&^#M1jRtSX1b|>iBlaZ*x2G% z{cuEobtGrjDO1HGbh-Jvcutqc^>}NRlNtQh*!B^-Qh$uiDI^<%}=|xv|tf(9yW>p%Ul-i+t_Mh@ewnow>wSa_q9gVKs;u~#GE7nbsW|;PgVo*LY5Xq)-_jZ zkJf>BF)Jj2S@g@um0F?C?-C7d+2bi_2Vn=zn4E(}$(nsvDP5!U9#?||U)stj1`94p z-mM1VYkGnRqhruMnQEsp@V5lVwWFt1ZBwIl%f#8a8syChKO5U*%;P!ZU?1#dD5scS zisLH8L-(LDB*ZrWbe%enYowhbpgk8S?;(H>C5qX?W5zO!C=!(B2u3cF08WbHm>3Rs z?5SWdOfSti%Z+%<$ugI!v65VIfL| z2(ObotGB2cgwG70gn1T87g80o*5bTOpE%VZ?2YY_v1p`~%(DNj|3@0FSJQ|^qhdtx zbfQLT)gaty`1rUz;g|hGsRrR@!%bSk8G2KzZsWG3o4Q%6e3~zplFze^huEafeW_dG zWH}#@ay3W?#yE>4AMa*ReaG@Pijw%3&^C>g?QMhU6$Diz0n|kWTp?DFke87#<4N$V zB=CF3ILbN=1JS-ti-KW%lCcVxw`(?IK2JYH8a|)b(Dr>Y4ej$9TD-6M9InwWOB8cP z;SE|-1=ksFaVei*eVm+WlF(PgqXvn+AD*@Ew#I^25;eHdaP!mxcT$9lQ^kh8jw+r6 z^!f`RQ_mSs_L;zy0T>ZMm-gQtBzVlI7OXLfWHfzx<2lwlpWtSL>*l4zYFuN~b#rV1 zg$x|JmpN5q4nlY*Wn(o+Ogv@ZqI|d~^^C3dkT_Z5{q~nssm1=qh_EjjoNLK9Ru<594`FZUdC~0;n$*{1A6Yo>XI*cIJ77 zdt!%Um;!~;f?u=Jb`NJjlI(!r_@zMhZSK8fPP9!BFzQG|y5=Q-Y5<^N)xVE#H z#`MqZ)m+Ge&uzZ^q2e*oUeX}=Jnk1TNr&G$L|C7s)qjxS5nIJz3CoM(5tH6@U1%hme^~4Jo1aNz|RBuQR0ihh0q@wB9`N0k&ss!~ z$<;lZdi>3FdE~iTqh|BuEad?;FHc0!5y9CI`|jM z;DgS^dI<#R5;FNsaZZy;L2a>MUJ9F+!lxaRS9kh(B9G5IY0%}8$wwDx1%W5#Tp91iIoE>(m)d=5Hok~cG9M(k-0mynY?HE;ON1&6jX@MC z^!d_Tj3Z&eYwZ>JLnR^?3p#RTj2ei~p-HUZ($1|Ux>N<#AY9t%|H~zRAu`oKeAQj% z;#8S0!7>+j`k@x7*?2!*sRrRXdo?=z<6N4EjT3Z`XKCY#x1SZgxVODn0%{O0&ZrIw z53%SOy$Wu$Iq*rRA5>wck@}Q#5eRPXsN_b#^J?P|6u1Qu%bEHSTL|rb9vb3YuK5VA z?MN>!5;%Nrgz|@SaWyZ-^9W&mXXROF^^=ShgczNe5fYs0SF^EP$2krXd}>q-)?0RY z2bu5EjAeq#$}!?Gr<^T#voo~;yLl^a($46EBtXCL!jPcJp*`|xqiz&@(doxhgx(hN zx(J1hdsGV3TRZm9rBEWjuM`H8QU=4*wjwQ--<-50o)~{=AK)jnWn}$J>1Di}CJ7j% zWC>_`Z1z1t0$NjkKs-``cRF&k{Ou8}R59_8ppkw&*#0K@qhL#hPet%>drl8m%X?fV zsX^G3;Ug9V_q0=zAv-RWGyY^Ti)VC^%`75A@iV7W-1t$E<55qioKL-wM%!UC1<~l0 zg7-U?QwUh0mf`)5O3YIs{M6yV3RR8wI~J#|N}k|QI(%?fG>H@E8%5Y^>65-{ zOz@ATp#nofWGQ(P5!YxvtpUxu^Y}pPvsZ8hhx(q4_I5COB8bbA#rVYL#^u~ZpXl@P zacIotLQ}KxYKMb6NpPbg)eRGp-aal_$_dG0ykXN|Vzxt^=o1>Emvf#RC-_~FUWDqMJ? zy_oCZ{tWJk0`Xw0t%za@+z2@^yc!QB9XO;2quqkFNe3gcN$Ky z`J-mznyW)fJTeY3zUxA~L>ahCZ-;GfrMJV^nc5R0Ajspk$MQDqkc{F6 zA-A|OrFZ5J6OSx)X(#-Ec)e98i$^Zi1cb3Z;*rnw(QAP5Atq+77W_6OVROpaI-;#^ zvdky>p$Qlr#RA27ZfB$n4+_VTlz9Y)S!Rb?!o4s?EoSGAG~7>Wn+W6786zVw+=B(u zU+_t6IcM>b%xY4ifM|yU8h96S1YF>Gf{Y?%;0|rYSoKc2&38?0JdMbDIZ_arzwi8N zFOoy*I5u3FSw@#Ev%q3HSGQ{A=N(h45LdVQ)gZiUhJp-rXr+hAAiQUidrf6Pw46>v`XOgo|!p>GdmYBYLZ-ID7GJa@d_Jcu!izGBjc=$OyhSUAH zlkr98XVL(Pr)tuFnuwoan$PH%_c%93x3X zfp|=mIB-k|t`M612vp)}TL}M7RN^OFwTj?bHi+AL#c099KW%QD;=ph>PO;jU?jV1} zq&-#>YBp|bBZ7aqXyyHUcMCkZ?x#WhwFOz z@W)E4QQVRA|3_o&WKFNo$$tFFFZ6!($S%vzbP&NGb$(#VReC?4?Yakxd`v z3|9ydKUyl0<5m%D*KOU{D}**blp7rm3_`tP;OA}Ph8)tKu?Q*O{i);#p$ zNVm07N?Iz_YBoOCqh2a8ZY1{yLFjm^e3aeGjEzEMPbRCA|APpR3cf!e_I)yaHBT#E%{fvvvpb8EE(44 zI8T!k(uHK3wzJqiP8Yk=Di)BLbCrRu`t!J+&-Z0z3r$3iStg>go-YrlzHGFVAGA6OE!s7^xSPW{`QgokUy7tn^TQ@` zo}2V)=-_J5m>uwG3h{YxrFhSOj{o5#5%8#vL+QrA?=%K#yD{)!QlsE;TM7reY->rh z{sRXWCQ~>#e?J`PbC?tow2ir30x2Y%mqx;(WH%B{)JPbmk??h93JHs2-AI_QKN9|& z`~?zT>p{ZF7}|n?|ZuKF?S!!^JO% z>iK`g<`!%I?@e+@k7v479v+JMwGN79f}=ugxJ%QTGp#BAB(|6yLW2bTi@daQs613V zXsg4gi8d~ZWyZXt8PZO1n0s-qTmBL3lkQ)FY#?;Z^N9YLMX7M7N-#^00y;FW)|wu}lIibw|5@AveC5 zcr~NQ+RoRsGnCD8``gyj)ra5{av4}K0KwS*q?<2af-Kz~PynM&KBDgZH z*YyW>ExTM9=c@XU5BQt@`y;zg4Z@>5YGmb2?OYUFGs=Vl4Bu=qQXD^0bz&=s## zdHBNaqhum@B!foKJiJ1ox^*9Ze7QDqZu=&+O!NOY3(D_iK>@uj$M{tK{wye8{x=KC z7yK#<%0CDel)pa<%9s6EQ2u{oLHTlE7IfaO^!Wcb3(8NkAPWP((-_!~1?5w~`d=(4 zUw)khvF#o{{9jm5{{Ac|U-n}``GQ|(LHTlE7BuX8nKDN^~^)RtmGx9DUO`n02z_D{DsRX(=2{Wm5wjCNF&50j+l6LG72ENkbXslrR6uit=SYR#f(5x~qd{Mfvh8 ztcbgs^o)#&==jjioG)ZW`TMb=eEB6S%9mfVqI~%UE6V=`D>_!QqNSP@<;$ z2rCkm{Qka9P{osf^EX_J8N2u8O|Nw7RdHhvZ+f|NKC9gXHzxa2yy^GkO<${Om9Kfz zQ1YfNtcjbzt}fuR!6$|rQ`>kjTJ6v}L_p9$x6L%$%HM}=*GeO5{?imDlypNX-)r)r*TK#rsHJx;c596Pjmk-p7yNfY5BNwf1b9fTfrn# z%a?tbT0Z`*=bcO~|CdZH|GzRdn_C0%3eeBTbUIFXn7SFhPt>r~UyTjol-c5ui4aZ|8^Jg& z@Y66vfxm#pb4%ZQ+v;zXp_QG#Xl18B@LkMtDq9u2#zRHRsOjXFXpI_#%rcAe7NFfB zUJ26hkswlUF^JTY>8K}8*`#!Hu$VmR?6MTnWm;;l z%1E!A$M@%i%#+!pj2%M9$Vry|_2=YrJ)1lrm}BW)k4lj$z^mPCZ>h`^k1D`-ZCXaW zo@yxBUmcN#&-Z12e@f|Kb$Ut~d7N6O3UDkL;EUo`1z4vUAdxby`xtPND!|b`(gsSc z7BRaj%@qp-Z?*9(P>Li^lAJhv8`leIk$s*-c5C=w3Q5DHl*?5M9aD%g5GXRS*s}# zdgv8~C{)k(oA|9e1cZVJl7O8Qr0Hvr;EZ3Ko~Z&1qk){qXLE9qpE^F9=2wF-jQ|}H z>e1_J{Hg%Q?8{1T(X6yUu>IFqDQy8^>B5F2^|`Kn)Vg~$FFmhUdVzdzr!SrwgpK>D zbp^t+F#`TjBCXaH;J$9PZi80q3IxyesC5rzkoFV^9@1*vd@Y&}%Sv}OpSgK<^{91s z|5vrHK=9yxYTZwrdZy=5w-Nl*Nqo!)dFhY(?+Z|&24Rh6eFcIyv|4vdMoO(K5PZGwSLXW_5@t6Fy_?M+m`(^}mVgh+6I59j=Q z=X^Hu0Ngl>i-KC+Fmld!6luV&_DbZFbKb+6cmOfFtfO-so2Fv-VrLDv3HL#V05(bcI!DXs6i#4jwcssR7&;gJ8nXU zf2s9-ul*X99GY5MgR`*A%27zCQu>9{)19~A2E;_$9&tiFkB-$k)y8{z2b3MwT^H*Z zkOW1$r5R*knSpJ(%&ML;n=CRK7L(?zSNc&4W=^7j8jOdHMe@A_WN)y$%a<9Pl*C``A9Z1y}lmOzJ#y_`7dpSgyR#fbcy#gUXBv`UQ8CYty zzy3Ep?cZehF=nN>c0Jj=}yZX54p!-x~j_~r`$2IORla^%gEstO-c1(<3EBk-EaR)x4Lo})%!zFk{+{$Z=2R`^z; zQWfIKL^0zP(Z{DoU`Ox%+IU{93bCsp2R9ge`+jd)HVOqRn%ZdiZ|89(;f9?#Cqb!F z%q`-inQcPa1+@iu8Y)G8hnn6F4cjX<4) zef@?9E4*Nw$(-2mqqaJow)EkoU+nd}cyz$1sxTuj%vx^sWUk&!_IXmP!`iwqr-TV{ z^|UTIvb)bLEI_szfoF_Wst|W3h?xtF5dA@jnJ|05GeM`85rUITR3VRnol>AZx5F}+ z9#eaSq5mE+kCK#gZ7oX=+N%ngCYCwH8G|@cM~pd9J6Ui9t-N#{V1V3qamp<5plYii zmmkc&;yD3{b%Jwqt+rk>_U@0!n-ZJob*>Tlb*FZnt?Jh^sArIUHA5o?aEg>$N_CV= zkpwQJr;bFWRyIlP--Y*6U#E$a?dYD`AL)#BH}w0;-oEL>ry6=Q_p$wUd~=x+KhW^9mJ!OQW*YycP8-Kr4Z z#!IACrxvB3y>p71jE9nwS>;1YP0~ac?kkdQ)Gc1M`SR5mT;9ng|0yc;-ws!mge9R0 z@ewNUFf&*S5BT|mhvNF2<#D@vurNw4pvK_E_*PYje<5_KRBN;LHhpd|0S_jM)fl`Q z_p3tOU=QJ8BZSR~#dyRBO+j*#Kt~+n;^brk^PbI@?^R=Pk%nd$m?(IR@X^bF3I-^UKnu?pPLW9Lg{Jv;VHs8Nc3pZAxn7US?SdAFJ&!WcDiLI=*#&Anm z#tOcUM+JYe>rhc;;2OPN#trOQFIQ)1(r-?cunvU6t(5;WMr?BS~VFjceW8*Hz7nqSFR6gZ|s;%g7P}u zIb_A?1aB#7fd$kNCyEE{#dN5fNw?rJf~_67su1_;VQ=l|S@CzN3S<;9 ziV=qw>A*y%cv#^d9bCj~RS3TcVU8b}p>gQoFBz=H;Bk$`hjec1F@ncC9IkFe-lr@lJduc8Ux$%dob{sHS3gX=ICQv3KYc1l@>-mKxh!1TNY?5LRcnw z@m_llR?(M9^0}if*5G~B4c^83fcI~P!?x#=y)rAN3UR`JGE01K#%m8W9-mzI$=pdB092pmpDhroC1kd3KVmF)pCxIxdknL8XC~< zuctIHhX0WJy{)~E1~}3H+;0I8fKiRarXn3xOHZRu$4X$dJR$*^D2;;=+XS&bnoN&l z9xnl*ZyO5)&>B?+9@R}(9hYu;+X0(Kd^M9T>WY1jPgh)+nJs}EB#%ovDB-g?Y-=i$fJ61{bqb3P&uh;xeIr_2h99J&e}^szm*oUSR8a9gGuyPAt}QI=as za~dj{6u|ELL3C2ZD$3JS@L_X~L~uveA~aQ^?_R;wN{+2hnKtk_Whw5BF-1uJ5Tbl- zJXdf>mQPHqjm_72Lp_XyzCP~99a+^v&GSCXu`tc&i^%7@B!KJVn^=ftdWC2*!hZir}+gghW?zd){7o&>2{qR&vvEXOZhhyFNEbhP;hMVhVJDr)X&E%5OQ#RYxkEzy+ z#3T8f{3Y!URfsP#+%gkiwdCNIUKFc!Q9Re;7c9*5v2Psh#`&=l!Tp)b7-vz89}G8g z+>C1}AS7&3jlhp>dVS63ff88>phInCTE4T`e9|7t>9G@p!CvL3=JY z(2tt7%^WQw@O9jQOYLq4cE)qD$nGA3ql*Z|hIonKE5nU5{Fv@QE?47Jt|Sry7gn_9 z-~&4B6-gCZ{Tf-uJOusX#9OvHtWG-cmMx@z-_y1ZTcw)D_6HMwJZ-o!&Vk3;{P-x- zjk6p*}ZJ7cuYjup<=;bu+07v_>3sy{XC z_bK5LkL%aoQ@xFsP~Bx{wpq)+B4QrS9l5rtSOR#tw_8RLqMMtFML#W-Mx5?PVzS;E z5iza!S|?7}h=~rkLYG{;_~OM#F1{Fbi^+Q#(Qn@`TK^Bqz``avgDe@HM!=(eGy($J z+umNVO9JD9!u4W0wHHo6uGao+Vd;`F=Sbrb%E0}NY-H65-Hl}7y*}Bp07n&3Jb0VT ze?elhbZKgz@9Kv?a}>LKyY(hX3?=1cM3%Q7erzlj%-($Rjnq@fs}AEF6q7Da)Mn$$;T$2k6kez>rqSg`95 zUSZ-CtYJ8QzU1Lwjef!MKCH+aoAiANGN~VTs;eK~B~(}S`4xCy<(C`!_y${ScV<6q z=bK%e%Cwa%wyIuXfc&DKlS02I*lq)VA?iS2p)K9*6m^>U&J}eYWC>Hpro{-r(Wo17v zUh767Zcj3jmK>Q#W8zwm_Wk-yoHCOMOp1wxcMUg|B^*}J9-d72vEFbanyWiK-4PNG zno7{yO?60a7|B&{6p0hFOX$k7AnC{VHaGJm;KJlbm}j^druk8#QvccDKzT!W^!pBIlbIPmBpB>9uX zbDB#Q_B(EPKit<)EKWRmh+Dw;D2kdh^?1Ecxn!Z>HfywR8*cn9;UHk!j1U@21c!5o zYZ{92db*pceqO9?aNyPMZaUeGIOU4r{jgg1^v)q}JrmRE8-^lTx=&}GacC^T*9kvb z9C(plv&z7(x!i_3$8~Q*{B&q`*3;J08x=)**>454nqJ99~0u0GT! z4A)G_nLq2y(5nKec8YjQP!`h#In8?sNWKK*O3_I)-ZYCOOet(lYmFKxc+Cu1Pk!wv z7o*sEi*<4pOgG1L(QBBe#6+)+Xr@eTrH0<>3cSPJ#e2_wWix>W-59>wuCV$4H3T&}>-A+Tu8GB!?tC@hdgnIU&3jl3H*E}vI&wJ<}n<@!Wv~R3@qYxI{^uxGFNaI1;jfzxf=Gz1WcBZ z9YY2arFaBW{K$`yxsKH))H>2kH0$NZ^cbJ&Ngq&}hTxwT1f@I^C}u_*H3IMSDpC%t zZtC=eQIOzjU?QRMlk}e6zvz(zdq!mmSCjn_}BAT?qZ(U(Dfi-t_ z*E}BoAPJ(yjw$?g-mX%;yj;$ZaTde@B<_|0%+R4xysf9sr92yB9doIKcgR3x;9t7TxId-a zUBPuCD^TF0`URa<%@Zt7klW8B{N?59M9ec7h;2sH@q)i3{R}`st$&P!t*O_T3kZg- z6%YR8Z#k}zte(7@cemsTFG-w9Sxl8l0QNfFRd1S;$U)C=}R6I?5GnO;)cX9G%s6;&Itl?QB1yQ=K2)4u>{C2P1t&TVG zlx?HrQ4&-UdR>Z#ZM<)b4Pjcc3FGP9A@-rTEV)Ml>Uex=s}}p9-EzB{jcb#B7WUEY zhoQfE26T2X8U%V*sM)wNS*ec4E4FH3g!KfeM4Mk~)oc^NFS|d?uB2l$nk)JG{^WAD zIgEp_5By$`wE^c=3eMCa=UE&0af_{5YV8*oi0+X;(H41u@gslz&Dg_VrD�W6IT{ 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

miq=zjE!iE?pHCL*%crorXi$th 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%0A5;`7GJ(^ZT?Oo_@}dGzgSYtBUCEKBVZwRx+#ARR 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�d4P0@c!45mD2yyC%^On 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

!X3b4rww~}iaFJm0;#V+$=Of++?fe%Fl3emh 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

m42B9 zk%?z3X-YAx;I3n1fNjjpe%k&@)xJqmCF}h8&F(Wx5G>Ngau^F8dx{Gp*)N|bmYCxC zHTQOo0$OXErEkZOm;>x$!5V$0->a=qoD>MpDrUxZmy@S~`u0j}FpfeF7RT`PZExuj zVNz=ytL&4hyAfv}0*r@diUs-bPuTwa$0FHUjGbhMW%HAqZ5ii1z{Zt=;NcKv1q=XR9xj zeff4cXB;IFIX7$(cvCYdC1pvuh05D~nZw<|d#c9nLwBx)f_Q}0NqHo-vWztWd`HKw zzZxD2aU-y7@G#!M1}IyGg+*(BV}4`|ix^fU(t+JORlYDXX~k)tEbZZI+kJ7e#_g6RHkaUM&!}oNY2`Q`)R~qAvXUi80 z<`WWTve`-uAE(O~yq&4}%7C*wAusn>j=8L$6->qY38PM8nF(dqTvonvH=MeYpiXzc(tTjE7+61@ZF^u+~{Q->fZeeBldhs!EOHq*%@!% zHlrsng2F{n;)SuC8^Ku4i$XSJ%6@YzjI5wd$W|*$hJDq3YjW=P1>>aLw2a70&dk_j zUL6IsW0!e+l@5*NWC^f|5=Q1b>_Pv+)K?hN%x@)!Gb+DJ#lji`>oyfP@OysDVhFd$ zd_}&=9p&(d<)8}HTnXFEt-CXqs+cy_a(K?`g6LJFLF*R11%!)}7cOR=5o+cg?-=^8=EMDl>YV3ke zJBYHgna*4Mc*5-%j+l-0^$qsdF&uEpZp6uhP+EIz{ARK^mb3miU z6I5h2+P&7Bn}x)kn;nf!-$LS<;1hj1<)1S{4J&@^%8@&VEy1e7bX9iWxI+23_&$Dz zf?imzYTQsH@;x;>cq3afx0xiFf2Bq-^igZyPgxqjEg2QcXz%BaWQj=_>)16M#g;qE zV;fBDK(b-o9Aw~>G+3RsMnM?ZSa6txQIsd`8&DvL7aOK%u;vXEH@W)QxV2t~2&_@25C&Mz>Wj$sBBq$3d$$ua z*%Rg@hEIH%H6eR60z-Ge2LT=vCbD(wRt}jp7#JW!#ItR&YA8!eRITGJ7J*`0J0#VM@tP=J^r_hsNk;CrNc5{+ z+3CRy<`V2jE$MIe9wy~@>M(OhFJkDRtYR6<$G#I)*Fc|fq9F-NEJc({m?w->y}(0DM5J7}Jit@bmPlb1y6{_78p*uSK% z(l48%wJL5bw|Pu9t{@}ko6LBp&dG;r<;^j>g9V{f9?yv#%4n@Yu@^R;QJHz}tD%3o z87bizvQXaYcU$|dKdX{+Tk!o{tJ{pJV7Fs}$0+~SFqYdU8?iTw`*ogg$IzYd@-tznl1uFyIBh}l>Knw$=^OO4%R^7Re)kp2Gkr3#>a?m1o`12(VqOceo)^Y) z8RSd*pqigOuPb90ZvrZgUu823V@E54 z-aXzfG`tInu>i`gWpT=GuWZ=y;K|x^0&-99I>WYcp3^ZUVC!7>J(klut!?4X`Hkf! zP^0n=skb-U+`$pt8s0;MA-GfXSje(xRmNZ+UjwnFF}IDK()d8^KzY=@Y}j9o33#4B z#Bn(cF}}n@$QEZ75n^1V++jUCAhHdFNeN=#n>CVKoV;vv`mUqW@4;rE;P!R zPPGK1h}6Sa^kNf_d$c-PvtO1OgTRi;d_URrE-QWrG4i^|O|+7cS+N24#k?^~ijRp0 z<28!S(qea?vkNk&Y8I?NIl8`_J)XB?6HSxInrA^YO#*FB&cJ5J+}#B^RuPV0g-W4( zq>g>e#c4ZEc~tk=nq(NOh=F~_uSnY}TT6Oll`*^JS0=J}PIVonPG;K4nBiwa9%U8L zv6C@qwP8PbjA0{RHgC;vQV?s5YL}1*77yixb2}Y;y1s!GC%nOmX+~RNw&2QXa515q zCx5wOtYQ{T9iv)dCg!B@Xe`4ZD|Sj^6JPRnqnH|n{fz1;oQW&Zc+-1hQ#DL(M9Im7 zA;!mJ&LA^3i%5axb7U$*UI?^fs*mdtGxTBdI_tonE%$_WDTqyz#O0M=GiZ!QEw^T8b3l+UDz^7$YW9wQQOg$KiAih1 zXuL2jv+lTjdFv)>Oa0bs4mh%>(u?ICh-v$zYRq(zfr9B)v>F35GUN2Z5CE)cw4nm zuslSuK4^9UZ?Dj=*tW8d7AGayA}qbwSSpUxoMtY!=01C0KLznT!qA9p=?Iulk;G%sgGVGRzM2ew3^ zGzr@U&>r_z-+UMHRI&1}mMZmKl%w;XFjOf=J9!7)n1f5;#2N*eB(Z9C0)0m0TMBmi z6b{(atrOY2d&&+4vF<>5V*8kI9`J=?o8D=Y%W)**Vn`bG@i;H(u69f>KW78<}s-%IVKaz86HKc1iFM;VWQ{R zbza3*D{K@<5G7{K7#q#{9%n0!WWZA<<{+|(<=;^y1(v0(*d-C6jCt%5)Xb*MZIv4C zG?u59r|TN#d|XqJ#M^~hCgegD-Y(7{=56pp+s&}X_6AJWn;M^h->BihI&4+*2VQvY zsLR;M-NrT%dxyq*!3g{4uqhSmBKB=g57OI_t#d=AoiTI9-tLNw#uByOume#UiS4~9 z!aE;Utp-ACWE6z8*S`aq)5sY%A-W;#P;#Dq5#AjHQQ&7rjJ$MJv<+^--6X;oyc~)3 z`ktoNi3)djFygJ$X1w(u2yvP1J2kfUV5&urnQ(3>?z62qGib=FaPN`}Vz`NSO?Nqq zSmu2`RhUNV#b9aT4IdrcG6yA^B;TJZc?`|1aUoXDyxm06S{j~ai=*}pC0ut@jr9Pp zf$C;j#LAlq;0^Y|x9MyQ4NKnSh_}o z<0doCag#=>XO{B0Iglhr0Mni3jMmV)Tyggbl(QsE6N(ZlXv%5M zQxkT-C;$_K?2wsydm|lE@F(v?RF}CBSYs1p2%ggI z1k+~430KQp;;q$+eRgLVrwGdyMsLg#h~0rgS+=>xk76iShPW%D4iAmg9UqJXPfQ!c z6l11nzhe{Mu$i!56OIgzH_lmlp(tL%Fm5DRs|*ihGU&Bmx|OIrWs69yhbjrECnrT$ z9#49xWN$wigu4qDjnCVKaZcT=y_y|;N}DqId`^~PCd zhTcreSxqhyTK&`ry)~IgX022hVbXexr$`RcA5~yv@2S=P$GDpF!-Z4U=Fm^egJIJZ zC$r7ugO!x4@V%xNE?#&yxSd;16AwB*Q{OQ;Rxk^?Uj5rD=k2K~H1QQ+vz69a`;@UT z4gx|ef!DO_!SR(AnO9D5SJ|`b0)zM7;Ow2p$Y{_-Q6xHN;wrw8@m&cC68Tv3DSot zSUIp{UwrxA1dZvpVM~^~YH#f16lQFywbMrIl=@yy62^|?W@*~0c)OCod&&jd$V=7J zCPyI~P)r8Az}d3(Kxm2vNpch;xXNB=40icR3qEI<7<8j@e#DPCl-nIk%4gmP@uD`n zIz1Vd!aNBAdlHOWo%RNcvY+jE!+{ltCth^kw5chdktNqr-RS^`)n7T%2+Ur*V??qigbtHg(?m__>}ut6(dz#w)UWwe*c zov2)+)+KapTV?=nMCQ%1fz?P@{7}_2vCyJ@5_Rt#x1ek$3RSjFMs3l1K3DFBcc<{8YMrJj4R(l4;9lvxp&Z8J?Ynp7%_BF# zT4w&Ra}<9NuSi=4GY7IZX;zW0X~rUxV@SpGD7?NJh3ML(A|}U>O3Z0G>8Q3%N*wpL zx{&ok$@Zd5L!`-BoW$ZeUN(o*jvW|Ljp>@54PZ9PnITwS9FRRA#LT3;7-{*2$;PPj z7KvFK$14~9L5$eSZ0~tAm{hBGj|oNJ;O2?#D;6TCPqux03>hpx~oV0M2UAGE2Y+L zNWZO;)Njm3S7I--U<8ICP;3zc;!5d=+0=j%+xatcdBpSOlM{vQwxOKX?J!<(Pg?@- z#a!$yD(9_vm|7z}WN#!wfAZHzA;L3-G&^f{U4%`}oP{df@3hTsev@VQ-7Xl)t7WF; zZt>1nh3+EHcZtZ^*=qzfdjqmaoJVB}>drTWM2Nj__N*R6GBOyz^t#u-RAH68?zAMK z;3?5+u_888nBJBpIsT}>BA@j+V#YSng%XW7@h&3s0@;-JE{rJrd1aBAF}53}5&3;E zw2k=zXuR)L1d>5_M%6oI)}X#9vmb@C^MKQ6V{gzHb9ZEJM7X!w-=Z=yybEbX7oKco zJv5r*uFP1-HT0%+#mt|8g^ZosjZe0OTYw&IWpE^j8dK3z0<ifMyZm)jlUKuSZyWWjR2K5b`Q;e=` zcSafJ+p2gG#RB)`q`+uBdq!n5l~u{o{LFV}JefC%WtypZT0-UF3>(kdXfSSco|~gE zyjggGk*qz^2%G1OkZi-G0 zY7Kd!cD8ev7_Iei!=?kv>TDrKUgldcj?B4~nBhkrtcg!~<1VSF zku<3=m1;s+oLBeIEWKrHNZb`{3gTPOv`PEDz_fF(8yFe-K+xvxf=jocN*cSRn#5B? zId9*s+%vY#@e0l|iGQ+=yn3LYH1NMKfQPm|chfc`vb7G792-+CN1JhVl?*ZC?x|hn$>jK*Q^1l2#2Qat&&D^ zu`e-uXT;H4w>tN5B_SN@Co@jYjtk6G*{@|8^nHg4{Reg<-GhflcUjPg_ZF)7+{yWq zMSB1tF2X!a?8hUQ<^4pC6>+Q9+=l`4Y|y92+Tx=+&YK}dx79sVK9cP;4$X_$d-1_o zZ|^s6IJ4t&S3i>^6#gL!&vKbb54@G zOSX)Dzd3BxGnZSa=Ld|ryn~IwA`~a(UCamJw!I|xVjjyLgqk?^;t)^_ zI1(=_;?5l&*y2TlqT5r8CKe-$wOVOKs);q-_^PjoM>ZO4!-VjMf34l|im?On*a%Z(0m^hQYhMOnDuP#_cg);i;Jx8w+LWJ&gpplx}wtGIJ z$lXywAc(`K5l4Ni`>vuypt4wKSw&v6-W#f@a34ZNbtAIw zwF!pZYvYFNdlC%S_jran@qy7nFZ3Na6uZJAE?_>x{Z<@qT6$P6Q+NDIsT>?QmU#az+boK;m*kYw9ph5KbAk z()m?-7W$~!lzLXyd~vC(KU=p(f=O!W*7i$eF&o^dtrK{X)veMn;hU#|L30;o__LFx zhP>Wvy%-iH6|+IPqo;G%E??MOn=D>fUf+X>m8kB*ijlamH`6)0+Kr*yxLCEg3S&6G z71NVupCtMtcG5Juy2SD5R}u|l6k=wC4d63W_!bw&(1Ye{enzGr`()_4ZC#(rR?QiK zfpTVIm%M!hY}BxS;z-x3Gj>l-mk+P-M8RI9 zFAIWV78LIh4#;k-Kr~R#=wfalz_`ASH6+W#NcN*$Mxpe9d?(&2-%=ctS3H8yp2F0d zr8Q;SipOOPRQ8&gf-s;_oiBwl8kq|51FF{5h{NKveGt_M=E(6PeiV8{Zoe1D%<7mq z%Z`E)v z1F2naMQvBEp$ThSmGIqRuYZatH;zY6tKc|?zc_&_80E2AnZjiFp3!~sx=@fmY@)^I zhzIIBv6FBgRs|vrju;#F6EdsFLAQ-eG1kE}VGyO<4)E@BWy!b6>~}j$=m@o+N4( zo`m8Fng`A~E1Zv0hIK7s+G6^rPJSIaUu6Q>i?H z4Vp!DSFR&@N3#cetnqE+iX+TmHhXo~cA4U31S-kM8DEYB&vpqRv6I5HgT%4hdvKR# zb+1=~P*GEb6G~2Un_1n3|7@MEPU2i&ug)U9G!6fHM_Tuy%G`bbI8J?7-BqnrG3gRD zDp$1+r#pw`vQ=0|jRo6+nQMHuJULEV8H+Viy7BtG0M86^S;U)2OAm0@Bn8~uV3fE! zOML|;qo_0^h z_i)z-C9%_7Zu;cdj-y((HKv-(C6nRMk}NWkNSBh5D4qWA_k9b3SP+oX++AlcmocCqHtuBTXH=!zlGI=gmA!)XgX(p2TLBkW*tw>TNKJ<-x9 z6sK(g9N`oAkL&bzbe7ERmEm{Jo-ysURrQ7zm zqR_~;8^|pOW)&>A%E~SB&FzP`*=RtV)DqqoNq~{&5CPj7UWD||ayaC(HPxpQRRd-C zBbVsh3@U>YHrlO5Lx%VKRCg}VYwTl0ADdkA8I%JhE=P=(8+_A7!F~>X8uA&?pedQl z!ml7nGMg#Ru&;I|HMS`1(G<7*3aP+Szs9c8Wx<09-Y4GlbKj{6f?`uktSQX2E&-1P zz1nv_e1QVX>Coi|K(wn7Fj%`dy*wS^!T#XdyJu=G(jv2rGkoNL_2p$)|AZXjZsQ_ff#0AUhkFYPt!b`8GR_ zh7Mo3N+;~$-cgQaCyEXStD$TXb08d`)j@xs7G&`qa(;?~6sOzA{lt9aK{}=__mc|n z2dRaz5qJwmo zh@RoQCwOw~qQ67yJ9VZBmM@fp^j5e5-e1`c_AsUJaTKqbt1kW^HL9Eae08t~DRG~- zpHc_=T}m9(2L?XLb(0*V8MIcX3kUdv)WXAWuL-*7eY9|~f}=t_YdcS{6hMt?vmJXNtO4-Q zs;Q2J@JPuAiLprsrc!PBT&2q-((Qbwtrc%C7AFv0aA9a(N8)+*WE_TQ7%~R)+IF9s1%gop{OZscv&*#2?#}vOg z88&CQO;Uk}5U+70%@XwQvAB`~6vXG^9TfdE+xcZ9A1Y%dpSj~{p@r+40xR(f>q+^B z7nQ0y&E`C2WcA75rIHwBS)TaQJS5uSupE5FGX_bBk0C}Kdfb4=&@HU#jt#_XK)W-L zv=6I|%lIG%t~YQ$X!0SlmTOA0%#&RFsT-#K_NBH|jo(ltX#CBb4+|*=VD~sL>f8E# zVLPdh9Dif)3yXDkKMNV+ zwPIT|uaEBl=rHsAX^flWn0Su=8Ii=XVVfZ=dw+N}I&Rq&TWOEm7B!!UeHm`neSFwB zCypMj^u~COS?4%8`6zcQypeTMIf*bV4QD2sRh~lXEcVz*PL5r3!90-`UIKsdT)}B4)Ij|{6>G#; z8@?2vuxKwSHHR-Fwfa{Go7B6l|3bx~g1d&pogd05yz#HjKam;USX7^?B2T%wcoq3h-4(=j+!X>l`} z8(H8Yl@pJxP_^!(mJ2(}DKH;2jDQof42xhmL-~|t&cc>QK^tEC*9aWOBeIqei;z>* zE_I9CQ#-4Ox+B}dDGXe_8k3XnkSZsELY_kR`*dkzL)cCapY+|Xvh>;_sxeFp^BKqP2psa_YM|Tp^%r?iA%d|pWegR}JXSERe{)b!gF(NrFA9W7IKL#k zo7vO2;;azkhyD-E0%y9dI(QEc*>h=m+z16`ivK_G!i2u0xhQ!<#G| zZSe=+j|P`dji}J~o^V;IXIV$)%l-C&hWzVZP(D^1i?#q6F)o`dJZyiFfCN1McKG}4 zdgt=80OEUpas}00-H1yRA4G-xh|?<^`@%VG@PmvN`D=B*4v-~p9s?*HQ0ol^qf04i zh#I7Y*=!khpHgf-MVMSuuSv_*yX2lV27i?#F)$?)g|o3E2w|TWzyY@u27NW6$a{$~ z$k6BjU%Wq$8~n#1 z9yF5TbYt*6|26z%aGU>Qee!q5q{)rmX1l1khrL59!`|k{sPYuNB{R3Z*wPgh6L!A! z<_o)@bPm0cw~@Ul6Aj8L0Rg%$@$hkH#+W z;-f&ZERYr$=+1eFQ4HP3lkWgklo+pnVRcgfw?{mIi2grk4gpzC4V{jPF(vVX+Xk77 zrgr`N;OG}~Cb4Xqx#cXry!OKr7 zdWCAw7-KLvH8A)%4k{;@8?^z81)U~mgFyy6@GjL}~^33`24ac!l*Ro(RJh)Mk2>NtiwNxn5`K+YBbt z4un^g)aR_kLmn_AZ}G6@TdcPW4JxKZdWIcHO^^OIVf9$8DhA|eA$69obUr+a27e!w zU_0;fyUhz6WmpPl>StEsU?0Ldy{}-V%RQGyBIb>f%ozqHqFxp}EpBOL+ex+-3JA~Q zOY%&~`3wh^ZJs>CYwg~*YCxR$)zxCADs-l551TXW(o|laRq1jxZ?JJMc;BFs@9KylNOOSCkmDQ=vng1SP2gkXQLg5-sy6JY zmeo!R_+pMDLCP}PbuS>`wU>OkLm)6!`HM|nRF59yD@?28T+#CS8YYuXL*lJA4NbuB zqpH>Atg7c;2e@2jbBryoQkQV&)Fr}p9k(Bv-P(5y_^vY24P|fiq=Q5QSO45t3 z6GT>!yQ!9>8e~IFd^hphWw@hicC1{hpIM%LLXX#w1+;_ebk`VDJN#2z!gpor^(6ob z2nYt#nh^YQbl1kK%owq&?)bb`isxEs>ua3pJY>Zb{aq2A!N#*l5$Z+jf@|ug^r~27 zi>3)lncbt;dlJN@EiTJD^TCZ8uL#4D!lXVOZdKg?R6X@(p%}VRz3xWCs}ijT?@;W} zFX7;nYrbu$x_hO;0&bM_b$;ZD;8l%%w0RvEseOYhJ3m+%D6zywD@@b~#Po zz(^l6ot7TK1Dsswd4RARc;)5PVD~|CJao6}CI^fw3B?a+B-Pv>1tg41>wSdB+j`*< zt_wXI+^!K=Rh59imZgW^K)a@=%f~#s#{+q)kKYQW@j*=o+|=+WI4XCOR@}G{BM&-& zv#=^vNDa3D_pR*>OZf_wRie}l0|C-KM;#4M40$-6yZ zlr2{~+zzP%aLtD9Ri;Vf&S(p<@OL>TqZDUyv`Ti!ZF+_|zSy*ODVOvPWugjNl+n{W7JLxq`#S0BRUIh_2!-qczL{;fbr)v?H~K z9IbI6haM43s&t2p5xm1ZC0i(4!X2D8WL`!T2R_xT7Y27TC~-9a@0iIkm#Cju1z^_K zqa(?-HP)(F%&25Kx2y?NT@qXsF=TMcQ!sz2pHPkHsT_dM-dIeE>D1E>d{f~aSGc+Y zNm1sQa}+~L)``+BiE62&df24rh+3o9G{Lxsr*wvak9Cn(V704O_nH{4C_Af}WVeJ9 zPI{Bg^#VP?%0E-$8be`A1Pm9pq;)mixsS4UMXLf#g7Z!pdly3}#DqJx$z z1FKjy%*V6kcCLnuZ7FE%au`F)gWW>bR)$EzO-Q zKfh76dus1DE~_z!26mO|62H}@!N8_4;~~LQJmvz~Qhk?Uo>Fb}4xJ6N&>2c{)S`Oi z-zvd-m-aoXeV={9+AYBgCVY3m7WG~U_dV>NTDTeq4;8jRoqZ%>ot+9nk;OK_Lq}LX zRiW~&T2#JOi}L&0&#qT0#sIG2`U&1zf7ypqJEnHJdqX|As%qpx!~oZ%Jn(4?H90R} zh%uc-auU=86!Z9K;d=-&;PT_<4lS#csVPg$QjgL!of%_Aan3lx^NHeM@{ zo!Rn{g%0It~Z1PA^v2HUQMAql7m*&8B{eL9yv+edME YQq0akLuXWrB~N{v1BQS;w_0I9AnIRF3v diff --git a/ciphers/rsa/RSAcipher.go b/ciphers/rsa_cipher/rsa_cipher.go similarity index 100% rename from ciphers/rsa/RSAcipher.go rename to ciphers/rsa_cipher/rsa_cipher.go diff --git a/ciphers/rsa/rsa_cipher_test.go b/ciphers/rsa_cipher/rsa_cipher_test.go similarity index 96% rename from ciphers/rsa/rsa_cipher_test.go rename to ciphers/rsa_cipher/rsa_cipher_test.go index 3a7a04153..c70040b40 100644 --- a/ciphers/rsa/rsa_cipher_test.go +++ b/ciphers/rsa_cipher/rsa_cipher_test.go @@ -24,7 +24,7 @@ var rsaTestData = []struct { "the quick brown fox jumps over the lazy dog.", }, { - "Encrypt full sentence from RSAcipher.go main function", + "Encrypt full sentence from rsa_cipher.go main function", "I think RSA is really great", }, } diff --git a/ciphers/rsaBig/RSAcipher(Big).go b/ciphers/rsa_cipher_big/rsa_cipher_big.go similarity index 100% rename from ciphers/rsaBig/RSAcipher(Big).go rename to ciphers/rsa_cipher_big/rsa_cipher_big.go diff --git a/ciphers/rsaBig/rsa_cipher_big_test.go b/ciphers/rsa_cipher_big/rsa_cipher_big_test.go similarity index 95% rename from ciphers/rsaBig/rsa_cipher_big_test.go rename to ciphers/rsa_cipher_big/rsa_cipher_big_test.go index 5be07d694..973be9672 100644 --- a/ciphers/rsaBig/rsa_cipher_big_test.go +++ b/ciphers/rsa_cipher_big/rsa_cipher_big_test.go @@ -23,7 +23,7 @@ var rsaTestData = []struct { "the quick brown fox jumps over the lazy dog.", }, { - "Encrypt full sentence from RSAcipher(Big).go main function", + "Encrypt full sentence from rsa_cipher_big.go main function", "Black Lives Matter, all lives can't matter until Black lives matter", }, } diff --git a/ciphers/xor/xorCipher.go b/ciphers/xor_cipher/xor_cipher.go similarity index 86% rename from ciphers/xor/xorCipher.go rename to ciphers/xor_cipher/xor_cipher.go index 0296c97ce..26a3c0225 100644 --- a/ciphers/xor/xorCipher.go +++ b/ciphers/xor_cipher/xor_cipher.go @@ -1,6 +1,6 @@ -// Package xor is an encryption algorithm that operates the exclusive disjunction(XOR) +// Package xor_cipher is an encryption algorithm that operates the exclusive disjunction(XOR) // ref: https://en.wikipedia.org/wiki/XOR_cipher -package xor +package xor_cipher // Encrypt encrypts with Xor encryption after converting each character to byte // The returned value might not be readable because there is no guarantee diff --git a/ciphers/xor/xor_cipher_test.go b/ciphers/xor_cipher/xor_cipher_test.go similarity index 99% rename from ciphers/xor/xor_cipher_test.go rename to ciphers/xor_cipher/xor_cipher_test.go index 999755188..48b266390 100644 --- a/ciphers/xor/xor_cipher_test.go +++ b/ciphers/xor_cipher/xor_cipher_test.go @@ -1,4 +1,4 @@ -package xor +package xor_cipher import ( "fmt" diff --git a/conversions/roman-to-integer/roman_to_integer.go b/conversions/roman_to_integer/roman_to_integer.go similarity index 100% rename from conversions/roman-to-integer/roman_to_integer.go rename to conversions/roman_to_integer/roman_to_integer.go diff --git a/conversions/roman-to-integer/roman_to_integer_test.go b/conversions/roman_to_integer/roman_to_integer_test.go similarity index 100% rename from conversions/roman-to-integer/roman_to_integer_test.go rename to conversions/roman_to_integer/roman_to_integer_test.go diff --git a/datastructures/binary-tree/binarysearchtree.go b/data_structures/binary_tree/binary_search_tree.go similarity index 100% rename from datastructures/binary-tree/binarysearchtree.go rename to data_structures/binary_tree/binary_search_tree.go diff --git a/datastructures/binary-tree/binarytree.go b/data_structures/binary_tree/binary_tree.go similarity index 100% rename from datastructures/binary-tree/binarytree.go rename to data_structures/binary_tree/binary_tree.go diff --git a/datastructures/binary-tree/btree.go b/data_structures/binary_tree/btree.go similarity index 100% rename from datastructures/binary-tree/btree.go rename to data_structures/binary_tree/btree.go diff --git a/datastructures/binary-tree/node.go b/data_structures/binary_tree/node.go similarity index 100% rename from datastructures/binary-tree/node.go rename to data_structures/binary_tree/node.go diff --git a/datastructures/dynamic-array/dynamicarray.go b/data_structures/dynamic-array/dynamic_array.go similarity index 100% rename from datastructures/dynamic-array/dynamicarray.go rename to data_structures/dynamic-array/dynamic_array.go diff --git a/datastructures/hashmap/hashmap.go b/data_structures/hashmap/hashmap.go similarity index 100% rename from datastructures/hashmap/hashmap.go rename to data_structures/hashmap/hashmap.go diff --git a/datastructures/hashmap/hashmap_test.go b/data_structures/hashmap/hashmap_test.go similarity index 100% rename from datastructures/hashmap/hashmap_test.go rename to data_structures/hashmap/hashmap_test.go diff --git a/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go b/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go similarity index 96% rename from datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go rename to data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go index eb0a1f08a..e6754e1e9 100644 --- a/datastructures/linkedlist/doublylinkedlist/doublylinkedlist.go +++ b/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go @@ -1,5 +1,5 @@ -// Package doublylinkedlist demonstration of doubly linked list in golang -package doublylinkedlist +// Package doubly_linkedlist demonstration of doubly linked list in golang +package doubly_linkedlist import "fmt" diff --git a/datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go b/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go similarity index 98% rename from datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go rename to data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go index 5f13b040c..eeac97e87 100644 --- a/datastructures/linkedlist/doublylinkedlist/doublylinkedlist_test.go +++ b/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go @@ -1,4 +1,4 @@ -package doublylinkedlist +package doubly_linkedlist import ( "reflect" diff --git a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go similarity index 98% rename from datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go rename to data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go index 9f7094692..11267a9a6 100644 --- a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist.go +++ b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go @@ -1,5 +1,5 @@ // Package singlelinkedlist Single Linked List -package singlylinkedlist +package singly_linkedlist // demonstration of singly linked list in golang import "fmt" diff --git a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go similarity index 98% rename from datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go rename to data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go index 3ad07ddc1..fb14fa7b8 100644 --- a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist2.go +++ b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go @@ -1,4 +1,4 @@ -package singlylinkedlist +package singly_linkedlist // TODO not needed because there is already an implementation of SingleLinkedList diff --git a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go similarity index 98% rename from datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go rename to data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go index 0ba8b94a7..7cd713fd4 100644 --- a/datastructures/linkedlist/singlylinkedlist/singlylinkedlist_test.go +++ b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go @@ -1,4 +1,4 @@ -package singlylinkedlist +package singly_linkedlist import ( "reflect" diff --git a/datastructures/trie/trie.go b/data_structures/trie/trie.go similarity index 100% rename from datastructures/trie/trie.go rename to data_structures/trie/trie.go diff --git a/datastructures/trie/trie_test.go b/data_structures/trie/trie_test.go similarity index 100% rename from datastructures/trie/trie_test.go rename to data_structures/trie/trie_test.go diff --git a/designpatterns/abstractfactory/abstractfactory_test.go b/design_patterns/abstract_factory/abstract_factory_test.go similarity index 100% rename from designpatterns/abstractfactory/abstractfactory_test.go rename to design_patterns/abstract_factory/abstract_factory_test.go diff --git a/designpatterns/abstractfactory/adidas.go b/design_patterns/abstract_factory/adidas.go similarity index 100% rename from designpatterns/abstractfactory/adidas.go rename to design_patterns/abstract_factory/adidas.go diff --git a/designpatterns/abstractfactory/adidasshoe.go b/design_patterns/abstract_factory/adidas_shoe.go similarity index 100% rename from designpatterns/abstractfactory/adidasshoe.go rename to design_patterns/abstract_factory/adidas_shoe.go diff --git a/designpatterns/abstractfactory/adidasshirt.go b/design_patterns/abstract_factory/adidasshirt.go similarity index 100% rename from designpatterns/abstractfactory/adidasshirt.go rename to design_patterns/abstract_factory/adidasshirt.go diff --git a/designpatterns/abstractfactory/ishirt.go b/design_patterns/abstract_factory/i_shirt.go similarity index 100% rename from designpatterns/abstractfactory/ishirt.go rename to design_patterns/abstract_factory/i_shirt.go diff --git a/designpatterns/abstractfactory/ishoe.go b/design_patterns/abstract_factory/i_shoe.go similarity index 100% rename from designpatterns/abstractfactory/ishoe.go rename to design_patterns/abstract_factory/i_shoe.go diff --git a/designpatterns/abstractfactory/isportsFactory.go b/design_patterns/abstract_factory/i_sports_factory.go similarity index 100% rename from designpatterns/abstractfactory/isportsFactory.go rename to design_patterns/abstract_factory/i_sports_factory.go diff --git a/designpatterns/abstractfactory/nike.go b/design_patterns/abstract_factory/nike.go similarity index 100% rename from designpatterns/abstractfactory/nike.go rename to design_patterns/abstract_factory/nike.go diff --git a/designpatterns/abstractfactory/nikeshirt.go b/design_patterns/abstract_factory/nike_shirt.go similarity index 100% rename from designpatterns/abstractfactory/nikeshirt.go rename to design_patterns/abstract_factory/nike_shirt.go diff --git a/designpatterns/abstractfactory/nikeshoe.go b/design_patterns/abstract_factory/nike_shoe.go similarity index 100% rename from designpatterns/abstractfactory/nikeshoe.go rename to design_patterns/abstract_factory/nike_shoe.go diff --git a/designpatterns/builder/builderinterface.go b/design_patterns/builder/builder_interface.go similarity index 100% rename from designpatterns/builder/builderinterface.go rename to design_patterns/builder/builder_interface.go diff --git a/designpatterns/builder/builderpattern_test.go b/design_patterns/builder/builder_pattern_test.go similarity index 100% rename from designpatterns/builder/builderpattern_test.go rename to design_patterns/builder/builder_pattern_test.go diff --git a/designpatterns/builder/director.go b/design_patterns/builder/director.go similarity index 100% rename from designpatterns/builder/director.go rename to design_patterns/builder/director.go diff --git a/designpatterns/builder/house.go b/design_patterns/builder/house.go similarity index 100% rename from designpatterns/builder/house.go rename to design_patterns/builder/house.go diff --git a/designpatterns/builder/igloobuilder.go b/design_patterns/builder/igloo_builder.go similarity index 100% rename from designpatterns/builder/igloobuilder.go rename to design_patterns/builder/igloo_builder.go diff --git a/designpatterns/builder/normalbuilder.go b/design_patterns/builder/normal_builder.go similarity index 100% rename from designpatterns/builder/normalbuilder.go rename to design_patterns/builder/normal_builder.go diff --git a/designpatterns/factorymethod/accountingDepartment.go b/design_patterns/factory_method/accounting_department.go similarity index 88% rename from designpatterns/factorymethod/accountingDepartment.go rename to design_patterns/factory_method/accounting_department.go index d6757922b..20fb1248f 100644 --- a/designpatterns/factorymethod/accountingDepartment.go +++ b/design_patterns/factory_method/accounting_department.go @@ -1,4 +1,4 @@ -package factorymethod +package factory_method type accounting struct { department diff --git a/designpatterns/factorymethod/department.go b/design_patterns/factory_method/department.go similarity index 93% rename from designpatterns/factorymethod/department.go rename to design_patterns/factory_method/department.go index 114159acc..9c54466f4 100644 --- a/designpatterns/factorymethod/department.go +++ b/design_patterns/factory_method/department.go @@ -1,4 +1,4 @@ -package factorymethod +package factory_method type department struct { name string diff --git a/designpatterns/factorymethod/departmentFactory.go b/design_patterns/factory_method/department_factory.go similarity index 92% rename from designpatterns/factorymethod/departmentFactory.go rename to design_patterns/factory_method/department_factory.go index e1e8dfca8..b72aff711 100644 --- a/designpatterns/factorymethod/departmentFactory.go +++ b/design_patterns/factory_method/department_factory.go @@ -1,4 +1,4 @@ -package factorymethod +package factory_method import "fmt" diff --git a/designpatterns/factorymethod/factorymethod_test.go b/design_patterns/factory_method/factory_method_test.go similarity index 97% rename from designpatterns/factorymethod/factorymethod_test.go rename to design_patterns/factory_method/factory_method_test.go index df8304b68..4245d7aad 100644 --- a/designpatterns/factorymethod/factorymethod_test.go +++ b/design_patterns/factory_method/factory_method_test.go @@ -1,4 +1,4 @@ -package factorymethod +package factory_method import ( "reflect" diff --git a/designpatterns/factorymethod/financeDepartment.go b/design_patterns/factory_method/finance_department.go similarity index 88% rename from designpatterns/factorymethod/financeDepartment.go rename to design_patterns/factory_method/finance_department.go index b6f2194fa..191ecf0a7 100644 --- a/designpatterns/factorymethod/financeDepartment.go +++ b/design_patterns/factory_method/finance_department.go @@ -1,4 +1,4 @@ -package factorymethod +package factory_method type finance struct { department diff --git a/designpatterns/factorymethod/idepartment.go b/design_patterns/factory_method/i_department.go similarity index 83% rename from designpatterns/factorymethod/idepartment.go rename to design_patterns/factory_method/i_department.go index e5c7b7148..4d6f6fadc 100644 --- a/designpatterns/factorymethod/idepartment.go +++ b/design_patterns/factory_method/i_department.go @@ -1,4 +1,4 @@ -package factorymethod +package factory_method type iDepartment interface { setName(name string) diff --git a/designpatterns/prototype/file.go b/design_patterns/prototype/file.go similarity index 100% rename from designpatterns/prototype/file.go rename to design_patterns/prototype/file.go diff --git a/designpatterns/prototype/folder.go b/design_patterns/prototype/folder.go similarity index 100% rename from designpatterns/prototype/folder.go rename to design_patterns/prototype/folder.go diff --git a/designpatterns/prototype/nodeInterface.go b/design_patterns/prototype/node_interface.go similarity index 100% rename from designpatterns/prototype/nodeInterface.go rename to design_patterns/prototype/node_interface.go diff --git a/designpatterns/prototype/prototype_test.go b/design_patterns/prototype/prototype_test.go similarity index 100% rename from designpatterns/prototype/prototype_test.go rename to design_patterns/prototype/prototype_test.go diff --git a/dynamicprogramming/binomialcoeffecient.go b/dynamic_programming/binomial_coefficient.go similarity index 96% rename from dynamicprogramming/binomialcoeffecient.go rename to dynamic_programming/binomial_coefficient.go index 3d5a43611..56682eab6 100644 --- a/dynamicprogramming/binomialcoeffecient.go +++ b/dynamic_programming/binomial_coefficient.go @@ -1,4 +1,4 @@ -package dynamicprogramming +package dynamic_programming // func main() { // myArrayOfK := [4]int{5, 6, 7, 8} diff --git a/dynamicprogramming/fibonacci.go b/dynamic_programming/fibonacci.go similarity index 92% rename from dynamicprogramming/fibonacci.go rename to dynamic_programming/fibonacci.go index 2d6d3417c..73fb49878 100644 --- a/dynamicprogramming/fibonacci.go +++ b/dynamic_programming/fibonacci.go @@ -1,4 +1,4 @@ -package dynamicprogramming +package dynamic_programming // https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/ diff --git a/dynamicprogramming/fibonacc_test.go b/dynamic_programming/fibonacci_test.go similarity index 96% rename from dynamicprogramming/fibonacc_test.go rename to dynamic_programming/fibonacci_test.go index e14806107..0d94b8edf 100644 --- a/dynamicprogramming/fibonacc_test.go +++ b/dynamic_programming/fibonacci_test.go @@ -1,4 +1,4 @@ -package dynamicprogramming +package dynamic_programming import ( "fmt" diff --git a/dynamicprogramming/knapsack.go b/dynamic_programming/knapsack.go similarity index 96% rename from dynamicprogramming/knapsack.go rename to dynamic_programming/knapsack.go index 257f0c6b4..7ccd64b02 100644 --- a/dynamicprogramming/knapsack.go +++ b/dynamic_programming/knapsack.go @@ -1,4 +1,4 @@ -package dynamicprogramming +package dynamic_programming // Knapsack Problem // https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ diff --git a/dynamicprogramming/longestCommonSubsequence.go b/dynamic_programming/longest_common_subsequence.go similarity index 97% rename from dynamicprogramming/longestCommonSubsequence.go rename to dynamic_programming/longest_common_subsequence.go index 04a12f8dd..e251b57ad 100644 --- a/dynamicprogramming/longestCommonSubsequence.go +++ b/dynamic_programming/longest_common_subsequence.go @@ -2,7 +2,7 @@ // DP - 4 // https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/ -package dynamicprogramming +package dynamic_programming // LongestCommonSubsequence function func LongestCommonSubsequence(a string, b string, m int, n int) int { diff --git a/dynamicprogramming/longest-palindromic-subsequence.go b/dynamic_programming/longest_palindromic_subsequence.go similarity index 97% rename from dynamicprogramming/longest-palindromic-subsequence.go rename to dynamic_programming/longest_palindromic_subsequence.go index d05e42129..da783d7f7 100644 --- a/dynamicprogramming/longest-palindromic-subsequence.go +++ b/dynamic_programming/longest_palindromic_subsequence.go @@ -1,7 +1,7 @@ // longest palindromic subsequence // http://www.geeksforgeeks.org/dynamic-programming-set-12-longest-palindromic-subsequence/ -package dynamicprogramming +package dynamic_programming // LpsRec function func LpsRec(word string, i, j int) int { diff --git a/dynamicprogramming/matrix-multiplication.go b/dynamic_programming/matrix_multiplication.go similarity index 85% rename from dynamicprogramming/matrix-multiplication.go rename to dynamic_programming/matrix_multiplication.go index 5faf0aa59..ff73b1762 100644 --- a/dynamicprogramming/matrix-multiplication.go +++ b/dynamic_programming/matrix_multiplication.go @@ -1,9 +1,9 @@ // matrix chain multiplication problem // https://en.wikipedia.org/wiki/Matrix_chain_multiplication -// www.geeksforgeeks.org/dynamicprogramming-set-8-matrix-chain-multiplication/ +// www.geeksforgeeks.org/dynamic_programming-set-8-matrix-chain-multiplication/ -// Package dynamicprogramming Package for dynamically run algorithms -package dynamicprogramming +// Package dynamic_programming Package for dynamically run algorithms +package dynamic_programming // MatrixChainRec function func MatrixChainRec(D []int, i, j int) int { diff --git a/dynamicprogramming/rod-cutting.go b/dynamic_programming/rod_cutting.go similarity index 97% rename from dynamicprogramming/rod-cutting.go rename to dynamic_programming/rod_cutting.go index 704745fb3..733798a39 100644 --- a/dynamicprogramming/rod-cutting.go +++ b/dynamic_programming/rod_cutting.go @@ -2,7 +2,7 @@ // https://en.wikipedia.org/wiki/Cutting_stock_problem // http://www.geeksforgeeks.org/dynamic-programming-set-13-cutting-a-rod/ -package dynamicprogramming +package dynamic_programming // CutRodRec solve the problem recursively: initial approach func CutRodRec(price []int, length int) int { diff --git a/genetic-algorithm/genetic_algo.go b/genetic_algorithm/genetic_algo.go similarity index 100% rename from genetic-algorithm/genetic_algo.go rename to genetic_algorithm/genetic_algo.go diff --git a/graphs/depthfirstsearch/depthfirstsearch.go b/graphs/depth_first_search/depth_first_search.go similarity index 98% rename from graphs/depthfirstsearch/depthfirstsearch.go rename to graphs/depth_first_search/depth_first_search.go index 2ebd3302f..07648e17c 100644 --- a/graphs/depthfirstsearch/depthfirstsearch.go +++ b/graphs/depth_first_search/depth_first_search.go @@ -1,4 +1,4 @@ -package depthfirstsearch +package depth_first_search func GetIdx(target int, nodes []int) int { for i := 0; i < len(nodes); i++ { diff --git a/graphs/floydwarshall/floydwarshall.go b/graphs/floyd_warshall/floyd_warshall.go similarity index 98% rename from graphs/floydwarshall/floydwarshall.go rename to graphs/floyd_warshall/floyd_warshall.go index 90f655a19..0a9f7e7a4 100644 --- a/graphs/floydwarshall/floydwarshall.go +++ b/graphs/floyd_warshall/floyd_warshall.go @@ -1,7 +1,7 @@ // Floyd-Warshall algorithm // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm -package floydwarshall +package floyd_warshall // Matrix Defining matrix to use 2d array easier type Matrix [][]float64 diff --git a/graphs/search/breadthFirstSearch.go b/graphs/search/breadth_first_search.go similarity index 100% rename from graphs/search/breadthFirstSearch.go rename to graphs/search/breadth_first_search.go diff --git a/graphs/search/breadthFirstSearch_test.go b/graphs/search/breadth_first_search_test.go similarity index 100% rename from graphs/search/breadthFirstSearch_test.go rename to graphs/search/breadth_first_search_test.go diff --git a/math/gcd/gcditerative.go b/math/gcd/gcd_iterative.go similarity index 100% rename from math/gcd/gcditerative.go rename to math/gcd/gcd_iterative.go diff --git a/math/modulararithmetic/modularexponentiation.go b/math/modular_arithmetic/modular_exponentiation.go similarity index 97% rename from math/modulararithmetic/modularexponentiation.go rename to math/modular_arithmetic/modular_exponentiation.go index 1480096b8..3b374f6d4 100644 --- a/math/modulararithmetic/modularexponentiation.go +++ b/math/modular_arithmetic/modular_exponentiation.go @@ -1,4 +1,4 @@ -package modulararithmetic +package modular_arithmetic import ( "errors" diff --git a/math/modulararithmetic/modularexponentiation_test.go b/math/modular_arithmetic/modular_exponentiation_test.go similarity index 98% rename from math/modulararithmetic/modularexponentiation_test.go rename to math/modular_arithmetic/modular_exponentiation_test.go index 9af4d7461..1726a3bfb 100644 --- a/math/modulararithmetic/modularexponentiation_test.go +++ b/math/modular_arithmetic/modular_exponentiation_test.go @@ -1,4 +1,4 @@ -package modulararithmetic +package modular_arithmetic import "testing" diff --git a/math/power/fastexponent.go b/math/power/fast_exponent.go similarity index 100% rename from math/power/fastexponent.go rename to math/power/fast_exponent.go diff --git a/math/power/fastexponent_test.go b/math/power/fast_exponent_test.go similarity index 100% rename from math/power/fastexponent_test.go rename to math/power/fast_exponent_test.go diff --git a/math/prime/millerrabinprimalitytest.go b/math/prime/miller_rabin_primality_test.go similarity index 91% rename from math/prime/millerrabinprimalitytest.go rename to math/prime/miller_rabin_primality_test.go index f38da3dfa..37ba9f48e 100644 --- a/math/prime/millerrabinprimalitytest.go +++ b/math/prime/miller_rabin_primality_test.go @@ -3,7 +3,7 @@ package prime import ( "math/rand" - "github.com/TheAlgorithms/Go/math/modulararithmetic" + "github.com/TheAlgorithms/Go/math/modular_arithmetic" ) // findD accepts a number and returns the @@ -24,7 +24,7 @@ func findRD(num int64) (int64, int64) { func MillerTest(d, num int64) (bool, error) { random := rand.Int63n(num-1) + 2 - res, err := modulararithmetic.ModularExponentiation(random, d, num) + res, err := modular_arithmetic.ModularExponentiation(random, d, num) if err != nil { return false, err diff --git a/math/prime/primecheck.go b/math/prime/prime_check.go similarity index 100% rename from math/prime/primecheck.go rename to math/prime/prime_check.go diff --git a/math/sieve/Sieve.go b/math/sieve/sieve.go similarity index 100% rename from math/sieve/Sieve.go rename to math/sieve/sieve.go diff --git a/other/maxsubarraysum/maxsubarraysum.go b/other/max_subarray_sum/max_subarray_sum.go similarity index 96% rename from other/maxsubarraysum/maxsubarraysum.go rename to other/max_subarray_sum/max_subarray_sum.go index e50453b3b..9101c4e6e 100644 --- a/other/maxsubarraysum/maxsubarraysum.go +++ b/other/max_subarray_sum/max_subarray_sum.go @@ -1,7 +1,7 @@ /* O(n) solution, for calculating maximum contiguous sum in the given array. */ -package maxsubarraysum +package max_subarray_sum // Max - already defined somewhere in this repository TODO: remove this definition and add the import path func Max(x int, y int) int { diff --git a/other/nestedbrackets/nestedbrackets.go b/other/nested_brackets/nested_brackets.go similarity index 98% rename from other/nestedbrackets/nestedbrackets.go rename to other/nested_brackets/nested_brackets.go index f2fd239d8..9a10a98ef 100644 --- a/other/nestedbrackets/nestedbrackets.go +++ b/other/nested_brackets/nested_brackets.go @@ -9,7 +9,7 @@ // returns true if input is nested and false otherwise. //note that only an even number of brackets can be properly nested -package nestedbrackets +package nested_brackets // IsBalanced function which checks whether the number of brackets are balanced func IsBalanced(input string) string { diff --git a/other/passwordgenerator/passwordgenerator.go b/other/password_generator/password_generator.go similarity index 98% rename from other/passwordgenerator/passwordgenerator.go rename to other/password_generator/password_generator.go index 742bd7303..f795c16a1 100644 --- a/other/passwordgenerator/passwordgenerator.go +++ b/other/password_generator/password_generator.go @@ -2,7 +2,7 @@ // You must provide a minimum length and a maximum length // This length is not fixed if you generate multiple passwords for the same range -package passwordgenerator +package password_generator import ( crand "crypto/rand" diff --git a/other/stringcombinations/stringcombinations.go b/other/string_combinations/string_combinations.go similarity index 90% rename from other/stringcombinations/stringcombinations.go rename to other/string_combinations/string_combinations.go index 0e1dc3d10..dc0f92fed 100644 --- a/other/stringcombinations/stringcombinations.go +++ b/other/string_combinations/string_combinations.go @@ -1,5 +1,5 @@ -// Package stringcombinations ... -package stringcombinations +// Package string_combinations ... +package string_combinations import "fmt" diff --git a/searches/binarysearch.go b/searches/binary_search.go similarity index 100% rename from searches/binarysearch.go rename to searches/binary_search.go diff --git a/searches/linearsearch.go b/searches/linear_search.go similarity index 100% rename from searches/linearsearch.go rename to searches/linear_search.go diff --git a/sorts/bubblesort.go b/sorts/bubble_sort.go similarity index 100% rename from sorts/bubblesort.go rename to sorts/bubble_sort.go diff --git a/sorts/heapsort.go b/sorts/heap_sort.go similarity index 100% rename from sorts/heapsort.go rename to sorts/heap_sort.go diff --git a/sorts/insertionsort.go b/sorts/insertion_sort.go similarity index 100% rename from sorts/insertionsort.go rename to sorts/insertion_sort.go diff --git a/sorts/mergesort.go b/sorts/merge_sort.go similarity index 100% rename from sorts/mergesort.go rename to sorts/merge_sort.go diff --git a/sorts/quicksort.go b/sorts/quick_sort.go similarity index 100% rename from sorts/quicksort.go rename to sorts/quick_sort.go diff --git a/sorts/radixsort.go b/sorts/radix_sort.go similarity index 100% rename from sorts/radixsort.go rename to sorts/radix_sort.go diff --git a/sorts/selectionsort.go b/sorts/selection_sort.go similarity index 100% rename from sorts/selectionsort.go rename to sorts/selection_sort.go diff --git a/sorts/shellsort.go b/sorts/shell_sort.go similarity index 100% rename from sorts/shellsort.go rename to sorts/shell_sort.go diff --git a/strings/levenshteindistance/levenshteinDistance.go b/strings/levenshtein_distance/levenshtein_distance.go similarity index 96% rename from strings/levenshteindistance/levenshteinDistance.go rename to strings/levenshtein_distance/levenshtein_distance.go index e4181e205..c718b1e5a 100644 --- a/strings/levenshteindistance/levenshteinDistance.go +++ b/strings/levenshtein_distance/levenshtein_distance.go @@ -4,7 +4,7 @@ Parameters: two strings to compare and weights of insertion, substitution and de Output: distance between both strings */ -package levenshteindistance +package levenshtein_distance // LevenshteinDistance Function that gives Levenshtein Distance func LevenshteinDistance(str1, str2 string, icost, scost, dcost int) int { diff --git a/strings/levenshteindistance/levenshteinDistance_test.go b/strings/levenshtein_distance/levenshtein_distance_test.go similarity index 96% rename from strings/levenshteindistance/levenshteinDistance_test.go rename to strings/levenshtein_distance/levenshtein_distance_test.go index d02053fd4..25537dc98 100644 --- a/strings/levenshteindistance/levenshteinDistance_test.go +++ b/strings/levenshtein_distance/levenshtein_distance_test.go @@ -1,4 +1,4 @@ -package levenshteindistance +package levenshtein_distance import "testing" diff --git a/strings/multiple-string-matching/advanced-aho-corasick/adac.go b/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick.go similarity index 100% rename from strings/multiple-string-matching/advanced-aho-corasick/adac.go rename to strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick.go diff --git a/strings/multiple-string-matching/advanced-aho-corasick/adac_test.go b/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick_test.go similarity index 100% rename from strings/multiple-string-matching/advanced-aho-corasick/adac_test.go rename to strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick_test.go diff --git a/strings/multiple-string-matching/aho-corasick/ac.go b/strings/multiple_string_matching/aho_corasick/aho_corasick.go similarity index 100% rename from strings/multiple-string-matching/aho-corasick/ac.go rename to strings/multiple_string_matching/aho_corasick/aho_corasick.go diff --git a/strings/multiple-string-matching/aho-corasick/ac_test.go b/strings/multiple_string_matching/aho_corasick/aho_corasick_test.go similarity index 100% rename from strings/multiple-string-matching/aho-corasick/ac_test.go rename to strings/multiple_string_matching/aho_corasick/aho_corasick_test.go diff --git a/strings/multiple-string-matching/patterns.txt b/strings/multiple_string_matching/patterns.txt similarity index 100% rename from strings/multiple-string-matching/patterns.txt rename to strings/multiple_string_matching/patterns.txt diff --git a/strings/multiple-string-matching/sbom/sbom.go b/strings/multiple_string_matching/sbom/sbom.go similarity index 100% rename from strings/multiple-string-matching/sbom/sbom.go rename to strings/multiple_string_matching/sbom/sbom.go diff --git a/strings/multiple-string-matching/sbom/sbom_test.go b/strings/multiple_string_matching/sbom/sbom_test.go similarity index 100% rename from strings/multiple-string-matching/sbom/sbom_test.go rename to strings/multiple_string_matching/sbom/sbom_test.go diff --git a/strings/multiple-string-matching/text.txt b/strings/multiple_string_matching/text.txt similarity index 100% rename from strings/multiple-string-matching/text.txt rename to strings/multiple_string_matching/text.txt diff --git a/strings/naivesearch/naiveStringSearch.go b/strings/naive_string_search/naive_string_search.go similarity index 95% rename from strings/naivesearch/naiveStringSearch.go rename to strings/naive_string_search/naive_string_search.go index e6f942190..3aa9692a6 100644 --- a/strings/naivesearch/naiveStringSearch.go +++ b/strings/naive_string_search/naive_string_search.go @@ -8,7 +8,7 @@ Time Complexity : O(n*m) m = length of pattern */ -package naivesearch +package naive_string_search func naivePatternSearch(text string, pattern string) []int { var positions []int diff --git a/strings/naivesearch/naiveStringSearch_test.go b/strings/naive_string_search/naive_string_search_test.go similarity index 96% rename from strings/naivesearch/naiveStringSearch_test.go rename to strings/naive_string_search/naive_string_search_test.go index 87943a679..89db92958 100644 --- a/strings/naivesearch/naiveStringSearch_test.go +++ b/strings/naive_string_search/naive_string_search_test.go @@ -1,4 +1,4 @@ -package naivesearch +package naive_string_search import ( "reflect" diff --git a/strings/single-string-matching/bom/bom.go b/strings/single_string_matching/bom/bom.go similarity index 100% rename from strings/single-string-matching/bom/bom.go rename to strings/single_string_matching/bom/bom.go diff --git a/strings/single-string-matching/horspool/horspool.go b/strings/single_string_matching/horspool/horspool.go similarity index 100% rename from strings/single-string-matching/horspool/horspool.go rename to strings/single_string_matching/horspool/horspool.go diff --git a/strings/single-string-matching/kmp/kmp.go b/strings/single_string_matching/kmp/kmp.go similarity index 100% rename from strings/single-string-matching/kmp/kmp.go rename to strings/single_string_matching/kmp/kmp.go diff --git a/strings/single-string-matching/kmp/kmp_test.go b/strings/single_string_matching/kmp/kmp_test.go similarity index 100% rename from strings/single-string-matching/kmp/kmp_test.go rename to strings/single_string_matching/kmp/kmp_test.go diff --git a/strings/single-string-matching/pattern.txt b/strings/single_string_matching/pattern.txt similarity index 100% rename from strings/single-string-matching/pattern.txt rename to strings/single_string_matching/pattern.txt diff --git a/strings/single-string-matching/text.txt b/strings/single_string_matching/text.txt similarity index 100% rename from strings/single-string-matching/text.txt rename to strings/single_string_matching/text.txt From cdb65a24624d108af003fd39471b55de53e02c75 Mon Sep 17 00:00:00 2001 From: Milad Date: Wed, 14 Jul 2021 19:11:10 -0700 Subject: [PATCH 195/488] fixed genetic_algo.go --- genetic_algorithm/genetic_algo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genetic_algorithm/genetic_algo.go b/genetic_algorithm/genetic_algo.go index a4648dcbd..908483e49 100644 --- a/genetic_algorithm/genetic_algo.go +++ b/genetic_algorithm/genetic_algo.go @@ -62,7 +62,7 @@ func geneticString(target string, charmap []rune) (int, int, string) { } // Generate random starting population - pop := make([]populationItem, populationNum, populationNum) + pop := make([]populationItem, populationNum) for i := 0; i < populationNum; i++ { key := "" for x := 0; x < utf8.RuneCountInString(target); x++ { From 48e0ccba4b9e7e2549b8fb00099b15b1374a4a52 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Wed, 14 Jul 2021 14:41:35 +0000 Subject: [PATCH 196/488] updating DIRECTORY.md --- DIRECTORY.md | 65 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 2d57c08ca..162a1b5a6 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,8 +1,8 @@ ## Ciphers * Caesar + * [Caesar Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_cipher.go) * [Caesar Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_test.go) - * [Caesarcipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_cipher.go) * Diffie Hellman Key Exchange * [Diffie Hellman Key Exchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go) * [Diffie Hellman Key Exchange Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go) @@ -12,15 +12,15 @@ * Rot13 * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13.go) * [Rot13 Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13_test.go) - * RSA Cipher + * Rsa Cipher + * [Rsa Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/rsa_cipher.go) * [Rsa Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/rsa_cipher_test.go) - * [Rsacipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/rsa_cipher.go) - * RSA Cipher Big - * [RSA Cipher Big Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big_test.go) - * [RSA Cipher Big](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big.go) - * XOR Cipher - * [XOR Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher_test.go) - * [XOR Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher.go) + * Rsa Cipher Big + * [Rsa Cipher Big](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big.go) + * [Rsa Cipher Big Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big_test.go) + * Xor Cipher + * [Xor Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher.go) + * [Xor Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher_test.go) ## Conversions * Roman To Integer @@ -31,20 +31,21 @@ * Binary Tree * [Binary Search Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_search_tree.go) * [Binary Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_tree.go) - * [B Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/btree.go) + * [Btree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/btree.go) * [Node](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/node.go) - * Dynamic Array - * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array.go) + * Dynamic-Array + * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic-array/dynamic_array.go) * Hashmap * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap.go) * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap_test.go) - * Linked-List - * Doubly Linked-List - * [Doublylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go) - * Singly Linked-List - * [Singlylinkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go) - * [Singlylinkedlist2](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go) - * [Singlylinkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go) + * Linkedlist + * Doubly Linkedlist + * [Doubly Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go) + * [Doubly Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go) + * Singly Linkedlist + * [Singly Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go) + * [Singly Linkedlist2](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go) + * [Singly Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go) * Trie * [Trie](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/trie.go) * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/trie_test.go) @@ -53,8 +54,8 @@ * Abstract Factory * [Abstract Factory Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/abstract_factory_test.go) * [Adidas](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas.go) - * [Adidas Shirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas_shirt.go) * [Adidas Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas_shoe.go) + * [Adidasshirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidasshirt.go) * [I Shirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_shirt.go) * [I Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_shoe.go) * [I Sports Factory](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_sports_factory.go) @@ -66,8 +67,8 @@ * [Builder Pattern Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/builder_pattern_test.go) * [Director](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/director.go) * [House](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/house.go) - * [Igloo Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/iglooـbuilder.go) - * [Normal Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/normalـbuilder.go) + * [Igloo Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/igloo_builder.go) + * [Normal Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/normal_builder.go) * Factory Method * [Accounting Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/accounting_department.go) * [Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/department.go) @@ -82,12 +83,12 @@ * [Prototype Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/prototype_test.go) ## Dynamic Programming - * [Binomial Coeffecient](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/binomial_coeffecient.go) - * [Fibonacci Test](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci_test.go) + * [Binomial Coefficient](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/binomial_coefficient.go) * [Fibonacci](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci.go) + * [Fibonacci Test](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci_test.go) * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/knapsack.go) - * [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longest_palindromic_subsequence.go) * [Longest Common Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longest_common_subsequence.go) + * [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longest_palindromic_subsequence.go) * [Matrix Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/matrix_multiplication.go) * [Rod Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/rod_cutting.go) @@ -106,8 +107,8 @@ ## Math * Gcd * [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go) - * [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go) * [Gcd Iterative](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_iterative.go) + * [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go) * Lcm * [Lcm](https://github.com/TheAlgorithms/Go/blob/master/math/lcm/lcm.go) * Modular Arithmetic @@ -120,9 +121,9 @@ * [Fast Exponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fast_exponent.go) * [Fast Exponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fast_exponent_test.go) * Prime - * [Millerrabinprimalitytest](https://github.com/TheAlgorithms/Go/blob/master/math/prime/miller_rabin_primality_test.go) - * [Prime Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_test.go) + * [Miller Rabin Primality Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/miller_rabin_primality_test.go) * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_check.go) + * [Prime Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_test.go) * Pythagoras * [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras.go) * [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go) @@ -131,8 +132,8 @@ * [Sieve Test](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve_test.go) ## Other - * Max SubArray Sum - * [Maxsubarraysum](https://github.com/TheAlgorithms/Go/blob/master/other/max_subarray_sum/max_subarray_sum.go) + * Max Subarray Sum + * [Max Subarray Sum](https://github.com/TheAlgorithms/Go/blob/master/other/max_subarray_sum/max_subarray_sum.go) * Monte Carlo Pi * [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi.go) * [Monte Carlo Pi Test](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi_test.go) @@ -166,8 +167,8 @@ * [Levenshtein Distance Test](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshtein_distance/levenshtein_distance_test.go) * Multiple String Matching * Advanced Aho Corasick - * [Advanced Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasic.go) - * [Advanced Aho Corasick Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasic_test.go) + * [Advanced Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick.go) + * [Advanced Aho Corasick Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick_test.go) * Aho Corasick * [Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/aho_corasick.go) * [Aho Corasick Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/aho_corasick_test.go) From a82de6742d24755ca94701c6f6be67af47c16ab1 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Thu, 19 Aug 2021 21:07:39 +0300 Subject: [PATCH 197/488] Add stale bot --- .github/stale.yml | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..009887105 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,62 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 30 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - "dont-close" + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: abandoned + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 1 + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +pulls: + # Comment to post when marking as stale. Set to `false` to disable + markComment: > + This pull request has been automatically marked as abandoned because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + + # Comment to post when closing a stale Pull Request. + closeComment: > + Please ping one of the maintainers once you commit the changes requested + or make improvements on the code. If this is not the case and you need + some help, feel free to ask for help in our [Gitter](https://gitter.im/TheAlgorithms) + channel. Thank you for your contributions! + +issues: + # Comment to post when marking as stale. Set to `false` to disable + markComment: > + This issue has been automatically marked as abandoned because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + + # Comment to post when closing a stale Issue. + closeComment: > + Please ping one of the maintainers once you add more information and updates here. + If this is not the case and you need some help, feel free to ask for help + in our [Gitter](https://gitter.im/TheAlgorithms) channel. Thank you for your contributions! From 273547e641e308f981c3f25faad384e50185eac7 Mon Sep 17 00:00:00 2001 From: Milad Date: Fri, 20 Aug 2021 10:44:19 +0430 Subject: [PATCH 198/488] fixed pull request path CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- DIRECTORY.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c617ec5c..2771be750 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,7 +147,7 @@ Common prefixes: ### Pull Requests -- Checkout our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.go +- Checkout our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.md ) #### Building Locally diff --git a/DIRECTORY.md b/DIRECTORY.md index 162a1b5a6..2e14e6b08 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -34,7 +34,7 @@ * [Btree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/btree.go) * [Node](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/node.go) * Dynamic-Array - * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic-array/dynamic_array.go) + * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array.go) * Hashmap * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap.go) * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap_test.go) From 46e0651f986622db32df4f3d053af05de784a027 Mon Sep 17 00:00:00 2001 From: Milad Date: Fri, 20 Aug 2021 10:48:05 +0430 Subject: [PATCH 199/488] change directory name based on contributing guideline format and added comments and testcast #272 to dynamic array data structure --- .../dynamic_array.go | 56 ++++------ .../dynamic_array/dynamic_array_test.go | 101 ++++++++++++++++++ 2 files changed, 124 insertions(+), 33 deletions(-) rename data_structures/{dynamic-array => dynamic_array}/dynamic_array.go (54%) create mode 100644 data_structures/dynamic_array/dynamic_array_test.go diff --git a/data_structures/dynamic-array/dynamic_array.go b/data_structures/dynamic_array/dynamic_array.go similarity index 54% rename from data_structures/dynamic-array/dynamic_array.go rename to data_structures/dynamic_array/dynamic_array.go index 30132a231..cab922951 100644 --- a/data_structures/dynamic-array/dynamic_array.go +++ b/data_structures/dynamic_array/dynamic_array.go @@ -1,5 +1,17 @@ +// Dynamic Array +// description: A dynamic array is quite similar to a regular array, but its size is modifiable during program runtime. +// details: for more details check out those links below here: +// geeks for geeks article : https://www.geeksforgeeks.org/how-do-dynamic-arrays-work/ +// We can mention that Dynamic Array is like Slice for more detail about golang slice check this articles : +// https://blog.golang.org/slices-intro +// https://blog.golang.org/slices +// authors [Wesllhey Holanda](https://github.com/wesllhey), [Milad](https://github.com/miraddo) +// see dynamic_array.go, dynamic_array_test.go + package dynamicarray + +// errors: used to handle CheckRangeFromIndex function with a reasonable error value import ( "errors" ) @@ -7,13 +19,16 @@ import ( var defaultCapacity = 10 // DynamicArray structure +// size: length of array +// capacity: the maximum length of the segment +// elementData: an array of any type of data with interface type DynamicArray struct { size int capacity int elementData []interface{} } -// Put function +// Put function is change/update the value in array with the index and new value func (da *DynamicArray) Put(index int, element interface{}) error { err := da.CheckRangeFromIndex(index) @@ -26,7 +41,7 @@ func (da *DynamicArray) Put(index int, element interface{}) error { return nil } -// Add function +// Add function is add new element to our array func (da *DynamicArray) Add(element interface{}) { if da.size == da.capacity { da.NewCapacity() @@ -36,7 +51,7 @@ func (da *DynamicArray) Add(element interface{}) { da.size++ } -// Remove function +// Remove function is remove an element with the index func (da *DynamicArray) Remove(index int) error { err := da.CheckRangeFromIndex(index) @@ -52,7 +67,7 @@ func (da *DynamicArray) Remove(index int) error { return nil } -// Get function +// Get function is return one element with the index of array func (da *DynamicArray) Get(index int) (interface{}, error) { err := da.CheckRangeFromIndex(index) @@ -63,17 +78,17 @@ func (da *DynamicArray) Get(index int) (interface{}, error) { return da.elementData[index], nil } -// IsEmpty function +// IsEmpty function is check that the array has value or not func (da *DynamicArray) IsEmpty() bool { return da.size == 0 } -// GetData function +// GetData function return all value of array func (da *DynamicArray) GetData() []interface{} { return da.elementData[:da.size] } -// CheckRangeFromIndex function +// CheckRangeFromIndex function it will check the range from the index func (da *DynamicArray) CheckRangeFromIndex(index int) error { if index >= da.size || index < 0 { return errors.New("index out of range") @@ -81,7 +96,7 @@ func (da *DynamicArray) CheckRangeFromIndex(index int) error { return nil } -// NewCapacity function +// NewCapacity function increase the capacity func (da *DynamicArray) NewCapacity() { if da.capacity == 0 { da.capacity = defaultCapacity @@ -95,28 +110,3 @@ func (da *DynamicArray) NewCapacity() { da.elementData = newDataElement } - -// func main() { -// numbers := dynamicArray{} -// fmt.Println(numbers.isEmpty()) - -// numbers.add(10) -// numbers.add(20) -// numbers.add(30) -// numbers.add(40) -// numbers.add(50) - -// fmt.Println(numbers.isEmpty()) - -// fmt.Println(numbers.getData()) - -// numbers.remove(1) - -// fmt.Println(numbers.getData()) - -// numberFound, _ := numbers.get(1) -// fmt.Println(numberFound) - -// numbers.put(0, 100) -// fmt.Println(numbers.getData()) -// } diff --git a/data_structures/dynamic_array/dynamic_array_test.go b/data_structures/dynamic_array/dynamic_array_test.go new file mode 100644 index 000000000..f0b7d5e0a --- /dev/null +++ b/data_structures/dynamic_array/dynamic_array_test.go @@ -0,0 +1,101 @@ +package dynamicarray + + +// reflect: used for check equal values +import ( + "reflect" + "testing" +) + +// TestDynamicArray some test for dynamic array to make sure everything is ok, and we got the right result +func TestDynamicArray(t *testing.T) { + numbers := DynamicArray{} + + // check numbers is empty or nut + t.Run("Check Empty Dynamic Array", func(t *testing.T) { + if numbers.IsEmpty() != true{ + t.Errorf("Expected be true but got %v", numbers.IsEmpty()) + } + }) + + numbers.Add(10) + numbers.Add(20) + numbers.Add(30) + numbers.Add(40) + numbers.Add(50) + + // check numbers added to our dynamic array + t.Run("Add Element into Dynamic Array", func(t *testing.T) { + if numbers.IsEmpty() != false{ + t.Errorf("Expected be false but got %v", numbers.IsEmpty()) + } + var res []interface{} + res = append(res, 10) + res = append(res, 20) + res = append(res, 30) + res = append(res, 40) + res = append(res, 50) + + if !reflect.DeepEqual(numbers.GetData(), res) { + t.Errorf("Expected be [10, 20, 30, 40, 50] but got %v", numbers.GetData()) + } + }) + + // Remove an Element inside the dynamic array with the index of array + t.Run("Remove in Dynamic Array", func(t *testing.T) { + if numbers.IsEmpty() != false{ + t.Errorf("Expected be false but got %v", numbers.IsEmpty()) + } + var res []interface{} + res = append(res, 10) + res = append(res, 30) + res = append(res, 40) + res = append(res, 50) + + // remove the element by the index + err := numbers.Remove(1) + + if err != nil{ + t.Errorf("Expected be [10, 30, 40, 50] but got an Error %v", err) + } + + if !reflect.DeepEqual(numbers.GetData(), res) { + t.Errorf("Expected be [10, 30, 40, 50] but got %v", numbers.GetData()) + } + }) + + // get one element by the index of the dynamic array + t.Run("Get in Dynamic Array", func(t *testing.T) { + if numbers.IsEmpty() != false{ + t.Errorf("Expected be false but got %v", numbers.IsEmpty()) + } + + // return one element with the index + getOne,_ := numbers.Get(2) + + if getOne != 40 { + t.Errorf("Expected be 40 but got %v", getOne) + } + + }) + + + // Put to add a value to specific index of Dynamic Array + t.Run("Put to Dynamic Array", func(t *testing.T) { + if numbers.IsEmpty() != false{ + t.Errorf("Expected be false but got %v", numbers.IsEmpty()) + } + + // change value of specific index + err := numbers.Put(0, 100) + if err != nil{ + t.Errorf("Expected be [10, 30, 40, 50] but got an Error %v", err) + } + + getOne,_ := numbers.Get(0) + if getOne != 100 { + t.Errorf("Expected be 100 but got %v", getOne) + } + }) + +} \ No newline at end of file From 1e42b5466c449831e04eb378e94e1931fd5a667f Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 20 Aug 2021 06:18:27 +0000 Subject: [PATCH 200/488] updating DIRECTORY.md --- DIRECTORY.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 2e14e6b08..ebd8927e2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -33,8 +33,9 @@ * [Binary Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_tree.go) * [Btree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/btree.go) * [Node](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/node.go) - * Dynamic-Array + * Dynamic Array * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array.go) + * [Dynamic Array Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array_test.go) * Hashmap * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap.go) * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap_test.go) From 5963c3058bad6a9dfbe3204c9f5d15d1324afcad Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Fri, 20 Aug 2021 06:18:27 +0000 Subject: [PATCH 201/488] updating DIRECTORY.md --- DIRECTORY.md | 3 ++- data_structures/dynamic_array/dynamic_array.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 2e14e6b08..ebd8927e2 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -33,8 +33,9 @@ * [Binary Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_tree.go) * [Btree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/btree.go) * [Node](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/node.go) - * Dynamic-Array + * Dynamic Array * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array.go) + * [Dynamic Array Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array_test.go) * Hashmap * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap.go) * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap_test.go) diff --git a/data_structures/dynamic_array/dynamic_array.go b/data_structures/dynamic_array/dynamic_array.go index cab922951..6e259c4b5 100644 --- a/data_structures/dynamic_array/dynamic_array.go +++ b/data_structures/dynamic_array/dynamic_array.go @@ -2,7 +2,7 @@ // description: A dynamic array is quite similar to a regular array, but its size is modifiable during program runtime. // details: for more details check out those links below here: // geeks for geeks article : https://www.geeksforgeeks.org/how-do-dynamic-arrays-work/ -// We can mention that Dynamic Array is like Slice for more detail about golang slice check this articles : +// We can mention that Dynamic Array is like Slice for more detail about `Go` Slices check those articles : // https://blog.golang.org/slices-intro // https://blog.golang.org/slices // authors [Wesllhey Holanda](https://github.com/wesllhey), [Milad](https://github.com/miraddo) From 86919b8cf03c26759eedf26c1885e71c308638ae Mon Sep 17 00:00:00 2001 From: Meet Valani <40715819+meetvalani@users.noreply.github.com> Date: Sat, 21 Aug 2021 10:02:16 +0530 Subject: [PATCH 202/488] Add set data structure (#314) Co-authored-by: Andrii Siriak --- DIRECTORY.md | 3 ++ set/set.go | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 set/set.go diff --git a/DIRECTORY.md b/DIRECTORY.md index ebd8927e2..17854bf51 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -150,6 +150,9 @@ * [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search.go) * [Search Test](https://github.com/TheAlgorithms/Go/blob/master/searches/search_test.go) +## Set + * [Set](https://github.com/TheAlgorithms/Go/blob/master/set/set.go) + ## Sorts * [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubble_sort.go) * [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heap_sort.go) diff --git a/set/set.go b/set/set.go new file mode 100644 index 000000000..70c215f8e --- /dev/null +++ b/set/set.go @@ -0,0 +1,147 @@ +package set + +// New gives new set. +func New(items ...interface{}) Set { + st := set{ + elements: make(map[interface{}]bool), + } + for _, item := range items { + st.Add(item) + } + return &st +} + +// Set is an interface of possible methods on 'set'. +type Set interface { + // Add: adds new element to the set + Add(item interface{}) + // Delete: delets the passed element from the set if present + Delete(item interface{}) + // Len: gives the length of the set (total no. of elements in set) + Len() int + // GetItems: gives the array( []interface{} ) of elements of the set. + GetItems() []interface{} + // In: checks whether item is present in set or not. + In(item interface{}) bool + // IsSubsetOf: checks wether set is subset of set2 or not. + IsSubsetOf(set2 Set) bool + // IsSupersetOf: checks wether set is superset of set2 or not. + IsSupersetOf(set2 Set) bool + // Union: gives new union set of both sets. + // ex: [1,2,3] union [3,4,5] -> [1,2,3,4,5] + Union(set2 Set) Set + // Intersection: gives new intersection set of both sets. + // ex: [1,2,3] Intersection [3,4,5] -> [3] + Intersection(set2 Set) Set + // Difference: gives new difference set of both sets. + // ex: [1,2,3] Difference [3,4,5] -> [1,2] + Difference(set2 Set) Set + // SymmetricDifference: gives new symmetric difference set of both sets. + // ex: [1,2,3] SymmetricDifference [3,4,5] -> [1,2,4,5] + SymmetricDifference(set2 Set) Set +} + +type set struct { + elements map[interface{}]bool +} + +func (st *set) Add(value interface{}) { + st.elements[value] = true +} + +func (st *set) Delete(value interface{}) { + delete(st.elements, value) +} + +func (st *set) GetItems() []interface{} { + keys := make([]interface{}, 0, len(st.elements)) + for k := range st.elements { + keys = append(keys, k) + } + return keys +} + +func (st *set) Len() int { + return len(st.elements) +} + +func (st *set) In(value interface{}) bool { + if _, in := st.elements[value]; in { + return true + } + return false +} + +func (st *set) IsSubsetOf(superSet Set) bool { + if st.Len() > superSet.Len() { + return false + } + + for _, item := range st.GetItems() { + if !superSet.In(item) { + return false + } + } + return true +} + +func (st *set) IsSupersetOf(subSet Set) bool { + return subSet.IsSubsetOf(st) +} + +func (st *set) Union(st2 Set) Set { + unionSet := New() + for _, item := range st.GetItems() { + unionSet.Add(item) + } + for _, item := range st2.GetItems() { + unionSet.Add(item) + } + return unionSet +} + +func (st *set) Intersection(st2 Set) Set { + intersectionSet := New() + var minSet, maxSet Set + if st.Len() > st2.Len() { + minSet = st2 + maxSet = st + } else { + minSet = st + maxSet = st2 + } + for _, item := range minSet.GetItems() { + if maxSet.In(item) { + intersectionSet.Add(item) + } + } + return intersectionSet +} + +func (st *set) Difference(st2 Set) Set { + differenceSet := New() + for _, item := range st.GetItems() { + if !st2.In(item) { + differenceSet.Add(item) + } + } + return differenceSet +} + +func (st *set) SymmetricDifference(st2 Set) Set { + symmetricDifferenceSet := New() + dropSet := New() + for _, item := range st.GetItems() { + if st2.In(item) { + dropSet.Add(item) + } else { + symmetricDifferenceSet.Add(item) + } + } + for _, item := range st2.GetItems() { + if !dropSet.In(item) { + symmetricDifferenceSet.Add(item) + } + } + return symmetricDifferenceSet +} From 3da34f8d87db46f82fac931a823f136d31216629 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Sun, 22 Aug 2021 08:28:18 +0300 Subject: [PATCH 203/488] Update CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 251a00707..6abc705d4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,6 +7,7 @@ # Order is important. The last matching pattern has the most precedence. +* @siriak /.* @cclauss /ciphers/ @vedantmamgain /data-structures/ @Mystigan @vedantmamgain From 1ee70c11ddb937203fc340f6f3ea0a69c5ec2087 Mon Sep 17 00:00:00 2001 From: Milad <14594374+Miraddo@users.noreply.github.com> Date: Wed, 25 Aug 2021 08:57:11 +0430 Subject: [PATCH 204/488] Change filenames based on #319 (#320) * docs: based on #319, all files changed to lowercase without '_' except for '_test.go' files * update go.mod version to go 1.17 * update golangci-lint version to v1.42.0 * update go-version to 1.17 * update contributing guidelines * add list from directory.md into readme.md * Delete DIRECTORY.md Co-authored-by: Christian Clauss Co-authored-by: Andrii Siriak --- .github/workflows/update_directory_md.yml | 67 ------ CONTRIBUTING.md | 48 +++-- DIRECTORY.md | 192 ------------------ README.md | 99 ++++++++- .../caesar/{caesar_cipher.go => caesar.go} | 0 ...xchange.go => diffiehellmankeyexchange.go} | 0 ...st.go => diffiehellmankeyexchange_test.go} | 0 .../{rsa_cipher.go => rsacipher.go} | 0 .../{rsa_cipher_test.go => rsacipher_test.go} | 2 +- .../{rsa_cipher_big.go => rsacipherbig.go} | 0 ...ipher_big_test.go => rsacipherbig_test.go} | 2 +- .../{xor_cipher.go => xorcipher.go} | 0 .../{xor_cipher_test.go => xorcipher_test.go} | 0 ...{roman_to_integer.go => romantointeger.go} | 0 ...integer_test.go => romantointeger_test.go} | 0 ...ary_search_tree.go => binarysearchtree.go} | 0 .../{binary_tree.go => binarytree.go} | 7 - data_structures/binary_tree/btree.go | 9 + .../{dynamic_array.go => dynamicarray.go} | 2 +- ...mic_array_test.go => dynamicarray_test.go} | 0 ...ubly_linkedlist.go => doublylinkedlist.go} | 0 ...dlist_test.go => doublylinkedlist_test.go} | 0 ...ngly_linkedlist.go => singlylinkedlist.go} | 0 ...dlist_test.go => singlylinkedlist_test.go} | 0 ...actory_test.go => abstractfactory_test.go} | 0 .../{adidas_shoe.go => adidasshoe.go} | 0 .../{i_shirt.go => ishirt.go} | 0 .../abstract_factory/{i_shoe.go => ishoe.go} | 0 ...{i_sports_factory.go => isportsfactory.go} | 0 .../{nike_shirt.go => nikeshirt.go} | 0 .../{nike_shoe.go => nikeshoe.go} | 0 ...ilder_interface.go => builderinterface.go} | 0 ...pattern_test.go => builderpattern_test.go} | 0 .../{igloo_builder.go => igloobuilder.go} | 0 .../{normal_builder.go => normalbuilder.go} | 0 ..._department.go => accountingdepartment.go} | 0 ...rtment_factory.go => departmentfactory.go} | 0 ...y_method_test.go => factorymethod_test.go} | 0 ...nce_department.go => financedepartment.go} | 0 .../{i_department.go => idepartment.go} | 0 .../{node_interface.go => nodeinterface.go} | 0 ..._coefficient.go => binomialcoefficient.go} | 0 ...equence.go => longestcommonsubsequence.go} | 0 ...ce.go => longestpalindromicsubsequence.go} | 0 ...tiplication.go => matrixmultiplication.go} | 0 .../{rod_cutting.go => rodcutting.go} | 0 .../{genetic_algo.go => geneticalgorithm.go} | 0 .../breadthfirstsearch.go} | 2 +- .../breadthfirstsearch_test.go} | 2 +- ...th_first_search.go => depthfirstsearch.go} | 0 .../{floyd_warshall.go => floydwarshall.go} | 0 .../gcd/{gcd_iterative.go => gcditerative.go} | 0 ...nentiation.go => modularexponentiation.go} | 0 ..._test.go => modularexponentiation_test.go} | 0 .../{fast_exponent.go => fastexponent.go} | 0 ..._exponent_test.go => fastexponent_test.go} | 0 ...ty_test.go => millerrabinprimalitytest.go} | 0 math/prime/{prime_check.go => primecheck.go} | 0 .../{prime_test.go => primecheck_test.go} | 0 ...{max_subarray_sum.go => maxsubarraysum.go} | 0 .../{monte_carlo_pi.go => montecarlopi.go} | 0 ..._carlo_pi_test.go => montecarlopi_test.go} | 0 .../{nested_brackets.go => nestedbrackets.go} | 0 ...word_generator.go => passwordgenerator.go} | 0 ..._combinations.go => stringcombinations.go} | 0 .../binarysearch.go} | 2 +- .../binarysearch_test.go} | 15 +- .../linearsearch.go} | 2 +- searches/linear_search/linearsearch_test.go | 34 ++++ sorts/{bubble_sort.go => bubblesort.go} | 0 sorts/{heap_sort.go => heapsort.go} | 0 sorts/{insertion_sort.go => insertionsort.go} | 0 sorts/{merge_sort.go => mergesort.go} | 0 sorts/{quick_sort.go => quicksort.go} | 0 sorts/{radix_sort.go => radixsort.go} | 0 sorts/{selection_sort.go => selectionsort.go} | 0 sorts/{shell_sort.go => shellsort.go} | 0 ...ein_distance.go => levenshteindistance.go} | 0 ...ce_test.go => levenshteindistance_test.go} | 0 ...aho_corasick.go => advancedahocorasick.go} | 0 ...ck_test.go => advancedahocorasick_test.go} | 0 .../{aho_corasick.go => ahocorasick.go} | 0 ...o_corasick_test.go => ahocorasick_test.go} | 0 ..._string_search.go => naivestringsearch.go} | 0 ...arch_test.go => naivestringsearch_test.go} | 0 85 files changed, 182 insertions(+), 303 deletions(-) delete mode 100644 .github/workflows/update_directory_md.yml delete mode 100644 DIRECTORY.md rename ciphers/caesar/{caesar_cipher.go => caesar.go} (100%) rename ciphers/diffie_hellman_key_exchange/{diffie_hellman_key_exchange.go => diffiehellmankeyexchange.go} (100%) rename ciphers/diffie_hellman_key_exchange/{diffie_hellman_key_exchange_test.go => diffiehellmankeyexchange_test.go} (100%) rename ciphers/rsa_cipher/{rsa_cipher.go => rsacipher.go} (100%) rename ciphers/rsa_cipher/{rsa_cipher_test.go => rsacipher_test.go} (96%) rename ciphers/rsa_cipher_big/{rsa_cipher_big.go => rsacipherbig.go} (100%) rename ciphers/rsa_cipher_big/{rsa_cipher_big_test.go => rsacipherbig_test.go} (95%) rename ciphers/xor_cipher/{xor_cipher.go => xorcipher.go} (100%) rename ciphers/xor_cipher/{xor_cipher_test.go => xorcipher_test.go} (100%) rename conversions/roman_to_integer/{roman_to_integer.go => romantointeger.go} (100%) rename conversions/roman_to_integer/{roman_to_integer_test.go => romantointeger_test.go} (100%) rename data_structures/binary_tree/{binary_search_tree.go => binarysearchtree.go} (100%) rename data_structures/binary_tree/{binary_tree.go => binarytree.go} (79%) rename data_structures/dynamic_array/{dynamic_array.go => dynamicarray.go} (98%) rename data_structures/dynamic_array/{dynamic_array_test.go => dynamicarray_test.go} (100%) rename data_structures/linkedlist/doubly_linkedlist/{doubly_linkedlist.go => doublylinkedlist.go} (100%) rename data_structures/linkedlist/doubly_linkedlist/{doubly_linkedlist_test.go => doublylinkedlist_test.go} (100%) rename data_structures/linkedlist/singly_linkedlist/{singly_linkedlist.go => singlylinkedlist.go} (100%) rename data_structures/linkedlist/singly_linkedlist/{singly_linkedlist_test.go => singlylinkedlist_test.go} (100%) rename design_patterns/abstract_factory/{abstract_factory_test.go => abstractfactory_test.go} (100%) rename design_patterns/abstract_factory/{adidas_shoe.go => adidasshoe.go} (100%) rename design_patterns/abstract_factory/{i_shirt.go => ishirt.go} (100%) rename design_patterns/abstract_factory/{i_shoe.go => ishoe.go} (100%) rename design_patterns/abstract_factory/{i_sports_factory.go => isportsfactory.go} (100%) rename design_patterns/abstract_factory/{nike_shirt.go => nikeshirt.go} (100%) rename design_patterns/abstract_factory/{nike_shoe.go => nikeshoe.go} (100%) rename design_patterns/builder/{builder_interface.go => builderinterface.go} (100%) rename design_patterns/builder/{builder_pattern_test.go => builderpattern_test.go} (100%) rename design_patterns/builder/{igloo_builder.go => igloobuilder.go} (100%) rename design_patterns/builder/{normal_builder.go => normalbuilder.go} (100%) rename design_patterns/factory_method/{accounting_department.go => accountingdepartment.go} (100%) rename design_patterns/factory_method/{department_factory.go => departmentfactory.go} (100%) rename design_patterns/factory_method/{factory_method_test.go => factorymethod_test.go} (100%) rename design_patterns/factory_method/{finance_department.go => financedepartment.go} (100%) rename design_patterns/factory_method/{i_department.go => idepartment.go} (100%) rename design_patterns/prototype/{node_interface.go => nodeinterface.go} (100%) rename dynamic_programming/{binomial_coefficient.go => binomialcoefficient.go} (100%) rename dynamic_programming/{longest_common_subsequence.go => longestcommonsubsequence.go} (100%) rename dynamic_programming/{longest_palindromic_subsequence.go => longestpalindromicsubsequence.go} (100%) rename dynamic_programming/{matrix_multiplication.go => matrixmultiplication.go} (100%) rename dynamic_programming/{rod_cutting.go => rodcutting.go} (100%) rename genetic_algorithm/{genetic_algo.go => geneticalgorithm.go} (100%) rename graphs/{search/breadth_first_search.go => breadth_first_search/breadthfirstsearch.go} (97%) rename graphs/{search/breadth_first_search_test.go => breadth_first_search/breadthfirstsearch_test.go} (98%) rename graphs/depth_first_search/{depth_first_search.go => depthfirstsearch.go} (100%) rename graphs/floyd_warshall/{floyd_warshall.go => floydwarshall.go} (100%) rename math/gcd/{gcd_iterative.go => gcditerative.go} (100%) rename math/modular_arithmetic/{modular_exponentiation.go => modularexponentiation.go} (100%) rename math/modular_arithmetic/{modular_exponentiation_test.go => modularexponentiation_test.go} (100%) rename math/power/{fast_exponent.go => fastexponent.go} (100%) rename math/power/{fast_exponent_test.go => fastexponent_test.go} (100%) rename math/prime/{miller_rabin_primality_test.go => millerrabinprimalitytest.go} (100%) rename math/prime/{prime_check.go => primecheck.go} (100%) rename math/prime/{prime_test.go => primecheck_test.go} (100%) rename other/max_subarray_sum/{max_subarray_sum.go => maxsubarraysum.go} (100%) rename other/monte_carlo_pi/{monte_carlo_pi.go => montecarlopi.go} (100%) rename other/monte_carlo_pi/{monte_carlo_pi_test.go => montecarlopi_test.go} (100%) rename other/nested_brackets/{nested_brackets.go => nestedbrackets.go} (100%) rename other/password_generator/{password_generator.go => passwordgenerator.go} (100%) rename other/string_combinations/{string_combinations.go => stringcombinations.go} (100%) rename searches/{binary_search.go => binary_search/binarysearch.go} (97%) rename searches/{search_test.go => binary_search/binarysearch_test.go} (79%) rename searches/{linear_search.go => linear_search/linearsearch.go} (91%) create mode 100644 searches/linear_search/linearsearch_test.go rename sorts/{bubble_sort.go => bubblesort.go} (100%) rename sorts/{heap_sort.go => heapsort.go} (100%) rename sorts/{insertion_sort.go => insertionsort.go} (100%) rename sorts/{merge_sort.go => mergesort.go} (100%) rename sorts/{quick_sort.go => quicksort.go} (100%) rename sorts/{radix_sort.go => radixsort.go} (100%) rename sorts/{selection_sort.go => selectionsort.go} (100%) rename sorts/{shell_sort.go => shellsort.go} (100%) rename strings/levenshtein_distance/{levenshtein_distance.go => levenshteindistance.go} (100%) rename strings/levenshtein_distance/{levenshtein_distance_test.go => levenshteindistance_test.go} (100%) rename strings/multiple_string_matching/advanced_aho_corasick/{advanced_aho_corasick.go => advancedahocorasick.go} (100%) rename strings/multiple_string_matching/advanced_aho_corasick/{advanced_aho_corasick_test.go => advancedahocorasick_test.go} (100%) rename strings/multiple_string_matching/aho_corasick/{aho_corasick.go => ahocorasick.go} (100%) rename strings/multiple_string_matching/aho_corasick/{aho_corasick_test.go => ahocorasick_test.go} (100%) rename strings/naive_string_search/{naive_string_search.go => naivestringsearch.go} (100%) rename strings/naive_string_search/{naive_string_search_test.go => naivestringsearch_test.go} (100%) diff --git a/.github/workflows/update_directory_md.yml b/.github/workflows/update_directory_md.yml deleted file mode 100644 index 019b478b3..000000000 --- a/.github/workflows/update_directory_md.yml +++ /dev/null @@ -1,67 +0,0 @@ -# This GitHub Action updates the DIRECTORY.md file (if needed) when doing a git push -name: update_directory_md -on: [push] -jobs: - update_directory_md: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - uses: actions/setup-python@master - - name: update_directory_md - shell: python - run: | - import os - from typing import Iterator - - URL_BASE = "https://github.com/TheAlgorithms/Go/blob/master" - g_output = [] - - - def good_filepaths(top_dir: str = ".") -> Iterator[str]: - for dirpath, dirnames, filenames in os.walk(top_dir): - dirnames[:] = [d for d in dirnames if d[0] not in "._"] - for filename in filenames: - if os.path.splitext(filename)[1].lower() == ".go": - yield os.path.join(dirpath, filename).lstrip("./") - - - def md_prefix(i): - return f"{i * ' '}*" if i else "\n##" - - - def print_path(old_path: str, new_path: str) -> str: - global g_output - old_parts = old_path.split(os.sep) - for i, new_part in enumerate(new_path.split(os.sep)): - if i + 1 > len(old_parts) or old_parts[i] != new_part: - if new_part: - g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ').title()}") - return new_path - - - def build_directory_md(top_dir: str = ".") -> str: - global g_output - old_path = "" - for filepath in sorted(good_filepaths(), key=str.lower): - filepath, filename = os.path.split(filepath) - if filepath != old_path: - old_path = print_path(old_path, filepath) - indent = (filepath.count(os.sep) + 1) if filepath else 0 - url = "/".join((URL_BASE, filepath, filename)).replace(" ", "%20") - filename = os.path.splitext(filename.replace("_", " ").title())[0] - g_output.append(f"{md_prefix(indent)} [{filename}]({url})") - return "\n".join(g_output) - - - with open("DIRECTORY.md", "w") as out_file: - out_file.write(build_directory_md(".") + "\n") - - - name: Update DIRECTORY.md - run: | - cat DIRECTORY.md - git config --global user.name github-actions - git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com' - git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY - git add DIRECTORY.md - git commit -am "updating DIRECTORY.md" || true - git push --force origin HEAD:$GITHUB_REF || true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2771be750..feaaeb162 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,13 +15,13 @@ Welcome to [TheAlgorithms/Go](https://github.com/TheAlgorithms/Go)! Before submi Being a contributor at The Algorithms, we request you to follow the points mentioned below: - You did your own work. - - No plagiarism allowed. Any plagiarized work will not be merged. + - No plagiarism is allowed. Any plagiarized work will not be merged. - Your work will be distributed under the [MIT License](https://github.com/TheAlgoritms/Go/blob/master/LICENSE) once your pull request has been merged. - Please follow the repository guidelines and standards mentioned below. **New implementation** New implementations are welcome! -You can add new algorithms or data structures which are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs or in any other resonable sense) +You can add new algorithms or data structures that are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs, or in any other reasonable sense) **Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers. @@ -33,7 +33,7 @@ You can add new algorithms or data structures which are **not present in the rep - Make sure the file extensions should be `*.go`. - Use meaning variable names. - Use standard library inside your code and avoid to import packages from other repositories -- If an implementation of the algorithm already exists, please refer to the [file-name section below](#new-file-name-guidelines). +- If an implementation of the algorithm already exists, please refer to the [filename section below](#new-file-name-guidelines). - You can suggest reasonable changes to existing algorithms. - Strictly use snake_case (underscore_separated) in filenames. - If you have added or modified code, please make sure the code compiles before submitting. @@ -55,6 +55,13 @@ You can add new algorithms or data structures which are **not present in the rep - If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes. - Please try to add one or more `Test` functions that will invoke the algorithm implementation on random test data with the expected output. +### Benchmark + +- Make sure to add examples and benchmark cases in your `filename_test.go` or `filename_bench.go` if you want separated test and benchmark files. +- If you find an algorithm or document without benchmarks, please feel free to create a pull request or issue describing suggested changes. +- Please try to add one or more `Benchmark` functions that will invoke the algorithm implementation. +- For running the benchmark, you could use this command `go test -bench=.` for more details, read this article [Using Subtests and Sub-benchmarks](https://go.dev/blog/subtests) + #### Typical structure of a program ```go @@ -66,8 +73,9 @@ You can add new algorithms or data structures which are **not present in the rep // description containing links, references, // math equations, etc. // author(s) [Name](https://github.com/handle), [Name](https://github.com/handle) -// see related_file.go, another_file.go, file_test.go +// see relatedfile.go, anotherfile.go, file_test.go +// ** Is just an example of how to write description for package and function and other stuff ... ** // Package sort provides primitives for sorting slices and user-defined // collections. @@ -78,13 +86,13 @@ package sort // name2 package : Add one line description here // ... import ( - ... + ... ) // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. -// It returns the number of bytes written and any write error encountered. +// It returns the number of bytes written, and any write error encountered. func Fprint(w io.Writer, a ...interface{}) (n int, err error) { ... } @@ -94,17 +102,21 @@ func Fprint(w io.Writer, a ...interface{}) (n int, err error) { #### New File Name guidelines -- Use lowercase words with ``"_"`` as a separator +- Use lowercase words without ``"_"`` for the file name +- Use ``"_"`` as a separator only for `_test.go` or `_bench.go` - For instance ```markdown MyNewGoFile.GO is incorrect -my_new_go_file.go is correct format +my_new_go_file.go is incorrect +mynewgofile.go is the correct format +mynewgofile_test.go is the correct format ``` - It will be used to dynamically create a directory of files and implementation. - File name validation will run on Docker to ensure validity. -- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example: if `binary_search.go` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `binary_search2.go` and for a third implementation, `binary_search3.go`. +- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example: if `binarysearch.go` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `binarysearch2.go` and for a third implementation, `binarysearch3.go`. +- Check out `Go` [Package names](https://go.dev/blog/package-names) roles #### New Directory guidelines @@ -125,17 +137,17 @@ some_new_fancy_category is correct - It is recommended to keep your changes grouped logically within individual commits. Maintainers find it easier to understand changes that are logically spilled across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected. ```bash -git add file_xyz.go +git add filexyz.go git commit -m "your message" ``` Examples of commit messages with semantic prefixes: ```markdown -fix: xyz algorithm bug -feat: add xyx algorithm -test: add test for xyz algorithm -docs: add comments and explanation to xyz algorithm +fix: XYZ algorithm bug +feat: add XYZ algorithm +test: add test for XYZ algorithm +docs: add comments and explanation to XYZ algorithm ``` Common prefixes: @@ -147,7 +159,7 @@ Common prefixes: ### Pull Requests -- Checkout our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.md +- Check out our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.md ) #### Building Locally @@ -162,9 +174,9 @@ go build . #### Code Formatter - Installation (only needs to be installed once.) - - Mac (using home-brew): `brew install go` - - Windows (MSYS2 64-bit): `choco install golang` [Chocolatey Package Manager](https://chocolatey.org/) - - Linux (Debian): `sudo apt-get install golang` + - Mac (using home-brew): `brew install go` + - Windows (MSYS2 64-bit): `choco install golang` [Chocolatey Package Manager](https://chocolatey.org/) + - Linux (Debian): `sudo apt-get install golang` - Running (all platforms): `go run main.go` or `go build main.go` #### GitHub Actions diff --git a/DIRECTORY.md b/DIRECTORY.md deleted file mode 100644 index 17854bf51..000000000 --- a/DIRECTORY.md +++ /dev/null @@ -1,192 +0,0 @@ - -## Ciphers - * Caesar - * [Caesar Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_cipher.go) - * [Caesar Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/caesar_test.go) - * Diffie Hellman Key Exchange - * [Diffie Hellman Key Exchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go) - * [Diffie Hellman Key Exchange Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go) - * Polybius - * [Polybius](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius.go) - * [Polybius Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/polybius_test.go) - * Rot13 - * [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13.go) - * [Rot13 Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/rot13_test.go) - * Rsa Cipher - * [Rsa Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/rsa_cipher.go) - * [Rsa Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/rsa_cipher_test.go) - * Rsa Cipher Big - * [Rsa Cipher Big](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big.go) - * [Rsa Cipher Big Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/rsa_cipher_big_test.go) - * Xor Cipher - * [Xor Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher.go) - * [Xor Cipher Test](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/xor_cipher_test.go) - -## Conversions - * Roman To Integer - * [Roman To Integer](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman_to_integer/roman_to_integer.go) - * [Roman To Integer Test](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman_to_integer/roman_to_integer_test.go) - -## Data Structures - * Binary Tree - * [Binary Search Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_search_tree.go) - * [Binary Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/binary_tree.go) - * [Btree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/btree.go) - * [Node](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/node.go) - * Dynamic Array - * [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array.go) - * [Dynamic Array Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/dynamic_array_test.go) - * Hashmap - * [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap.go) - * [Hashmap Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/hashmap_test.go) - * Linkedlist - * Doubly Linkedlist - * [Doubly Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go) - * [Doubly Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go) - * Singly Linkedlist - * [Singly Linkedlist](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go) - * [Singly Linkedlist2](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go) - * [Singly Linkedlist Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go) - * Trie - * [Trie](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/trie.go) - * [Trie Test](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/trie_test.go) - -## Design Patterns - * Abstract Factory - * [Abstract Factory Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/abstract_factory_test.go) - * [Adidas](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas.go) - * [Adidas Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidas_shoe.go) - * [Adidasshirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/adidasshirt.go) - * [I Shirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_shirt.go) - * [I Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_shoe.go) - * [I Sports Factory](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/i_sports_factory.go) - * [Nike](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/nike.go) - * [Nike Shirt](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/nike_shirt.go) - * [Nike Shoe](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/nike_shoe.go) - * Builder - * [Builder Interface](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/builder_interface.go) - * [Builder Pattern Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/builder_pattern_test.go) - * [Director](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/director.go) - * [House](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/house.go) - * [Igloo Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/igloo_builder.go) - * [Normal Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/normal_builder.go) - * Factory Method - * [Accounting Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/accounting_department.go) - * [Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/department.go) - * [Department Factory](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/department_factory.go) - * [Factory Method Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/factory_method_test.go) - * [Finance Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/finance_department.go) - * [I Department](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/i_department.go) - * Prototype - * [File](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/file.go) - * [Folder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/folder.go) - * [Node Interface](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/node_interface.go) - * [Prototype Test](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/prototype_test.go) - -## Dynamic Programming - * [Binomial Coefficient](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/binomial_coefficient.go) - * [Fibonacci](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci.go) - * [Fibonacci Test](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci_test.go) - * [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/knapsack.go) - * [Longest Common Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longest_common_subsequence.go) - * [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longest_palindromic_subsequence.go) - * [Matrix Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/matrix_multiplication.go) - * [Rod Cutting](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/rod_cutting.go) - -## Genetic Algorithm - * [Genetic Algo](https://github.com/TheAlgorithms/Go/blob/master/genetic_algorithm/genetic_algo.go) - -## Graphs - * Depth First Search - * [Depth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/depth_first_search/depth_first_search.go) - * Floyd Warshall - * [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall/floyd_warshall.go) - * Search - * [Breadth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadth_first_search.go) - * [Breadth First Search Test](https://github.com/TheAlgorithms/Go/blob/master/graphs/search/breadth_first_search_test.go) - -## Math - * Gcd - * [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd.go) - * [Gcd Iterative](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_iterative.go) - * [Gcd Test](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/gcd_test.go) - * Lcm - * [Lcm](https://github.com/TheAlgorithms/Go/blob/master/math/lcm/lcm.go) - * Modular Arithmetic - * [Modular Exponentiation](https://github.com/TheAlgorithms/Go/blob/master/math/modular_arithmetic/modular_exponentiation.go) - * [Modular Exponentiation Test](https://github.com/TheAlgorithms/Go/blob/master/math/modular_arithmetic/modular_exponentiation_test.go) - * Permutation - * [Heaps](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps.go) - * [Heaps Test](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/heaps_test.go) - * Power - * [Fast Exponent](https://github.com/TheAlgorithms/Go/blob/master/math/power/fast_exponent.go) - * [Fast Exponent Test](https://github.com/TheAlgorithms/Go/blob/master/math/power/fast_exponent_test.go) - * Prime - * [Miller Rabin Primality Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/miller_rabin_primality_test.go) - * [Prime Check](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_check.go) - * [Prime Test](https://github.com/TheAlgorithms/Go/blob/master/math/prime/prime_test.go) - * Pythagoras - * [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras.go) - * [Pythagoras Test](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/pythagoras_test.go) - * Sieve - * [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve.go) - * [Sieve Test](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/sieve_test.go) - -## Other - * Max Subarray Sum - * [Max Subarray Sum](https://github.com/TheAlgorithms/Go/blob/master/other/max_subarray_sum/max_subarray_sum.go) - * Monte Carlo Pi - * [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi.go) - * [Monte Carlo Pi Test](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/monte_carlo_pi_test.go) - * Nested Brackets - * [Nested Brackets](https://github.com/TheAlgorithms/Go/blob/master/other/nested_brackets/nested_brackets.go) - * Password Generator - * [Password Generator](https://github.com/TheAlgorithms/Go/blob/master/other/password_generator/password_generator.go) - * String Combinations - * [String Combinations](https://github.com/TheAlgorithms/Go/blob/master/other/string_combinations/string_combinations.go) - -## Searches - * [Binary Search](https://github.com/TheAlgorithms/Go/blob/master/searches/binary_search.go) - * [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search.go) - * [Search Test](https://github.com/TheAlgorithms/Go/blob/master/searches/search_test.go) - -## Set - * [Set](https://github.com/TheAlgorithms/Go/blob/master/set/set.go) - -## Sorts - * [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubble_sort.go) - * [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heap_sort.go) - * [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertion_sort.go) - * [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/merge_sort.go) - * [Quick Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quick_sort.go) - * [Radix Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radix_sort.go) - * [Selection Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selection_sort.go) - * [Shell Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shell_sort.go) - * [Sorts Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_test.go) - * [Sorts Testcases](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_testcases.go) - -## Strings - * Levenshtein Distance - * [Levenshtein Distance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshtein_distance/levenshtein_distance.go) - * [Levenshtein Distance Test](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshtein_distance/levenshtein_distance_test.go) - * Multiple String Matching - * Advanced Aho Corasick - * [Advanced Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick.go) - * [Advanced Aho Corasick Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick_test.go) - * Aho Corasick - * [Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/aho_corasick.go) - * [Aho Corasick Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/aho_corasick_test.go) - * Sbom - * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/sbom/sbom.go) - * [Sbom Test](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/sbom/sbom_test.go) - * Naive String Search - * [Naive String Search](https://github.com/TheAlgorithms/Go/blob/master/strings/naive_string_search/naive_string_search.go) - * [Naive String Search Test](https://github.com/TheAlgorithms/Go/blob/master/strings/naive_string_search/naive_string_search_test.go) - * Single String Matching - * Bom - * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/bom/bom.go) - * Horspool - * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/horspool/horspool.go) - * Kmp - * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/kmp/kmp.go) - * [Kmp Test](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/kmp/kmp_test.go) diff --git a/README.md b/README.md index ff2f00c0e..903b6bf04 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,101 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ## List of Algorithms -See our [directory](DIRECTORY.md). + +## Ciphers +* [Caesar](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/) +* [Diffie Hellman Key Exchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/) +* [Polybius](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/) +* [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/) +* [Rsa Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/) +* [Rsa Cipher Big](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/) +* [Xor Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/) + +## Conversions +* [Roman To Integer](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman_to_integer/) + +## Data Structures +* [Binary Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/) +* [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/) +* [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/) +* Linked-List + * [Doubly Linked-list](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/) + * [Singly Linked-list](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/) +* [Trie](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/) + +## Design Patterns +* [Abstract Factory](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/) +* [Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/) +* [Factory Method](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/) +* [Prototype](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/) + + +## Dynamic Programming +* [Binomial Coefficient](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/binomialcoefficient.go) +* [Fibonacci](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci.go) | [Test](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci_test.go) +* [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/knapsack.go) +* [Longest Common Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longestcommonsubsequence.go) +* [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longestpalindromicsubsequence.go) +* [Matrix Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/matrixmultiplication.go) +* [Cutting a Rod](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/rodcutting.go) + +## Genetic Algorithm +* [Genetic Algorithm](https://github.com/TheAlgorithms/Go/blob/master/genetic_algorithm/geneticalgorithm.go) + +## Graphs +* [Breadth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/breadth_first_search/) +* [Depth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/depth_first_search/) +* [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall/) + +## Math +* [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/) +* [Lcm](https://github.com/TheAlgorithms/Go/blob/master/math/lcm/) +* [Modular Arithmetic](https://github.com/TheAlgorithms/Go/blob/master/math/modular_arithmetic/) +* [Permutation](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/) +* [Power](https://github.com/TheAlgorithms/Go/blob/master/math/power/) +* [Prime](https://github.com/TheAlgorithms/Go/blob/master/math/prime/) +* [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/) +* [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/) + + +## Other +* [Max Subarray Sum](https://github.com/TheAlgorithms/Go/blob/master/other/max_subarray_sum/) +* [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/) +* [Nested Brackets](https://github.com/TheAlgorithms/Go/blob/master/other/nested_brackets/) +* [Password Generator](https://github.com/TheAlgorithms/Go/blob/master/other/password_generator/) +* [String Combinations](https://github.com/TheAlgorithms/Go/blob/master/other/string_combinations/) + +## Searches +* [Binary Search](https://github.com/TheAlgorithms/Go/blob/master/searches/binary_search/) +* [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search/) + +## Set +* [Set](https://github.com/TheAlgorithms/Go/blob/master/set/set.go) + +## Sorts +* [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubblesort.go) +* [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heapsort.go) +* [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertionsort.go) +* [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/mergesort.go) +* [Quick Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quicksort.go) +* [Radix Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radixsort.go) +* [Selection Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selectionsort.go) +* [Shell Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shellsort.go) + + +* Sorts Test + * [Sorts Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_test.go) + * [Sorts Testcases](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_testcases.go) + +## Strings +* [Levenshtein Distance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshtein_distance/) +* Multiple String Matching + * [Advanced Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/) + * [Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/) + * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/sbom/) +* [Naive String Search](https://github.com/TheAlgorithms/Go/blob/master/strings/naive_string_search/) +* Single String Matching + * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/bom/) + * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/horspool/) + * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/kmp/) + diff --git a/ciphers/caesar/caesar_cipher.go b/ciphers/caesar/caesar.go similarity index 100% rename from ciphers/caesar/caesar_cipher.go rename to ciphers/caesar/caesar.go diff --git a/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go b/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go similarity index 100% rename from ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange.go rename to ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go diff --git a/ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go b/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go similarity index 100% rename from ciphers/diffie_hellman_key_exchange/diffie_hellman_key_exchange_test.go rename to ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go diff --git a/ciphers/rsa_cipher/rsa_cipher.go b/ciphers/rsa_cipher/rsacipher.go similarity index 100% rename from ciphers/rsa_cipher/rsa_cipher.go rename to ciphers/rsa_cipher/rsacipher.go diff --git a/ciphers/rsa_cipher/rsa_cipher_test.go b/ciphers/rsa_cipher/rsacipher_test.go similarity index 96% rename from ciphers/rsa_cipher/rsa_cipher_test.go rename to ciphers/rsa_cipher/rsacipher_test.go index c70040b40..e063276e8 100644 --- a/ciphers/rsa_cipher/rsa_cipher_test.go +++ b/ciphers/rsa_cipher/rsacipher_test.go @@ -24,7 +24,7 @@ var rsaTestData = []struct { "the quick brown fox jumps over the lazy dog.", }, { - "Encrypt full sentence from rsa_cipher.go main function", + "Encrypt full sentence from rsacipher.go main function", "I think RSA is really great", }, } diff --git a/ciphers/rsa_cipher_big/rsa_cipher_big.go b/ciphers/rsa_cipher_big/rsacipherbig.go similarity index 100% rename from ciphers/rsa_cipher_big/rsa_cipher_big.go rename to ciphers/rsa_cipher_big/rsacipherbig.go diff --git a/ciphers/rsa_cipher_big/rsa_cipher_big_test.go b/ciphers/rsa_cipher_big/rsacipherbig_test.go similarity index 95% rename from ciphers/rsa_cipher_big/rsa_cipher_big_test.go rename to ciphers/rsa_cipher_big/rsacipherbig_test.go index 973be9672..1efcd919d 100644 --- a/ciphers/rsa_cipher_big/rsa_cipher_big_test.go +++ b/ciphers/rsa_cipher_big/rsacipherbig_test.go @@ -23,7 +23,7 @@ var rsaTestData = []struct { "the quick brown fox jumps over the lazy dog.", }, { - "Encrypt full sentence from rsa_cipher_big.go main function", + "Encrypt full sentence from rsacipherbig.go main function", "Black Lives Matter, all lives can't matter until Black lives matter", }, } diff --git a/ciphers/xor_cipher/xor_cipher.go b/ciphers/xor_cipher/xorcipher.go similarity index 100% rename from ciphers/xor_cipher/xor_cipher.go rename to ciphers/xor_cipher/xorcipher.go diff --git a/ciphers/xor_cipher/xor_cipher_test.go b/ciphers/xor_cipher/xorcipher_test.go similarity index 100% rename from ciphers/xor_cipher/xor_cipher_test.go rename to ciphers/xor_cipher/xorcipher_test.go diff --git a/conversions/roman_to_integer/roman_to_integer.go b/conversions/roman_to_integer/romantointeger.go similarity index 100% rename from conversions/roman_to_integer/roman_to_integer.go rename to conversions/roman_to_integer/romantointeger.go diff --git a/conversions/roman_to_integer/roman_to_integer_test.go b/conversions/roman_to_integer/romantointeger_test.go similarity index 100% rename from conversions/roman_to_integer/roman_to_integer_test.go rename to conversions/roman_to_integer/romantointeger_test.go diff --git a/data_structures/binary_tree/binary_search_tree.go b/data_structures/binary_tree/binarysearchtree.go similarity index 100% rename from data_structures/binary_tree/binary_search_tree.go rename to data_structures/binary_tree/binarysearchtree.go diff --git a/data_structures/binary_tree/binary_tree.go b/data_structures/binary_tree/binarytree.go similarity index 79% rename from data_structures/binary_tree/binary_tree.go rename to data_structures/binary_tree/binarytree.go index 6ee12ec9c..4d4529994 100644 --- a/data_structures/binary_tree/binary_tree.go +++ b/data_structures/binary_tree/binarytree.go @@ -1,13 +1,6 @@ // Package binarytree basic binary tree and related operations package binarytree -// Max Function that returns max of two numbers - possibly already declared. -func Max(a, b int) int { - if a > b { - return a - } - return b -} /* func main() { diff --git a/data_structures/binary_tree/btree.go b/data_structures/binary_tree/btree.go index 0e0ad8224..3ccd3b484 100644 --- a/data_structures/binary_tree/btree.go +++ b/data_structures/binary_tree/btree.go @@ -115,3 +115,12 @@ func LevelOrder(root *Node) { } } } + + +// Max Function that returns max of two numbers - possibly already declared. +func Max(a, b int) int { + if a > b { + return a + } + return b +} \ No newline at end of file diff --git a/data_structures/dynamic_array/dynamic_array.go b/data_structures/dynamic_array/dynamicarray.go similarity index 98% rename from data_structures/dynamic_array/dynamic_array.go rename to data_structures/dynamic_array/dynamicarray.go index 6e259c4b5..1d9a9763b 100644 --- a/data_structures/dynamic_array/dynamic_array.go +++ b/data_structures/dynamic_array/dynamicarray.go @@ -6,7 +6,7 @@ // https://blog.golang.org/slices-intro // https://blog.golang.org/slices // authors [Wesllhey Holanda](https://github.com/wesllhey), [Milad](https://github.com/miraddo) -// see dynamic_array.go, dynamic_array_test.go +// see dynamicarray.go, dynamicarray_test.go package dynamicarray diff --git a/data_structures/dynamic_array/dynamic_array_test.go b/data_structures/dynamic_array/dynamicarray_test.go similarity index 100% rename from data_structures/dynamic_array/dynamic_array_test.go rename to data_structures/dynamic_array/dynamicarray_test.go diff --git a/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go b/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go similarity index 100% rename from data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist.go rename to data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go diff --git a/data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go b/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go similarity index 100% rename from data_structures/linkedlist/doubly_linkedlist/doubly_linkedlist_test.go rename to data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go diff --git a/data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go b/data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go similarity index 100% rename from data_structures/linkedlist/singly_linkedlist/singly_linkedlist.go rename to data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go diff --git a/data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go b/data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go similarity index 100% rename from data_structures/linkedlist/singly_linkedlist/singly_linkedlist_test.go rename to data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go diff --git a/design_patterns/abstract_factory/abstract_factory_test.go b/design_patterns/abstract_factory/abstractfactory_test.go similarity index 100% rename from design_patterns/abstract_factory/abstract_factory_test.go rename to design_patterns/abstract_factory/abstractfactory_test.go diff --git a/design_patterns/abstract_factory/adidas_shoe.go b/design_patterns/abstract_factory/adidasshoe.go similarity index 100% rename from design_patterns/abstract_factory/adidas_shoe.go rename to design_patterns/abstract_factory/adidasshoe.go diff --git a/design_patterns/abstract_factory/i_shirt.go b/design_patterns/abstract_factory/ishirt.go similarity index 100% rename from design_patterns/abstract_factory/i_shirt.go rename to design_patterns/abstract_factory/ishirt.go diff --git a/design_patterns/abstract_factory/i_shoe.go b/design_patterns/abstract_factory/ishoe.go similarity index 100% rename from design_patterns/abstract_factory/i_shoe.go rename to design_patterns/abstract_factory/ishoe.go diff --git a/design_patterns/abstract_factory/i_sports_factory.go b/design_patterns/abstract_factory/isportsfactory.go similarity index 100% rename from design_patterns/abstract_factory/i_sports_factory.go rename to design_patterns/abstract_factory/isportsfactory.go diff --git a/design_patterns/abstract_factory/nike_shirt.go b/design_patterns/abstract_factory/nikeshirt.go similarity index 100% rename from design_patterns/abstract_factory/nike_shirt.go rename to design_patterns/abstract_factory/nikeshirt.go diff --git a/design_patterns/abstract_factory/nike_shoe.go b/design_patterns/abstract_factory/nikeshoe.go similarity index 100% rename from design_patterns/abstract_factory/nike_shoe.go rename to design_patterns/abstract_factory/nikeshoe.go diff --git a/design_patterns/builder/builder_interface.go b/design_patterns/builder/builderinterface.go similarity index 100% rename from design_patterns/builder/builder_interface.go rename to design_patterns/builder/builderinterface.go diff --git a/design_patterns/builder/builder_pattern_test.go b/design_patterns/builder/builderpattern_test.go similarity index 100% rename from design_patterns/builder/builder_pattern_test.go rename to design_patterns/builder/builderpattern_test.go diff --git a/design_patterns/builder/igloo_builder.go b/design_patterns/builder/igloobuilder.go similarity index 100% rename from design_patterns/builder/igloo_builder.go rename to design_patterns/builder/igloobuilder.go diff --git a/design_patterns/builder/normal_builder.go b/design_patterns/builder/normalbuilder.go similarity index 100% rename from design_patterns/builder/normal_builder.go rename to design_patterns/builder/normalbuilder.go diff --git a/design_patterns/factory_method/accounting_department.go b/design_patterns/factory_method/accountingdepartment.go similarity index 100% rename from design_patterns/factory_method/accounting_department.go rename to design_patterns/factory_method/accountingdepartment.go diff --git a/design_patterns/factory_method/department_factory.go b/design_patterns/factory_method/departmentfactory.go similarity index 100% rename from design_patterns/factory_method/department_factory.go rename to design_patterns/factory_method/departmentfactory.go diff --git a/design_patterns/factory_method/factory_method_test.go b/design_patterns/factory_method/factorymethod_test.go similarity index 100% rename from design_patterns/factory_method/factory_method_test.go rename to design_patterns/factory_method/factorymethod_test.go diff --git a/design_patterns/factory_method/finance_department.go b/design_patterns/factory_method/financedepartment.go similarity index 100% rename from design_patterns/factory_method/finance_department.go rename to design_patterns/factory_method/financedepartment.go diff --git a/design_patterns/factory_method/i_department.go b/design_patterns/factory_method/idepartment.go similarity index 100% rename from design_patterns/factory_method/i_department.go rename to design_patterns/factory_method/idepartment.go diff --git a/design_patterns/prototype/node_interface.go b/design_patterns/prototype/nodeinterface.go similarity index 100% rename from design_patterns/prototype/node_interface.go rename to design_patterns/prototype/nodeinterface.go diff --git a/dynamic_programming/binomial_coefficient.go b/dynamic_programming/binomialcoefficient.go similarity index 100% rename from dynamic_programming/binomial_coefficient.go rename to dynamic_programming/binomialcoefficient.go diff --git a/dynamic_programming/longest_common_subsequence.go b/dynamic_programming/longestcommonsubsequence.go similarity index 100% rename from dynamic_programming/longest_common_subsequence.go rename to dynamic_programming/longestcommonsubsequence.go diff --git a/dynamic_programming/longest_palindromic_subsequence.go b/dynamic_programming/longestpalindromicsubsequence.go similarity index 100% rename from dynamic_programming/longest_palindromic_subsequence.go rename to dynamic_programming/longestpalindromicsubsequence.go diff --git a/dynamic_programming/matrix_multiplication.go b/dynamic_programming/matrixmultiplication.go similarity index 100% rename from dynamic_programming/matrix_multiplication.go rename to dynamic_programming/matrixmultiplication.go diff --git a/dynamic_programming/rod_cutting.go b/dynamic_programming/rodcutting.go similarity index 100% rename from dynamic_programming/rod_cutting.go rename to dynamic_programming/rodcutting.go diff --git a/genetic_algorithm/genetic_algo.go b/genetic_algorithm/geneticalgorithm.go similarity index 100% rename from genetic_algorithm/genetic_algo.go rename to genetic_algorithm/geneticalgorithm.go diff --git a/graphs/search/breadth_first_search.go b/graphs/breadth_first_search/breadthfirstsearch.go similarity index 97% rename from graphs/search/breadth_first_search.go rename to graphs/breadth_first_search/breadthfirstsearch.go index 6781be597..c80bf8209 100644 --- a/graphs/search/breadth_first_search.go +++ b/graphs/breadth_first_search/breadthfirstsearch.go @@ -1,6 +1,6 @@ // Package search Graph search algorithms // reference: https://en.wikipedia.org/wiki/Tree_traversal -package search +package breadth_first_search /*BreadthFirstSearch is an algorithm for traversing and searching graph data structures. It starts at an arbitrary node of a graph, and explores all of the neighbor nodes diff --git a/graphs/search/breadth_first_search_test.go b/graphs/breadth_first_search/breadthfirstsearch_test.go similarity index 98% rename from graphs/search/breadth_first_search_test.go rename to graphs/breadth_first_search/breadthfirstsearch_test.go index d476c3bc1..d80d767f5 100644 --- a/graphs/search/breadth_first_search_test.go +++ b/graphs/breadth_first_search/breadthfirstsearch_test.go @@ -1,4 +1,4 @@ -package search +package breadth_first_search import ( "testing" diff --git a/graphs/depth_first_search/depth_first_search.go b/graphs/depth_first_search/depthfirstsearch.go similarity index 100% rename from graphs/depth_first_search/depth_first_search.go rename to graphs/depth_first_search/depthfirstsearch.go diff --git a/graphs/floyd_warshall/floyd_warshall.go b/graphs/floyd_warshall/floydwarshall.go similarity index 100% rename from graphs/floyd_warshall/floyd_warshall.go rename to graphs/floyd_warshall/floydwarshall.go diff --git a/math/gcd/gcd_iterative.go b/math/gcd/gcditerative.go similarity index 100% rename from math/gcd/gcd_iterative.go rename to math/gcd/gcditerative.go diff --git a/math/modular_arithmetic/modular_exponentiation.go b/math/modular_arithmetic/modularexponentiation.go similarity index 100% rename from math/modular_arithmetic/modular_exponentiation.go rename to math/modular_arithmetic/modularexponentiation.go diff --git a/math/modular_arithmetic/modular_exponentiation_test.go b/math/modular_arithmetic/modularexponentiation_test.go similarity index 100% rename from math/modular_arithmetic/modular_exponentiation_test.go rename to math/modular_arithmetic/modularexponentiation_test.go diff --git a/math/power/fast_exponent.go b/math/power/fastexponent.go similarity index 100% rename from math/power/fast_exponent.go rename to math/power/fastexponent.go diff --git a/math/power/fast_exponent_test.go b/math/power/fastexponent_test.go similarity index 100% rename from math/power/fast_exponent_test.go rename to math/power/fastexponent_test.go diff --git a/math/prime/miller_rabin_primality_test.go b/math/prime/millerrabinprimalitytest.go similarity index 100% rename from math/prime/miller_rabin_primality_test.go rename to math/prime/millerrabinprimalitytest.go diff --git a/math/prime/prime_check.go b/math/prime/primecheck.go similarity index 100% rename from math/prime/prime_check.go rename to math/prime/primecheck.go diff --git a/math/prime/prime_test.go b/math/prime/primecheck_test.go similarity index 100% rename from math/prime/prime_test.go rename to math/prime/primecheck_test.go diff --git a/other/max_subarray_sum/max_subarray_sum.go b/other/max_subarray_sum/maxsubarraysum.go similarity index 100% rename from other/max_subarray_sum/max_subarray_sum.go rename to other/max_subarray_sum/maxsubarraysum.go diff --git a/other/monte_carlo_pi/monte_carlo_pi.go b/other/monte_carlo_pi/montecarlopi.go similarity index 100% rename from other/monte_carlo_pi/monte_carlo_pi.go rename to other/monte_carlo_pi/montecarlopi.go diff --git a/other/monte_carlo_pi/monte_carlo_pi_test.go b/other/monte_carlo_pi/montecarlopi_test.go similarity index 100% rename from other/monte_carlo_pi/monte_carlo_pi_test.go rename to other/monte_carlo_pi/montecarlopi_test.go diff --git a/other/nested_brackets/nested_brackets.go b/other/nested_brackets/nestedbrackets.go similarity index 100% rename from other/nested_brackets/nested_brackets.go rename to other/nested_brackets/nestedbrackets.go diff --git a/other/password_generator/password_generator.go b/other/password_generator/passwordgenerator.go similarity index 100% rename from other/password_generator/password_generator.go rename to other/password_generator/passwordgenerator.go diff --git a/other/string_combinations/string_combinations.go b/other/string_combinations/stringcombinations.go similarity index 100% rename from other/string_combinations/string_combinations.go rename to other/string_combinations/stringcombinations.go diff --git a/searches/binary_search.go b/searches/binary_search/binarysearch.go similarity index 97% rename from searches/binary_search.go rename to searches/binary_search/binarysearch.go index 725c10c07..f3c9b7840 100644 --- a/searches/binary_search.go +++ b/searches/binary_search/binarysearch.go @@ -1,4 +1,4 @@ -package searches +package binarysearch // BinarySearch Binary Search func BinarySearch(array []int, target int, lowIndex int, highIndex int) int { diff --git a/searches/search_test.go b/searches/binary_search/binarysearch_test.go similarity index 79% rename from searches/search_test.go rename to searches/binary_search/binarysearch_test.go index dccd93c11..82909e99c 100644 --- a/searches/search_test.go +++ b/searches/binary_search/binarysearch_test.go @@ -1,6 +1,8 @@ -package searches +package binarysearch -import "testing" +import ( + "testing" +) type searchTest struct { data []int @@ -38,12 +40,3 @@ func TestIterBinarySearch(t *testing.T) { } } } - -func TestLinearSearch(t *testing.T) { - for _, test := range searchTests { - actual := LinearSearch(test.data, test.key) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} diff --git a/searches/linear_search.go b/searches/linear_search/linearsearch.go similarity index 91% rename from searches/linear_search.go rename to searches/linear_search/linearsearch.go index a41ef8a80..89be4fd8b 100644 --- a/searches/linear_search.go +++ b/searches/linear_search/linearsearch.go @@ -1,4 +1,4 @@ -package searches +package linear_search // LinearSearch Simple linear search algorithm that iterates over all elements of an array in the worst case scenario func LinearSearch(array []int, query int) int { diff --git a/searches/linear_search/linearsearch_test.go b/searches/linear_search/linearsearch_test.go new file mode 100644 index 000000000..d5db0c416 --- /dev/null +++ b/searches/linear_search/linearsearch_test.go @@ -0,0 +1,34 @@ +package linear_search + +import ( + "testing" +) + +type searchTest struct { + data []int + key int + expected int + name string +} + +var searchTests = []searchTest{ + //Sanity + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, + //Absent + {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, + {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, + //Empty slice + {[]int{}, 2, -1, "Empty"}, +} + + +func TestLinearSearch(t *testing.T) { + for _, test := range searchTests { + actual := LinearSearch(test.data, test.key) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/sorts/bubble_sort.go b/sorts/bubblesort.go similarity index 100% rename from sorts/bubble_sort.go rename to sorts/bubblesort.go diff --git a/sorts/heap_sort.go b/sorts/heapsort.go similarity index 100% rename from sorts/heap_sort.go rename to sorts/heapsort.go diff --git a/sorts/insertion_sort.go b/sorts/insertionsort.go similarity index 100% rename from sorts/insertion_sort.go rename to sorts/insertionsort.go diff --git a/sorts/merge_sort.go b/sorts/mergesort.go similarity index 100% rename from sorts/merge_sort.go rename to sorts/mergesort.go diff --git a/sorts/quick_sort.go b/sorts/quicksort.go similarity index 100% rename from sorts/quick_sort.go rename to sorts/quicksort.go diff --git a/sorts/radix_sort.go b/sorts/radixsort.go similarity index 100% rename from sorts/radix_sort.go rename to sorts/radixsort.go diff --git a/sorts/selection_sort.go b/sorts/selectionsort.go similarity index 100% rename from sorts/selection_sort.go rename to sorts/selectionsort.go diff --git a/sorts/shell_sort.go b/sorts/shellsort.go similarity index 100% rename from sorts/shell_sort.go rename to sorts/shellsort.go diff --git a/strings/levenshtein_distance/levenshtein_distance.go b/strings/levenshtein_distance/levenshteindistance.go similarity index 100% rename from strings/levenshtein_distance/levenshtein_distance.go rename to strings/levenshtein_distance/levenshteindistance.go diff --git a/strings/levenshtein_distance/levenshtein_distance_test.go b/strings/levenshtein_distance/levenshteindistance_test.go similarity index 100% rename from strings/levenshtein_distance/levenshtein_distance_test.go rename to strings/levenshtein_distance/levenshteindistance_test.go diff --git a/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick.go b/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go similarity index 100% rename from strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick.go rename to strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go diff --git a/strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick_test.go b/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go similarity index 100% rename from strings/multiple_string_matching/advanced_aho_corasick/advanced_aho_corasick_test.go rename to strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go diff --git a/strings/multiple_string_matching/aho_corasick/aho_corasick.go b/strings/multiple_string_matching/aho_corasick/ahocorasick.go similarity index 100% rename from strings/multiple_string_matching/aho_corasick/aho_corasick.go rename to strings/multiple_string_matching/aho_corasick/ahocorasick.go diff --git a/strings/multiple_string_matching/aho_corasick/aho_corasick_test.go b/strings/multiple_string_matching/aho_corasick/ahocorasick_test.go similarity index 100% rename from strings/multiple_string_matching/aho_corasick/aho_corasick_test.go rename to strings/multiple_string_matching/aho_corasick/ahocorasick_test.go diff --git a/strings/naive_string_search/naive_string_search.go b/strings/naive_string_search/naivestringsearch.go similarity index 100% rename from strings/naive_string_search/naive_string_search.go rename to strings/naive_string_search/naivestringsearch.go diff --git a/strings/naive_string_search/naive_string_search_test.go b/strings/naive_string_search/naivestringsearch_test.go similarity index 100% rename from strings/naive_string_search/naive_string_search_test.go rename to strings/naive_string_search/naivestringsearch_test.go From 81267bbbe7f446b79cf06b104736675f7f3f5800 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Wed, 25 Aug 2021 09:14:07 +0300 Subject: [PATCH 205/488] Remove design patterns (#321) * Remove design patterns * Remove inactive code owners * Move set to data structures --- .github/CODEOWNERS | 9 -- README.md | 127 +++++++++--------- {set => data_structures/set}/set.go | 0 .../abstract_factory/abstractfactory_test.go | 52 ------- design_patterns/abstract_factory/adidas.go | 23 ---- .../abstract_factory/adidasshirt.go | 6 - .../abstract_factory/adidasshoe.go | 6 - design_patterns/abstract_factory/ishirt.go | 31 ----- design_patterns/abstract_factory/ishoe.go | 30 ----- .../abstract_factory/isportsfactory.go | 21 --- design_patterns/abstract_factory/nike.go | 23 ---- design_patterns/abstract_factory/nikeshirt.go | 6 - design_patterns/abstract_factory/nikeshoe.go | 7 - design_patterns/builder/builderinterface.go | 19 --- .../builder/builderpattern_test.go | 52 ------- design_patterns/builder/director.go | 21 --- design_patterns/builder/house.go | 7 - design_patterns/builder/igloobuilder.go | 31 ----- design_patterns/builder/normalbuilder.go | 31 ----- .../factory_method/accountingdepartment.go | 14 -- design_patterns/factory_method/department.go | 23 ---- .../factory_method/departmentfactory.go | 13 -- .../factory_method/factorymethod_test.go | 43 ------ .../factory_method/financedepartment.go | 14 -- design_patterns/factory_method/idepartment.go | 8 -- design_patterns/prototype/file.go | 15 --- design_patterns/prototype/folder.go | 27 ---- design_patterns/prototype/nodeinterface.go | 5 - design_patterns/prototype/prototype_test.go | 36 ----- 29 files changed, 63 insertions(+), 637 deletions(-) rename {set => data_structures/set}/set.go (100%) delete mode 100644 design_patterns/abstract_factory/abstractfactory_test.go delete mode 100644 design_patterns/abstract_factory/adidas.go delete mode 100644 design_patterns/abstract_factory/adidasshirt.go delete mode 100644 design_patterns/abstract_factory/adidasshoe.go delete mode 100644 design_patterns/abstract_factory/ishirt.go delete mode 100644 design_patterns/abstract_factory/ishoe.go delete mode 100644 design_patterns/abstract_factory/isportsfactory.go delete mode 100644 design_patterns/abstract_factory/nike.go delete mode 100644 design_patterns/abstract_factory/nikeshirt.go delete mode 100644 design_patterns/abstract_factory/nikeshoe.go delete mode 100644 design_patterns/builder/builderinterface.go delete mode 100644 design_patterns/builder/builderpattern_test.go delete mode 100644 design_patterns/builder/director.go delete mode 100644 design_patterns/builder/house.go delete mode 100644 design_patterns/builder/igloobuilder.go delete mode 100644 design_patterns/builder/normalbuilder.go delete mode 100644 design_patterns/factory_method/accountingdepartment.go delete mode 100644 design_patterns/factory_method/department.go delete mode 100644 design_patterns/factory_method/departmentfactory.go delete mode 100644 design_patterns/factory_method/factorymethod_test.go delete mode 100644 design_patterns/factory_method/financedepartment.go delete mode 100644 design_patterns/factory_method/idepartment.go delete mode 100644 design_patterns/prototype/file.go delete mode 100644 design_patterns/prototype/folder.go delete mode 100644 design_patterns/prototype/nodeinterface.go delete mode 100644 design_patterns/prototype/prototype_test.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6abc705d4..6d29ca705 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,12 +9,3 @@ * @siriak /.* @cclauss -/ciphers/ @vedantmamgain -/data-structures/ @Mystigan @vedantmamgain -/dynamic-programming/ @vedantmamgain -/graphs/ @vedantmamgain -/math/ @vedantmamgain @Mystigan -/other/ @vedantmamgain -/searches/ @Mystigan @vedantmamgain -/sorts/ @Mystigan @vedantmamgain -/strings/ @vedantmamgain diff --git a/README.md b/README.md index 903b6bf04..cc210b6c5 100644 --- a/README.md +++ b/README.md @@ -15,99 +15,98 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ## Ciphers -* [Caesar](https://github.com/TheAlgorithms/Go/blob/master/ciphers/caesar/) -* [Diffie Hellman Key Exchange](https://github.com/TheAlgorithms/Go/blob/master/ciphers/diffie_hellman_key_exchange/) -* [Polybius](https://github.com/TheAlgorithms/Go/blob/master/ciphers/polybius/) -* [Rot13](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rot13/) -* [Rsa Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher/) -* [Rsa Cipher Big](https://github.com/TheAlgorithms/Go/blob/master/ciphers/rsa_cipher_big/) -* [Xor Cipher](https://github.com/TheAlgorithms/Go/blob/master/ciphers/xor_cipher/) +* [Caesar](./ciphers/caesar/) +* [Diffie Hellman Key Exchange](./ciphers/diffie_hellman_key_exchange/) +* [Polybius](./ciphers/polybius/) +* [Rot13](./ciphers/rot13/) +* [Rsa Cipher](./ciphers/rsa_cipher/) +* [Rsa Cipher Big](./ciphers/rsa_cipher_big/) +* [Xor Cipher](./ciphers/xor_cipher/) ## Conversions -* [Roman To Integer](https://github.com/TheAlgorithms/Go/blob/master/conversions/roman_to_integer/) +* [Roman To Integer](./conversions/roman_to_integer/) ## Data Structures -* [Binary Tree](https://github.com/TheAlgorithms/Go/blob/master/data_structures/binary_tree/) -* [Dynamic Array](https://github.com/TheAlgorithms/Go/blob/master/data_structures/dynamic_array/) -* [Hashmap](https://github.com/TheAlgorithms/Go/blob/master/data_structures/hashmap/) +* [Binary Tree](./data_structures/binary_tree/) +* [Dynamic Array](./data_structures/dynamic_array/) +* [Hashmap](./data_structures/hashmap/) * Linked-List - * [Doubly Linked-list](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/doubly_linkedlist/) - * [Singly Linked-list](https://github.com/TheAlgorithms/Go/blob/master/data_structures/linkedlist/singly_linkedlist/) -* [Trie](https://github.com/TheAlgorithms/Go/blob/master/data_structures/trie/) + * [Doubly Linked-list](./data_structures/linkedlist/doubly_linkedlist/) + * [Singly Linked-list](./data_structures/linkedlist/singly_linkedlist/) +* [Trie](./data_structures/trie/) ## Design Patterns -* [Abstract Factory](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/abstract_factory/) -* [Builder](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/builder/) -* [Factory Method](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/factory_method/) -* [Prototype](https://github.com/TheAlgorithms/Go/blob/master/design_patterns/prototype/) +* [Abstract Factory](./design_patterns/abstract_factory/) +* [Builder](./design_patterns/builder/) +* [Factory Method](./design_patterns/factory_method/) +* [Prototype](./design_patterns/prototype/) ## Dynamic Programming -* [Binomial Coefficient](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/binomialcoefficient.go) -* [Fibonacci](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci.go) | [Test](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/fibonacci_test.go) -* [Knapsack](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/knapsack.go) -* [Longest Common Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longestcommonsubsequence.go) -* [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/longestpalindromicsubsequence.go) -* [Matrix Multiplication](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/matrixmultiplication.go) -* [Cutting a Rod](https://github.com/TheAlgorithms/Go/blob/master/dynamic_programming/rodcutting.go) +* [Binomial Coefficient](./dynamic_programming/binomialcoefficient.go) +* [Fibonacci](./dynamic_programming/fibonacci.go) | [Test](./dynamic_programming/fibonacci_test.go) +* [Knapsack](./dynamic_programming/knapsack.go) +* [Longest Common Subsequence](./dynamic_programming/longestcommonsubsequence.go) +* [Longest Palindromic Subsequence](./dynamic_programming/longestpalindromicsubsequence.go) +* [Matrix Multiplication](./dynamic_programming/matrixmultiplication.go) +* [Cutting a Rod](./dynamic_programming/rodcutting.go) ## Genetic Algorithm -* [Genetic Algorithm](https://github.com/TheAlgorithms/Go/blob/master/genetic_algorithm/geneticalgorithm.go) +* [Genetic Algorithm](./genetic_algorithm/geneticalgorithm.go) ## Graphs -* [Breadth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/breadth_first_search/) -* [Depth First Search](https://github.com/TheAlgorithms/Go/blob/master/graphs/depth_first_search/) -* [Floyd Warshall](https://github.com/TheAlgorithms/Go/blob/master/graphs/floyd_warshall/) +* [Breadth First Search](./graphs/breadth_first_search/) +* [Depth First Search](./graphs/depth_first_search/) +* [Floyd Warshall](./graphs/floyd_warshall/) ## Math -* [Gcd](https://github.com/TheAlgorithms/Go/blob/master/math/gcd/) -* [Lcm](https://github.com/TheAlgorithms/Go/blob/master/math/lcm/) -* [Modular Arithmetic](https://github.com/TheAlgorithms/Go/blob/master/math/modular_arithmetic/) -* [Permutation](https://github.com/TheAlgorithms/Go/blob/master/math/permutation/) -* [Power](https://github.com/TheAlgorithms/Go/blob/master/math/power/) -* [Prime](https://github.com/TheAlgorithms/Go/blob/master/math/prime/) -* [Pythagoras](https://github.com/TheAlgorithms/Go/blob/master/math/pythagoras/) -* [Sieve](https://github.com/TheAlgorithms/Go/blob/master/math/sieve/) +* [Gcd](./math/gcd/) +* [Lcm](./math/lcm/) +* [Modular Arithmetic](./math/modular_arithmetic/) +* [Permutation](./math/permutation/) +* [Power](./math/power/) +* [Prime](./math/prime/) +* [Pythagoras](./math/pythagoras/) +* [Sieve](./math/sieve/) ## Other -* [Max Subarray Sum](https://github.com/TheAlgorithms/Go/blob/master/other/max_subarray_sum/) -* [Monte Carlo Pi](https://github.com/TheAlgorithms/Go/blob/master/other/monte_carlo_pi/) -* [Nested Brackets](https://github.com/TheAlgorithms/Go/blob/master/other/nested_brackets/) -* [Password Generator](https://github.com/TheAlgorithms/Go/blob/master/other/password_generator/) -* [String Combinations](https://github.com/TheAlgorithms/Go/blob/master/other/string_combinations/) +* [Max Subarray Sum](./other/max_subarray_sum/) +* [Monte Carlo Pi](./other/monte_carlo_pi/) +* [Nested Brackets](./other/nested_brackets/) +* [Password Generator](./other/password_generator/) +* [String Combinations](./other/string_combinations/) ## Searches -* [Binary Search](https://github.com/TheAlgorithms/Go/blob/master/searches/binary_search/) -* [Linear Search](https://github.com/TheAlgorithms/Go/blob/master/searches/linear_search/) +* [Binary Search](./searches/binary_search/) +* [Linear Search](./searches/linear_search/) ## Set -* [Set](https://github.com/TheAlgorithms/Go/blob/master/set/set.go) +* [Set](./data_structures/set/set.go) ## Sorts -* [Bubble Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/bubblesort.go) -* [Heap Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/heapsort.go) -* [Insertion Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/insertionsort.go) -* [Merge Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/mergesort.go) -* [Quick Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/quicksort.go) -* [Radix Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/radixsort.go) -* [Selection Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/selectionsort.go) -* [Shell Sort](https://github.com/TheAlgorithms/Go/blob/master/sorts/shellsort.go) +* [Bubble Sort](./sorts/bubblesort.go) +* [Heap Sort](./sorts/heapsort.go) +* [Insertion Sort](./sorts/insertionsort.go) +* [Merge Sort](./sorts/mergesort.go) +* [Quick Sort](./sorts/quicksort.go) +* [Radix Sort](./sorts/radixsort.go) +* [Selection Sort](./sorts/selectionsort.go) +* [Shell Sort](./sorts/shellsort.go) * Sorts Test - * [Sorts Test](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_test.go) - * [Sorts Testcases](https://github.com/TheAlgorithms/Go/blob/master/sorts/sorts_testcases.go) + * [Sorts Test](./sorts/sorts_test.go) + * [Sorts Testcases](./sorts/sorts_testcases.go) ## Strings -* [Levenshtein Distance](https://github.com/TheAlgorithms/Go/blob/master/strings/levenshtein_distance/) +* [Levenshtein Distance](./strings/levenshtein_distance/) * Multiple String Matching - * [Advanced Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/advanced_aho_corasick/) - * [Aho Corasick](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/aho_corasick/) - * [Sbom](https://github.com/TheAlgorithms/Go/blob/master/strings/multiple_string_matching/sbom/) -* [Naive String Search](https://github.com/TheAlgorithms/Go/blob/master/strings/naive_string_search/) + * [Advanced Aho Corasick](./strings/multiple_string_matching/advanced_aho_corasick/) + * [Aho Corasick](./strings/multiple_string_matching/aho_corasick/) + * [Sbom](./strings/multiple_string_matching/sbom/) +* [Naive String Search](./strings/naive_string_search/) * Single String Matching - * [Bom](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/bom/) - * [Horspool](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/horspool/) - * [Kmp](https://github.com/TheAlgorithms/Go/blob/master/strings/single_string_matching/kmp/) - + * [Bom](./strings/single_string_matching/bom/) + * [Horspool](./strings/single_string_matching/horspool/) + * [Kmp](./strings/single_string_matching/kmp/) diff --git a/set/set.go b/data_structures/set/set.go similarity index 100% rename from set/set.go rename to data_structures/set/set.go diff --git a/design_patterns/abstract_factory/abstractfactory_test.go b/design_patterns/abstract_factory/abstractfactory_test.go deleted file mode 100644 index 7505be461..000000000 --- a/design_patterns/abstract_factory/abstractfactory_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package abstractfactorry - -import ( - "reflect" - "testing" -) - -// test client code and how to use the factory - -func TestAbstractFactory(t *testing.T) { - - t.Run("Test Nike Factory", func(t *testing.T) { - nikeFactory, _ := getSportsFactory("nike") - nikeShoe := nikeFactory.makeShoe() - nikeShirt := nikeFactory.makeShirt() - if !reflect.DeepEqual(nikeShoe.getLogo(), "nike") { - t.Errorf("got: %v, want: %v", nikeShoe.getLogo(), "nike") - } - if !reflect.DeepEqual(nikeShoe.getSize(), 14) { - t.Errorf("got: %v, want: %v", nikeShoe.getSize(), 14) - } - if !reflect.DeepEqual(nikeShirt.getLogo(), "nike") { - t.Errorf("got: %v, want: %v", nikeShirt.getLogo(), "nike") - } - if !reflect.DeepEqual(nikeShirt.getSize(), 14) { - t.Errorf("got: %v, want: %v", nikeShirt.getLogo(), 14) - } - }) - - t.Run("Test Adidas Factory", func(t *testing.T) { - adidasFactory, _ := getSportsFactory("adidas") - adidasShoe := adidasFactory.makeShoe() - adidasShirt := adidasFactory.makeShirt() - - if !reflect.DeepEqual(adidasShoe.getLogo(), "adidas") { - t.Errorf("got: %v, want: %v", adidasShoe.getLogo(), "adidas") - } - if !reflect.DeepEqual(adidasShoe.getSize(), 14) { - t.Errorf("got: %v, want: %v", adidasShoe.getSize(), 14) - } - if !reflect.DeepEqual(adidasShirt.getLogo(), "adidas") { - t.Errorf("got: %v, want: %v", adidasShirt.getLogo(), "adidas") - } - if !reflect.DeepEqual(adidasShirt.getSize(), 14) { - t.Errorf("got: %v, want: %v", adidasShirt.getLogo(), 14) - } - }) - -} - - - diff --git a/design_patterns/abstract_factory/adidas.go b/design_patterns/abstract_factory/adidas.go deleted file mode 100644 index d5285068d..000000000 --- a/design_patterns/abstract_factory/adidas.go +++ /dev/null @@ -1,23 +0,0 @@ -package abstractfactorry - -// Concrete factory -type adidas struct { -} - -func (a *adidas) makeShoe() iShoe { - return &adidasShoe{ - shoe: shoe{ - logo: "adidas", - size: 14, - }, - } -} - -func (a *adidas) makeShirt() iShirt { - return &adidasShirt{ - shirt: shirt{ - logo: "adidas", - size: 14, - }, - } -} \ No newline at end of file diff --git a/design_patterns/abstract_factory/adidasshirt.go b/design_patterns/abstract_factory/adidasshirt.go deleted file mode 100644 index 0b6fd8d1d..000000000 --- a/design_patterns/abstract_factory/adidasshirt.go +++ /dev/null @@ -1,6 +0,0 @@ -package abstractfactorry - -// Concrete product -type adidasShirt struct { - shirt -} \ No newline at end of file diff --git a/design_patterns/abstract_factory/adidasshoe.go b/design_patterns/abstract_factory/adidasshoe.go deleted file mode 100644 index 79528f04f..000000000 --- a/design_patterns/abstract_factory/adidasshoe.go +++ /dev/null @@ -1,6 +0,0 @@ -package abstractfactorry - -// Concrete product -type adidasShoe struct { - shoe -} \ No newline at end of file diff --git a/design_patterns/abstract_factory/ishirt.go b/design_patterns/abstract_factory/ishirt.go deleted file mode 100644 index 9378f08a7..000000000 --- a/design_patterns/abstract_factory/ishirt.go +++ /dev/null @@ -1,31 +0,0 @@ -package abstractfactorry - -// Abstract product - -type iShirt interface { - setLogo(logo string) - setSize(size int) - getLogo() string - getSize() int -} - -type shirt struct { - logo string - size int -} - -func (s *shirt) setLogo(logo string) { - s.logo = logo -} - -func (s *shirt) getLogo() string { - return s.logo -} - -func (s *shirt) setSize(size int) { - s.size = size -} - -func (s *shirt) getSize() int { - return s.size -} diff --git a/design_patterns/abstract_factory/ishoe.go b/design_patterns/abstract_factory/ishoe.go deleted file mode 100644 index ca25ff8c7..000000000 --- a/design_patterns/abstract_factory/ishoe.go +++ /dev/null @@ -1,30 +0,0 @@ -package abstractfactorry - -// Abstract product -type iShoe interface { - setLogo(logo string) - setSize(size int) - getLogo() string - getSize() int -} - -type shoe struct { - logo string - size int -} - -func (s *shoe) setLogo(logo string) { - s.logo = logo -} - -func (s *shoe) getLogo() string { - return s.logo -} - -func (s *shoe) setSize(size int) { - s.size = size -} - -func (s *shoe) getSize() int { - return s.size -} \ No newline at end of file diff --git a/design_patterns/abstract_factory/isportsfactory.go b/design_patterns/abstract_factory/isportsfactory.go deleted file mode 100644 index 991c8de24..000000000 --- a/design_patterns/abstract_factory/isportsfactory.go +++ /dev/null @@ -1,21 +0,0 @@ -package abstractfactorry - -import "fmt" - -// Abstract factory interface -type iSportsFactory interface { - makeShoe() iShoe - makeShirt() iShirt -} - -func getSportsFactory(brand string) (iSportsFactory, error) { - if brand == "adidas" { - return &adidas{}, nil - } - - if brand == "nike" { - return &nike{}, nil - } - - return nil, fmt.Errorf("Wrong brand type passed") -} \ No newline at end of file diff --git a/design_patterns/abstract_factory/nike.go b/design_patterns/abstract_factory/nike.go deleted file mode 100644 index 8b4f4346f..000000000 --- a/design_patterns/abstract_factory/nike.go +++ /dev/null @@ -1,23 +0,0 @@ -package abstractfactorry - -// Concrete factory -type nike struct { -} - -func (n *nike) makeShoe() iShoe { - return &nikeShoe{ - shoe: shoe{ - logo: "nike", - size: 14, - }, - } -} - -func (n *nike) makeShirt() iShirt { - return &nikeShirt{ - shirt: shirt{ - logo: "nike", - size: 14, - }, - } -} diff --git a/design_patterns/abstract_factory/nikeshirt.go b/design_patterns/abstract_factory/nikeshirt.go deleted file mode 100644 index 530f822d1..000000000 --- a/design_patterns/abstract_factory/nikeshirt.go +++ /dev/null @@ -1,6 +0,0 @@ -package abstractfactorry - -// Concrete product -type nikeShirt struct { - shirt -} \ No newline at end of file diff --git a/design_patterns/abstract_factory/nikeshoe.go b/design_patterns/abstract_factory/nikeshoe.go deleted file mode 100644 index b2bc2c7cf..000000000 --- a/design_patterns/abstract_factory/nikeshoe.go +++ /dev/null @@ -1,7 +0,0 @@ -package abstractfactorry - -// Concrete product - -type nikeShoe struct { - shoe -} \ No newline at end of file diff --git a/design_patterns/builder/builderinterface.go b/design_patterns/builder/builderinterface.go deleted file mode 100644 index b1cf6ad5c..000000000 --- a/design_patterns/builder/builderinterface.go +++ /dev/null @@ -1,19 +0,0 @@ -package builder - -type iBuilder interface { - setWindowType() - setDoorType() - setNumFloor() - getHouse() house -} - -func getBuilder(builderType string) iBuilder { - if builderType == "normal" { - return newNormalBuilder() - } - - if builderType == "igloo" { - return newIglooBuilder() - } - return nil -} diff --git a/design_patterns/builder/builderpattern_test.go b/design_patterns/builder/builderpattern_test.go deleted file mode 100644 index 18965feee..000000000 --- a/design_patterns/builder/builderpattern_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package builder -import ( - "fmt" - "reflect" - "testing" -) - -func TestBuilderPatter(t *testing.T){ - t.Run("Test Normal Builder", func(t *testing.T) { - normalBuilder := getBuilder("normal") - director := newDirector(normalBuilder) - normalHouse := director.buildHouse() - if !reflect.DeepEqual(normalHouse.doorType, "Wooden Door") { - t.Errorf("got: %v, want: %v", normalHouse.doorType, "Wooden Door") - } - if !reflect.DeepEqual(normalHouse.windowType, "Wooden Window") { - t.Errorf("got: %v, want: %v", normalHouse.windowType, "Wooden Window") - } - if !reflect.DeepEqual(normalHouse.floor, 2) { - t.Errorf("got: %v, want: %v", normalHouse.floor, 2) - } - }) - t.Run("Test Igloo Builder", func(t *testing.T) { - iglooBuilder := getBuilder("igloo") - director := newDirector(iglooBuilder) - iglooHouse := director.buildHouse() - if !reflect.DeepEqual(iglooHouse.doorType, "Snow Door") { - t.Errorf("got: %v, want: %v", iglooHouse.doorType, "Snow Door") - } - if !reflect.DeepEqual(iglooHouse.windowType, "Snow Window") { - t.Errorf("got: %v, want: %v", iglooHouse.windowType, "Snow Window") - } - if !reflect.DeepEqual(iglooHouse.floor, 1) { - t.Errorf("got: %v, want: %v", iglooHouse.floor, 1) - } - }) - - t.Run("Test set builder ", func(t *testing.T) { - iglooBuilder := getBuilder("igloo") - director := director{} - director.setBuilder(iglooBuilder) - iglooHouse := director.buildHouse() - fmt.Println(iglooHouse) - if !reflect.DeepEqual(iglooHouse.floor, 1) { - t.Errorf("got: %v, want: %v", iglooHouse.floor, 1) - } - - }) - -} - - diff --git a/design_patterns/builder/director.go b/design_patterns/builder/director.go deleted file mode 100644 index 9ca220454..000000000 --- a/design_patterns/builder/director.go +++ /dev/null @@ -1,21 +0,0 @@ -package builder - -type director struct { - builder iBuilder -} - -func newDirector(b iBuilder) *director { - return &director{ - builder: b, - } -} -func (d *director) setBuilder(b iBuilder) { - d.builder = b -} - -func (d *director) buildHouse() house { - d.builder.setDoorType() - d.builder.setWindowType() - d.builder.setNumFloor() - return d.builder.getHouse() -} \ No newline at end of file diff --git a/design_patterns/builder/house.go b/design_patterns/builder/house.go deleted file mode 100644 index f7e9954e9..000000000 --- a/design_patterns/builder/house.go +++ /dev/null @@ -1,7 +0,0 @@ -package builder - -type house struct { - windowType string - doorType string - floor int -} \ No newline at end of file diff --git a/design_patterns/builder/igloobuilder.go b/design_patterns/builder/igloobuilder.go deleted file mode 100644 index f7803199c..000000000 --- a/design_patterns/builder/igloobuilder.go +++ /dev/null @@ -1,31 +0,0 @@ -package builder - -type iglooBuilder struct { - windowType string - doorType string - floor int -} - -func newIglooBuilder() *iglooBuilder { - return &iglooBuilder{} -} - -func (b *iglooBuilder) setWindowType() { - b.windowType = "Snow Window" -} - -func (b *iglooBuilder) setDoorType() { - b.doorType = "Snow Door" -} - -func (b *iglooBuilder) setNumFloor() { - b.floor = 1 -} - -func (b *iglooBuilder) getHouse() house { - return house{ - doorType: b.doorType, - windowType: b.windowType, - floor: b.floor, - } -} \ No newline at end of file diff --git a/design_patterns/builder/normalbuilder.go b/design_patterns/builder/normalbuilder.go deleted file mode 100644 index 9b389b718..000000000 --- a/design_patterns/builder/normalbuilder.go +++ /dev/null @@ -1,31 +0,0 @@ -package builder - -type normalBuilder struct { - windowType string - doorType string - floor int -} - -func newNormalBuilder() *normalBuilder { - return &normalBuilder{} -} - -func (b *normalBuilder) setWindowType() { - b.windowType = "Wooden Window" -} - -func (b *normalBuilder) setDoorType() { - b.doorType = "Wooden Door" -} - -func (b *normalBuilder) setNumFloor() { - b.floor = 2 -} - -func (b *normalBuilder) getHouse() house { - return house{ - doorType: b.doorType, - windowType: b.windowType, - floor: b.floor, - } -} \ No newline at end of file diff --git a/design_patterns/factory_method/accountingdepartment.go b/design_patterns/factory_method/accountingdepartment.go deleted file mode 100644 index 20fb1248f..000000000 --- a/design_patterns/factory_method/accountingdepartment.go +++ /dev/null @@ -1,14 +0,0 @@ -package factory_method - -type accounting struct { - department -} - -func newAccounting() iDepartment { - return &accounting{ - department: department{ - name: "Accounting Department", - employees: 1, - }, - } -} \ No newline at end of file diff --git a/design_patterns/factory_method/department.go b/design_patterns/factory_method/department.go deleted file mode 100644 index 9c54466f4..000000000 --- a/design_patterns/factory_method/department.go +++ /dev/null @@ -1,23 +0,0 @@ -package factory_method - -type department struct { - name string - employees int -} - - -func (g *department) setName(name string) { - g.name = name -} - -func (g *department) getName() string { - return g.name -} - -func (g *department) setEmployees(employees int) { - g.employees = employees -} - -func (g *department) getEmployees() int { - return g.employees -} \ No newline at end of file diff --git a/design_patterns/factory_method/departmentfactory.go b/design_patterns/factory_method/departmentfactory.go deleted file mode 100644 index b72aff711..000000000 --- a/design_patterns/factory_method/departmentfactory.go +++ /dev/null @@ -1,13 +0,0 @@ -package factory_method - -import "fmt" - -func getDepartment(departmentType string) (iDepartment, error) { - if departmentType == "accounting" { - return newAccounting(), nil - } - if departmentType == "finance" { - return newFinance(), nil - } - return nil, fmt.Errorf("wrong department type passed") -} diff --git a/design_patterns/factory_method/factorymethod_test.go b/design_patterns/factory_method/factorymethod_test.go deleted file mode 100644 index 4245d7aad..000000000 --- a/design_patterns/factory_method/factorymethod_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package factory_method - -import ( - "reflect" - "testing" -) - -// test client code and how to use the factory -func TestFactoryMethod(t *testing.T) { - t.Run("Test Accounting Department", func(t *testing.T) { - accounting, _ := getDepartment("accounting") - if !reflect.DeepEqual(accounting.getName(), "Accounting Department") { - t.Errorf("got: %v, want: %v", accounting.getName(), "Accounting Department") - } - if !reflect.DeepEqual(accounting.getEmployees(), 1) { - t.Errorf("got: %v, want: %v", accounting.getName(), 1) - } - }) - - - t.Run("Test Finance Department", func(t *testing.T) { - finance, _ := getDepartment("finance") - if !reflect.DeepEqual(finance.getName(), "Finance Department") { - t.Errorf("got: %v, want: %v", finance.getName(), "Finance Department") - } - if !reflect.DeepEqual(finance.getEmployees(), 2) { - t.Errorf("got: %v, want: %v", finance.getEmployees(), 2) - } - }) - - t.Run("Test not existing department", func(t *testing.T) { - random, _ := getDepartment("test") - - if !reflect.DeepEqual(random, nil) { - t.Errorf("should return empty nil for non existing department") - } - - }) -} - - - - diff --git a/design_patterns/factory_method/financedepartment.go b/design_patterns/factory_method/financedepartment.go deleted file mode 100644 index 191ecf0a7..000000000 --- a/design_patterns/factory_method/financedepartment.go +++ /dev/null @@ -1,14 +0,0 @@ -package factory_method - -type finance struct { - department -} - -func newFinance() iDepartment { - return &finance{ - department: department{ - name: "Finance Department", - employees: 2, - }, - } -} \ No newline at end of file diff --git a/design_patterns/factory_method/idepartment.go b/design_patterns/factory_method/idepartment.go deleted file mode 100644 index 4d6f6fadc..000000000 --- a/design_patterns/factory_method/idepartment.go +++ /dev/null @@ -1,8 +0,0 @@ -package factory_method - -type iDepartment interface { - setName(name string) - setEmployees(employees int) - getName() string - getEmployees() int -} \ No newline at end of file diff --git a/design_patterns/prototype/file.go b/design_patterns/prototype/file.go deleted file mode 100644 index 67c7cc9cc..000000000 --- a/design_patterns/prototype/file.go +++ /dev/null @@ -1,15 +0,0 @@ -package prototype - -import "fmt" - -type file struct { - name string -} - -func (f *file) print(indentation string) { - fmt.Println(indentation + f.name) -} - -func (f *file) clone() nodeInterface { - return &file{name: f.name + "_clone"} -} diff --git a/design_patterns/prototype/folder.go b/design_patterns/prototype/folder.go deleted file mode 100644 index a6700b3ae..000000000 --- a/design_patterns/prototype/folder.go +++ /dev/null @@ -1,27 +0,0 @@ -package prototype - -import "fmt" - -type folder struct { - children []nodeInterface - name string -} - -func (f *folder) print(indentation string) { - fmt.Println(indentation + f.name) - for _, i := range f.children { - i.print(indentation + indentation) - } -} - -func (f *folder) clone() nodeInterface { - cloneFolder := &folder{name: f.name + "_clone"} - var tempChildren []nodeInterface - for _, i := range f.children { - copy := i.clone() - tempChildren = append(tempChildren, copy) - } - cloneFolder.children = tempChildren - return cloneFolder -} - diff --git a/design_patterns/prototype/nodeinterface.go b/design_patterns/prototype/nodeinterface.go deleted file mode 100644 index ca25dcc79..000000000 --- a/design_patterns/prototype/nodeinterface.go +++ /dev/null @@ -1,5 +0,0 @@ -package prototype -type nodeInterface interface { - print(string) - clone() nodeInterface -} diff --git a/design_patterns/prototype/prototype_test.go b/design_patterns/prototype/prototype_test.go deleted file mode 100644 index baf874f61..000000000 --- a/design_patterns/prototype/prototype_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package prototype - -import ( - "fmt" - "testing" -) - -// test client code and how to use the factory -func TestProtoType(t *testing.T) { - t.Run("Test File And Folder Hierarchy", func(t *testing.T) { - file1 := &file{name: "File1"} - file2 := &file{name: "File2"} - file3 := &file{name: "File3"} - - folder1 := &folder{ - children: []nodeInterface{file1}, - name: "Folder1", - } - - folder2 := &folder{ - children: []nodeInterface{folder1, file2, file3}, - name: "Folder2", - } - fmt.Println("\nPrinting hierarchy for Folder2") - folder2.print(" ") - - cloneFolder := folder2.clone() - fmt.Println("\nPrinting hierarchy for clone Folder") - cloneFolder.print(" ") - }) -} - - - - - From e24747c6c495afd58b68c2ecfd7dd4136231237a Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Thu, 26 Aug 2021 18:21:27 +0300 Subject: [PATCH 206/488] Update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6d29ca705..496ff7a76 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,5 +7,5 @@ # Order is important. The last matching pattern has the most precedence. -* @siriak +* @siriak @raklaptudirm /.* @cclauss From 204a7378bcbfc69fd38cbe1e5f54ffe95e575573 Mon Sep 17 00:00:00 2001 From: Milad <14594374+Miraddo@users.noreply.github.com> Date: Fri, 27 Aug 2021 12:26:23 +0430 Subject: [PATCH 207/488] Add Stack and Queue Data Structures (#323) * Add Queue Data Structure With Array, Linked-List, Container/List, and tests * Add Stack Data Structure With Array, Linked-List, Container/List, and tests * Update list of algorithms --- README.md | 6 +- data_structures/queue/queue_test.go | 257 ++++++++++++++++++ data_structures/queue/queuearray.go | 46 ++++ data_structures/queue/queuelinkedlist.go | 77 ++++++ .../queue/queuelinklistwithlist.go | 73 +++++ data_structures/stack/stack_test.go | 191 +++++++++++++ data_structures/stack/stackarray.go | 39 +++ data_structures/stack/stacklinkedlist.go | 73 +++++ .../stack/stacklinkedlistwithlist.go | 60 ++++ 9 files changed, 819 insertions(+), 3 deletions(-) create mode 100644 data_structures/queue/queue_test.go create mode 100644 data_structures/queue/queuearray.go create mode 100644 data_structures/queue/queuelinkedlist.go create mode 100644 data_structures/queue/queuelinklistwithlist.go create mode 100644 data_structures/stack/stack_test.go create mode 100644 data_structures/stack/stackarray.go create mode 100644 data_structures/stack/stacklinkedlist.go create mode 100644 data_structures/stack/stacklinkedlistwithlist.go diff --git a/README.md b/README.md index cc210b6c5..605f27816 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * Linked-List * [Doubly Linked-list](./data_structures/linkedlist/doubly_linkedlist/) * [Singly Linked-list](./data_structures/linkedlist/singly_linkedlist/) +* [Queue](./data_structures/queue/) | Array, Linked-List, STL(Container/List), Test +* [Stack](./data_structures/stack/) | Array, Linked-List, STL(Container/List), Test +* [Set](./data_structures/set/) * [Trie](./data_structures/trie/) ## Design Patterns @@ -81,9 +84,6 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Binary Search](./searches/binary_search/) * [Linear Search](./searches/linear_search/) -## Set -* [Set](./data_structures/set/set.go) - ## Sorts * [Bubble Sort](./sorts/bubblesort.go) * [Heap Sort](./sorts/heapsort.go) diff --git a/data_structures/queue/queue_test.go b/data_structures/queue/queue_test.go new file mode 100644 index 000000000..0e20afe5c --- /dev/null +++ b/data_structures/queue/queue_test.go @@ -0,0 +1,257 @@ +// Queue Test +// description: based on `geeksforgeeks` description A Queue is a linear structure which follows a particular order in which the operations are performed. +// The order is First In First Out (FIFO). +// details: +// Queue Data Structure : https://www.geeksforgeeks.org/queue-data-structure/ +// Queue (abstract data type) : https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see queuearray.go, queuelinkedlist.go, queuelinkedlistwithlist.go + +package queue + +import ( + "container/list" + "testing" +) + +func TestQueue(t *testing.T) { + + // Handle Queue Linked List + t.Run("Test Queue Linked List", func(t *testing.T) { + + t.Run("Test EnQueue", func(t *testing.T) { + var newQueue Queue + newQueue.enqueue(2) + newQueue.enqueue(3) + newQueue.enqueue(4) + newQueue.enqueue(45) + + if newQueue.frontQueue() != 2 && newQueue.backQueue() != 45 { + t.Errorf("Test EnQueue is wrong the result must be %v and %v but got %v and %v", 2, 45, newQueue.frontQueue(), newQueue.backQueue()) + } + + }) + + t.Run("Test DeQueue", func(t *testing.T) { + var newQueue Queue + newQueue.enqueue(2) + newQueue.enqueue(3) + newQueue.enqueue(4) + + newQueue.dequeue() + if newQueue.dequeue() != 3 { + t.Errorf("Test DeQueue is wrong the result must be %v but got %v", 3, newQueue.dequeue()) + } + + //fmt.Println(newQueue.show()) + }) + + t.Run("Test Queue isEmpty", func(t *testing.T) { + var newQueue Queue + if newQueue.isEmpty() != true { + t.Errorf("Test Queue isEmpty is wrong the result must be %v but got %v", true, newQueue.isEmpty()) + } + + newQueue.enqueue(3) + newQueue.enqueue(4) + + if newQueue.isEmpty() != false { + t.Errorf("Test Queue isEmpty is wrong the result must be %v but got %v", false, newQueue.isEmpty()) + } + }) + + t.Run("Test Queue Length", func(t *testing.T) { + var newQueue Queue + if newQueue.len() != 0 { + t.Errorf("Test Queue Length is wrong the result must be %v but got %v", 0, newQueue.len()) + } + + newQueue.enqueue(3) + newQueue.enqueue(4) + newQueue.dequeue() + newQueue.enqueue(22) + newQueue.enqueue(99) + newQueue.dequeue() + newQueue.dequeue() + + if newQueue.len() != 1 { + t.Errorf("Test Queue Length is wrong the result must be %v but got %v", 1, newQueue.len()) + } + + }) + }) + + // Handle Queue Array + t.Run("Test Queue Array", func(t *testing.T) { + t.Run("Test EnQueue", func(t *testing.T) { + EnQueue(2) + EnQueue(23) + EnQueue(45) + EnQueue(66) + + if FrontQueue() != 2 && BackQueue() != 66 { + t.Errorf("Test EnQueue is wrong the result must be %v and %v but got %v and %v", 2, 66, FrontQueue(), BackQueue()) + } + + }) + + t.Run("Test DeQueue", func(t *testing.T) { + EnQueue(2) + EnQueue(23) + EnQueue(45) + EnQueue(66) + + DeQueue() + DeQueue() + + if DeQueue() != 45 { + t.Errorf("Test DeQueue is wrong the result must be %v but got %v", 45, DeQueue()) + } + }) + + ListQueue = []interface{}{} + + t.Run("Test Queue isEmpty", func(t *testing.T) { + + if IsEmptyQueue() != true { + t.Errorf("Test Queue isEmpty is wrong the result must be %v but got %v", true, IsEmptyQueue()) + } + + EnQueue(3) + EnQueue(4) + + if IsEmptyQueue() != false { + t.Errorf("Test Queue isEmpty is wrong the result must be %v but got %v", false, IsEmptyQueue()) + } + }) + + ListQueue = []interface{}{} + t.Run("Test Queue Length", func(t *testing.T) { + if LenQueue() != 0 { + t.Errorf("Test Queue Length is wrong the result must be %v but got %v", 0, LenQueue()) + } + + EnQueue(3) + EnQueue(4) + DeQueue() + EnQueue(22) + EnQueue(99) + DeQueue() + DeQueue() + + if LenQueue() != 1 { + t.Errorf("Test Queue Length is wrong the result must be %v but got %v", 1, LenQueue()) + } + + }) + + + }) + + // Handle Queue Linked-List With Container/List (STL) + t.Run("Test Container/List For Queue", func(t *testing.T) { + listQueue := &LQueue{ + queue: list.New(), + } + + + t.Run("List Enqueue", func(t *testing.T) { + listQueue.Enqueue("Snap") + listQueue.Enqueue(123) + listQueue.Enqueue(true) + listQueue.Enqueue(212.545454) + + if listQueue.Len() != 4{ + t.Errorf("List Enqueue is not correct expected %d but got %d",4, listQueue.Len()) + } + }) + + + t.Run("List Dequeue", func(t *testing.T) { + + + err := listQueue.Dequeue() + + if err != nil{ + t.Error("got an unexpected error ", err) + } + if listQueue.Len() != 3{ + t.Errorf("List Dequeue is not correct expected %d but got %d",3, listQueue.Len()) + } + }) + + t.Run("List Front", func(t *testing.T) { + + + err := listQueue.Dequeue() + + if err != nil{ + t.Error("got an unexpected error ", err) + } + + result , err := listQueue.Front() + + if err != nil{ + t.Error("got an unexpected error ", err) + } + + if result != true{ + t.Errorf("List Front is not correct expected %v but got %v",true, result) + } + }) + + t.Run("List Back", func(t *testing.T) { + + + + err := listQueue.Dequeue() + + if err != nil{ + t.Error("got an unexpected error ", err) + } + + result , err := listQueue.Back() + + if err != nil{ + t.Error("got an unexpected error ", err) + } + + if result != 212.545454{ + t.Errorf("List Back is not correct expected %v but got %v",212.545454, result) + } + }) + + + t.Run("List Length", func(t *testing.T) { + + listQueue.Enqueue("Snap") + + + err := listQueue.Dequeue() + + if err != nil{ + t.Error("got an unexpected error ", err) + } + + if listQueue.Len() != 1{ + t.Errorf("List Length is not correct expected %v but got %v",1, listQueue.Len() ) + } + }) + + + t.Run("List Empty", func(t *testing.T) { + + err := listQueue.Dequeue() + + if err != nil{ + t.Error("got an unexpected error ", err) + } + + if !listQueue.Empty(){ + t.Errorf("List Empty is not correct expected %v but got %v",true, listQueue.Empty() ) + } + }) + + }) + +} diff --git a/data_structures/queue/queuearray.go b/data_structures/queue/queuearray.go new file mode 100644 index 000000000..215e30159 --- /dev/null +++ b/data_structures/queue/queuearray.go @@ -0,0 +1,46 @@ +// Queue Array +// description: based on `geeksforgeeks` description A Queue is a linear structure which follows a particular order in which the operations are performed. +// The order is First In First Out (FIFO). +// details: +// Queue Data Structure : https://www.geeksforgeeks.org/queue-data-structure/ +// Queue (abstract data type) : https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see queuelinkedlist.go, queuelinkedlistwithlist.go, queue_test.go + +package queue + + +var ListQueue []interface{} + + +// EnQueue it will be added new value into our list +func EnQueue(n interface{}) { + ListQueue = append(ListQueue, n) +} + +// DeQueue it will be removed the first value that added into the list +func DeQueue() interface{} { + data := ListQueue[0] + ListQueue = ListQueue[1:] + return data +} + +// FrontQueue return the Front value +func FrontQueue() interface{} { + return ListQueue[0] +} + +// BackQueue return the Back value +func BackQueue() interface{} { + return ListQueue[len(ListQueue)-1] +} + +// LenQueue will return the length of the queue list +func LenQueue() int { + return len(ListQueue) +} + +// IsEmptyQueue check our list is empty or not +func IsEmptyQueue() bool { + return len(ListQueue) == 0 +} \ No newline at end of file diff --git a/data_structures/queue/queuelinkedlist.go b/data_structures/queue/queuelinkedlist.go new file mode 100644 index 000000000..c3935e33e --- /dev/null +++ b/data_structures/queue/queuelinkedlist.go @@ -0,0 +1,77 @@ +// Queue Linked-List +// description: based on `geeksforgeeks` description A Queue is a linear structure which follows a particular order in which the operations are performed. +// The order is First In First Out (FIFO). +// details: +// Queue Data Structure : https://www.geeksforgeeks.org/queue-data-structure/ +// Queue (abstract data type) : https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see queuearray.go, queuelinkedlistwithlist.go, queue_test.go + +package queue + +// Node will be store the value and the next node as well +type Node struct { + Data interface{} + Next *Node +} + +// Queue structure is tell us what our head is and what tail should be with length of the list +type Queue struct { + head *Node + tail *Node + length int +} + +// enqueue it will be added new value into queue +func (ll *Queue) enqueue(n interface{}) { + var newNode Node // create new Node + newNode.Data = n // set the data + + if ll.tail != nil{ + ll.tail.Next = &newNode + } + + ll.tail = &newNode + + if ll.head == nil{ + ll.head = &newNode + } + ll.length++ +} + +// dequeue it will be removed the first value into queue (First In First Out) +func (ll *Queue) dequeue() interface{} { + if ll.isEmpty(){ + return -1 // if is empty return -1 + } + data := ll.head.Data + + ll.head = ll.head.Next + + if ll.head == nil{ + ll.tail = nil + } + + ll.length-- + return data +} + +// isEmpty it will check our list is empty or not +func (ll *Queue) isEmpty() bool { + return ll.length == 0 +} + +// len is return the length of queue +func (ll *Queue) len() int { + return ll.length +} + +// frontQueue it will return the front data +func (ll *Queue) frontQueue() interface{} { + return ll.head.Data +} + +// backQueue it will return the back data +func (ll *Queue) backQueue() interface{} { + return ll.tail.Data +} diff --git a/data_structures/queue/queuelinklistwithlist.go b/data_structures/queue/queuelinklistwithlist.go new file mode 100644 index 000000000..3a0c9cb64 --- /dev/null +++ b/data_structures/queue/queuelinklistwithlist.go @@ -0,0 +1,73 @@ +// Queue Linked-List with standard library (Container/List) +// description: based on `geeksforgeeks` description A Queue is a linear structure which follows a particular order in which the operations are performed. +// The order is First In First Out (FIFO). +// details: +// Queue Data Structure : https://www.geeksforgeeks.org/queue-data-structure/ +// Queue (abstract data type) : https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see queuearray.go, queuelinkedlist.go, queue_test.go + +package queue + + +// container/list: is used as linked-list +// fmt: used to return fmt.Errorf for the error part +import ( + "container/list" + "fmt" +) + +// LQueue will be store the value into the list +type LQueue struct { + queue *list.List +} + +// Enqueue will be added new value +func (lq *LQueue) Enqueue(value interface{}) { + lq.queue.PushBack(value) +} + + +// Dequeue will be removed the first value that input (First In First Out - FIFO) +func (lq *LQueue) Dequeue() error { + + if !lq.Empty() { + element := lq.queue.Front() + lq.queue.Remove(element) + + return nil + } + + return fmt.Errorf("dequeue is empty we got an error") +} + +// Front it will return the front value +func (lq *LQueue) Front() (interface{}, error) { + if !lq.Empty() { + val := lq.queue.Front().Value + return val, nil + } + + return "", fmt.Errorf("error queue is empty") +} + +// Back it will return the back value +func (lq *LQueue) Back() (interface{}, error) { + if !lq.Empty() { + val := lq.queue.Back().Value + return val, nil + } + + return "", fmt.Errorf("error queue is empty") +} + +// Len it will return the length of list +func (lq *LQueue) Len() int { + return lq.queue.Len() +} + +// Empty is check our list is empty or not +func (lq *LQueue) Empty() bool { + return lq.queue.Len() == 0 +} + diff --git a/data_structures/stack/stack_test.go b/data_structures/stack/stack_test.go new file mode 100644 index 000000000..d1e69750e --- /dev/null +++ b/data_structures/stack/stack_test.go @@ -0,0 +1,191 @@ +// Stack Test +// description: based on `geeksforgeeks` description Stack is a linear data structure which follows a particular order in which the operations are performed. +// The order may be LIFO(Last In First Out) or FILO(First In Last Out). +// details: +// Stack Data Structure : https://www.geeksforgeeks.org/stack-data-structure-introduction-program/ +// Stack (abstract data type) : https://en.wikipedia.org/wiki/Stack_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see stackarray.go, stacklinkedlist.go, stacklinkedlistwithlist.go + +package stack + +import ( + "container/list" + "reflect" + "testing" +) + +// TestStackLinkedList for testing Stack with LinkedList +func TestStackLinkedList(t *testing.T) { + var newStack Stack + + newStack.push(1) + newStack.push(2) + + t.Run("Stack Push", func(t *testing.T) { + result := newStack.show() + expected := []interface{}{2,1} + for x := range result{ + if result[x] != expected[x]{ + t.Errorf("Stack Push is not work, got %v but expected %v", result, expected) + } + } + }) + + + t.Run("Stack isEmpty", func(t *testing.T) { + if newStack.isEmpty(){ + t.Error("Stack isEmpty is returned true but expected false", newStack.isEmpty()) + } + + }) + + + t.Run("Stack Length", func(t *testing.T) { + if newStack.len() != 2{ + t.Error("Stack Length should be 2 but got", newStack.len()) + } + }) + + newStack.pop() + pop := newStack.pop() + + t.Run("Stack Pop", func(t *testing.T) { + if pop != 1{ + t.Error("Stack Pop should return 1 but is returned", pop) + } + + }) + + newStack.push(52) + newStack.push(23) + newStack.push(99) + t.Run("Stack Peak", func(t *testing.T) { + if newStack.peak() != 99{ + t.Error("Stack Peak should return 99 but got ", newStack.peak()) + } + }) +} + + +// TestStackArray for testing Stack with Array +func TestStackArray(t *testing.T) { + t.Run("Stack With Array", func(t *testing.T) { + + stackPush(2) + stackPush(3) + + t.Run("Stack Push", func(t *testing.T) { + if !reflect.DeepEqual([]interface{}{3,2}, stackArray){ + t.Errorf("Stack Push is not work we expected %v but got %v", []interface{}{3,2}, stackArray) + } + }) + + pop := stackPop() + + t.Run("Stack Pop", func(t *testing.T) { + + if stackLength() == 2 && pop != 3 { + t.Errorf("Stack Pop is not work we expected %v but got %v", 3, pop) + } + }) + + stackPush(2) + stackPush(83) + + t.Run("Stack Peak", func(t *testing.T) { + + if stackPeak() != 83 { + t.Errorf("Stack Peak is not work we expected %v but got %v", 83, stackPeak()) + } + }) + + t.Run("Stack Length", func(t *testing.T) { + if stackLength() != 3{ + t.Errorf("Stack Length is not work we expected %v but got %v", 3, stackLength()) + } + }) + + t.Run("Stack Empty", func(t *testing.T) { + if stackEmpty() == true{ + t.Errorf("Stack Emtpy is not work we expected %v but got %v", false, stackEmpty()) + } + + stackPop() + stackPop() + stackPop() + + if stackEmpty() == false{ + t.Errorf("Stack Emtpy is not work we expected %v but got %v", true, stackEmpty()) + } + }) + }) +} + + + + + + +// TestStackLinkedListWithList for testing Stack with Container/List Library (STL) +func TestStackLinkedListWithList(t *testing.T) { + stackList := &SList{ + stack: list.New(), + } + + + t.Run("Stack Push", func(t *testing.T) { + + stackList.Push(2) + stackList.Push(3) + + if stackList.Length() != 2{ + t.Errorf("Stack Push is not work we expected %v but got %v", 2, stackList.Length()) + } + }) + + + t.Run("Stack Pop", func(t *testing.T) { + pop, _ := stackList.Pop() + + if stackList.Length() == 1 && pop != 3 { + t.Errorf("Stack Pop is not work we expected %v but got %v", 3, pop) + } + }) + + + + t.Run("Stack Peak", func(t *testing.T) { + + stackList.Push(2) + stackList.Push(83) + peak, _ := stackList.Peak() + if peak != 83 { + t.Errorf("Stack Peak is not work we expected %v but got %v", 83, peak) + } + }) + + t.Run("Stack Length", func(t *testing.T) { + if stackList.Length() != 3{ + t.Errorf("Stack Length is not work we expected %v but got %v", 3, stackList.Length()) + } + }) + + t.Run("Stack Empty", func(t *testing.T) { + if stackList.Empty() == true{ + t.Errorf("Stack Emtpy is not work we expected %v but got %v", false, stackList.Empty()) + } + + d1 , err := stackList.Pop() + d2 , _ := stackList.Pop() + d3 , _ := stackList.Pop() + + if err != nil{ + t.Errorf("got an unexpected error %v, pop1: %v, pop2: %v, pop3: %v", err, d1, d2, d3) + } + + if stackList.Empty() == false{ + t.Errorf("Stack Emtpy is not work we expected %v but got %v", true, stackList.Empty()) + } + }) +} \ No newline at end of file diff --git a/data_structures/stack/stackarray.go b/data_structures/stack/stackarray.go new file mode 100644 index 000000000..300698d4b --- /dev/null +++ b/data_structures/stack/stackarray.go @@ -0,0 +1,39 @@ +// Stack Array +// description: based on `geeksforgeeks` description Stack is a linear data structure which follows a particular order in which the operations are performed. +// The order may be LIFO(Last In First Out) or FILO(First In Last Out). +// details: +// Stack Data Structure : https://www.geeksforgeeks.org/stack-data-structure-introduction-program/ +// Stack (abstract data type) : https://en.wikipedia.org/wiki/Stack_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see stacklinkedlist.go, stacklinkedlistwithlist.go, stack_test.go + +package stack + +var stackArray []interface{} + +// stackPush push to first index of array +func stackPush(n interface{}) { + stackArray = append([]interface{}{n}, stackArray...) +} + +// stackLength return length of array +func stackLength() int { + return len(stackArray) +} + +// stackPeak return last input of array +func stackPeak() interface{} { + return stackArray[0] +} + +// stackEmpty check array is empty or not +func stackEmpty() bool { + return len(stackArray) == 0 +} + +// stackPop return last input and remove it in array +func stackPop() interface{} { + pop := stackArray[0] + stackArray = stackArray[1:] + return pop +} \ No newline at end of file diff --git a/data_structures/stack/stacklinkedlist.go b/data_structures/stack/stacklinkedlist.go new file mode 100644 index 000000000..42a9c611d --- /dev/null +++ b/data_structures/stack/stacklinkedlist.go @@ -0,0 +1,73 @@ +// Stack Linked-List +// description: based on `geeksforgeeks` description Stack is a linear data structure which follows a particular order in which the operations are performed. +// The order may be LIFO(Last In First Out) or FILO(First In Last Out). +// details: +// Stack Data Structure : https://www.geeksforgeeks.org/stack-data-structure-introduction-program/ +// Stack (abstract data type) : https://en.wikipedia.org/wiki/Stack_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see stacklinkedlistwithlist.go, stackarray.go, stack_test.go + +package stack + +// Node structure +type Node struct { + Val interface{} + Next *Node +} + +// Stack has jost top of node and with length +type Stack struct { + top *Node + length int +} + +// push add value to last index +func (ll *Stack) push(n interface{}) { + newStack := &Node{} // new node + + newStack.Val = n + newStack.Next = ll.top + + ll.top = newStack + ll.length++ +} + +// pop remove last item as first output +func (ll *Stack) pop() interface{} { + result := ll.top.Val + if ll.top.Next == nil { + ll.top = nil + } else { + ll.top.Val, ll.top.Next = ll.top.Next.Val, ll.top.Next.Next + } + + ll.length-- + return result +} + +// isEmpty to check our array is empty or not +func (ll *Stack) isEmpty() bool { + return ll.length == 0 +} + + +// len use to return length of our stack +func (ll *Stack) len() int { + return ll.length +} + +// peak return last input value +func (ll *Stack) peak() interface{} { + return ll.top.Val +} + +// show all value as an interface array +func (ll *Stack) show() (in []interface{}) { + current := ll.top + + for current != nil { + in = append(in, current.Val) + current = current.Next + } + return +} diff --git a/data_structures/stack/stacklinkedlistwithlist.go b/data_structures/stack/stacklinkedlistwithlist.go new file mode 100644 index 000000000..599b02bf9 --- /dev/null +++ b/data_structures/stack/stacklinkedlistwithlist.go @@ -0,0 +1,60 @@ +// Stack Linked-List with standard library (Container/List) +// description: based on `geeksforgeeks` description Stack is a linear data structure which follows a particular order in which the operations are performed. +// The order may be LIFO(Last In First Out) or FILO(First In Last Out). +// details: +// Stack Data Structure : https://www.geeksforgeeks.org/stack-data-structure-introduction-program/ +// Stack (abstract data type) : https://en.wikipedia.org/wiki/Stack_(abstract_data_type) +// author [Milad](https://github.com/miraddo) +// see stacklinkedlist.go, stackarray.go, stack_test.go + +package stack + +import ( + "container/list" + "fmt" +) + +// SList is our struct that point to stack with container/list.List library +type SList struct { + stack *list.List +} + +// Push add a value into our stack +func (sl *SList) Push(val interface{}) { + sl.stack.PushFront(val) +} + +// Peak is return last value that insert into our stack +func (sl *SList) Peak() (interface{}, error) { + if !sl.Empty() { + element := sl.stack.Front() + return element.Value, nil + } + return "", fmt.Errorf("stack list is empty") +} + +// Pop is return last value that insert into our stack +//also it will remove it in our stack +func (sl *SList) Pop() (interface{}, error) { + if !sl.Empty() { + // get last element that insert into stack + element := sl.stack.Front() + // remove element in stack + sl.stack.Remove(element) + // return element value + return element.Value, nil + } + return "", fmt.Errorf("stack list is empty") +} + +// Length return length of our stack +func (sl *SList) Length() int { + return sl.stack.Len() +} + +// Empty check our stack has value or not +func (sl *SList) Empty() bool { + // check our stack is empty or not + // if is 0 it means our stack is empty otherwise is not empty + return sl.stack.Len() == 0 +} \ No newline at end of file From 22c2739316fd67259049d56ed26f131e1b511c62 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Sat, 28 Aug 2021 18:46:56 +0530 Subject: [PATCH 208/488] Fix failing tests (#324) Co-authored-by: Andrii Siriak --- .github/workflows/golang_lint_and_test.yml | 2 +- README.md | 2 - ciphers/rsa_cipher/rsacipher.go | 2 - ciphers/rsa_cipher/rsacipher_test.go | 2 +- ciphers/rsa_cipher_big/rsacipherbig.go | 133 --------- ciphers/rsa_cipher_big/rsacipherbig_test.go | 62 ---- data_structures/binary_tree/binarytree.go | 1 - data_structures/binary_tree/btree.go | 3 +- data_structures/dynamic_array/dynamicarray.go | 1 - .../dynamic_array/dynamicarray_test.go | 22 +- .../doubly_linkedlist/doublylinkedlist.go | 2 +- math/permutation/heaps.go | 12 +- math/permutation/heaps_test.go | 12 +- searches/linear_search/linearsearch_test.go | 1 - sorts/quicksort.go | 2 +- strings/multiple_string_matching/sbom/sbom.go | 280 ------------------ .../sbom/sbom_test.go | 85 ------ 17 files changed, 27 insertions(+), 597 deletions(-) delete mode 100644 ciphers/rsa_cipher_big/rsacipherbig.go delete mode 100644 ciphers/rsa_cipher_big/rsacipherbig_test.go delete mode 100644 strings/multiple_string_matching/sbom/sbom.go delete mode 100644 strings/multiple_string_matching/sbom/sbom_test.go diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index 63bafe8c5..89c4193a2 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -16,4 +16,4 @@ jobs: # specified without patch version: we always use the latest patch version. # https://github.com/golangci/golangci-lint/releases version: v1.39 - - run: go test $(go list ./... | grep -v /sbom | grep -v /rsa_cipher) + - run: go test ./... diff --git a/README.md b/README.md index 605f27816..06abef133 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,6 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Polybius](./ciphers/polybius/) * [Rot13](./ciphers/rot13/) * [Rsa Cipher](./ciphers/rsa_cipher/) -* [Rsa Cipher Big](./ciphers/rsa_cipher_big/) * [Xor Cipher](./ciphers/xor_cipher/) ## Conversions @@ -104,7 +103,6 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * Multiple String Matching * [Advanced Aho Corasick](./strings/multiple_string_matching/advanced_aho_corasick/) * [Aho Corasick](./strings/multiple_string_matching/aho_corasick/) - * [Sbom](./strings/multiple_string_matching/sbom/) * [Naive String Search](./strings/naive_string_search/) * Single String Matching * [Bom](./strings/single_string_matching/bom/) diff --git a/ciphers/rsa_cipher/rsacipher.go b/ciphers/rsa_cipher/rsacipher.go index 5752dfef3..145ca3e78 100644 --- a/ciphers/rsa_cipher/rsacipher.go +++ b/ciphers/rsa_cipher/rsacipher.go @@ -1,8 +1,6 @@ package rsacipher import ( - //"math/big" - "fmt" "math" "math/rand" diff --git a/ciphers/rsa_cipher/rsacipher_test.go b/ciphers/rsa_cipher/rsacipher_test.go index e063276e8..3f98a495f 100644 --- a/ciphers/rsa_cipher/rsacipher_test.go +++ b/ciphers/rsa_cipher/rsacipher_test.go @@ -74,7 +74,7 @@ func TestRSACipher(t *testing.T) { if actual := decrypted; !reflect.DeepEqual(actual, expected) { t.Logf("FAIL: %s", test.description) - t.Fatalf("Expecting %v, actual %v", expected, actual) + t.Fatalf("Expecting %v, actual %v", expected, ToRune(actual)) } }) } diff --git a/ciphers/rsa_cipher_big/rsacipherbig.go b/ciphers/rsa_cipher_big/rsacipherbig.go deleted file mode 100644 index 3056ad3b2..000000000 --- a/ciphers/rsa_cipher_big/rsacipherbig.go +++ /dev/null @@ -1,133 +0,0 @@ -package bigrsacipher - -import ( - "fmt" - "math/big" - "strconv" - "strings" -) - -/* -Care has been taken to uses cryptographic secure functions -The primes numbers are 1024 bits which is as secure as u can get really -crypto/rand library has been imported as crypto and not rand -This import style will make it easier to spot all the cryptographic secure functions -*/ -// func main() { -// p, _ := crypto.Prime(crypto.Reader, 1024) -// q, _ := crypto.Prime(crypto.Reader, 1024) -// if !(primeCheck(p) || primeCheck(q)) { -// //they are always prime, no worries -// fmt.Println("These numbers ain't prime") -// } -// n := new(big.Int).Mul(p, q) - -// one := big.NewInt(1) - -// delta := lcmBig(p.Sub(p, one), q.Sub(q, one)) - -// e, _ := crypto.Prime(crypto.Reader, delta.BitLen()) -// d := big.NewInt(0) -// d.ModInverse(e, delta) - -// cleartext := "Black Lives Matter, all lives can't matter until Black lives matter" -// runes := []rune(cleartext) -// ASCIIs := toASCII(runes) -// stringEncoded := stringEncode(ASCIIs) -// bigNum, _ := new(big.Int).SetString(stringEncoded, 0) -// /* -// TODO: check that bigNum is not larger than N if larger break -// into two or more strings and encrypt separately -// */ -// fmt.Printf("Message to be encrypted: %v \n", cleartext) -// fmt.Printf("ASCII encoded: %v\n", bigNum) -// encrypted := encryptBig(bigNum, e, n) -// fmt.Printf("ciphertext: %v \n", encrypted) -// decrypted := decryptBig(encrypted, d, n) -// fmt.Printf("Decrypted but still ASCII encoded: %v \n", decrypted) -// decryptASCIIs := stringDecode(decrypted) -// fmt.Printf("Plaintext (original message) :%v", toRune(decryptASCIIs)) -// } - -// EncryptBig Main encryption function -func EncryptBig(num *big.Int, privateExponent *big.Int, modulus *big.Int) *big.Int { - //encrypts by modular exponentiation - encrypted := new(big.Int).Exp(num, privateExponent, modulus) - return encrypted -} - -// DecryptBig Main decryption function -func DecryptBig(num *big.Int, publicExponent *big.Int, modulus *big.Int) *big.Int { - //decrypts by modular exponentiation - decrypted := new(big.Int).Exp(num, publicExponent, modulus) - return decrypted -} - -func lcmBig(x *big.Int, y *big.Int) *big.Int { - //an lcm implementation for big.Int numbers - gcd := new(big.Int).GCD(nil, nil, x, y) - temp := new(big.Int).Mul(x, y) - lcm := new(big.Int).Div(temp, gcd) - return lcm -} - -// PrimeCheck primality test -func PrimeCheck(prime *big.Int) bool { - //primality test - return prime.ProbablyPrime(256) -} - -func toASCII(slice []rune) []int { - //runs in O(n) where n = len(slice) - var converted []int - for _, v := range slice { - converted = append(converted, int(v)) - } - return converted -} - -// ToRune convert a string to a rune -func ToRune(slice []int) string { - //runs in O(n) where n = len(slice) - // var str string - var str strings.Builder - for _, v := range slice { - str.WriteString(fmt.Sprint(v)) - } - return str.String() -} - -func stringEncode(slice []int) string { - //encodes the ASCII to a string - var out []string - for _, v := range slice { - if v < 100 { - out = append(out, "0"+strconv.Itoa(v)) - continue - } - out = append(out, strconv.Itoa(v)) - } - var str string - for _, v := range out { - str += v - } - //strips leading 0 if present to avoid conversion errors - if str[0] == '0' { - str = str[1:] - } - return str -} - -func stringDecode(decryptedBig *big.Int) []int { - //decodes the number to string then ASCII values - str := decryptedBig.String() - if len(str)%3 != 0 { - str = "0" + str - } - var ASCII []int - for i := 0; i < len(str); i += 3 { - temp, _ := strconv.Atoi(str[i : i+3]) - ASCII = append(ASCII, temp) - } - return ASCII -} diff --git a/ciphers/rsa_cipher_big/rsacipherbig_test.go b/ciphers/rsa_cipher_big/rsacipherbig_test.go deleted file mode 100644 index 1efcd919d..000000000 --- a/ciphers/rsa_cipher_big/rsacipherbig_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package bigrsacipher - -import ( - crypto "crypto/rand" - "math/big" - "testing" -) - -var rsaTestData = []struct { - description string - input string -}{ - { - "Encrypt letter 'a'", - "a", - }, - { - "Encrypt 'hello world'", - "hello world", - }, - { - "Encrypt full sentence", - "the quick brown fox jumps over the lazy dog.", - }, - { - "Encrypt full sentence from rsacipherbig.go main function", - "Black Lives Matter, all lives can't matter until Black lives matter", - }, -} - -func TestRSABigCipher(t *testing.T) { - p, _ := crypto.Prime(crypto.Reader, 1024) - q, _ := crypto.Prime(crypto.Reader, 1024) - n := new(big.Int).Mul(p, q) - - one := big.NewInt(1) - - delta := lcmBig(p.Sub(p, one), q.Sub(q, one)) - - e, _ := crypto.Prime(crypto.Reader, delta.BitLen()) - d := big.NewInt(0) - d.ModInverse(e, delta) - - for _, test := range rsaTestData { - t.Run(test.description, func(t *testing.T) { - - runes := []rune(test.input) - ASCIIs := toASCII(runes) - stringEncoded := stringEncode(ASCIIs) - bigNum, _ := new(big.Int).SetString(stringEncoded, 0) - - encrypted := EncryptBig(bigNum, e, n) - decrypted := DecryptBig(encrypted, d, n) - decryptASCIIs := stringDecode(decrypted) - - if actual := ToRune(decryptASCIIs); actual != test.input { - t.Logf("FAIL: %s", test.description) - t.Fatalf("Expecting %s, actual %s", test.input, actual) - } - }) - } -} diff --git a/data_structures/binary_tree/binarytree.go b/data_structures/binary_tree/binarytree.go index 4d4529994..003b89ba7 100644 --- a/data_structures/binary_tree/binarytree.go +++ b/data_structures/binary_tree/binarytree.go @@ -1,7 +1,6 @@ // Package binarytree basic binary tree and related operations package binarytree - /* func main() { t := btree{nil} diff --git a/data_structures/binary_tree/btree.go b/data_structures/binary_tree/btree.go index 3ccd3b484..51c2aec5e 100644 --- a/data_structures/binary_tree/btree.go +++ b/data_structures/binary_tree/btree.go @@ -116,11 +116,10 @@ func LevelOrder(root *Node) { } } - // Max Function that returns max of two numbers - possibly already declared. func Max(a, b int) int { if a > b { return a } return b -} \ No newline at end of file +} diff --git a/data_structures/dynamic_array/dynamicarray.go b/data_structures/dynamic_array/dynamicarray.go index 1d9a9763b..0d09bb8a3 100644 --- a/data_structures/dynamic_array/dynamicarray.go +++ b/data_structures/dynamic_array/dynamicarray.go @@ -10,7 +10,6 @@ package dynamicarray - // errors: used to handle CheckRangeFromIndex function with a reasonable error value import ( "errors" diff --git a/data_structures/dynamic_array/dynamicarray_test.go b/data_structures/dynamic_array/dynamicarray_test.go index f0b7d5e0a..adb1cd81a 100644 --- a/data_structures/dynamic_array/dynamicarray_test.go +++ b/data_structures/dynamic_array/dynamicarray_test.go @@ -1,6 +1,5 @@ package dynamicarray - // reflect: used for check equal values import ( "reflect" @@ -13,7 +12,7 @@ func TestDynamicArray(t *testing.T) { // check numbers is empty or nut t.Run("Check Empty Dynamic Array", func(t *testing.T) { - if numbers.IsEmpty() != true{ + if numbers.IsEmpty() != true { t.Errorf("Expected be true but got %v", numbers.IsEmpty()) } }) @@ -26,7 +25,7 @@ func TestDynamicArray(t *testing.T) { // check numbers added to our dynamic array t.Run("Add Element into Dynamic Array", func(t *testing.T) { - if numbers.IsEmpty() != false{ + if numbers.IsEmpty() != false { t.Errorf("Expected be false but got %v", numbers.IsEmpty()) } var res []interface{} @@ -43,7 +42,7 @@ func TestDynamicArray(t *testing.T) { // Remove an Element inside the dynamic array with the index of array t.Run("Remove in Dynamic Array", func(t *testing.T) { - if numbers.IsEmpty() != false{ + if numbers.IsEmpty() != false { t.Errorf("Expected be false but got %v", numbers.IsEmpty()) } var res []interface{} @@ -55,7 +54,7 @@ func TestDynamicArray(t *testing.T) { // remove the element by the index err := numbers.Remove(1) - if err != nil{ + if err != nil { t.Errorf("Expected be [10, 30, 40, 50] but got an Error %v", err) } @@ -66,12 +65,12 @@ func TestDynamicArray(t *testing.T) { // get one element by the index of the dynamic array t.Run("Get in Dynamic Array", func(t *testing.T) { - if numbers.IsEmpty() != false{ + if numbers.IsEmpty() != false { t.Errorf("Expected be false but got %v", numbers.IsEmpty()) } // return one element with the index - getOne,_ := numbers.Get(2) + getOne, _ := numbers.Get(2) if getOne != 40 { t.Errorf("Expected be 40 but got %v", getOne) @@ -79,23 +78,22 @@ func TestDynamicArray(t *testing.T) { }) - // Put to add a value to specific index of Dynamic Array t.Run("Put to Dynamic Array", func(t *testing.T) { - if numbers.IsEmpty() != false{ + if numbers.IsEmpty() != false { t.Errorf("Expected be false but got %v", numbers.IsEmpty()) } // change value of specific index err := numbers.Put(0, 100) - if err != nil{ + if err != nil { t.Errorf("Expected be [10, 30, 40, 50] but got an Error %v", err) } - getOne,_ := numbers.Get(0) + getOne, _ := numbers.Get(0) if getOne != 100 { t.Errorf("Expected be 100 but got %v", getOne) } }) -} \ No newline at end of file +} diff --git a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go b/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go index e6754e1e9..7df7abcef 100644 --- a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go +++ b/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go @@ -29,7 +29,7 @@ func (ll *DoubleLinkedList) AddAtBeg(val int) { n := NewNode(val) n.next = ll.head - if ll.head != nil{ + if ll.head != nil { ll.head.prev = n } diff --git a/math/permutation/heaps.go b/math/permutation/heaps.go index 81b0a15d6..f3d79f464 100644 --- a/math/permutation/heaps.go +++ b/math/permutation/heaps.go @@ -17,15 +17,15 @@ func Heaps(out chan []string, n int) { permutations = append(permutations, strings.Join(elements, "")) } else { for i := 0; i < n; i++ { - recursiveGenerate(previousIteration, n - 1, elements) - if n % 2 == 1 { + recursiveGenerate(previousIteration, n-1, elements) + if n%2 == 1 { tmp := elements[i] - elements[i] = elements[n - 1] - elements[n - 1] = tmp + elements[i] = elements[n-1] + elements[n-1] = tmp } else { tmp := elements[0] - elements[0] = elements[n - 1] - elements[n - 1] = tmp + elements[0] = elements[n-1] + elements[n-1] = tmp } } } diff --git a/math/permutation/heaps_test.go b/math/permutation/heaps_test.go index d65069d1f..224ea15b2 100644 --- a/math/permutation/heaps_test.go +++ b/math/permutation/heaps_test.go @@ -7,8 +7,8 @@ import ( ) func TestHeaps(t *testing.T) { - t.Run("Should generate permutations for various size sets", func (t *testing.T) { - expectedValues := [][]string { + t.Run("Should generate permutations for various size sets", func(t *testing.T) { + expectedValues := [][]string{ {"1"}, {"12", "21"}, {"123", "213", "321", "231", "312", "132"}, @@ -20,11 +20,11 @@ func TestHeaps(t *testing.T) { for i := 1; i <= 5; i++ { go Heaps(permutationsCh, i) - value = <- permutationsCh + value = <-permutationsCh sort.Strings(value) - sort.Strings(expectedValues[i - 1]) - if !reflect.DeepEqual(value, expectedValues[i - 1]) { - t.Errorf("Permutation set is incorrect for element size of %v. Expected (%v) and received (%v)", i, expectedValues[i - 1], value) + sort.Strings(expectedValues[i-1]) + if !reflect.DeepEqual(value, expectedValues[i-1]) { + t.Errorf("Permutation set is incorrect for element size of %v. Expected (%v) and received (%v)", i, expectedValues[i-1], value) } } }) diff --git a/searches/linear_search/linearsearch_test.go b/searches/linear_search/linearsearch_test.go index d5db0c416..121dcd4a6 100644 --- a/searches/linear_search/linearsearch_test.go +++ b/searches/linear_search/linearsearch_test.go @@ -23,7 +23,6 @@ var searchTests = []searchTest{ {[]int{}, 2, -1, "Empty"}, } - func TestLinearSearch(t *testing.T) { for _, test := range searchTests { actual := LinearSearch(test.data, test.key) diff --git a/sorts/quicksort.go b/sorts/quicksort.go index 1ed1b3bc1..6cb73e5b5 100644 --- a/sorts/quicksort.go +++ b/sorts/quicksort.go @@ -1,7 +1,7 @@ //Package sorts a package for demonstrating sorting algorithms in Go package sorts -func QuickSort(array []int)[]int { +func QuickSort(array []int) []int { if len(array) <= 1 { return array } diff --git a/strings/multiple_string_matching/sbom/sbom.go b/strings/multiple_string_matching/sbom/sbom.go deleted file mode 100644 index 1c0c8904f..000000000 --- a/strings/multiple_string_matching/sbom/sbom.go +++ /dev/null @@ -1,280 +0,0 @@ -package sbom - -import ( - "fmt" - "strings" - "time" -) - -type Result struct { - occurrences map[string][]int -} - -// Implementation of Set Backward Oracle Matching algorithm (Factor based). -// Searches for a set of strings (in 'patterns.txt') in text.txt. -// func main() { -// patFile, err := ioutil.ReadFile("../patterns.txt") -// if err != nil { -// log.Fatal(err) -// } -// textFile, err := ioutil.ReadFile("../text.txt") -// if err != nil { -// log.Fatal(err) -// } -// patterns := strings.Split(string(patFile), " ") -// fmt.Printf("\nRunning: Set Backward Oracle Matching algorithm.\n\n") -// if debugMode { -// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) -// } -// for i := 0; i < len(patterns); i++ { -// if len(patterns[i]) > len(textFile) { -// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) -// } -// if debugMode { -// fmt.Printf("%q ", patterns[i]) -// } -// } -// if debugMode { -// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) -// } -// r := sbom(string(textFile), patterns) -// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) -// for i := range value { -// fmt.Printf("%d", value[i]) -// if i != len(value)-1 { -// fmt.Printf(", ") -// } -// } -// fmt.Printf(".") -// } - -// } - -// Sbom Function sbom performing the Set Backward Oracle Matching algorithm. -// Finds and prints occurrences of each pattern. -func Sbom(t string, p []string) Result { - startTime := time.Now() - occurrences := make(map[int][]int) - lmin := computeMinLength(p) - or, f := buildOracleMultiple(reverseAll(trimToLength(p, lmin))) - pos := 0 - for pos <= len(t)-lmin { - current := 0 - j := lmin - for j >= 1 && stateExists(current, or) { - current = getTransition(current, t[pos+j-1], or) - j-- - } - word := getWord(pos, pos+lmin-1, t) - if stateExists(current, or) && j == 0 && strings.HasPrefix(word, getCommonPrefix(p, f[current], lmin)) { //check for prefix match - for i := range f[current] { - if p[f[current][i]] == getWord(pos, pos-1+len(p[f[current][i]]), t) { //check for word match - newOccurrences := intArrayCapUp(occurrences[f[current][i]]) - occurrences[f[current][i]] = newOccurrences - occurrences[f[current][i]][len(newOccurrences)-1] = pos - } - } - j = 0 - } - pos = pos + j + 1 - } - elapsed := time.Since(startTime) - fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - var resultOccurrences = make(map[string][]int) - for key, value := range occurrences { - resultOccurrences[p[key]] = value - } - - return Result{ - resultOccurrences, - } -} - -// Function that builds factor oracle. -func buildOracleMultiple(p []string) (orToReturn map[int]map[uint8]int, f map[int][]int) { - orTrie, stateIsTerminal, f := constructTrie(p) - s := make([]int, len(stateIsTerminal)) //supply function - i := 0 //root of trie - orToReturn = orTrie - s[i] = -1 - for current := 1; current < len(stateIsTerminal); current++ { - o, parent := getParent(current, orTrie) - down := s[parent] - for stateExists(down, orToReturn) && getTransition(down, o, orToReturn) == -1 { - createTransition(down, o, current, orToReturn) - down = s[down] - } - if stateExists(down, orToReturn) { - s[current] = getTransition(down, o, orToReturn) - } else { - s[current] = i - } - } - return orToReturn, f -} - -// Function that constructs Trie as an automaton for a set of reversed & trimmed strings. -func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { - trie = make(map[int]map[uint8]int) - stateIsTerminal = make([]bool, 1) - f = make(map[int][]int) - state := 1 - createNewState(0, trie) - for i := 0; i < len(p); i++ { - current := 0 - j := 0 - for j < len(p[i]) && getTransition(current, p[i][j], trie) != -1 { - current = getTransition(current, p[i][j], trie) - j++ - } - for j < len(p[i]) { - stateIsTerminal = boolArrayCapUp(stateIsTerminal) - createNewState(state, trie) - stateIsTerminal[state] = false - createTransition(current, p[i][j], state, trie) - current = state - j++ - state++ - } - if stateIsTerminal[current] { - newArray := intArrayCapUp(f[current]) - newArray[len(newArray)-1] = i - f[current] = newArray //F(Current) <- F(Current) union {i} - } else { - stateIsTerminal[current] = true - f[current] = []int{i} //F(Current) <- {i} - } - } - return trie, stateIsTerminal, f -} - -// Dynamically increases an array size of int's by 1. -func intArrayCapUp(old []int) (new []int) { - new = make([]int, cap(old)+1) - copy(new, old) //copy(dst,src) - // old = new - return new -} - -// Dynamically increases an array size of bool's by 1. -func boolArrayCapUp(old []bool) (new []bool) { - new = make([]bool, cap(old)+1) - copy(new, old) - // old = new - return new -} - -// Function that takes an array of strings and reverses it. -func reverseAll(s []string) (reversed []string) { - reversed = make([]string, len(s)) - for i := 0; i < len(s); i++ { - reversed[i] = reverse(s[i]) - } - return reversed -} - -// Function that takes a single string and reverses it. -func reverse(s string) string { - l := len(s) - m := make([]rune, l) - for _, c := range s { - l-- - m[l] = c - } - return string(m) -} - -// Returns a prefix size 'lmin' for one string 'p' of first index found in 'f'. -// It is not needed to compare all the strings from 'p' indexed in 'f', -// thanks to the konwledge of 'lmin'. -func getCommonPrefix(p []string, f []int, lmin int) string { - r := []rune(p[f[0]]) - newR := make([]rune, lmin) - for j := 0; j < lmin; j++ { - newR[j] = r[j] - } - return string(newR) -} - -// Function that takes a set of strings 'p' and their wanted 'length' -// and then trims each string in that set to have desired 'length'. -func trimToLength(p []string, length int) (trimmedP []string) { - trimmedP = make([]string, len(p)) - for i := range p { - r := []rune(p[i]) - newR := make([]rune, length) - for j := 0; j < length; j++ { - newR[j] = r[j] - } - trimmedP[i] = string(newR) - } - return trimmedP -} - -// Function that returns word found in text 't' at position range 'begin' to 'end'. -func getWord(begin, end int, t string) string { - for end >= len(t) { - return "" - } - d := make([]uint8, end-begin+1) - for j, i := 0, begin; i <= end; i, j = i+1, j+1 { - d[j] = t[i] - } - return string(d) -} - -// Function that computes minimal length string in a set of strings. -func computeMinLength(p []string) (lmin int) { - lmin = len(p[0]) - for i := 1; i < len(p); i++ { - if len(p[i]) < lmin { - lmin = len(p[i]) - } - } - return lmin -} - -// Function that finds the first previous state of a state and returns it. -// Used for trie where there is only one parent. -func getParent(state int, at map[int]map[uint8]int) (uint8, int) { - for beginState, transitions := range at { - for c, endState := range transitions { - if endState == state { - return c, beginState - } - } - } - return 0, 0 //unreachable -} - -// Automaton function for creating a new state 'state'. -func createNewState(state int, at map[int]map[uint8]int) { - at[state] = make(map[uint8]int) -} - -// Creates a transition for function σ(state,letter) = end. -func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { - at[fromState][overChar] = toState -} - -// Returns ending state for transition σ(fromState,overChar), '-1' if there is none. -func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { - if !stateExists(fromState, at) { - return -1 - } - toState, ok := at[fromState][overChar] - if ok { - return -1 - } - return toState -} - -// Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. -func stateExists(state int, at map[int]map[uint8]int) bool { - _, ok := at[state] - if !ok || state == -1 || at[state] == nil { - return false - } - return true -} diff --git a/strings/multiple_string_matching/sbom/sbom_test.go b/strings/multiple_string_matching/sbom/sbom_test.go deleted file mode 100644 index 786c1c16a..000000000 --- a/strings/multiple_string_matching/sbom/sbom_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package sbom - -import ( - "fmt" - "reflect" - "strings" - "testing" -) - -var testCases = []struct { - name string - words []string - text string - expected Result -}{ - - { - "String comparison on all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conferenceannounce_announce_annually_announce", - Result{ - map[string][]int{ - "annual": {4, 39}, - "announce": {21, 30, 48}, - "annually": {39}, - }, - }, - }, - { - "String comparison on not all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conference_announce", - Result{ - map[string][]int{ - "annual": {4}, - "announce": {22}, - }, - }, - }, - { - "String comparison on not all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conference_announce", - Result{ - map[string][]int{ - "annual": {4}, - "announce": {22}, - }, - }, - }, -} - -func TestAhoCorasick(t *testing.T) { - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - actual := Sbom(tc.text, tc.words) - if !reflect.DeepEqual(actual, tc.expected) { - actualString := convertToString(actual) - expectedString := convertToString(tc.expected) - t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", - tc.words, tc.text, actualString, expectedString) - } - }) - } -} - -func convertToString(res Result) string { - // var r string - var r strings.Builder - for key, val := range res.occurrences { - // r = r + fmt.Sprintf("Word: '%s' at positions: ", key) - r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) - for i := range val { - // r = r + fmt.Sprintf("%d", val[i]) - r.WriteString(fmt.Sprintf("%d", val[i])) - if i != len(val)-1 { - // r = r + fmt.Sprintf(", ") - r.WriteString(", ") - } - } - // r = r + fmt.Sprintf(". ") - r.WriteString(". ") - } - return r.String() -} From 5459f18e9cfac6233dad31172f5cc6a2090ac67e Mon Sep 17 00:00:00 2001 From: Imran Khan Date: Sun, 29 Aug 2021 13:31:29 +0530 Subject: [PATCH 209/488] Use multiple assignment instead of a temp variable (#300) Co-authored-by: Andrii Siriak --- sorts/selectionsort.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sorts/selectionsort.go b/sorts/selectionsort.go index 7923a8fae..997f3b6cb 100644 --- a/sorts/selectionsort.go +++ b/sorts/selectionsort.go @@ -11,9 +11,7 @@ func SelectionSort(arr []int) []int { } } - tmp := arr[i] - arr[i] = arr[min] - arr[min] = tmp + arr[i], arr[min] = arr[min], arr[i] } return arr } From 75b99a2b7143e141c1ddd5cf65f283967cdf4239 Mon Sep 17 00:00:00 2001 From: Vitaly Tikhoplav <62797411+tikhoplav@users.noreply.github.com> Date: Mon, 30 Aug 2021 23:06:28 +0300 Subject: [PATCH 210/488] fix: Add docs and tests to IsBalanced (#326) --- other/nested_brackets/nestedbrackets.go | 91 +++++++++++--------- other/nested_brackets/nestedbrackets_test.go | 79 +++++++++++++++++ 2 files changed, 130 insertions(+), 40 deletions(-) create mode 100644 other/nested_brackets/nestedbrackets_test.go diff --git a/other/nested_brackets/nestedbrackets.go b/other/nested_brackets/nestedbrackets.go index 9a10a98ef..5ec4e7cc1 100644 --- a/other/nested_brackets/nestedbrackets.go +++ b/other/nested_brackets/nestedbrackets.go @@ -1,51 +1,62 @@ -// The nested brackets problem is a problem that determines if a sequence of -// brackets are properly nested. A sequence of brackets s is considered properly nested +// Package nested_brackets provides functions for testing +// strings propper brackets nesting. +package nested_brackets + +// IsBalanced returns true if provided input string is properly nested. +// +// Input is a sequence of brackets: '(', ')', '[', ']', '{', '}'. +// +// A sequence of brackets `s` is considered properly nested // if any of the following conditions are true: -// - s is empty -// - s has the form (U) or [U] or {U} where U is a properly nested string -// - s has the form VW where V and W are properly nested strings +// - `s` is empty; +// - `s` has the form (U) or [U] or {U} where U is a properly nested string; +// - `s` has the form VW where V and W are properly nested strings. +// // For example, the string "()()[()]" is properly nested but "[(()]" is not. -// The function called isBalanced takes as input a string which is a sequence of brackets and -// returns true if input is nested and false otherwise. -//note that only an even number of brackets can be properly nested - -package nested_brackets +// +// **Note** Providing characters other then brackets would return false, +// despite brackets sequence in the string. Make sure to filter +// input before useage. +func IsBalanced(input string) bool { + if len(input) == 0 { + return true + } -// IsBalanced function which checks whether the number of brackets are balanced -func IsBalanced(input string) string { if len(input)%2 != 0 { - return input + "is not balanced." + return false } - if len(input) > 0 { - var stack []byte - for i := 0; i < len(input); i++ { - if input[i] == '(' || input[i] == '{' || input[i] == '[' { - stack = append(stack, input[i]) - } else { - if len(stack) > 0 { - pair := string(stack[len(stack)-1]) + string(input[i]) - stack = stack[:len(stack)-1] - if pair != "[]" && pair != "{}" && pair != "()" { - return input + " is not balanced." - } - } else { - return input + " is not balanced." + // Brackets such as '{', '[', '(' are valid UTF-8 characters, + // which means that only one byte is required to code them, + // so can be stored as bytes. + var stack []byte + + for i := 0; i < len(input); i++ { + if input[i] == '(' || input[i] == '{' || input[i] == '[' { + stack = append(stack, input[i]) + } else { + if len(stack) > 0 { + pair := string(stack[len(stack)-1]) + string(input[i]) + stack = stack[:len(stack)-1] + + if pair != "[]" && pair != "{}" && pair != "()" { + // This means that two types of brackets has + // been mixed together, for example "([)]", + // which makes seuqence invalid by definition. + return false } + } else { + // This means that closing bracket is encountered + // before opening one, which makes all sequence + // invalid by definition. + return false } } - if len(stack) == 0 { - return input + " is balanced." - } } - return "Please enter a sequence of brackets." -} - -// func main() { -// reader := bufio.NewReader(os.Stdin) -// fmt.Print("Enter sequence of brackets: ") -// text, _ := reader.ReadString('\n') -// text = strings.TrimSpace(text) -// fmt.Println(isBalanced(text)) -// } + // If sequence is properly nested, all elements in stack + // has been paired with closing elements. If even one + // element has not been paired with a closing bracket, + // means that sequence is invalid by definition. + return len(stack) == 0 +} diff --git a/other/nested_brackets/nestedbrackets_test.go b/other/nested_brackets/nestedbrackets_test.go new file mode 100644 index 000000000..658cc4837 --- /dev/null +++ b/other/nested_brackets/nestedbrackets_test.go @@ -0,0 +1,79 @@ +package nested_brackets + +import ( + "testing" +) + +func TestIsBalancedSimple(t *testing.T) { + input := "{[()]}" + + got := IsBalanced(input) + want := true + + if got != want { + t.Errorf("\nInput: %s\nGot: %v\nWant: %v\n", input, got, want) + } +} + +func TestIsBalancedFalty(t *testing.T) { + input := "{([()]}" + + got := IsBalanced(input) + want := false + + if got != want { + t.Errorf("\nInput: %s\nGot: %v\nWant: %v\n", input, got, want) + } +} + +func TestIsBalancedHandlesEmpty(t *testing.T) { + input := "" + + got := IsBalanced(input) + want := true + + if got != want { + t.Errorf("\nInput: %s\nGot: %v\nWant: %v\n", input, got, want) + } +} + +func TestIsBalancedHandlesOneChar(t *testing.T) { + input := "{" + + got := IsBalanced(input) + want := false + + if got != want { + t.Errorf("\nInput: %s\nGot: %v\nWant: %v\n", input, got, want) + } +} + +func TestIsBalancedHandlesNonBracketsCorrectly(t *testing.T) { + input := "aaaa" + + got := IsBalanced(input) + want := false + + if got != want { + t.Errorf("\nInput: %s\nGot: %v\nWant: %v\n", input, got, want) + } +} + +func TestIsBalancedHandlesOrdering(t *testing.T) { + input := "([)]" + + got := IsBalanced(input) + want := false + + if got != want { + t.Errorf("\nInput: %s\nGot: %v\nWant: %v\n", input, got, want) + } +} + +func BenchmarkIsBalanced(b *testing.B) { + input := "{[()]}" + + for i := 0; i < b.N; i++ { + IsBalanced(input) + } +} From fef0b9549aad1256839cd9525cd88ed7176d3fcc Mon Sep 17 00:00:00 2001 From: Sumita Canopas <69897605+cp-sumi-k@users.noreply.github.com> Date: Tue, 31 Aug 2021 10:29:46 +0530 Subject: [PATCH 211/488] Add moser-de bruijin sequence (#255) --- math/moserdebruijnsequence/sequence.go | 34 +++++++++++++++++++++ math/moserdebruijnsequence/sequence_test.go | 25 +++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 math/moserdebruijnsequence/sequence.go create mode 100644 math/moserdebruijnsequence/sequence_test.go diff --git a/math/moserdebruijnsequence/sequence.go b/math/moserdebruijnsequence/sequence.go new file mode 100644 index 000000000..1c02201b3 --- /dev/null +++ b/math/moserdebruijnsequence/sequence.go @@ -0,0 +1,34 @@ +// The Moser-de Bruijn sequence is the sequence obtained by +// adding up the distinct powers of the number 4 (For example 1, 4, 16, 64, etc). +// You can get more details on https://en.wikipedia.org/wiki/Moser%E2%80%93de_Bruijn_sequence. + +package moserdebruijnsequence + +func MoserDeBruijnSequence(number int) []int { + sequence := []int{} + + for i := 0; i < number; i++ { + res := generateNthTerm(i) + sequence = append(sequence, res) + } + + return sequence +} + +func generateNthTerm(num int) int { + if num == 0 || num == 1 { + return num + } + + //number is even + if num%2 == 0 { + return 4 * generateNthTerm(num/2) + } + + //number is odd + if num%2 != 0 { + return 4*generateNthTerm(num/2) + 1 + } + + return 0 +} diff --git a/math/moserdebruijnsequence/sequence_test.go b/math/moserdebruijnsequence/sequence_test.go new file mode 100644 index 000000000..8036ddc47 --- /dev/null +++ b/math/moserdebruijnsequence/sequence_test.go @@ -0,0 +1,25 @@ +package moserdebruijnsequence + +import ( + "reflect" + "testing" +) + +var testCases = []struct { + name string + inputNum int + expected []int +}{ + {"first 15 terms", 15, []int{0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84}}, +} + +func TestMoserDeBruijnSequence(t *testing.T) { + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + if output := MoserDeBruijnSequence(test.inputNum); !reflect.DeepEqual(output, test.expected) { + t.Errorf("For input: %d, expected: %v, but got: %v", test.inputNum, test.expected, output) + } + }) + } +} From 066d15ef0699e9b279c62e1a91aebabf7169e99e Mon Sep 17 00:00:00 2001 From: Hariprasad Date: Tue, 31 Aug 2021 12:36:06 +0530 Subject: [PATCH 212/488] chore: Add Interpolation Search (#308) --- .../interpolation_search_test.go | 31 +++++++++++ .../interpolationsearch.go | 51 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 searches/interpolation_search.go/interpolation_search_test.go create mode 100644 searches/interpolation_search.go/interpolationsearch.go diff --git a/searches/interpolation_search.go/interpolation_search_test.go b/searches/interpolation_search.go/interpolation_search_test.go new file mode 100644 index 000000000..0ca829f14 --- /dev/null +++ b/searches/interpolation_search.go/interpolation_search_test.go @@ -0,0 +1,31 @@ +package interpolationsearch + +import "testing" + +type searchTest struct { + data []int + key int + expected int + name string +} + +var searchTests = []searchTest{ + //Sanity + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, + //Absent + {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, + {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, + //Empty slice + {[]int{}, 2, -1, "Empty"}, +} + +func TestInterpolationSearch(t *testing.T) { + for _, test := range searchTests { + actual := InterpolationSearch(test.data, test.key) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/searches/interpolation_search.go/interpolationsearch.go b/searches/interpolation_search.go/interpolationsearch.go new file mode 100644 index 000000000..7e4de0277 --- /dev/null +++ b/searches/interpolation_search.go/interpolationsearch.go @@ -0,0 +1,51 @@ +package interpolationsearch + +/* +InterpolationSearch searches for the entity in the given sortedData. +if the entity is present, it will return the index of the entity, if not -1 will be returned. +see: https://en.wikipedia.org/wiki/Interpolation_search +Complexity + Worst: O(N) + Average: O(log(log(N)) if the elements are uniformly distributed + Best: O(1) + +Example + fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) +*/ +func InterpolationSearch(sortedData []int, guess int) int { + if len(sortedData) == 0 { + return -1 + } + + var ( + low, high = 0, len(sortedData) - 1 + lowVal, highVal = sortedData[low], sortedData[high] + ) + + for lowVal != highVal && (lowVal <= guess) && (guess <= highVal) { + mid := low + int(float64(float64((guess-lowVal)*(high-low))/float64(highVal-lowVal))) + + // if guess is found, array can also have duplicate values, so scan backwards and find the first index + if sortedData[mid] == guess { + for mid > 0 && sortedData[mid-1] == guess { + mid-- + } + return mid + + } + + // adjust our guess and continue + if sortedData[mid] > guess { + high, highVal = mid-1, sortedData[high] + + } else { + low, lowVal = mid+1, sortedData[low] + } + + } + + if guess == lowVal { + return low + } + return -1 +} From 5654ce9e4cd0225bb19a897907d04b1307356c31 Mon Sep 17 00:00:00 2001 From: Munia Balayil Date: Thu, 2 Sep 2021 00:10:01 +0530 Subject: [PATCH 213/488] Add test file for lcm (#302) Co-authored-by: Andrii Siriak --- math/lcm/lcm_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 math/lcm/lcm_test.go diff --git a/math/lcm/lcm_test.go b/math/lcm/lcm_test.go new file mode 100644 index 000000000..e685a6728 --- /dev/null +++ b/math/lcm/lcm_test.go @@ -0,0 +1,44 @@ +package lcm + +import "testing" + +func TestLcm(t *testing.T) { + testCases := []struct { + name string + a int64 + b int64 + output int64 + }{ + { + name: "LCM of 1 & 5", + a: 1, + b: 5, + output: 5, + }, { + name: "LCM of 2 & 5", + a: 2, + b: 5, + output: 10, + }, { + name: "LCM of 5 & 10", + a: 10, + b: 5, + output: 10, + }, { + name: "LCM of 5 & 5", + a: 5, + b: 5, + output: 5, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual_output := Lcm(tc.a, tc.b) + if actual_output != tc.output { + t.Errorf("Expected LCM of %d and %d is %d, but got %d", tc.a, tc.b, tc.output, + actual_output) + } + }) + } +} From 2ce0de8a9c67dee9529663fd1c980e0b6294d00e Mon Sep 17 00:00:00 2001 From: liyl <30368453+yaolin-Li@users.noreply.github.com> Date: Fri, 3 Sep 2021 00:28:38 +0800 Subject: [PATCH 214/488] Cleanup romantointeger.go (#328) Co-authored-by: Yaolin_Li <1586505611@qq.com> Co-authored-by: Andrii Siriak --- conversions/roman_to_integer/romantointeger.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/conversions/roman_to_integer/romantointeger.go b/conversions/roman_to_integer/romantointeger.go index b9601e7db..b0e250bc2 100644 --- a/conversions/roman_to_integer/romantointeger.go +++ b/conversions/roman_to_integer/romantointeger.go @@ -11,14 +11,12 @@ var romans = map[string]int{"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500 func RomanToInteger(roman string) int { total := 0 - holder := 0 - for holder < len(roman) { - if holder+1 < len(roman) && (romans[string(roman[holder])] < romans[string(roman[holder+1])]) { - total += romans[string(roman[holder+1])] - romans[string(roman[holder])] - holder += 2 + romanLen := len(roman) + for holder := range roman { + if holder+1 < romanLen && romans[string(roman[holder])] < romans[string(roman[holder+1])] { + total -= romans[string(roman[holder])] } else { total += romans[string(roman[holder])] - holder++ } } return total From a50e4a6fe1081c2e369072078f40f5a392d73084 Mon Sep 17 00:00:00 2001 From: Ryusei Nagai Date: Fri, 3 Sep 2021 18:08:13 +0900 Subject: [PATCH 215/488] Add extended gcd (#307) Co-authored-by: Christian Clauss Co-authored-by: Andrii Siriak --- math/gcd/extendedgcd.go | 12 +++++++ math/gcd/extendedgcd_test.go | 57 ++++++++++++++++++++++++++++++++ math/gcd/extendedgcditerative.go | 13 ++++++++ 3 files changed, 82 insertions(+) create mode 100644 math/gcd/extendedgcd.go create mode 100644 math/gcd/extendedgcd_test.go create mode 100644 math/gcd/extendedgcditerative.go diff --git a/math/gcd/extendedgcd.go b/math/gcd/extendedgcd.go new file mode 100644 index 000000000..004a91ead --- /dev/null +++ b/math/gcd/extendedgcd.go @@ -0,0 +1,12 @@ +package gcd + +// ExtendedRecursive finds and returns gcd(a, b), x, y satisfying a*x + b*y = gcd(a, b). +func ExtendedRecursive(a, b int64) (int64, int64, int64) { + if b > 0 { + d, y, x := ExtendedRecursive(b, a%b) + y -= (a / b) * x + return d, x, y + } + + return a, 1, 0 +} diff --git a/math/gcd/extendedgcd_test.go b/math/gcd/extendedgcd_test.go new file mode 100644 index 000000000..d967ad57c --- /dev/null +++ b/math/gcd/extendedgcd_test.go @@ -0,0 +1,57 @@ +package gcd + +import "testing" + +type testExtendedFunction func(int64, int64) (int64, int64, int64) + +var testCasesExtended = []struct { + name string + a int64 + b int64 + gcd int64 + x int64 + y int64 +}{ + {"gcd of 10 and 0", 10, 0, 10, 1, 0}, + {"gcd of 98 and 56", 98, 56, 14, -1, 2}, + {"gcd of 0 and 10", 0, 10, 10, 0, 1}, +} + +func TemplateTestExtendedGCD(t *testing.T, f testExtendedFunction) { + for _, tc := range testCasesExtended { + t.Run(tc.name, func(t *testing.T) { + actualGcd, actualX, actualY := f(tc.a, tc.b) + if actualGcd != tc.gcd { + t.Errorf("Expected GCD of %d and %d to be: %v, but got: %d", tc.a, tc.b, tc.gcd, actualGcd) + } + if actualX != tc.x { + t.Errorf("Expected x satisfying %d * x + %d * y = gcd to be: %v, but got: %d", tc.a, tc.b, tc.x, actualX) + } + if actualY != tc.y { + t.Errorf("Expected y satisfying %d * x + %d * y = gcd to be: %v, but got: %d", tc.a, tc.b, tc.y, actualY) + } + }) + } +} + +func TestExtendedGCDRecursive(t *testing.T) { + TemplateTestExtendedGCD(t, ExtendedRecursive) +} + +func TestExtendedGCDIterative(t *testing.T) { + TemplateTestExtendedGCD(t, ExtendedIterative) +} + +func TemplateBenchmarkExtendedGCD(b *testing.B, f testExtendedFunction) { + for i := 0; i < b.N; i++ { + f(98, 56) + } +} + +func BenchmarkExtendedGCDRecursive(b *testing.B) { + TemplateBenchmarkExtendedGCD(b, ExtendedRecursive) +} + +func BenchmarkExtendedGCDIterative(b *testing.B) { + TemplateBenchmarkExtendedGCD(b, ExtendedIterative) +} diff --git a/math/gcd/extendedgcditerative.go b/math/gcd/extendedgcditerative.go new file mode 100644 index 000000000..1c8e8ad72 --- /dev/null +++ b/math/gcd/extendedgcditerative.go @@ -0,0 +1,13 @@ +package gcd + +// ExtendedIterative finds and returns gcd(a, b), x, y satisfying a*x + b*y = gcd(a, b). +func ExtendedIterative(a, b int64) (int64, int64, int64) { + var u, y, v, x int64 = 1, 1, 0, 0 + for a > 0 { + var q int64 = b / a + x, u = u, x-q*u + y, v = v, y-q*v + b, a = a, b-q*a + } + return b, x, y +} From 4037fd72876e03a0d28b53c5ebea0f5e9e71e6df Mon Sep 17 00:00:00 2001 From: Rengoku <47633677+Om1kami@users.noreply.github.com> Date: Fri, 3 Sep 2021 16:12:23 +0700 Subject: [PATCH 216/488] Add Linked Cycle List struct (#293) Co-authored-by: Andrii Siriak --- .../Linked_Cyclic_List.jpg | Bin 0 -> 261856 bytes .../linkedlist/cyclicallylinkedlist/Readme.md | 12 ++ .../cyclicallylinkedlist.go | 144 ++++++++++++++++++ .../cyclicallylinkedlist_test.go | 129 ++++++++++++++++ 4 files changed, 285 insertions(+) create mode 100644 datastructures/linkedlist/cyclicallylinkedlist/Linked_Cyclic_List.jpg create mode 100644 datastructures/linkedlist/cyclicallylinkedlist/Readme.md create mode 100644 datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go create mode 100644 datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go diff --git a/datastructures/linkedlist/cyclicallylinkedlist/Linked_Cyclic_List.jpg b/datastructures/linkedlist/cyclicallylinkedlist/Linked_Cyclic_List.jpg new file mode 100644 index 0000000000000000000000000000000000000000..84c432516aea93ff971baaa90e3f7b8bcc0d241c GIT binary patch literal 261856 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
+ ahocorasick + +--- + +##### Functions: + +1. [`Advanced`](./strings/ahocorasick/advancedahocorasick.go#L10): Advanced Function performing the Advanced Aho-Corasick algorithm. Finds and prints occurrences of each pattern. +2. [`AhoCorasick`](./strings/ahocorasick/ahocorasick.go#L15): AhoCorasick Function performing the Basic Aho-Corasick algorithm. Finds and prints occurrences of each pattern. +3. [`ArrayUnion`](./strings/ahocorasick/shared.go#L86): ArrayUnion Concats two arrays of int's into one. +4. [`BoolArrayCapUp`](./strings/ahocorasick/shared.go#L78): BoolArrayCapUp Dynamically increases an array size of bool's by 1. +5. [`BuildAc`](./strings/ahocorasick/ahocorasick.go#L54): Functions that builds Aho Corasick automaton. +6. [`BuildExtendedAc`](./strings/ahocorasick/advancedahocorasick.go#L46): BuildExtendedAc Functions that builds extended Aho Corasick automaton. +7. [`ComputeAlphabet`](./strings/ahocorasick/shared.go#L61): ComputeAlphabet Function that returns string of all the possible characters in given patterns. +8. [`ConstructTrie`](./strings/ahocorasick/shared.go#L4): ConstructTrie Function that constructs Trie as an automaton for a set of reversed & trimmed strings. +9. [`Contains`](./strings/ahocorasick/shared.go#L39): Contains Returns 'true' if array of int's 's' contains int 'e', 'false' otherwise. +10. [`CreateNewState`](./strings/ahocorasick/shared.go#L111): CreateNewState Automaton function for creating a new state 'state'. +11. [`CreateTransition`](./strings/ahocorasick/shared.go#L116): CreateTransition Creates a transition for function σ(state,letter) = end. +12. [`GetParent`](./strings/ahocorasick/shared.go#L99): GetParent Function that finds the first previous state of a state and returns it. Used for trie where there is only one parent. +13. [`GetTransition`](./strings/ahocorasick/shared.go#L121): GetTransition Returns ending state for transition σ(fromState,overChar), '-1' if there is none. +14. [`GetWord`](./strings/ahocorasick/shared.go#L49): GetWord Function that returns word found in text 't' at position range 'begin' to 'end'. +15. [`IntArrayCapUp`](./strings/ahocorasick/shared.go#L70): IntArrayCapUp Dynamically increases an array size of int's by 1. +16. [`StateExists`](./strings/ahocorasick/shared.go#L133): StateExists Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. + +--- +##### Types + +1. [`Result`](./strings/ahocorasick/ahocorasick.go#L9): No description provided. + + +--- +
+ avl + +--- + +##### Package avl is a Adelson-Velskii and Landis tree implemnation avl is self-balancing tree, i.e for all node in a tree, height difference between its left and right child will not exceed 1 more information : https://en.wikipedia.org/wiki/AVL_tree + +--- +##### Functions: + +1. [`Delete`](./structure/avl/avl.go#L72): Delete : remove given key from the tree +2. [`Get`](./structure/avl/avl.go#L20): Get : return node with given key +3. [`Insert`](./structure/avl/avl.go#L35): Insert a new item +4. [`NewTree`](./structure/avl/avl.go#L15): NewTree create a new AVL tree + +--- +##### Types + +1. [`Node`](./structure/avl/avl.go#L8): No description provided. + + +--- +
+ binary + +--- + +##### Package binary describes algorithms that use binary operations for different calculations. + +--- +##### Functions: + +1. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. +2. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 +3. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L11): No description provided. +4. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L15): No description provided. +5. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. +6. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L10): No description provided. + +--- +
+ binarytree + +--- + +##### Functions: + +1. [`AccessNodesByLayer`](./structure/binarysearchtree/bstree.go#L145): AccessNodesByLayer Function that access nodes layer by layer instead of printing the results as one line. +2. [`BstDelete`](./structure/binarysearchtree/bstree.go#L44): BstDelete removes the node +3. [`InOrder`](./structure/binarysearchtree/bstree.go#L79): Travers the tree in the following order left --> root --> right +4. [`InOrderSuccessor`](./structure/binarysearchtree/bstree.go#L35): InOrderSuccessor Goes to the left +5. [`Insert`](./structure/binarysearchtree/bstree.go#L17): Insert a value in the BSTree +6. [`LevelOrder`](./structure/binarysearchtree/bstree.go#L138): No description provided. +7. [`Max`](./structure/binarysearchtree/bstree.go#L174): Max Function that returns max of two numbers - possibly already declared. +8. [`NewNode`](./structure/binarysearchtree/node.go#L11): NewNode Returns a new pointer to an empty Node +9. [`PostOrder`](./structure/binarysearchtree/bstree.go#L113): Travers the tree in the following order left --> right --> root +10. [`PreOrder`](./structure/binarysearchtree/bstree.go#L96): Travers the tree in the following order root --> left --> right + +--- +##### Types + +1. [`BSTree`](./structure/binarysearchtree/bstree.go#L4): No description provided. + +2. [`Node`](./structure/binarysearchtree/node.go#L4): No description provided. + + +--- +
+ caesar + +--- + +##### Package caesar is the shift cipher ref: https://en.wikipedia.org/wiki/Caesar_cipher + +--- +##### Functions: + +1. [`Decrypt`](./cipher/caesar/caesar.go#L27): Decrypt decrypts by left shift of "key" each character of "input" +2. [`Encrypt`](./cipher/caesar/caesar.go#L6): Encrypt encrypts by right shift of "key" each character of "input" + +--- +
+ coloring + +--- + +##### Package coloring provides implementation of different graph coloring algorithms, e.g. coloring using BFS, using Backtracking, using greedy approach. Author(s): [Shivam](https://github.com/Shivam010) + +--- +##### Functions: + +1. [`BipartiteCheck`](./graph/coloring/bipartite.go#L40): basically tries to color the graph in two colors if each edge connects 2 differently colored nodes the graph can be considered bipartite + +--- +##### Types + +1. [`Graph`](./graph/coloring/graph.go#L14): No description provided. + + +--- +
+ combination + +--- + +##### Package combination ... + +--- +##### Functions: + +1. [`Start`](./strings/combination/combination.go#L13): Start ... + +--- +##### Types + +1. [`Combinations`](./strings/combination/combination.go#L7): No description provided. + + +--- +
+ conversion + +--- + +##### Package conversion is a package of implementations which converts one data structure to another. + +--- +##### Functions: + +1. [`BinaryToDecimal`](./conversion/binarytodecimal.go#L25): BinaryToDecimal() function that will take Binary number as string, and return it's Decimal equivalent as integer. +2. [`DecimalToBinary`](./conversion/decimaltobinary.go#L32): DecimalToBinary() function that will take Decimal number as int, and return it's Binary equivalent as string. +3. [`HEXToRGB`](./conversion/rgbhex.go#L10): HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) into the individual components: red, green and blue +4. [`IntToRoman`](./conversion/integertoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. +5. [`RGBToHEX`](./conversion/rgbhex.go#L41): RGBToHEX does exactly the opposite of HEXToRGB: it combines the three components red, green and blue to an RGB value, which can be converted to e.g. Hex +6. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. +7. [`RomanToInteger`](./conversion/romantointeger.go#L40): RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. + +--- +
+ diffiehellman + +--- + +##### Package diffiehellman implements Deffie Hellman Key Exchange Algorithm for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI + +--- +##### Functions: + +1. [`GenerateMutualKey`](./cipher/diffiehellman/diffiehellmankeyexchange.go#L19): GenerateMutualKey : generates a mutual key that can be used by only alice and bob mutualKey = (shareKey^prvKey)%primeNumber +2. [`GenerateShareKey`](./cipher/diffiehellman/diffiehellmankeyexchange.go#L13): GenerateShareKey : generates a key using client private key , generator and primeNumber this key can be made public shareKey = (g^key)%primeNumber + +--- +
+ dynamic + +--- + +##### Package dynamic is a package of certain implementations of dynamically run algorithms. + +--- +##### Functions: + +1. [`Bin2`](./dynamic/binomialcoefficient.go#L21): Bin2 function +2. [`CutRodDp`](./dynamic/rodcutting.go#L21): CutRodDp solve the same problem using dynamic programming +3. [`CutRodRec`](./dynamic/rodcutting.go#L8): CutRodRec solve the problem recursively: initial approach +4. [`EditDistanceDP`](./dynamic/editdistance.go#L35): EditDistanceDP is an optimised implementation which builds on the ideas of the recursive implementation. We use dynamic programming to compute the DP table where dp[i][j] denotes the edit distance value of first[0..i-1] and second[0..j-1]. Time complexity is O(m * n) where m and n are lengths of the strings, first and second respectively. +5. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity. +6. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided. +7. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit +8. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L8): LongestCommonSubsequence function +9. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order +10. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function +11. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function +12. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function +13. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function +14. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate +15. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) +16. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number + +--- +
+ dynamicarray + +--- + +##### Package dynamicarray A dynamic array is quite similar to a regular array, but its Size is modifiable during program runtime, very similar to how a slice in Go works. The implementation is for educational purposes and explains how one might go about implementing their own version of slices. For more details check out those links below here: GeeksForGeeks article : https://www.geeksforgeeks.org/how-do-dynamic-arrays-work/ Go blog: https://blog.golang.org/slices-intro Go blog: https://blog.golang.org/slices authors [Wesllhey Holanda](https://github.com/wesllhey), [Milad](https://github.com/miraddo) see dynamicarray.go, dynamicarray_test.go + +--- +##### Types + +1. [`DynamicArray`](./structure/dynamicarray/dynamicarray.go#L21): No description provided. + + +--- +
+ factorial + +--- + +##### Package factorial describes algorithms Factorials calculations. + +--- +##### Functions: + +1. [`BruteForceFactorial`](./math/factorial/factorial.go#L11): No description provided. +2. [`CalculateFactorialUseTree`](./math/factorial/factorial.go#L27): No description provided. +3. [`RecursiveFactorial`](./math/factorial/factorial.go#L19): No description provided. + +--- +
+ gcd + +--- + +##### Functions: + +1. [`Extended`](./math/gcd/extended.go#L12): Extended simple extended gcd +2. [`ExtendedIterative`](./math/gcd/extendedgcditerative.go#L4): ExtendedIterative finds and returns gcd(a, b), x, y satisfying a*x + b*y = gcd(a, b). +3. [`ExtendedRecursive`](./math/gcd/extendedgcd.go#L4): ExtendedRecursive finds and returns gcd(a, b), x, y satisfying a*x + b*y = gcd(a, b). +4. [`Iterative`](./math/gcd/gcditerative.go#L4): Iterative Faster iterative version of GcdRecursive without holding up too much of the stack +5. [`Recursive`](./math/gcd/gcd.go#L4): Recursive finds and returns the greatest common divisor of a given integer. +6. [`TemplateBenchmarkExtendedGCD`](./math/gcd/extendedgcd_test.go#L44): No description provided. +7. [`TemplateBenchmarkGCD`](./math/gcd/gcd_test.go#L37): No description provided. +8. [`TemplateTestExtendedGCD`](./math/gcd/extendedgcd_test.go#L7): No description provided. +9. [`TemplateTestGCD`](./math/gcd/gcd_test.go#L18): No description provided. + +--- +
+ generateparentheses + +--- + +##### Functions: + +1. [`GenerateParenthesis`](./strings/generateparentheses/generateparentheses.go#L12): No description provided. + +--- +
+ genetic + +--- + +##### Package genetic provides functions to work with strings using genetic algorithm. https://en.wikipedia.org/wiki/Genetic_algorithm Author: D4rkia + +--- +##### Functions: + +1. [`GeneticString`](./strings/genetic/genetic.go#L71): GeneticString generates PopultaionItem based on the imputed target string, and a set of possible runes to build a string with. In order to optimise string generation additional configurations can be provided with Conf instance. Empty instance of Conf (&Conf{}) can be provided, then default values would be set. Link to the same algorithm implemented in python: https://github.com/TheAlgorithms/Python/blob/master/genetic_algorithm/basic_string.py + +--- +##### Types + +1. [`Conf`](./strings/genetic/genetic.go#L32): No description provided. + +2. [`PopulationItem`](./strings/genetic/genetic.go#L26): No description provided. + +3. [`Result`](./strings/genetic/genetic.go#L52): No description provided. + + +--- +
+ geometry + +--- + +##### Functions: + +1. [`Distance`](./math/geometry/straightlines.go#L17): Calculates the shortest distance between two points. +2. [`Intercept`](./math/geometry/straightlines.go#L36): Calculates the Y-Intercept of a line from a specific Point. +3. [`IsParallel`](./math/geometry/straightlines.go#L41): Checks if two lines are parallel or not. +4. [`IsPerpendicular`](./math/geometry/straightlines.go#L46): Checks if two lines are perpendicular or not. +5. [`PointDistance`](./math/geometry/straightlines.go#L52): Calculates the distance of a given Point from a given line. The slice should contain the coefficiet of x, the coefficient of y and the constant in the respective order. +6. [`Section`](./math/geometry/straightlines.go#L23): Calculates the Point that divides a line in specific ratio. DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. +7. [`Slope`](./math/geometry/straightlines.go#L31): Calculates the slope (gradient) of a line. + +--- +##### Types + +1. [`Line`](./math/geometry/straightlines.go#L12): No description provided. + +2. [`Point`](./math/geometry/straightlines.go#L8): No description provided. + + +--- +
+ graph + +--- + +##### Package graph demonstrates Graph search algorithms reference: https://en.wikipedia.org/wiki/Tree_traversal + +--- +##### Functions: + +1. [`BreadthFirstSearch`](./graph/breadthfirstsearch.go#L9): BreadthFirstSearch is an algorithm for traversing and searching graph data structures. It starts at an arbitrary node of a graph, and explores all of the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level. Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) reference: https://en.wikipedia.org/wiki/Breadth-first_search +2. [`DepthFirstSearch`](./graph/depthfirstsearch.go#L53): No description provided. +3. [`DepthFirstSearchHelper`](./graph/depthfirstsearch.go#L21): No description provided. +4. [`FloydWarshall`](./graph/floydwarshall.go#L15): FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm +5. [`GetIdx`](./graph/depthfirstsearch.go#L3): No description provided. +6. [`KruskalMST`](./graph/kruskal.go#L87): KruskalMST will return a minimum spanning tree along with its total cost to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is the number of edges in the graph and n is number of nodes in it. +7. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) +8. [`NewDSU`](./graph/kruskal.go#L34): NewDSU will return an initialised DSU using the value of n which will be treated as the number of elements out of which the DSU is being made +9. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. +10. [`Topological`](./graph/topological.go#L7): Assumes that graph given is valid and possible to get a topo ordering. constraints are array of []int{a, b}, representing an edge going from a to b + +--- +##### Types + +1. [`DisjointSetUnion`](./graph/kruskal.go#L29): No description provided. + +2. [`DisjointSetUnionElement`](./graph/kruskal.go#L21): No description provided. + +3. [`Edge`](./graph/kruskal.go#L14): No description provided. + +4. [`Graph`](./graph/graph.go#L9): No description provided. + +5. [`Item`](./graph/dijkstra.go#L5): No description provided. + +6. [`WeightedGraph`](./graph/floydwarshall.go#L9): No description provided. + + +--- +
+ hashmap + +--- + +##### Functions: + +1. [`New`](./structure/hashmap/hashmap.go#L24): New return new HashMap instance + +--- +##### Types + +1. [`HashMap`](./structure/hashmap/hashmap.go#L17): No description provided. + + +--- +
+ kmp + +--- + +##### Functions: + +1. [`Kmp`](./strings/kmp/kmp.go#L70): Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. Prints whether the word/pattern was found and on what position in the text or not. m - current match in text, i - current character in w, c - amount of comparisons. + +--- +##### Types + +1. [`Result`](./strings/kmp/kmp.go#L15): No description provided. + + +--- +
+ lcm + +--- + +##### Functions: + +1. [`Lcm`](./math/lcm/lcm.go#L10): Lcm returns the lcm of two numbers using the fact that lcm(a,b) * gcd(a,b) = | a * b | + +--- +
+ levenshtein + +--- + +##### Functions: + +1. [`Distance`](./strings/levenshtein/levenshteindistance.go#L10): Distance Function that gives Levenshtein Distance + +--- +
+ linkedlist + +--- + +##### Package linkedlist demonstates different implementations on linkedlists. + +--- +##### Functions: + +1. [`JosephusProblem`](./structure/linkedlist/cyclic.go#L120): https://en.wikipedia.org/wiki/Josephus_problem This is a struct-based solution for Josephus problem. +2. [`NewCyclic`](./structure/linkedlist/cyclic.go#L12): Create new list. +3. [`NewDoubly`](./structure/linkedlist/doubly.go#L22): No description provided. +4. [`NewNode`](./structure/linkedlist/shared.go#L12): Create new node. +5. [`NewSingly`](./structure/linkedlist/singlylinkedlist.go#L19): NewSingly returns a new instance of a linked list + +--- +##### Types + +1. [`Cyclic`](./structure/linkedlist/cyclic.go#L6): No description provided. + +2. [`Doubly`](./structure/linkedlist/doubly.go#L18): No description provided. + +3. [`Node`](./structure/linkedlist/shared.go#L5): No description provided. + +4. [`Singly`](./structure/linkedlist/singlylinkedlist.go#L10): No description provided. + +5. [`testCase`](./structure/linkedlist/cyclic_test.go#L105): No description provided. + + +--- +
+ manacher + +--- + +##### Functions: + +1. [`LongestPalindrome`](./strings/manacher/longestpalindrome.go#L37): No description provided. + +--- +
+ math + +--- + +##### Package math is a package that contains mathematical algorithms and its different implementations. + +--- +##### Functions: + +1. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +2. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. + +--- +
+ max + +--- + +##### Functions: + +1. [`BitwiseMax`](./math/max/bitwisemax.go#L10): No description provided. +2. [`Int`](./math/max/max.go#L4): Int is a function which returns the maximum of all the integers provided as arguments. + +--- +
+ maxsubarraysum + +--- + +##### Package maxsubarraysum is a package containing a solution to a common problem of finding max contiguous sum within a array of ints. + +--- +##### Functions: + +1. [`MaxSubarraySum`](./other/maxsubarraysum/maxsubarraysum.go#L13): MaxSubarraySum returns the maximum subarray sum + +--- +
+ min + +--- + +##### Functions: + +1. [`Bitwise`](./math/min/bitwisemin.go#L10): No description provided. +2. [`Int`](./math/min/min.go#L4): Int is a function which returns the minimum of all the integers provided as arguments. + +--- +
+ modular + +--- + +##### Functions: + +1. [`Exponentiation`](./math/modular/exponentiation.go#L22): Exponentiation returns base^exponent % mod +2. [`Inverse`](./math/modular/inverse.go#L20): Inverse Modular function +3. [`Multiply64BitInt`](./math/modular/exponentiation.go#L51): Multiply64BitInt Checking if the integer multiplication overflows + +--- +
+ moserdebruijnsequence + +--- + +##### Functions: + +1. [`MoserDeBruijnSequence`](./math/moserdebruijnsequence/sequence.go#L7): No description provided. + +--- +
+ nested + +--- + +##### Package nested provides functions for testing strings proper brackets nesting. + +--- +##### Functions: + +1. [`IsBalanced`](./other/nested/nestedbrackets.go#L20): IsBalanced returns true if provided input string is properly nested. Input is a sequence of brackets: '(', ')', '[', ']', '{', '}'. A sequence of brackets `s` is considered properly nested if any of the following conditions are true: - `s` is empty; - `s` has the form (U) or [U] or {U} where U is a properly nested string; - `s` has the form VW where V and W are properly nested strings. For example, the string "()()[()]" is properly nested but "[(()]" is not. **Note** Providing characters other then brackets would return false, despite brackets sequence in the string. Make sure to filter input before usage. + +--- +
+ palindrome + +--- + +##### Functions: + +1. [`IsPalindrome`](./strings/palindrome/ispalindrome.go#L26): No description provided. + +--- +
+ password + +--- + +##### Package password contains functions to help generate random passwords + +--- +##### Functions: + +1. [`Generate`](./other/password/generator.go#L15): Generate returns a newly generated password + +--- +
+ permutation + +--- + +##### Functions: + +1. [`GenerateElementSet`](./math/permutation/heaps.go#L37): No description provided. +2. [`Heaps`](./math/permutation/heaps.go#L8): Heap's Algorithm for generating all permutations of n objects + +--- +
+ pi + +--- + +##### spigotpi_test.go description: Test for Spigot Algorithm for the Digits of Pi author(s) [red_byte](https://github.com/i-redbyte) see spigotpi.go + +--- +##### Functions: + +1. [`MonteCarloPi`](./math/pi/montecarlopi.go#L15): No description provided. +2. [`Spigot`](./math/pi/spigotpi.go#L12): No description provided. + +--- +
+ polybius + +--- + +##### Package polybius is encrypting method with polybius square ref: https://en.wikipedia.org/wiki/Polybius_square#Hybrid_Polybius_Playfair_Cipher + +--- +##### Functions: + +1. [`NewPolybius`](./cipher/polybius/polybius.go#L21): NewPolybius returns a pointer to object of Polybius. If the size of "chars" is longer than "size", "chars" are truncated to "size". + +--- +##### Types + +1. [`Polybius`](./cipher/polybius/polybius.go#L12): No description provided. + + +--- +
+ power + +--- + +##### Functions: + +1. [`IterativePower`](./math/power/fastexponent.go#L4): IterativePower is iterative O(logn) function for pow(x, y) +2. [`RecursivePower`](./math/power/fastexponent.go#L18): RecursivePower is recursive O(logn) function for pow(x, y) +3. [`RecursivePower1`](./math/power/fastexponent.go#L30): RecursivePower1 is recursive O(n) function for pow(x, y) +4. [`UsingLog`](./math/power/powvialogarithm.go#L14): No description provided. + +--- +
+ prime + +--- + +##### Functions: + +1. [`Factorize`](./math/prime/primefactorization.go#L5): Factorize is a function that computes the exponents of each prime in the prime factorization of n +2. [`Generate`](./math/prime/sieve.go#L26): Generate returns a int slice of prime numbers up to the limit +3. [`GenerateChannel`](./math/prime/sieve.go#L9): Generate generates the sequence of integers starting at 2 and sends it to the channel `ch` +4. [`MillerRabinTest`](./math/prime/millerrabinprimalitytest.go#L59): MillerRabinTest Probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin. +5. [`MillerTest`](./math/prime/millerrabinprimalitytest.go#L32): MillerTest This is the intermediate step that repeats within the miller rabin primality test for better probabilitic chances of receiving the correct result. +6. [`NaiveApproach`](./math/prime/primecheck.go#L8): NaiveApproach checks if an integer is prime or not. Returns a bool. +7. [`PairApproach`](./math/prime/primecheck.go#L22): PairApproach checks primality of an integer and returns a bool. More efficient than the naive approach as number of iterations are less. +8. [`Sieve`](./math/prime/sieve.go#L16): Sieve Sieving the numbers that are not prime from the channel - basically removing them from the channels + +--- +
+ pythagoras + +--- + +##### Functions: + +1. [`Distance`](./math/pythagoras/pythagoras.go#L15): Distance calculates the distance between to vectors with the Pythagoras theorem + +--- +##### Types + +1. [`Vector`](./math/pythagoras/pythagoras.go#L8): No description provided. + + +--- +
+ queue + +--- + +##### Functions: + +1. [`BackQueue`](./structure/queue/queuearray.go#L32): BackQueue return the Back value +2. [`DeQueue`](./structure/queue/queuearray.go#L20): DeQueue it will be removed the first value that added into the list +3. [`EnQueue`](./structure/queue/queuearray.go#L15): EnQueue it will be added new value into our list +4. [`FrontQueue`](./structure/queue/queuearray.go#L27): FrontQueue return the Front value +5. [`IsEmptyQueue`](./structure/queue/queuearray.go#L42): IsEmptyQueue check our list is empty or not +6. [`LenQueue`](./structure/queue/queuearray.go#L37): LenQueue will return the length of the queue list + +--- +##### Types + +1. [`LQueue`](./structure/queue/queuelinklistwithlist.go#L20): No description provided. + +2. [`Node`](./structure/queue/queuelinkedlist.go#L13): No description provided. + +3. [`Queue`](./structure/queue/queuelinkedlist.go#L19): No description provided. + + +--- +
+ rsa + +--- + +##### Package rsa shows a simple implementation of RSA algorithm + +--- +##### Functions: + +1. [`Decrypt`](./cipher/rsa/rsa.go#L43): Decrypt decrypts encrypted rune slice based on the RSA algorithm +2. [`Encrypt`](./cipher/rsa/rsa.go#L28): Encrypt encrypts based on the RSA algorithm - uses modular exponentitation in math directory + +--- +
+ search + +--- + +##### Functions: + +1. [`BoyerMoore`](./strings/search/boyermoore.go#L5): Implementation of boyer moore string search O(l) where l=len(text) +2. [`Naive`](./strings/search/naive.go#L5): Implementation of naive string search O(n*m) where n=len(txt) and m=len(pattern) + +--- +
+ segmenttree + +--- + +##### Functions: + +1. [`NewSegmentTree`](./structure/segmenttree/segmenttree.go#L114): No description provided. + +--- +##### Types + +1. [`SegmentTree`](./structure/segmenttree/segmenttree.go#L17): No description provided. + + +--- +
+ set + +--- + +##### package set implements a Set using a golang map. This implies that only the types that are accepted as valid map keys can be used as set elements. For instance, do not try to Add a slice, or the program will panic. + +--- +##### Functions: + +1. [`New`](./structure/set/set.go#L7): New gives new set. + +--- +
+ sort + +--- + +##### Package sort a package for demonstrating sorting algorithms in Go + +--- +##### Functions: + +1. [`Count`](./sort/countingsort.go#L9): No description provided. +2. [`Exchange`](./sort/exchangesort.go#L6): No description provided. +3. [`HeapSort`](./sort/heapsort.go#L121): No description provided. +4. [`ImprovedSimpleSort`](./sort/simplesort.go#L25): ImprovedSimpleSort is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort +5. [`InsertionSort`](./sort/insertionsort.go#L3): No description provided. +6. [`Mergesort`](./sort/mergesort.go#L35): Mergesort Perform mergesort on a slice of ints +7. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. +8. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array +9. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array +10. [`RadixSort`](./sort/radixsort.go#L35): No description provided. +11. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. +12. [`ShellSort`](./sort/shellsort.go#L3): No description provided. +13. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. + +--- +##### Types + +1. [`Int`](#L0): + + Methods: + 1. [`More`](./sort/heapsort.go#L114): No description provided. +2. [`MaxHeap`](./sort/heapsort.go#L3): No description provided. + + +--- +
+ stack + +--- + +##### Types + +1. [`Node`](./structure/stack/stacklinkedlist.go#L13): No description provided. + +2. [`SList`](./structure/stack/stacklinkedlistwithlist.go#L18): No description provided. + +3. [`Stack`](./structure/stack/stacklinkedlist.go#L19): No description provided. + + +--- +
+ transposition + +--- + +##### Functions: + +1. [`Decrypt`](./cipher/transposition/transposition.go#L82): No description provided. +2. [`Encrypt`](./cipher/transposition/transposition.go#L54): No description provided. + +--- +##### Types + +1. [`KeyMissingError`](./cipher/transposition/transposition.go#L16): No description provided. + +2. [`NoTextToEncryptError`](./cipher/transposition/transposition.go#L15): No description provided. + + +--- +
+ trie + +--- + +##### Package trie provides Trie data structures in golang. Wikipedia: https://en.wikipedia.org/wiki/Trie + +--- +##### Functions: + +1. [`NewNode`](./structure/trie/trie.go#L14): NewNode creates a new Trie node with initialized children map. + +--- +##### Types + +1. [`Node`](./structure/trie/trie.go#L7): No description provided. + + +--- +
+ xor + +--- + +##### Package xor is an encryption algorithm that operates the exclusive disjunction(XOR) ref: https://en.wikipedia.org/wiki/XOR_cipher + +--- +##### Functions: + +1. [`Decrypt`](./cipher/xor/xor.go#L19): Decrypt decrypts with Xor encryption +2. [`Encrypt`](./cipher/xor/xor.go#L10): Encrypt encrypts with Xor encryption after converting each character to byte The returned value might not be readable because there is no guarantee which is within the ASCII range If using other type such as string, []int, or some other types, add the statements for converting the type to []byte. + +--- +
+ diff --git a/conversion/binarytodecimal.go b/conversion/binarytodecimal.go index 54ac7993a..bc67745fd 100644 --- a/conversion/binarytodecimal.go +++ b/conversion/binarytodecimal.go @@ -10,7 +10,6 @@ Date: 19-Oct-2021 // Function receives a Binary Number as string and returns the Decimal number as integer. // Supported Binary number range is 0 to 2^(31-1). -// Package name. package conversion // Importing necessary package. diff --git a/conversion/decimaltobinary.go b/conversion/decimaltobinary.go index f5cc9bbbe..63ef8b1c0 100644 --- a/conversion/decimaltobinary.go +++ b/conversion/decimaltobinary.go @@ -9,7 +9,6 @@ Date: 14-Oct-2021 // Function receives a integer as a Decimal number and returns the Binary number. // Supported integer value range is 0 to 2^(31 -1). -// Package name. package conversion // Importing necessary package. diff --git a/graph/bellmanford.go b/graph/bellmanford.go index 6fe3e42c9..c9e791f6d 100644 --- a/graph/bellmanford.go +++ b/graph/bellmanford.go @@ -3,6 +3,7 @@ // It is slower than Dijkstra but capable of handling negative edge weights. // https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm // Implementation is based on the book 'Introduction to Algorithms' (CLRS) + package graph import ( diff --git a/math/binary/xorsearch_test.go b/math/binary/xorsearch_test.go index 40bc8a8ef..2168a49f6 100644 --- a/math/binary/xorsearch_test.go +++ b/math/binary/xorsearch_test.go @@ -2,6 +2,7 @@ // description: Test for Find a missing number in a sequence // author(s) [red_byte](https://github.com/i-redbyte) // see xorsearch.go + package binary import ( diff --git a/sort/countingsort.go b/sort/countingsort.go index 9ac7fbdfc..3dae5934a 100644 --- a/sort/countingsort.go +++ b/sort/countingsort.go @@ -4,7 +4,6 @@ // author [Phil](https://github.com/pschik) // see sort_test.go for a test implementation, test function TestQuickSort -// package sort provides primitives for sorting slices and user-defined collections package sort func Count(data []int) []int { diff --git a/structure/set/set.go b/structure/set/set.go index 32624b63a..00ffd0629 100644 --- a/structure/set/set.go +++ b/structure/set/set.go @@ -1,3 +1,6 @@ +// package set implements a Set using a golang map. +// This implies that only the types that are accepted as valid map keys can be used as set elements. +// For instance, do not try to Add a slice, or the program will panic. package set // New gives new set. diff --git a/structure/set/set_test.go b/structure/set/set_test.go index 35ccaa5d7..b07fe89a2 100644 --- a/structure/set/set_test.go +++ b/structure/set/set_test.go @@ -1,6 +1,3 @@ -// package set implements a Set using a golang map. -// This implies that only the types that are accepted as valid map keys can be used as set elements. -// For instance, do not try to Add a slice, or the program will panic. package set import ( diff --git a/structure/set/setexample_test.go b/structure/set/setexample_test.go index 801298217..7cd929462 100644 --- a/structure/set/setexample_test.go +++ b/structure/set/setexample_test.go @@ -1,7 +1,3 @@ -// package set implements a Set using a golang map. -// This implies that only the types that are accepted as valid map keys can be used as set elements. -// For instance, do not try to Add a slice, or the program will panic. -// package set import ( From a671c904d9153474c9ca85d0bdf27b132afc25c7 Mon Sep 17 00:00:00 2001 From: Taj Date: Wed, 10 Nov 2021 04:30:08 +0000 Subject: [PATCH 291/488] fix: godocmd (#432) --- .github/workflows/godocmd.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index 86abaa4cc..6494d6bd7 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -5,6 +5,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - uses: actions/setup-go@v2 with: go-version: '^1.17' From 9f8a45b39b9cb645d6d6f6b13ffa3d1cc3830730 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Wed, 10 Nov 2021 08:00:24 +0300 Subject: [PATCH 292/488] merge: Feat/catalan number (#430) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: Catalan number * fix: add details * fix: change test struct * Updated Documentation in README.md Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 10 ++++++++ math/catalan/catalannumber.go | 17 ++++++++++++++ math/catalan/catalannumber_test.go | 37 ++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 math/catalan/catalannumber.go create mode 100644 math/catalan/catalannumber_test.go diff --git a/README.md b/README.md index 9d6dc902a..a6d6afd99 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Decrypt`](./cipher/caesar/caesar.go#L27): Decrypt decrypts by left shift of "key" each character of "input" 2. [`Encrypt`](./cipher/caesar/caesar.go#L6): Encrypt encrypts by right shift of "key" each character of "input" +--- +
+ catalan + +--- + +##### Functions: + +1. [`CatalanNumber`](./math/catalan/catalannumber.go#L15): No description provided. + ---
coloring diff --git a/math/catalan/catalannumber.go b/math/catalan/catalannumber.go new file mode 100644 index 000000000..b899d2569 --- /dev/null +++ b/math/catalan/catalannumber.go @@ -0,0 +1,17 @@ +// catalannumber.go +// description: Returns the Catalan number +// details: +// In combinatorial mathematics, the Catalan numbers are a sequence of natural numbers that occur in various counting problems, often involving recursively defined objects. - [Catalan number](https://en.wikipedia.org/wiki/Catalan_number) +// The input is the number of the Catalan number n, at the output we get the value of the number +// author(s) [red_byte](https://github.com/i-redbyte) +// see catalannumber_test.go + +package catalan + +import ( + f "github.com/TheAlgorithms/Go/math/factorial" +) + +func CatalanNumber(n int) int { + return f.BruteForceFactorial(n*2) / (f.BruteForceFactorial(n) * f.BruteForceFactorial(n+1)) +} diff --git a/math/catalan/catalannumber_test.go b/math/catalan/catalannumber_test.go new file mode 100644 index 000000000..6d7896d35 --- /dev/null +++ b/math/catalan/catalannumber_test.go @@ -0,0 +1,37 @@ +// catalannumber_test.go +// description: Test for returns the Catalan number +// author(s) [red_byte](https://github.com/i-redbyte) +// see catalannumber.go + +package catalan + +import "testing" + +func TestCatalanNumber(t *testing.T) { + tests := []struct { + name string + n int + want int + }{ + {"zero Catalan number ", 0, 1}, + {"second Catalan number ", 2, 2}, + {"third Catalan number ", 3, 5}, + {"fourth Catalan number ", 4, 14}, + {"fifth Catalan number ", 5, 42}, + {"sixth Catalan number ", 6, 132}, + {"tenth Catalan number ", 10, 16796}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := CatalanNumber(test.n); got != test.want { + t.Errorf("CatalanNumber() = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkCatalanNumber(b *testing.B) { + for i := 0; i < b.N; i++ { + CatalanNumber(10) + } +} From 37cb38e9d91f675ef3b2f53663d8fb5a6fce6159 Mon Sep 17 00:00:00 2001 From: kavithajm <91771245+kavithajm@users.noreply.github.com> Date: Fri, 12 Nov 2021 00:22:11 +0530 Subject: [PATCH 293/488] Comb Sort algorithm implementation (#407) * Adding comb sort * Update sort/combSort.go Co-authored-by: Taj * Updating test for comb sort * Updated Documentation in README.md Co-authored-by: Taj Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 27 ++++++++++++++------------- sort/combSort.go | 30 ++++++++++++++++++++++++++++++ sort/sorts_test.go | 8 ++++++++ 3 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 sort/combSort.go diff --git a/README.md b/README.md index a6d6afd99..a5c904b18 100644 --- a/README.md +++ b/README.md @@ -758,19 +758,20 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`Count`](./sort/countingsort.go#L9): No description provided. -2. [`Exchange`](./sort/exchangesort.go#L6): No description provided. -3. [`HeapSort`](./sort/heapsort.go#L121): No description provided. -4. [`ImprovedSimpleSort`](./sort/simplesort.go#L25): ImprovedSimpleSort is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort -5. [`InsertionSort`](./sort/insertionsort.go#L3): No description provided. -6. [`Mergesort`](./sort/mergesort.go#L35): Mergesort Perform mergesort on a slice of ints -7. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. -8. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array -9. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array -10. [`RadixSort`](./sort/radixsort.go#L35): No description provided. -11. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. -12. [`ShellSort`](./sort/shellsort.go#L3): No description provided. -13. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. +1. [`Comb`](./sort/combSort.go#L14): No description provided. +2. [`Count`](./sort/countingsort.go#L9): No description provided. +3. [`Exchange`](./sort/exchangesort.go#L6): No description provided. +4. [`HeapSort`](./sort/heapsort.go#L121): No description provided. +5. [`ImprovedSimpleSort`](./sort/simplesort.go#L25): ImprovedSimpleSort is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort +6. [`InsertionSort`](./sort/insertionsort.go#L3): No description provided. +7. [`Mergesort`](./sort/mergesort.go#L35): Mergesort Perform mergesort on a slice of ints +8. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. +9. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array +10. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array +11. [`RadixSort`](./sort/radixsort.go#L35): No description provided. +12. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. +13. [`ShellSort`](./sort/shellsort.go#L3): No description provided. +14. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. --- ##### Types diff --git a/sort/combSort.go b/sort/combSort.go new file mode 100644 index 000000000..fa7b173d9 --- /dev/null +++ b/sort/combSort.go @@ -0,0 +1,30 @@ +// Implementation of comb sort algorithm, an improvement of bubble sort +// Reference: https://www.geeksforgeeks.org/comb-sort/ + +package sort + +func getNextGap(gap int) int { + gap = (gap * 10) / 13 + if gap < 1 { + return 1 + } + return gap +} + +func Comb(data []int) []int { + n := len(data) + gap := n + swapped := true + + for gap != 1 || swapped { + gap = getNextGap(gap) + swapped = false + for i := 0; i < n-gap; i++ { + if data[i] > data[i+gap] { + data[i], data[i+gap] = data[i+gap], data[i] + swapped = true + } + } + } + return data +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 5342121cc..be239205e 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -122,6 +122,10 @@ func TestSelection(t *testing.T) { testFramework(t, SelectionSort) } +func TestComb(t *testing.T) { + testFramework(t, Comb) +} + func TestPigeonhole(t *testing.T) { testFramework(t, Pigeonhole) } @@ -216,6 +220,10 @@ func BenchmarkSelection(b *testing.B) { benchmarkFramework(b, SelectionSort) } +func BenchmarkComb(b *testing.B) { + benchmarkFramework(b, Comb) +} + func BenchmarkPigeonhole(b *testing.B) { benchmarkFramework(b, Pigeonhole) } From eb39cb7b8f1d2aedc32a80856e15d2c6da672324 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Fri, 12 Nov 2021 09:57:55 +0300 Subject: [PATCH 294/488] Feat/pascal (#433) Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 10 ++++++++ math/pascal/pascaltriangle.go | 34 +++++++++++++++++++++++++++ math/pascal/pascaltriangle_test.go | 37 ++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 math/pascal/pascaltriangle.go create mode 100644 math/pascal/pascaltriangle_test.go diff --git a/README.md b/README.md index a5c904b18..706c86e9a 100644 --- a/README.md +++ b/README.md @@ -565,6 +565,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`IsPalindrome`](./strings/palindrome/ispalindrome.go#L26): No description provided. +--- +
+ pascal + +--- + +##### Functions: + +1. [`GenerateTriangle`](./math/pascal/pascaltriangle.go#L24): GenerateTriangle This function generates a Pascal's triangle of n lines + ---
password diff --git a/math/pascal/pascaltriangle.go b/math/pascal/pascaltriangle.go new file mode 100644 index 000000000..12f227fd0 --- /dev/null +++ b/math/pascal/pascaltriangle.go @@ -0,0 +1,34 @@ +// pascaltriangle.go +// description: Pascal's triangle +// details: +// Pascal's triangle is a triangular array of the binomial coefficients that arises in probability theory, combinatorics, and algebra. - [Pascal's triangle](https://en.wikipedia.org/wiki/Pascal%27s_triangle) +// example: +//1 +//1 1 +//1 2 1 +//1 3 3 1 +//1 4 6 4 1 +//1 5 10 10 5 1 +//1 6 15 20 15 6 1 +//1 7 21 35 35 21 7 1 +//1 8 28 56 70 56 28 8 1 +//1 9 36 84 126 126 84 36 9 1 +//1 10 45 120 210 252 210 120 45 10 1 +//... +// author(s) [red_byte](https://github.com/i-redbyte) +// see pascaltriangle_test.go + +package pascal + +// GenerateTriangle This function generates a Pascal's triangle of n lines +func GenerateTriangle(n int) [][]int { + var triangle = make([][]int, n) + for i := 0; i < n; i++ { + triangle[i] = make([]int, i+1) + triangle[i][0], triangle[i][i] = 1, 1 + for j := 1; j < i; j++ { + triangle[i][j] = triangle[i-1][j] + triangle[i-1][j-1] + } + } + return triangle +} diff --git a/math/pascal/pascaltriangle_test.go b/math/pascal/pascaltriangle_test.go new file mode 100644 index 000000000..33fe53e2c --- /dev/null +++ b/math/pascal/pascaltriangle_test.go @@ -0,0 +1,37 @@ +// pascaltriangle_test.go +// description: Test for Pascal's triangle +// author(s) [red_byte](https://github.com/i-redbyte) +// see pascaltriangle.go + +package pascal + +import ( + "reflect" + "testing" +) + +func TestGenerateTriangle(t *testing.T) { + tests := []struct { + name string + n int + want [][]int + }{ + {name: "Pascal's three-line triangle", n: 3, want: [][]int{{1}, {1, 1}, {1, 2, 1}}}, + {name: "Pascal's 0-line triangle", n: 0, want: [][]int{}}, + {name: "Pascal's one-line triangle", n: 1, want: [][]int{{1}}}, + {name: "Pascal's 7-line triangle", n: 7, want: [][]int{{1}, {1, 1}, {1, 2, 1}, {1, 3, 3, 1}, {1, 4, 6, 4, 1}, {1, 5, 10, 10, 5, 1}, {1, 6, 15, 20, 15, 6, 1}}}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := GenerateTriangle(test.n); !reflect.DeepEqual(got, test.want) { + t.Errorf("GenerateTriangle() = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkGenerateTriangle(b *testing.B) { + for i := 0; i < b.N; i++ { + GenerateTriangle(10) + } +} From 28b4df5eab31f96a71ea3e4d7b69df033b8d2e52 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Fri, 12 Nov 2021 23:39:59 +0100 Subject: [PATCH 295/488] test: improve coverage on hashmap package (#435) * test: improve coverage on hashmap package * Updated Documentation in README.md Co-authored-by: Michele Caci Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 3 ++- structure/hashmap/hashmap.go | 9 +++++++++ structure/hashmap/hashmap_test.go | 30 ++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 706c86e9a..cc96f6fe3 100644 --- a/README.md +++ b/README.md @@ -386,7 +386,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`New`](./structure/hashmap/hashmap.go#L24): New return new HashMap instance +1. [`Make`](./structure/hashmap/hashmap.go#L32): Make creates a new HashMap instance with input size and capacity +2. [`New`](./structure/hashmap/hashmap.go#L24): New return new HashMap instance --- ##### Types diff --git a/structure/hashmap/hashmap.go b/structure/hashmap/hashmap.go index bd03e641f..1665a50c7 100644 --- a/structure/hashmap/hashmap.go +++ b/structure/hashmap/hashmap.go @@ -28,6 +28,15 @@ func New() *HashMap { } } +// Make creates a new HashMap instance with input size and capacity +func Make(size, capacity uint64) HashMap { + return HashMap{ + size: size, + capacity: capacity, + table: make([]*node, capacity), + } +} + // Get returns value associated with given key func (hm *HashMap) Get(key interface{}) interface{} { node := hm.getNodeByHash(hm.hash(key)) diff --git a/structure/hashmap/hashmap_test.go b/structure/hashmap/hashmap_test.go index 64a276d46..2b0030b7e 100644 --- a/structure/hashmap/hashmap_test.go +++ b/structure/hashmap/hashmap_test.go @@ -1,12 +1,14 @@ -package hashmap +package hashmap_test import ( "testing" + + "github.com/TheAlgorithms/Go/structure/hashmap" ) func TestHashMap(t *testing.T) { - mp := New() + mp := hashmap.New() t.Run("Test 1: Put(10) and checking if Get() is correct", func(t *testing.T) { mp.Put("test", 10) @@ -48,12 +50,32 @@ func TestHashMap(t *testing.T) { } }) - t.Run("Test 6: Checking if the key that doesn't exists returns false", func(t *testing.T) { + t.Run("Test 6: Checking if the key that does not exist returns false", func(t *testing.T) { want := false got := mp.Contains(2) if got != want { - t.Errorf("Key '2' doesn't exists in the map but it says otherwise") + t.Errorf("Key '2' does not exist in the map but it says otherwise") + } + }) + + t.Run("Test 7: Checking if the key does not exist Get func returns nil", func(t *testing.T) { + want := interface{}(nil) + got := mp.Get(2) + if got != want { + t.Errorf("Key '2' does not exists in the map but it says otherwise") } }) + t.Run("Test 8: Resizing a map", func(t *testing.T) { + mp := hashmap.Make(4, 4) + + for i := 0; i < 20; i++ { + mp.Put(i, 40) + } + + got := mp.Get(5) + if got != 40 { + t.Errorf("Put: %v, Got: %v", got, 40) + } + }) } From e9ba9c447d7084caa6bf68b944ee881a41a68ca3 Mon Sep 17 00:00:00 2001 From: kavithajm <91771245+kavithajm@users.noreply.github.com> Date: Wed, 17 Nov 2021 14:17:12 +0530 Subject: [PATCH 296/488] merge: Add Pangram program (#441) * Add Pangram program * Updated Documentation in README.md Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 10 ++++++ strings/pangram/ispangram.go | 31 ++++++++++++++++++ strings/pangram/ispangram_test.go | 53 +++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 strings/pangram/ispangram.go create mode 100644 strings/pangram/ispangram_test.go diff --git a/README.md b/README.md index cc96f6fe3..aad7edd56 100644 --- a/README.md +++ b/README.md @@ -566,6 +566,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`IsPalindrome`](./strings/palindrome/ispalindrome.go#L26): No description provided. +--- +
+ pangram + +--- + +##### Functions: + +1. [`IsPangram`](./strings/pangram/ispangram.go#L21): No description provided. + ---
pascal diff --git a/strings/pangram/ispangram.go b/strings/pangram/ispangram.go new file mode 100644 index 000000000..18d9f90b4 --- /dev/null +++ b/strings/pangram/ispangram.go @@ -0,0 +1,31 @@ +// ispangram.go +// description: Checks if a given string is pangram or not +// details: A pangram is a sentence or expression that uses all the letters of the alphabet. +// Reference: https://www.geeksforgeeks.org/pangram-checking/ +// Author : Kavitha J + +package pangram + +import ( + "regexp" + "strings" +) + +func cleanString(text string) string { + cleanText := strings.ToLower(text) // Convert to lowercase + cleanText = strings.Join(strings.Fields(cleanText), "") // Remove spaces + regex, _ := regexp.Compile(`[^\p{L}\p{N} ]+`) // Regular expression for alphanumeric only characters + return regex.ReplaceAllString(cleanText, "") +} + +func IsPangram(text string) bool { + cleanText := cleanString(text) + if len(cleanText) < 26 { + return false + } + var data = make(map[rune]bool) + for _, i := range cleanText { + data[i] = true + } + return len(data) == 26 +} diff --git a/strings/pangram/ispangram_test.go b/strings/pangram/ispangram_test.go new file mode 100644 index 000000000..29e48de21 --- /dev/null +++ b/strings/pangram/ispangram_test.go @@ -0,0 +1,53 @@ +package pangram + +import ( + "testing" +) + +var testCases = []struct { + name string // test description + input string // user input + expected bool // expected return +}{ + { + "empty string", + "", + false, + }, + { + "non pangram string without spaces", + "abc", + false, + }, + { + "non pangram string with spaces", + "Hello World", + false, + }, + { + "Pangram string 1", + " Abcdefghijklmnopqrstuvwxyz", + true, + }, + { + "pangram string 2", + "cdefghijklmnopqrstuvwxABC zyb", + true, + }, + { + "pangram string 3", + "The Quick Brown Fox Jumps Over the Lazy Dog", + true, + }, +} + +func TestIsPangram(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + func_result := IsPangram(test.input) + if test.expected != func_result { + t.Errorf("Expected answer '%t' for string '%s' but answer given was %t", test.expected, test.input, func_result) + } + }) + } +} From 9fec515fa43429012d1eba1b4924d8db953d36a4 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Wed, 17 Nov 2021 11:55:08 +0300 Subject: [PATCH 297/488] merge: Feat: bits counter (#439) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: bits counter * Updated Documentation in README.md * fix: change test cases name Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 13 +++++++------ math/binary/bitcounter.go | 20 ++++++++++++++++++++ math/binary/bitcounter_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 math/binary/bitcounter.go create mode 100644 math/binary/bitcounter_test.go diff --git a/README.md b/README.md index aad7edd56..d8a2b8894 100644 --- a/README.md +++ b/README.md @@ -79,12 +79,13 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. -2. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 -3. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L11): No description provided. -4. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L15): No description provided. -5. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. -6. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L10): No description provided. +1. [`BitCounter`](./math/binary/bitcounter.go#L11): BitCounter - The function returns the number of set bits for an unsigned integer number +2. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. +3. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 +4. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L11): No description provided. +5. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L15): No description provided. +6. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. +7. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L10): No description provided. ---
diff --git a/math/binary/bitcounter.go b/math/binary/bitcounter.go new file mode 100644 index 000000000..33e24256d --- /dev/null +++ b/math/binary/bitcounter.go @@ -0,0 +1,20 @@ +// bitcounter.go +// description: Counts the number of set bits in a number +// details: +// For unsigned integer number N, return the number of bits set to 1 - [Bit numbering](https://en.wikipedia.org/wiki/Bit_numbering) +// author(s) [red_byte](https://github.com/i-redbyte) +// see bitcounter_test.go + +package binary + +// BitCounter - The function returns the number of set bits for an unsigned integer number +func BitCounter(n uint) int { + counter := 0 + for n != 0 { + if n&1 == 1 { + counter++ + } + n >>= 1 + } + return counter +} diff --git a/math/binary/bitcounter_test.go b/math/binary/bitcounter_test.go new file mode 100644 index 000000000..f5d61ec3f --- /dev/null +++ b/math/binary/bitcounter_test.go @@ -0,0 +1,33 @@ +// bitcounter_test.go +// description: Test for counts the number of set bits in a number +// author(s) [red_byte](https://github.com/i-redbyte) +// see bitcounter.go + +package binary + +import "testing" + +func TestBitCounter(t *testing.T) { + tests := []struct { + name string + number uint + want int + }{ + {"Number of bits in a number 0", 0, 0}, + {"Number of bits in a number 1", 1, 1}, + {"Number of bits in a number 255", 255, 8}, + {"Number of bits in a number 7", 7, 3}, + {"Number of bits in a number 8", 8, 1}, + {"Number of bits in a number 9223372036854775807", 9223372036854775807, 63}, + {"Number of bits in a number 2147483647", 2147483647, 31}, + {"Number of bits in a number 15", 15, 4}, + {"Number of bits in a number 16", 16, 1}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := BitCounter(test.number); got != test.want { + t.Errorf("BitCounter() = %v, want %v", got, test.want) + } + }) + } +} From 57a20cf48ea0d2dcdb63bf50da65977e358189ff Mon Sep 17 00:00:00 2001 From: kavithajm <91771245+kavithajm@users.noreply.github.com> Date: Fri, 19 Nov 2021 22:41:09 +0530 Subject: [PATCH 298/488] Adding program to check if the number is an Armstrong number (#442) * Adding program to check if the number is an armstrong number * Updated Documentation in README.md * Update loop in isarmstrong Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 10 ++++++ math/armstrong/isarmstrong.go | 32 ++++++++++++++++++ math/armstrong/isarmstrong_test.go | 53 ++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 math/armstrong/isarmstrong.go create mode 100644 math/armstrong/isarmstrong_test.go diff --git a/README.md b/README.md index d8a2b8894..f88a49ea1 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Result`](./strings/ahocorasick/ahocorasick.go#L9): No description provided. +--- +
+ armstrong + +--- + +##### Functions: + +1. [`IsArmstrong`](./math/armstrong/isarmstrong.go#L14): No description provided. + ---
avl diff --git a/math/armstrong/isarmstrong.go b/math/armstrong/isarmstrong.go new file mode 100644 index 000000000..68055dee8 --- /dev/null +++ b/math/armstrong/isarmstrong.go @@ -0,0 +1,32 @@ +// isarmstrong.go +// description: Checks if the given number is armstrong number or not +// details: An Armstrong number is a n-digit number that is equal to the sum of each of its digits taken to the nth power. +// ref: https://mathlair.allfunandgames.ca/armstrong.php +// author: Kavitha J + +package armstrong + +import ( + "math" + "strconv" +) + +func IsArmstrong(number int) bool { + var rightMost int + var sum int = 0 + var tempNum int = number + + // to get the number of digits in the number + length := float64(len(strconv.Itoa(number))) + + // get the right most digit and break the loop once all digits are iterated + for tempNum > 0 { + rightMost = tempNum % 10 + sum += int(math.Pow(float64(rightMost), length)) + + // update the input digit minus the processed rightMost + tempNum /= 10 + } + + return number == sum +} diff --git a/math/armstrong/isarmstrong_test.go b/math/armstrong/isarmstrong_test.go new file mode 100644 index 000000000..bab9601c8 --- /dev/null +++ b/math/armstrong/isarmstrong_test.go @@ -0,0 +1,53 @@ +// isarmstrong_test.go + +package armstrong + +import "testing" + +var testCases = []struct { + name string // test description + input int // user input + expected bool // expected return +}{ + { + "negative number: Not an armstrong number", + -140, + false, + }, + { + "positive number: Not an armstrong number", + 23, + false, + }, + { + "smallest armstrong number", + 0, + true, + }, + { + "smallest armstrong number with more than one digit", + 153, + true, + }, + { + "random armstrong number", + 407, + true, + }, + { + "random armstrong number", + 9474, + true, + }, +} + +func TestIsArmstrong(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + funcResult := IsArmstrong(test.input) + if test.expected != funcResult { + t.Errorf("Expected answer '%t' for the number '%d' but answer given was %t", test.expected, test.input, funcResult) + } + }) + } +} From 6fd8a07848d9ac72601205777714f7b86474bf06 Mon Sep 17 00:00:00 2001 From: Paul Leydier <75126792+paul-leydier@users.noreply.github.com> Date: Fri, 19 Nov 2021 19:44:12 +0100 Subject: [PATCH 299/488] feat: add Conversion/base64 algorithm (#437) * feat: base64 encoding * test: base64 encoding * docs: Added base64 declaration to README.md * feat: use string builder to drastically improve efficiency of Encode * docs: formatting * feat: base64 decoding * test: base64 decoding * docs: added base64 Decode function to README.md * test: test base64 Encode and Decode inverse functions * docs: base64 Decode docstring * docs: improve package documentation Co-authored-by: Taj * feat: remove usage of predefined return values * feat: base64 move to conversion package * fix: remove deleted line in README.md * Update conversion/base64.go * Update conversion/base64.go Co-authored-by: Taj Co-authored-by: Rak Laptudirm Co-authored-by: Andrii Siriak --- conversion/base64.go | 81 ++++++++++++++++++++++++++++ conversion/base64_test.go | 111 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 conversion/base64.go create mode 100644 conversion/base64_test.go diff --git a/conversion/base64.go b/conversion/base64.go new file mode 100644 index 000000000..8828f6a7a --- /dev/null +++ b/conversion/base64.go @@ -0,0 +1,81 @@ +// base64.go +// description: The base64 encoding algorithm as defined in the RFC4648 standard. +// author: [Paul Leydier] (https://github.com/paul-leydier) +// ref: https://datatracker.ietf.org/doc/html/rfc4648#section-4 +// ref: https://en.wikipedia.org/wiki/Base64 +// see base64_test.go + +package conversion + +import ( + "strings" // Used for efficient string builder (more efficient than simply appending strings) +) + +const Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +// Base64Encode encodes the received input bytes slice into a base64 string. +// The implementation follows the RFC4648 standard, which is documented +// at https://datatracker.ietf.org/doc/html/rfc4648#section-4 +func Base64Encode(input []byte) string { + var sb strings.Builder + // If not 24 bits (3 bytes) multiple, pad with 0 value bytes, and with "=" for the output + var padding string + for i := len(input) % 3; i > 0 && i < 3; i++ { + var zeroByte byte + input = append(input, zeroByte) + padding += "=" + } + + // encode 24 bits per 24 bits (3 bytes per 3 bytes) + for i := 0; i < len(input); i += 3 { + // select 3 8-bit input groups, and re-arrange them into 4 6-bit groups + // the literal 0x3F corresponds to the byte "0011 1111" + // the operation "byte & 0x3F" masks the two left-most bits + group := [4]byte{ + input[i] >> 2, + (input[i]<<4)&0x3F + input[i+1]>>4, + (input[i+1]<<2)&0x3F + input[i+2]>>6, + input[i+2] & 0x3F, + } + + // translate each group into a char using the static map + for _, b := range group { + sb.WriteString(string(Alphabet[int(b)])) + } + } + encoded := sb.String() + + // Apply the output padding + encoded = encoded[:len(encoded)-len(padding)] + padding[:] + + return encoded +} + +// Base64Decode decodes the received input base64 string into a byte slice. +// The implementation follows the RFC4648 standard, which is documented +// at https://datatracker.ietf.org/doc/html/rfc4648#section-4 +func Base64Decode(input string) []byte { + padding := strings.Count(input, "=") // Number of bytes which will be ignored + var decoded []byte + + // select 4 6-bit input groups, and re-arrange them into 3 8-bit groups + for i := 0; i < len(input); i += 4 { + // translate each group into a byte using the static map + byteInput := [4]byte{ + byte(strings.IndexByte(Alphabet, input[i])), + byte(strings.IndexByte(Alphabet, input[i+1])), + byte(strings.IndexByte(Alphabet, input[i+2])), + byte(strings.IndexByte(Alphabet, input[i+3])), + } + + group := [3]byte{ + byteInput[0]<<2 + byteInput[1]>>4, + byteInput[1]<<4 + byteInput[2]>>2, + byteInput[2]<<6 + byteInput[3], + } + + decoded = append(decoded, group[:]...) + } + + return decoded[:len(decoded)-padding] +} diff --git a/conversion/base64_test.go b/conversion/base64_test.go new file mode 100644 index 000000000..ed882634c --- /dev/null +++ b/conversion/base64_test.go @@ -0,0 +1,111 @@ +package conversion + +import "testing" + +func TestBase64Encode(t *testing.T) { + testCases := []struct { + in string + expected string + }{ + {"Hello World!", "SGVsbG8gV29ybGQh"}, // multiple of 3 byte length (multiple of 24-bits) + {"Hello World!a", "SGVsbG8gV29ybGQhYQ=="}, // multiple of 3 byte length + 1 + {"Hello World!ab", "SGVsbG8gV29ybGQhYWI="}, // multiple of 3 byte length + 2 + {"", ""}, // empty byte slice + {"6", "Ng=="}, // short text + {"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg=="}, // Long text + } + + for _, tc := range testCases { + result := Base64Encode([]byte(tc.in)) + if result != tc.expected { + t.Fatalf("Base64Encode(%s) = %s, want %s", tc.in, result, tc.expected) + } + } +} + +func BenchmarkBase64Encode(b *testing.B) { + benchmarks := []struct { + name string + in string + expected string + }{ + {"Hello World!", "Hello World!", "SGVsbG8gV29ybGQh"}, // multiple of 3 byte length (multiple of 24-bits) + {"Hello World!a", "Hello World!a", "SGVsbG8gV29ybGQhYQ=="}, // multiple of 3 byte length + 1 + {"Hello World!ab", "Hello World!ab", "SGVsbG8gV29ybGQhYWI="}, // multiple of 3 byte length + 2 + {"Empty", "", ""}, // empty byte slice + {"6", "6", "Ng=="}, // short text + {"Lorem ipsum", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg=="}, // Long text + } + + for _, bm := range benchmarks { + b.Run(bm.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + Base64Encode([]byte(bm.in)) + } + }) + } +} + +func TestBase64Decode(t *testing.T) { + testCases := []struct { + expected string + in string + }{ + {"Hello World!", "SGVsbG8gV29ybGQh"}, // multiple of 3 byte length (multiple of 24-bits) + {"Hello World!a", "SGVsbG8gV29ybGQhYQ=="}, // multiple of 3 byte length + 1 + {"Hello World!ab", "SGVsbG8gV29ybGQhYWI="}, // multiple of 3 byte length + 2 + {"", ""}, // empty byte slice + {"6", "Ng=="}, // short text + {"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg=="}, // Long text + } + + for _, tc := range testCases { + result := string(Base64Decode(tc.in)) + if result != tc.expected { + t.Fatalf("Base64Decode(%s) = %s, want %s", tc.in, result, tc.expected) + } + } +} + +func BenchmarkBase64Decode(b *testing.B) { + benchmarks := []struct { + name string + expected string + in string + }{ + {"Hello World!", "Hello World!", "SGVsbG8gV29ybGQh"}, // multiple of 3 byte length (multiple of 24-bits) + {"Hello World!a", "Hello World!a", "SGVsbG8gV29ybGQhYQ=="}, // multiple of 3 byte length + 1 + {"Hello World!ab", "Hello World!ab", "SGVsbG8gV29ybGQhYWI="}, // multiple of 3 byte length + 2 + {"Empty", "", ""}, // empty byte slice + {"6", "6", "Ng=="}, // short text + {"Lorem ipsum", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBpbiByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xvcmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNhdCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lhIGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg=="}, // Long text + } + + for _, bm := range benchmarks { + b.Run(bm.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + Base64Decode(bm.in) + } + }) + } +} + +func TestBase64EncodeDecodeInverse(t *testing.T) { + testCases := []struct { + in string + }{ + {"Hello World!"}, // multiple of 3 byte length (multiple of 24-bits) + {"Hello World!a"}, // multiple of 3 byte length + 1 + {"Hello World!ab"}, // multiple of 3 byte length + 2 + {""}, // empty byte slice + {"6"}, // short text + {"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."}, // Long text + } + + for _, tc := range testCases { + result := string(Base64Decode(Base64Encode([]byte(tc.in)))) + if result != tc.in { + t.Fatalf("Base64Decode(Base64Encode(%s)) = %s, want %s", tc.in, result, tc.in) + } + } +} From 385fe843dfe8de60dc9fb4288d2c7d7ed4d843f6 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Mon, 22 Nov 2021 16:38:14 +0300 Subject: [PATCH 300/488] fix: docs (#445) Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 34 ++++++++++++++-------------- math/binary/arithmeticmean.go | 2 ++ math/binary/xorsearch.go | 1 + math/catalan/catalannumber.go | 3 ++- math/factorial/factorial.go | 11 +++++---- math/factorial/factorial_test.go | 12 +++++----- math/max/bitwisemax.go | 3 ++- math/max/bitwisemax_test.go | 38 ++++++++++++++++---------------- math/min/bitwisemin.go | 1 + 9 files changed, 58 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index f88a49ea1..1fca7fa00 100644 --- a/README.md +++ b/README.md @@ -92,10 +92,10 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`BitCounter`](./math/binary/bitcounter.go#L11): BitCounter - The function returns the number of set bits for an unsigned integer number 2. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. 3. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 -4. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L11): No description provided. -5. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L15): No description provided. +4. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations +5. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift 6. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. -7. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L10): No description provided. +7. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---
@@ -146,7 +146,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`CatalanNumber`](./math/catalan/catalannumber.go#L15): No description provided. +1. [`CatalanNumber`](./math/catalan/catalannumber.go#L16): CatalanNumber This function returns the `nth` Catalan number ---
@@ -197,13 +197,15 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`BinaryToDecimal`](./conversion/binarytodecimal.go#L25): BinaryToDecimal() function that will take Binary number as string, and return it's Decimal equivalent as integer. -2. [`DecimalToBinary`](./conversion/decimaltobinary.go#L32): DecimalToBinary() function that will take Decimal number as int, and return it's Binary equivalent as string. -3. [`HEXToRGB`](./conversion/rgbhex.go#L10): HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) into the individual components: red, green and blue -4. [`IntToRoman`](./conversion/integertoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. -5. [`RGBToHEX`](./conversion/rgbhex.go#L41): RGBToHEX does exactly the opposite of HEXToRGB: it combines the three components red, green and blue to an RGB value, which can be converted to e.g. Hex -6. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. -7. [`RomanToInteger`](./conversion/romantointeger.go#L40): RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. +1. [`Base64Decode`](./conversion/base64.go#L57): Base64Decode decodes the received input base64 string into a byte slice. The implementation follows the RFC4648 standard, which is documented at https://datatracker.ietf.org/doc/html/rfc4648#section-4 +2. [`Base64Encode`](./conversion/base64.go#L19): Base64Encode encodes the received input bytes slice into a base64 string. The implementation follows the RFC4648 standard, which is documented at https://datatracker.ietf.org/doc/html/rfc4648#section-4 +3. [`BinaryToDecimal`](./conversion/binarytodecimal.go#L25): BinaryToDecimal() function that will take Binary number as string, and return it's Decimal equivalent as integer. +4. [`DecimalToBinary`](./conversion/decimaltobinary.go#L32): DecimalToBinary() function that will take Decimal number as int, and return it's Binary equivalent as string. +5. [`HEXToRGB`](./conversion/rgbhex.go#L10): HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) into the individual components: red, green and blue +6. [`IntToRoman`](./conversion/integertoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. +7. [`RGBToHEX`](./conversion/rgbhex.go#L41): RGBToHEX does exactly the opposite of HEXToRGB: it combines the three components red, green and blue to an RGB value, which can be converted to e.g. Hex +8. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. +9. [`RomanToInteger`](./conversion/romantointeger.go#L40): RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. ---
@@ -272,9 +274,9 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`BruteForceFactorial`](./math/factorial/factorial.go#L11): No description provided. -2. [`CalculateFactorialUseTree`](./math/factorial/factorial.go#L27): No description provided. -3. [`RecursiveFactorial`](./math/factorial/factorial.go#L19): No description provided. +1. [`Iterative`](./math/factorial/factorial.go#L12): Iterative returns the iteratively brute forced factorial of n +2. [`Recursive`](./math/factorial/factorial.go#L21): Recursive This function recursively computes the factorial of a number +3. [`UsingTree`](./math/factorial/factorial.go#L30): UsingTree This function finds the factorial of a number using a binary tree ---
@@ -505,7 +507,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`BitwiseMax`](./math/max/bitwisemax.go#L10): No description provided. +1. [`Bitwise`](./math/max/bitwisemax.go#L11): Bitwise computes using bitwise operator the maximum of all the integer input and returns it 2. [`Int`](./math/max/max.go#L4): Int is a function which returns the maximum of all the integers provided as arguments. --- @@ -529,7 +531,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`Bitwise`](./math/min/bitwisemin.go#L10): No description provided. +1. [`Bitwise`](./math/min/bitwisemin.go#L11): Bitwise This function returns the minimum integer using bit operations 2. [`Int`](./math/min/min.go#L4): Int is a function which returns the minimum of all the integers provided as arguments. --- diff --git a/math/binary/arithmeticmean.go b/math/binary/arithmeticmean.go index 3fbce0631..9fa56560e 100644 --- a/math/binary/arithmeticmean.go +++ b/math/binary/arithmeticmean.go @@ -8,10 +8,12 @@ // Package binary describes algorithms that use binary operations for different calculations. package binary +// MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations func MeanUsingAndXor(a int, b int) int { return ((a ^ b) >> 1) + (a & b) } +// MeanUsingRightShift This function finds arithmetic mean using right shift func MeanUsingRightShift(a int, b int) int { return (a + b) >> 1 } diff --git a/math/binary/xorsearch.go b/math/binary/xorsearch.go index cdd4e09c8..b16b7846b 100644 --- a/math/binary/xorsearch.go +++ b/math/binary/xorsearch.go @@ -7,6 +7,7 @@ package binary +// XorSearchMissingNumber This function finds a missing number in a sequence func XorSearchMissingNumber(a []int) int { n := len(a) result := len(a) diff --git a/math/catalan/catalannumber.go b/math/catalan/catalannumber.go index b899d2569..31a424347 100644 --- a/math/catalan/catalannumber.go +++ b/math/catalan/catalannumber.go @@ -12,6 +12,7 @@ import ( f "github.com/TheAlgorithms/Go/math/factorial" ) +// CatalanNumber This function returns the `nth` Catalan number func CatalanNumber(n int) int { - return f.BruteForceFactorial(n*2) / (f.BruteForceFactorial(n) * f.BruteForceFactorial(n+1)) + return f.Iterative(n*2) / (f.Iterative(n) * f.Iterative(n+1)) } diff --git a/math/factorial/factorial.go b/math/factorial/factorial.go index 2d376a87b..6b7f5f516 100644 --- a/math/factorial/factorial.go +++ b/math/factorial/factorial.go @@ -8,7 +8,8 @@ // Package factorial describes algorithms Factorials calculations. package factorial -func BruteForceFactorial(n int) int { +// Iterative returns the iteratively brute forced factorial of n +func Iterative(n int) int { result := 1 for i := 2; i <= n; i++ { result *= i @@ -16,15 +17,17 @@ func BruteForceFactorial(n int) int { return result } -func RecursiveFactorial(n int) int { +// Recursive This function recursively computes the factorial of a number +func Recursive(n int) int { if n == 1 { return 1 } else { - return n * RecursiveFactorial(n-1) + return n * Recursive(n-1) } } -func CalculateFactorialUseTree(n int) int { +// UsingTree This function finds the factorial of a number using a binary tree +func UsingTree(n int) int { if n < 0 { return 0 } diff --git a/math/factorial/factorial_test.go b/math/factorial/factorial_test.go index 9a083441d..04eceb973 100644 --- a/math/factorial/factorial_test.go +++ b/math/factorial/factorial_test.go @@ -30,7 +30,7 @@ func TestBruteForceFactorial(t *testing.T) { tests := getTests() for _, tv := range tests { t.Run(tv.name, func(t *testing.T) { - result := BruteForceFactorial(tv.n) + result := Iterative(tv.n) if result != tv.result { t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) } @@ -42,7 +42,7 @@ func TestRecursiveFactorial(t *testing.T) { tests := getTests() for _, tv := range tests { t.Run(tv.name, func(t *testing.T) { - result := RecursiveFactorial(tv.n) + result := Recursive(tv.n) if result != tv.result { t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) } @@ -54,7 +54,7 @@ func TestCalculateFactorialUseTree(t *testing.T) { tests := getTests() for _, tv := range tests { t.Run(tv.name, func(t *testing.T) { - result := CalculateFactorialUseTree(tv.n) + result := UsingTree(tv.n) if result != tv.result { t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) } @@ -64,18 +64,18 @@ func TestCalculateFactorialUseTree(t *testing.T) { func BenchmarkBruteForceFactorial(b *testing.B) { for i := 0; i < b.N; i++ { - BruteForceFactorial(10) + Iterative(10) } } func BenchmarkRecursiveFactorial(b *testing.B) { for i := 0; i < b.N; i++ { - RecursiveFactorial(10) + Recursive(10) } } func BenchmarkCalculateFactorialUseTree(b *testing.B) { for i := 0; i < b.N; i++ { - RecursiveFactorial(10) + Recursive(10) } } diff --git a/math/max/bitwisemax.go b/math/max/bitwisemax.go index ece9c4dbe..b6c3a4623 100644 --- a/math/max/bitwisemax.go +++ b/math/max/bitwisemax.go @@ -7,7 +7,8 @@ package max -func BitwiseMax(a int, b int, base int) int { +// Bitwise computes using bitwise operator the maximum of all the integer input and returns it +func Bitwise(a int, b int, base int) int { z := a - b i := (z >> base) & 1 return a - (i * z) diff --git a/math/max/bitwisemax_test.go b/math/max/bitwisemax_test.go index addf45733..c28bb1cf6 100644 --- a/math/max/bitwisemax_test.go +++ b/math/max/bitwisemax_test.go @@ -1,5 +1,5 @@ // bitwiseMax_test.go -// description: Test for BitwiseMax +// description: Test for Bitwise // author(s) [red_byte](https://github.com/i-redbyte) // see bitwiseMax.go @@ -11,67 +11,67 @@ func TestBitwiseMax(t *testing.T) { base32 := 31 t.Run("Testing(32bit) a = 32 and m = 64: ", func(t *testing.T) { - max := BitwiseMax(32, 64, base32) + max := Bitwise(32, 64, base32) if max != 64 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) t.Run("Testing(32bit) a = 1024 and m = -9: ", func(t *testing.T) { - max := BitwiseMax(1024, -9, base32) + max := Bitwise(1024, -9, base32) if max != 1024 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) t.Run("Testing(32bit) a = -6 and m = -6: ", func(t *testing.T) { - max := BitwiseMax(-6, -6, base32) + max := Bitwise(-6, -6, base32) if max != -6 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) t.Run("Testing(32bit) a = -72 and m = -73: ", func(t *testing.T) { - max := BitwiseMax(-72, -73, base32) + max := Bitwise(-72, -73, base32) if max != -72 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) base64 := 63 t.Run("Testing(64bit) a = 32 and m = 9223372036854775807: ", func(t *testing.T) { - max := BitwiseMax(32, 9223372036854775807, base64) + max := Bitwise(32, 9223372036854775807, base64) if max != 9223372036854775807 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) t.Run("Testing(64bit) a = 1024 and m = -9223372036854770001: ", func(t *testing.T) { - max := BitwiseMax(1024, -9223372036854770001, base64) + max := Bitwise(1024, -9223372036854770001, base64) if max != 1024 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) t.Run("Testing(64bit) a = -6 and m = -6: ", func(t *testing.T) { - max := BitwiseMax(-6, -6, base64) + max := Bitwise(-6, -6, base64) if max != -6 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) t.Run("Testing(64bit) a = -4223372036854775809 and m = -4223372036854775808: ", func(t *testing.T) { - max := BitwiseMax(-4223372036854775809, -4223372036854775808, base64) + max := Bitwise(-4223372036854775809, -4223372036854775808, base64) if max != -4223372036854775808 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) base8 := 7 t.Run("Testing(8bit) a = 257 and m = 256: ", func(t *testing.T) { - max := BitwiseMax(8, 16, base8) + max := Bitwise(8, 16, base8) if max != 16 { - t.Fatalf("Error: BitwiseMax returned bad value") + t.Fatalf("Error: Bitwise returned bad value") } }) } diff --git a/math/min/bitwisemin.go b/math/min/bitwisemin.go index 9710910aa..679d95840 100644 --- a/math/min/bitwisemin.go +++ b/math/min/bitwisemin.go @@ -7,6 +7,7 @@ package min +// Bitwise This function returns the minimum integer using bit operations func Bitwise(base int, value int, values ...int) int { min := value for _, val := range values { From 068ea4bc63c66cd57a00399966b8fea731b65859 Mon Sep 17 00:00:00 2001 From: Paul Leydier <75126792+paul-leydier@users.noreply.github.com> Date: Tue, 23 Nov 2021 17:58:32 +0100 Subject: [PATCH 301/488] feat: add hashing/sha256 implementation (#447) * feat: new hashing package * feat: sha256 hashing function * test: sha256 hashing test cases and benchmarks * doc: improve sha256 docs --- hashing/doc.go | 2 + hashing/hashing_test.go | 3 + hashing/sha256/sha256.go | 112 ++++++++++++++++++++++++++++++++++ hashing/sha256/sha256_test.go | 48 +++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 hashing/doc.go create mode 100644 hashing/hashing_test.go create mode 100644 hashing/sha256/sha256.go create mode 100644 hashing/sha256/sha256_test.go diff --git a/hashing/doc.go b/hashing/doc.go new file mode 100644 index 000000000..1e4425334 --- /dev/null +++ b/hashing/doc.go @@ -0,0 +1,2 @@ +// Package hashing containing different implementation of certain hashing +package hashing diff --git a/hashing/hashing_test.go b/hashing/hashing_test.go new file mode 100644 index 000000000..9067f8411 --- /dev/null +++ b/hashing/hashing_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package hashing diff --git a/hashing/sha256/sha256.go b/hashing/sha256/sha256.go new file mode 100644 index 000000000..9061f3801 --- /dev/null +++ b/hashing/sha256/sha256.go @@ -0,0 +1,112 @@ +// sha256.go +// description: The sha256 cryptographic hash function as defined in the RFC6234 standard. +// author: [Paul Leydier] (https://github.com/paul-leydier) +// ref: https://datatracker.ietf.org/doc/html/rfc6234 +// ref: https://en.wikipedia.org/wiki/SHA-2 +// see sha256_test.go + +package sha256 + +import ( + "encoding/binary" // Used for interacting with uint at the byte level + "math/bits" // Used for bits rotation operations +) + +var K = [64]uint32{ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +} + +const chunkSize = 64 + +// pad returns a padded version of the input message, such as the padded message's length is a multiple +// of 512 bits. +// The padding methodology is as follows: +// A "1" bit is appended at the end of the input message, followed by m "0" bits such as the length is +// 64 bits short of a 512 bits multiple. The remaining 64 bits are filled with the initial length of the +// message, represented as a 64-bits unsigned integer. +// For more details, see: https://datatracker.ietf.org/doc/html/rfc6234#section-4.1 +func pad(message []byte) []byte { + L := make([]byte, 8) + binary.BigEndian.PutUint64(L, uint64(len(message)*8)) + message = append(message, 0x80) // "1" bit followed by 7 "0" bits + for (len(message)+8)%64 != 0 { + message = append(message, 0x00) // 8 "0" bits + } + message = append(message, L...) + + return message +} + +// Hash hashes the input message using the sha256 hashing function, and return a 32 byte array. +// The implementation follows the RGC6234 standard, which is documented +// at https://datatracker.ietf.org/doc/html/rfc6234 +func Hash(message []byte) [32]byte { + message = pad(message) + + // Initialize round constants + h0, h1, h2, h3, h4, h5, h6, h7 := uint32(0x6a09e667), uint32(0xbb67ae85), uint32(0x3c6ef372), uint32(0xa54ff53a), + uint32(0x510e527f), uint32(0x9b05688c), uint32(0x1f83d9ab), uint32(0x5be0cd19) + + // Iterate through 512-bit chunks + for chunkStart := 0; chunkStart < len(message); chunkStart += chunkSize { + // Message schedule + var w [64]uint32 + for i := 0; i*4 < chunkSize; i++ { + w[i] = binary.BigEndian.Uint32(message[chunkStart+i*4 : chunkStart+(i+1)*4]) + } + + // Extend the 16 bytes chunk to the whole 64 bytes message schedule + for i := 16; i < 64; i++ { + s0 := bits.RotateLeft32(w[i-15], -7) ^ bits.RotateLeft32(w[i-15], -18) ^ (w[i-15] >> 3) + s1 := bits.RotateLeft32(w[i-2], -17) ^ bits.RotateLeft32(w[i-2], -19) ^ (w[i-2] >> 10) + w[i] = w[i-16] + s0 + w[i-7] + s1 + } + + // Actual hashing loop + a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7 + for i := 0; i < 64; i++ { + S1 := bits.RotateLeft32(e, -6) ^ bits.RotateLeft32(e, -11) ^ bits.RotateLeft32(e, -25) + ch := (e & f) ^ ((^e) & g) + tmp1 := h + S1 + ch + K[i] + w[i] + S0 := bits.RotateLeft32(a, -2) ^ bits.RotateLeft32(a, -13) ^ bits.RotateLeft32(a, -22) + maj := (a & b) ^ (a & c) ^ (b & c) + tmp2 := S0 + maj + h = g + g = f + f = e + e = d + tmp1 + d = c + c = b + b = a + a = tmp1 + tmp2 + } + h0 += a + h1 += b + h2 += c + h3 += d + h4 += e + h5 += f + h6 += g + h7 += h + } + + // Export digest + digest := [32]byte{} + binary.BigEndian.PutUint32(digest[:4], h0) + binary.BigEndian.PutUint32(digest[4:8], h1) + binary.BigEndian.PutUint32(digest[8:12], h2) + binary.BigEndian.PutUint32(digest[12:16], h3) + binary.BigEndian.PutUint32(digest[16:20], h4) + binary.BigEndian.PutUint32(digest[20:24], h5) + binary.BigEndian.PutUint32(digest[24:28], h6) + binary.BigEndian.PutUint32(digest[28:], h7) + + return digest +} diff --git a/hashing/sha256/sha256_test.go b/hashing/sha256/sha256_test.go new file mode 100644 index 000000000..7e87a71ef --- /dev/null +++ b/hashing/sha256/sha256_test.go @@ -0,0 +1,48 @@ +package sha256 + +import ( + "encoding/hex" + "testing" +) + +func TestHash(t *testing.T) { + testCases := []struct { + in string + expected string + }{ + {"hello world", "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"}, + {"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}, + {"a", "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"}, + {"The quick brown fox jumps over the lazy dog", "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"}, + {"The quick brown fox jumps over the lazy dog.", "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"}, + {"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "2d8c2f6d978ca21712b5f6de36c9d31fa8e96a4fa5d8ff8b0188dfb9e7c171bb"}, + } + for _, tc := range testCases { + res := Hash([]byte(tc.in)) + result := hex.EncodeToString(res[:]) + if result != tc.expected { + t.Fatalf("Hash(%s) = %s, expected %s", tc.in, result, tc.expected) + } + } +} + +func BenchmarkHash(b *testing.B) { + testCases := []struct { + name string + in string + }{ + {"hello world", "hello world"}, + {"empty", ""}, + {"a", "a"}, + {"The quick brown fox jumps over the lazy dog", "The quick brown fox jumps over the lazy dog"}, + {"The quick brown fox jumps over the lazy dog.", "The quick brown fox jumps over the lazy dog."}, + {"Lorem ipsum", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."}, + } + for _, testCase := range testCases { + b.Run(testCase.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + Hash([]byte(testCase.in)) + } + }) + } +} From 8594e1119945653e7db3d78fa2080f27fb21a484 Mon Sep 17 00:00:00 2001 From: Taj Date: Thu, 25 Nov 2021 18:24:26 +0000 Subject: [PATCH 302/488] fix: pull request check hanging (#444) Co-authored-by: Andrii Siriak --- .github/workflows/godocmd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index 6494d6bd7..3b4f0ef4c 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -1,5 +1,5 @@ name: godocmd -on: [push, pull_request] +on: [push] jobs: generate_readme: runs-on: ubuntu-latest From 83832b6be79d0223424226d06d91460fed04883a Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 25 Nov 2021 21:26:54 +0300 Subject: [PATCH 303/488] feat: fibonacci with matrix (#446) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * feat: n-th fibonacci number use matrix method * Updated Documentation in README.md * fix: ineffectual assignment to ta (ineffassign) * fix: ineffectual assignment to tb (ineffassign) * Updated Documentation in README.md Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Andrii Siriak --- README.md | 20 ++++++++++ math/fibonacci/fibonacci.go | 34 ++++++++++++++++ math/fibonacci/fibonacci_test.go | 66 ++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 math/fibonacci/fibonacci.go create mode 100644 math/fibonacci/fibonacci_test.go diff --git a/README.md b/README.md index 1fca7fa00..20aade7f6 100644 --- a/README.md +++ b/README.md @@ -278,6 +278,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 2. [`Recursive`](./math/factorial/factorial.go#L21): Recursive This function recursively computes the factorial of a number 3. [`UsingTree`](./math/factorial/factorial.go#L30): UsingTree This function finds the factorial of a number using a binary tree +--- +
+ fibonacci + +--- + +##### Functions: + +1. [`Matrix`](./math/fibonacci/fibonacci.go#L11): Matrix This function calculates the n-th fibonacci number using the matrix method. [See](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) + ---
gcd @@ -781,6 +791,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`New`](./structure/set/set.go#L7): New gives new set. +--- +
+ sha256 + +--- + +##### Functions: + +1. [`Hash`](./hashing/sha256/sha256.go#L50): Hash hashes the input message using the sha256 hashing function, and return a 32 byte array. The implementation follows the RGC6234 standard, which is documented at https://datatracker.ietf.org/doc/html/rfc6234 + ---
sort diff --git a/math/fibonacci/fibonacci.go b/math/fibonacci/fibonacci.go new file mode 100644 index 000000000..06d8830e3 --- /dev/null +++ b/math/fibonacci/fibonacci.go @@ -0,0 +1,34 @@ +// fibonacci.go +// description: Get the nth Fibonacci Number +// details: +// In mathematics, the Fibonacci numbers, commonly denoted Fn, form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. [Fibonacci number](https://en.wikipedia.org/wiki/Fibonacci_number) +// author(s) [red_byte](https://github.com/i-redbyte) +// see fibonacci_test.go + +package fibonacci + +// Matrix This function calculates the n-th fibonacci number using the matrix method. [See](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) +func Matrix(n uint) uint { + a, b := 1, 1 + c, rc, tc := 1, 0, 0 + d, rd := 0, 1 + + for n != 0 { + if n&1 == 1 { + tc = rc + rc = rc*a + rd*c + rd = tc*b + rd*d + } + + ta := a + tb := b + tc = c + a = a*a + b*c + b = ta*b + b*d + c = c*ta + d*c + d = tc*tb + d*d + + n >>= 1 + } + return uint(rc) +} diff --git a/math/fibonacci/fibonacci_test.go b/math/fibonacci/fibonacci_test.go new file mode 100644 index 000000000..32fa7da6e --- /dev/null +++ b/math/fibonacci/fibonacci_test.go @@ -0,0 +1,66 @@ +package fibonacci + +import ( + "github.com/TheAlgorithms/Go/dynamic" + "testing" +) + +func getTests() []struct { + name string + n uint + want uint +} { + tests := []struct { + name string + n uint + want uint + }{ + {"Fibonacci 0-th number == 0", 0, 0}, + {"Fibonacci 1-th number == 1", 1, 1}, + {"Fibonacci 2-th number == 1", 2, 1}, + {"Fibonacci 3-th number == 2", 3, 2}, + {"Fibonacci 4-th number == 3", 4, 3}, + {"Fibonacci 5-th number == 5", 5, 5}, + {"Fibonacci 6-th number == 8", 6, 8}, + {"Fibonacci 7-th number == 13", 7, 13}, + {"Fibonacci 8-th number == 21", 8, 21}, + {"Fibonacci 9-th number == 34", 9, 34}, + {"Fibonacci 10-th number == 55", 10, 55}, + {"Fibonacci 90-th number == 2880067194370816120", 90, 2880067194370816120}, + } + return tests +} + +func TestMatrix(t *testing.T) { + tests := getTests() + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := Matrix(test.n); got != test.want { + t.Errorf("Return value = %v, want %v", got, test.want) + } + }) + } +} + +func TestNthFibonacci(t *testing.T) { + tests := getTests() + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := dynamic.NthFibonacci(test.n); got != test.want { + t.Errorf("Return value = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkNthFibonacci(b *testing.B) { + for i := 0; i < b.N; i++ { + dynamic.NthFibonacci(90) + } +} + +func BenchmarkMatrix(b *testing.B) { + for i := 0; i < b.N; i++ { + Matrix(90) + } +} From c85f9314b5c8b2c0ae4fad3c39de326dbf322d97 Mon Sep 17 00:00:00 2001 From: Paul Leydier <75126792+paul-leydier@users.noreply.github.com> Date: Sat, 27 Nov 2021 23:01:25 +0100 Subject: [PATCH 304/488] feat: add math/MontecarloPi2 implementation (#448) * feat: Parallel MonteCarloPi using channels * test: Parallel MonteCarloPi using channels * doc: MonteCarloPi2 documentation * doc: fix typo * feat: rename MonteCarloPi2 to MonteCarloPiConcurrent Co-authored-by: Taj --- math/pi/montecarlopi.go | 74 ++++++++++++++++++++++++++++++++++-- math/pi/montecarlopi_test.go | 56 +++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 4 deletions(-) diff --git a/math/pi/montecarlopi.go b/math/pi/montecarlopi.go index d31b20a45..7bbadf01c 100644 --- a/math/pi/montecarlopi.go +++ b/math/pi/montecarlopi.go @@ -1,15 +1,17 @@ // montecarlopi.go // description: Calculating pi by the Monte Carlo method // details: -// implementation of Monte Carlo Algorithm for the calculating of Pi - [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method) -// author(s) [red_byte](https://github.com/i-redbyte) +// implementations of Monte Carlo Algorithm for the calculating of Pi - [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method) +// author(s): [red_byte](https://github.com/i-redbyte), [Paul Leydier] (https://github.com/paul-leydier) // see montecarlopi_test.go package pi import ( - "math/rand" - "time" + "fmt" // Used for error formatting + "math/rand" // Used for random number generation in Monte Carlo method + "runtime" // Used to get information on available CPUs + "time" // Used for seeding the random number generation ) func MonteCarloPi(randomPoints int) float64 { @@ -25,3 +27,67 @@ func MonteCarloPi(randomPoints int) float64 { pi := float64(inside) / float64(randomPoints) * 4 return pi } + +// MonteCarloPiConcurrent approximates the value of pi using the Monte Carlo method. +// Unlike the MonteCarloPi function (first version), this implementation uses +// goroutines and channels to parallelize the computation. +// More details on the Monte Carlo method available at https://en.wikipedia.org/wiki/Monte_Carlo_method. +// More details on goroutines parallelization available at https://go.dev/doc/effective_go#parallel. +func MonteCarloPiConcurrent(n int) (float64, error) { + numCPU := runtime.GOMAXPROCS(0) + c := make(chan int, numCPU) + pointsToDraw, err := splitInt(n, numCPU) // split the task in sub-tasks of approximately equal sizes + if err != nil { + return 0, err + } + + // launch numCPU parallel tasks + for _, p := range pointsToDraw { + go drawPoints(p, c) + } + + // collect the tasks results + inside := 0 + for i := 0; i < numCPU; i++ { + inside += <-c + } + return float64(inside) / float64(n) * 4, nil +} + +// drawPoints draws n random two-dimensional points in the interval [0, 1), [0, 1) and sends through c +// the number of points which where within the circle of center 0 and radius 1 (unit circle) +func drawPoints(n int, c chan<- int) { + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + inside := 0 + for i := 0; i < n; i++ { + x, y := rnd.Float64(), rnd.Float64() + if x*x+y*y <= 1 { + inside++ + } + } + c <- inside +} + +// splitInt takes an integer x and splits it within an integer slice of length n in the most uniform +// way possible. +// For example, splitInt(10, 3) will return []int{4, 3, 3}, nil +func splitInt(x int, n int) ([]int, error) { + if x < n { + return nil, fmt.Errorf("x must be < n - given values are x=%d, n=%d", x, n) + } + split := make([]int, n) + if x%n == 0 { + for i := 0; i < n; i++ { + split[i] = x / n + } + } else { + limit := x % n + for i := 0; i < limit; i++ { + split[i] = x/n + 1 + } + for i := limit; i < n; i++ { + split[i] = x / n + } + } + return split, nil +} diff --git a/math/pi/montecarlopi_test.go b/math/pi/montecarlopi_test.go index 4c650899e..acf862453 100644 --- a/math/pi/montecarlopi_test.go +++ b/math/pi/montecarlopi_test.go @@ -25,3 +25,59 @@ func BenchmarkMonteCarloPi(b *testing.B) { MonteCarloPi(100000000) } } + +func TestSplitInt(t *testing.T) { + testCases := []struct { + name string + x int + n int + expectedResult []int + expectedError bool + }{ + {"multiple", 10, 5, []int{2, 2, 2, 2, 2}, false}, + {"n=1", 10, 1, []int{10}, false}, + {"x=10, n=3", 10, 3, []int{4, 3, 3}, false}, + {"x=10, n=7", 10, 7, []int{2, 2, 2, 1, 1, 1, 1}, false}, + {"n>x", 10, 11, nil, true}, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + res, err := splitInt(testCase.x, testCase.n) + for i := 0; i < len(testCase.expectedResult); i++ { + if res[i] != testCase.expectedResult[i] { + t.Fatalf("unexpected result at index %d: %d - expected %d", i, res[i], testCase.expectedResult[i]) + } + } + if testCase.expectedError { + if err == nil { + t.Fatal("expected an error, got nil") + } + } else { + if err != nil { + t.Fatalf("unexpected error - %s", err) + } + } + }) + } +} + +func TestMonteCarloPi2(t *testing.T) { + res, err := MonteCarloPiConcurrent(100000000) + if err != nil { + t.Errorf("unexpected error %s", err) + } + result := fmt.Sprintf("%.2f", res) + t.Log(result) + if result != "3.14" { + t.Errorf("Wrong result! Expected:%f, returned:%s ", 3.1415, result) + } +} + +func BenchmarkMonteCarloPi2(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := MonteCarloPiConcurrent(100000000) + if err != nil { + b.Fatalf("unexpected error - %s", err) + } + } +} From e6cf58267ccff495fe3262093de2258f3541107e Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Wed, 1 Dec 2021 20:49:34 +0300 Subject: [PATCH 305/488] Feat: reflected binary code (#449) --- README.md | 8 +++++--- math/binary/rbc.go | 18 ++++++++++++++++++ math/binary/rbc_test.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 math/binary/rbc.go create mode 100644 math/binary/rbc_test.go diff --git a/README.md b/README.md index 20aade7f6..f11140a6f 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 4. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations 5. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift 6. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. -7. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence +7. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n +8. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---
@@ -644,8 +645,9 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`MonteCarloPi`](./math/pi/montecarlopi.go#L15): No description provided. -2. [`Spigot`](./math/pi/spigotpi.go#L12): No description provided. +1. [`MonteCarloPi`](./math/pi/montecarlopi.go#L17): No description provided. +2. [`MonteCarloPiConcurrent`](./math/pi/montecarlopi.go#L36): MonteCarloPiConcurrent approximates the value of pi using the Monte Carlo method. Unlike the MonteCarloPi function (first version), this implementation uses goroutines and channels to parallelize the computation. More details on the Monte Carlo method available at https://en.wikipedia.org/wiki/Monte_Carlo_method. More details on goroutines parallelization available at https://go.dev/doc/effective_go#parallel. +3. [`Spigot`](./math/pi/spigotpi.go#L12): No description provided. ---
diff --git a/math/binary/rbc.go b/math/binary/rbc.go new file mode 100644 index 000000000..c0a6e78f1 --- /dev/null +++ b/math/binary/rbc.go @@ -0,0 +1,18 @@ +// rbc.go +// description: Reflected binary code (RBC) +// details: +// The reflected binary code (RBC), also known just as reflected binary (RB) or Gray code after Frank Gray, is an ordering of the binary numeral system such that two successive values differ in only one bit (binary digit). - [RBC](https://en.wikipedia.org/wiki/Gray_code) +// author(s) [red_byte](https://github.com/i-redbyte) +// see rbc_test.go + +package binary + +// SequenceGrayCode The function generates an "Gray code" sequence of length n +func SequenceGrayCode(n uint) []uint { + result := make([]uint, 0) + var i uint + for i = 0; i < 1<>1)) + } + return result +} diff --git a/math/binary/rbc_test.go b/math/binary/rbc_test.go new file mode 100644 index 000000000..60b6ff448 --- /dev/null +++ b/math/binary/rbc_test.go @@ -0,0 +1,37 @@ +// rbc_test.go +// description: Test for Reflected binary code +// author(s) [red_byte](https://github.com/i-redbyte) +// see rbc.go + +package binary + +import ( + "reflect" + "testing" +) + +func TestSequenceGrayCode(t *testing.T) { + tests := []struct { + name string + n uint + want []uint + }{ + {"Sequence of values for 1", 1, []uint{0, 1}}, + {"Sequence of values for 2", 2, []uint{0, 1, 3, 2}}, + {"Sequence of values for 6", 6, []uint{0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8, 24, 25, 27, 26, 30, 31, 29, 28, 20, 21, 23, 22, 18, 19, 17, 16, 48, 49, 51, 50, 54, 55, 53, 52, 60, 61, 63, 62, 58, 59, 57, 56, 40, 41, 43, 42, 46, 47, 45, 44, 36, 37, 39, 38, 34, 35, 33, 32}}, + {"Sequence of values for 8", 8, []uint{0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8, 24, 25, 27, 26, 30, 31, 29, 28, 20, 21, 23, 22, 18, 19, 17, 16, 48, 49, 51, 50, 54, 55, 53, 52, 60, 61, 63, 62, 58, 59, 57, 56, 40, 41, 43, 42, 46, 47, 45, 44, 36, 37, 39, 38, 34, 35, 33, 32, 96, 97, 99, 98, 102, 103, 101, 100, 108, 109, 111, 110, 106, 107, 105, 104, 120, 121, 123, 122, 126, 127, 125, 124, 116, 117, 119, 118, 114, 115, 113, 112, 80, 81, 83, 82, 86, 87, 85, 84, 92, 93, 95, 94, 90, 91, 89, 88, 72, 73, 75, 74, 78, 79, 77, 76, 68, 69, 71, 70, 66, 67, 65, 64, 192, 193, 195, 194, 198, 199, 197, 196, 204, 205, 207, 206, 202, 203, 201, 200, 216, 217, 219, 218, 222, 223, 221, 220, 212, 213, 215, 214, 210, 211, 209, 208, 240, 241, 243, 242, 246, 247, 245, 244, 252, 253, 255, 254, 250, 251, 249, 248, 232, 233, 235, 234, 238, 239, 237, 236, 228, 229, 231, 230, 226, 227, 225, 224, 160, 161, 163, 162, 166, 167, 165, 164, 172, 173, 175, 174, 170, 171, 169, 168, 184, 185, 187, 186, 190, 191, 189, 188, 180, 181, 183, 182, 178, 179, 177, 176, 144, 145, 147, 146, 150, 151, 149, 148, 156, 157, 159, 158, 154, 155, 153, 152, 136, 137, 139, 138, 142, 143, 141, 140, 132, 133, 135, 134, 130, 131, 129, 128}}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := SequenceGrayCode(test.n); !reflect.DeepEqual(got, test.want) { + t.Errorf("SequenceGrayCode() = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkSequenceGrayCode(b *testing.B) { + for i := 0; i < b.N; i++ { + SequenceGrayCode(6) + } +} From 37664206f73d5618b5b8f2f6db4b76c7054fd538 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Sun, 5 Dec 2021 17:22:40 +0300 Subject: [PATCH 306/488] feat: nth Fibonacci number using formula (#450) Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 3 ++- math/fibonacci/fibonacci.go | 13 +++++++++++++ math/fibonacci/fibonacci_test.go | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f11140a6f..0cd05d43e 100644 --- a/README.md +++ b/README.md @@ -287,7 +287,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`Matrix`](./math/fibonacci/fibonacci.go#L11): Matrix This function calculates the n-th fibonacci number using the matrix method. [See](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) +1. [`Formula`](./math/fibonacci/fibonacci.go#L42): Formula This function calculates the n-th fibonacci number using the [formula](https://en.wikipedia.org/wiki/Fibonacci_number#Relation_to_the_golden_ratio) Attention! Tests for large values fall due to rounding error of floating point numbers, works well, only on small numbers +2. [`Matrix`](./math/fibonacci/fibonacci.go#L15): Matrix This function calculates the n-th fibonacci number using the matrix method. [See](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) ---
diff --git a/math/fibonacci/fibonacci.go b/math/fibonacci/fibonacci.go index 06d8830e3..9718acbbc 100644 --- a/math/fibonacci/fibonacci.go +++ b/math/fibonacci/fibonacci.go @@ -7,6 +7,10 @@ package fibonacci +import ( + "math" +) + // Matrix This function calculates the n-th fibonacci number using the matrix method. [See](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) func Matrix(n uint) uint { a, b := 1, 1 @@ -32,3 +36,12 @@ func Matrix(n uint) uint { } return uint(rc) } + +// Formula This function calculates the n-th fibonacci number using the [formula](https://en.wikipedia.org/wiki/Fibonacci_number#Relation_to_the_golden_ratio) +// Attention! Tests for large values fall due to rounding error of floating point numbers, works well, only on small numbers +func Formula(n uint) uint { + sqrt5 := math.Sqrt(5) + phi := (sqrt5 + 1) / 2 + powPhi := math.Pow(phi, float64(n)) + return uint(powPhi/sqrt5 + 0.5) +} diff --git a/math/fibonacci/fibonacci_test.go b/math/fibonacci/fibonacci_test.go index 32fa7da6e..990930251 100644 --- a/math/fibonacci/fibonacci_test.go +++ b/math/fibonacci/fibonacci_test.go @@ -53,6 +53,17 @@ func TestNthFibonacci(t *testing.T) { } } +func TestFormula(t *testing.T) { + tests := getTests() + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := Formula(test.n); test.n <= 10 && got != test.want { + t.Errorf("Return value = %v, want %v", got, test.want) + } + }) + } +} + func BenchmarkNthFibonacci(b *testing.B) { for i := 0; i < b.N; i++ { dynamic.NthFibonacci(90) @@ -64,3 +75,9 @@ func BenchmarkMatrix(b *testing.B) { Matrix(90) } } + +func BenchmarkFormula(b *testing.B) { + for i := 0; i < b.N; i++ { + Formula(90) + } +} From 7fcbe26e5cf455b4ba27e75d15a65534f424a967 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Fri, 10 Dec 2021 23:02:47 +0300 Subject: [PATCH 307/488] Feat: Luhn algorithm (#451) Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 13 +++++++++++++ checksum/luhn.go | 28 ++++++++++++++++++++++++++++ checksum/luhn_test.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 checksum/luhn.go create mode 100644 checksum/luhn_test.go diff --git a/README.md b/README.md index 0cd05d43e..a3956cf92 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,19 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`CatalanNumber`](./math/catalan/catalannumber.go#L16): CatalanNumber This function returns the `nth` Catalan number +--- +
+ checksum + +--- + +##### Package checksum describes algorithms for finding various checksums + +--- +##### Functions: + +1. [`LuhnAlgorithm`](./checksum/luhn.go#L11): LuhnAlgorithm This function calculates the checksum using the Luna algorithm + ---
coloring diff --git a/checksum/luhn.go b/checksum/luhn.go new file mode 100644 index 000000000..f3e230ead --- /dev/null +++ b/checksum/luhn.go @@ -0,0 +1,28 @@ +// lunh.go +// description: Luhn algorithm +// details: is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers, etc [Lunh](https://en.wikipedia.org/wiki/Luhn_algorithm) +// author(s) [red_byte](https://github.com/i-redbyte) +// see lunh_test.go + +// Package checksum describes algorithms for finding various checksums +package checksum + +// LuhnAlgorithm This function calculates the checksum using the Luna algorithm +func LuhnAlgorithm(s []rune) bool { + n := len(s) + number := 0 + result := 0 + for i := 0; i < n; i++ { + number = int(s[i]) - '0' + if i%2 != 0 { + result += number + continue + } + number *= 2 + if number > 9 { + number -= 9 + } + result += number + } + return result%10 == 0 +} diff --git a/checksum/luhn_test.go b/checksum/luhn_test.go new file mode 100644 index 000000000..e928e51b6 --- /dev/null +++ b/checksum/luhn_test.go @@ -0,0 +1,37 @@ +// luhn_test.go +// description: Test for Luhn algorithm +// author(s) [red_byte](https://github.com/i-redbyte) +// see luhn.go + +package checksum + +import "testing" + +func TestLuhnAlgorithm(t *testing.T) { + tests := []struct { + name string + s []rune + want bool + }{ + {"check 4242424242424242", []rune("4242424242424242"), true}, + {"check 6200000000000005", []rune("6200000000000005"), true}, + {"check 5534200028533164", []rune("5534200028533164"), true}, + {"check 36227206271667", []rune("36227206271667"), true}, + {"check 471629309440", []rune("471629309440"), false}, + {"check 1111", []rune("1111"), false}, + {"check 12345674", []rune("12345674"), true}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := LuhnAlgorithm(test.s); got != test.want { + t.Errorf("LuhnAlgorithm() = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkBruteForceFactorial(b *testing.B) { + for i := 0; i < b.N; i++ { + LuhnAlgorithm([]rune("4242424242424242")) + } +} From 75b615cc38ffc111ddcd4f0dfadc5fdf2d417201 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 23 Dec 2021 20:09:34 +0300 Subject: [PATCH 308/488] Abs algo (#453) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * feat: abs algo * Updated Documentation in README.md * fix: add comment * Updated Documentation in README.md * fix: new comment * Updated Documentation in README.md * fix: rename func and remove package * Updated Documentation in README.md * Update math/abs.go Co-authored-by: Taj * Updated Documentation in README.md * Update math/binary/abs.go Co-authored-by: Taj * Updated Documentation in README.md * fix: rename func and move binary test Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- README.md | 22 ++++++++------- math/abs.go | 16 +++++++++++ math/abs_test.go | 61 +++++++++++++++++++++++++++++++++++++++++ math/binary/abs.go | 13 +++++++++ math/binary/abs_test.go | 37 +++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 math/abs.go create mode 100644 math/abs_test.go create mode 100644 math/binary/abs.go create mode 100644 math/binary/abs_test.go diff --git a/README.md b/README.md index a3956cf92..03f8529c5 100644 --- a/README.md +++ b/README.md @@ -89,14 +89,15 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`BitCounter`](./math/binary/bitcounter.go#L11): BitCounter - The function returns the number of set bits for an unsigned integer number -2. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. -3. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 -4. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations -5. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift -6. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. -7. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n -8. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence +1. [`Abs`](./math/binary/abs.go#L10): Abs returns absolute value using binary operation Principle of operation: 1) Get the mask by right shift by the base 2) Base is the size of an integer variable in bits, for example, for int32 it will be 32, for int64 it will be 64 3) For negative numbers, above step sets mask as 1 1 1 1 1 1 1 1 and 0 0 0 0 0 0 0 0 for positive numbers. 4) Add the mask to the given number. 5) XOR of mask + n and mask gives the absolute value. +2. [`BitCounter`](./math/binary/bitcounter.go#L11): BitCounter - The function returns the number of set bits for an unsigned integer number +3. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. +4. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 +5. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations +6. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift +7. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. +8. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n +9. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---
@@ -521,8 +522,9 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -2. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +1. [`Abs`](./math/abs.go#L11): Abs returns absolute value +2. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +3. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. ---
diff --git a/math/abs.go b/math/abs.go new file mode 100644 index 000000000..7d0b3e6ac --- /dev/null +++ b/math/abs.go @@ -0,0 +1,16 @@ +// abs.go +// description: Absolute value +// details: +// In mathematics, the absolute value or modulus of a real number x, denoted |x|, is the non-negative value of x without regard to its sign. [Absolute value](https://en.wikipedia.org/wiki/Average#Arithmetic_mean) +// author(s) [red_byte](https://github.com/i-redbyte) +// see abs_test.go + +package math + +// Abs returns absolute value +func Abs(n int) int { + if n < 0 { + return -n + } + return n +} diff --git a/math/abs_test.go b/math/abs_test.go new file mode 100644 index 000000000..cd166f91d --- /dev/null +++ b/math/abs_test.go @@ -0,0 +1,61 @@ +package math + +import ( + "github.com/TheAlgorithms/Go/math/binary" + "math" + "testing" +) + +func TestAbs(t *testing.T) { + tests := getTests() + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := Abs(test.n); got != test.want { + t.Errorf("Abs() = %v, want %v", got, test.want) + } + }) + } +} + +func getTests() []struct { + name string + n int + want int +} { + tests := []struct { + name string + n int + want int + }{ + {"-1 = |1| ", -1, 1}, + {"-255 = |255| ", -255, 255}, + {"0 = |0| ", 0, 0}, + {"5 = |5| ", 5, 5}, + {"-5 = |5| ", -5, 5}, + {"-98368972 = |98368972| ", -98368972, 98368972}, + } + return tests +} + +func BenchmarkSimpleAbs(b *testing.B) { + for i := 0; i < b.N; i++ { + Abs(-1024) + } +} +func BenchmarkBinaryAbs32(b *testing.B) { + for i := 0; i < b.N; i++ { + binary.Abs(32, -1024) + } +} + +func BenchmarkBinaryAbs64(b *testing.B) { + for i := 0; i < b.N; i++ { + binary.Abs(64, -1024) + } +} + +func BenchmarkStdLibAbs(b *testing.B) { + for i := 0; i < b.N; i++ { + math.Abs(-1024) + } +} diff --git a/math/binary/abs.go b/math/binary/abs.go new file mode 100644 index 000000000..9762c7c8a --- /dev/null +++ b/math/binary/abs.go @@ -0,0 +1,13 @@ +package binary + +// Abs returns absolute value using binary operation +// Principle of operation: +// 1) Get the mask by right shift by the base +// 2) Base is the size of an integer variable in bits, for example, for int32 it will be 32, for int64 it will be 64 +// 3) For negative numbers, above step sets mask as 1 1 1 1 1 1 1 1 and 0 0 0 0 0 0 0 0 for positive numbers. +// 4) Add the mask to the given number. +// 5) XOR of mask + n and mask gives the absolute value. +func Abs(base, n int) int { + m := n >> (base - 1) + return (n + m) ^ m +} diff --git a/math/binary/abs_test.go b/math/binary/abs_test.go new file mode 100644 index 000000000..20500ec5a --- /dev/null +++ b/math/binary/abs_test.go @@ -0,0 +1,37 @@ +package binary + +import "testing" + +func TestAbs(t *testing.T) { + tests := getAbsTests() + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := Abs(test.base, test.n); got != test.want { + t.Errorf("Abs() = %v, want %v", got, test.want) + } + }) + } +} + +func getAbsTests() []struct { + name string + base int + n int + want int +} { + tests := []struct { + name string + base int + n int + want int + }{ + {"-1 = |1| ", 32, -1, 1}, + {"-255 = |255| ", 32, -255, 255}, + {"0 = |0| ", 64, 0, 0}, + {"5 = |5| ", 16, 5, 5}, + {"-5 = |5| ", 32, -5, 5}, + {"-98368972 = |98368972| ", 64, -98368972, 98368972}, + {"-110298368972 = |110298368972| ", 64, -98368972, 98368972}, + } + return tests +} From b46d6dafde58817feafefa5788f6fa052bcd2903 Mon Sep 17 00:00:00 2001 From: Nischal Patel Date: Wed, 29 Dec 2021 01:26:27 +0530 Subject: [PATCH 309/488] Add recursive method for palindrome (#455) --- strings/palindrome/ispalindrome.go | 18 ++++++++++++++++++ strings/palindrome/ispalindrome_test.go | 11 +++++++++++ 2 files changed, 29 insertions(+) diff --git a/strings/palindrome/ispalindrome.go b/strings/palindrome/ispalindrome.go index 65d525dd3..eb3ab289e 100644 --- a/strings/palindrome/ispalindrome.go +++ b/strings/palindrome/ispalindrome.go @@ -35,3 +35,21 @@ func IsPalindrome(text string) bool { } return true } + +func IsPalindromeRecursive(text string) bool { + clean_text := cleanString(text) + runes := []rune(clean_text) + return isPalindromeRecursiveHelper(runes, 0, int64(len(runes))) +} + +func isPalindromeRecursiveHelper(runes []rune, start int64, end int64) bool { + if start >= end { + return true + } + if runes[start] != runes[end-1] { + return false + } + start = start + 1 + end = end - 1 + return isPalindromeRecursiveHelper(runes, start, end) +} diff --git a/strings/palindrome/ispalindrome_test.go b/strings/palindrome/ispalindrome_test.go index 409e6bb8f..7b973b1d5 100644 --- a/strings/palindrome/ispalindrome_test.go +++ b/strings/palindrome/ispalindrome_test.go @@ -51,3 +51,14 @@ func TestIsPalindrome(t *testing.T) { }) } } + +func TestIsPalindromeRecursive(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + func_result := IsPalindromeRecursive(test.input) + if test.expected != func_result { + t.Errorf("Expected answer '%t' for string '%s' but answer given was %t", test.expected, test.input, func_result) + } + }) + } +} From ef59b691c1ade0c8576aae85d80367471324be55 Mon Sep 17 00:00:00 2001 From: 1327253585 <1327253585@qq.com> Date: Tue, 4 Jan 2022 00:49:27 +0800 Subject: [PATCH 310/488] merge: feat: add a clear implemention of jump search (#458) --- search/jump2.go | 24 ++++++++++++++++++++++++ search/jump2_test.go | 23 +++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 search/jump2.go create mode 100644 search/jump2_test.go diff --git a/search/jump2.go b/search/jump2.go new file mode 100644 index 000000000..ca16a94fb --- /dev/null +++ b/search/jump2.go @@ -0,0 +1,24 @@ +package search + +import "math" + +func Jump2(arr []int, target int) (int, error) { + step := int(math.Round(math.Sqrt(float64(len(arr))))) + rbound := len(arr) + for i := step; i < len(arr); i += step { + if arr[i] > target { + rbound = i + break + } + } + + for i := rbound - step; i < rbound; i++ { + if arr[i] == target { + return i, nil + } + if arr[i] > target { + break + } + } + return -1, ErrNotFound +} diff --git a/search/jump2_test.go b/search/jump2_test.go new file mode 100644 index 000000000..fc2cdb4af --- /dev/null +++ b/search/jump2_test.go @@ -0,0 +1,23 @@ +package search + +import "testing" + +func TestJump2(t *testing.T) { + for _, test := range searchTests { + actualValue, actualError := Jump2(test.data, test.key) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) + } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) + } + } +} + +func BenchmarkJump2(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // exclude time taken to generate test case + for i := 0; i < b.N; i++ { + _, _ = Jump2(testCase, i) + } +} From a918456a93209ce3a13e4347d69247febfa42723 Mon Sep 17 00:00:00 2001 From: 1327253585 <1327253585@qq.com> Date: Tue, 4 Jan 2022 00:53:25 +0800 Subject: [PATCH 311/488] merge: feat: add qucik select algorithm (#457) Co-authored-by: Rak Laptudirm --- search/selectk.go | 32 ++++++++++++++++++++++++++++++++ search/selectk_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 search/selectk.go create mode 100644 search/selectk_test.go diff --git a/search/selectk.go b/search/selectk.go new file mode 100644 index 000000000..bb81937b4 --- /dev/null +++ b/search/selectk.go @@ -0,0 +1,32 @@ +package search + +func SelectK(array []int, k int) (int, error) { + if k > len(array) { + return -1, ErrNotFound + } + return selectK(array, 0, len(array), len(array)-k), nil +} + +// search the element which index is idx +func selectK(array []int, l, r, idx int) int { + index := partition(array, l, r) + if index == idx { + return array[index] + } + if index < idx { + return selectK(array, index+1, r, idx) + } + return selectK(array, l, index, idx) +} + +func partition(array []int, l, r int) int { + elem, j := array[l], l+1 + for i := l + 1; i < r; i++ { + if array[i] <= elem { + array[i], array[j] = array[j], array[i] + j++ + } + } + array[l], array[j-1] = array[j-1], array[l] + return j - 1 +} diff --git a/search/selectk_test.go b/search/selectk_test.go new file mode 100644 index 000000000..bf81fb9d1 --- /dev/null +++ b/search/selectk_test.go @@ -0,0 +1,41 @@ +package search + +import ( + "testing" +) + +func TestSelectK(t *testing.T) { + tests := []struct { + data []int + k int + expected int + err error + name string + }{ + {[]int{1, 2, 3, 4, 5}, 1, 5, nil, "sorted data"}, + {[]int{5, 4, 3, 2, 1}, 2, 4, nil, "reversed data"}, + {[]int{3, 1, 2, 5, 4}, 3, 3, nil, "random data"}, + {[]int{3, 2, 1, 5, 4}, 10, -1, ErrNotFound, " absent data"}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + elem, err := SelectK(tc.data, tc.k) + if err != tc.err { + t.Errorf("name:%v SelectK() = _, %v, want err: %v", tc.name, err, tc.err) + } + if elem != tc.expected { + t.Errorf("name:%v SelectK() = %v,_ , want: %v", tc.name, elem, tc.expected) + } + }) + } +} + +func BenchmarkSelectK(b *testing.B) { + testCase := generateBenchmarkTestCase() + testCase = append(testCase, 1) // make sure len(testCase)/2+1 is valid + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, _ = SelectK(testCase, len(testCase)/2) + } +} From 6134d6e383f0e2f42d9123c50d22d6e7333c1a3f Mon Sep 17 00:00:00 2001 From: 1327253585 <1327253585@qq.com> Date: Tue, 4 Jan 2022 17:29:55 +0800 Subject: [PATCH 312/488] merge: add merge sort (#456) * add merge sort * change code style * move iterative implementation to mergesort.go * fix: rename MegrgeSortIter to MergeIter Co-authored-by: zhaodeliang Co-authored-by: Rak Laptudirm --- sort/mergesort.go | 12 ++++++++++++ sort/sorts_test.go | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/sort/mergesort.go b/sort/mergesort.go index a5b4e2a36..45c17ab04 100644 --- a/sort/mergesort.go +++ b/sort/mergesort.go @@ -1,5 +1,7 @@ package sort +import "github.com/TheAlgorithms/Go/math/min" + func merge(a []int, b []int) []int { var r = make([]int, len(a)+len(b)) @@ -45,3 +47,13 @@ func Mergesort(items []int) []int { return merge(a, b) } + +func MergeIter(items []int) []int { + for step := 1; step < len(items); step += step { + for i := 0; i+step < len(items); i += 2 * step { + tmp := merge(items[i:i+step], items[i+step:min.Int(i+2*step, len(items))]) + copy(items[i:], tmp) + } + } + return items +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index be239205e..828b907cb 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -90,6 +90,10 @@ func TestMerge(t *testing.T) { testFramework(t, Mergesort) } +func TestMergeIter(t *testing.T) { + testFramework(t, MergeIter) +} + func TestHeap(t *testing.T) { testFramework(t, HeapSort) } @@ -187,6 +191,10 @@ func BenchmarkMerge(b *testing.B) { benchmarkFramework(b, Mergesort) } +func BenchmarkMergeIter(b *testing.B) { + benchmarkFramework(b, MergeIter) +} + func BenchmarkHeap(b *testing.B) { benchmarkFramework(b, HeapSort) } From 1378d8ce359f7b488da0af65a142350be205bde7 Mon Sep 17 00:00:00 2001 From: Aniruddha Bhattacharjee Date: Tue, 11 Jan 2022 17:05:30 +0530 Subject: [PATCH 313/488] Graphs articulation points (#452) * Articualtion point initial commit * Refactor the function definitions * Add introduction comments and helpful links * Add test for articulation point algorithm * Inital commit for articulation point test * Correct test cases * Rename files to conform to the naming conventions * Add comments * Updated Documentation in README.md * Remove earlier files * Updated Documentation in README.md * Rename dfs to ArticulationPointHelper to avoid confusion * Updated Documentation in README.md * Make the helper function unexported * Updated Documentation in README.md * Refactor the code to avoid global variables * Updated Documentation in README.md * Refactor to use structs instead function parameters * Updated Documentation in README.md * Restructure comments to compile with project conventions * Updated Documentation in README.md * Linting changes * Reduce comment length and accommodate review comments * Updated Documentation in README.md * Updated Documentation in README.md * Modify function definition to pass graph parameter as a pointer Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj Co-authored-by: Rak Laptudirm --- README.md | 39 ++++++------ graph/articulationpoints.go | 100 +++++++++++++++++++++++++++++++ graph/articulationpoints_test.go | 82 +++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 18 deletions(-) create mode 100644 graph/articulationpoints.go create mode 100644 graph/articulationpoints_test.go diff --git a/README.md b/README.md index 03f8529c5..0743c1981 100644 --- a/README.md +++ b/README.md @@ -390,16 +390,17 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`BreadthFirstSearch`](./graph/breadthfirstsearch.go#L9): BreadthFirstSearch is an algorithm for traversing and searching graph data structures. It starts at an arbitrary node of a graph, and explores all of the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level. Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) reference: https://en.wikipedia.org/wiki/Breadth-first_search -2. [`DepthFirstSearch`](./graph/depthfirstsearch.go#L53): No description provided. -3. [`DepthFirstSearchHelper`](./graph/depthfirstsearch.go#L21): No description provided. -4. [`FloydWarshall`](./graph/floydwarshall.go#L15): FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm -5. [`GetIdx`](./graph/depthfirstsearch.go#L3): No description provided. -6. [`KruskalMST`](./graph/kruskal.go#L87): KruskalMST will return a minimum spanning tree along with its total cost to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is the number of edges in the graph and n is number of nodes in it. -7. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) -8. [`NewDSU`](./graph/kruskal.go#L34): NewDSU will return an initialised DSU using the value of n which will be treated as the number of elements out of which the DSU is being made -9. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. -10. [`Topological`](./graph/topological.go#L7): Assumes that graph given is valid and possible to get a topo ordering. constraints are array of []int{a, b}, representing an edge going from a to b +1. [`ArticulationPoint`](./graph/articulationpoints.go#L19): ArticulationPoint is a function to identify articulation points in a graph. The function takes the graph as an argument and returns a boolean slice which indicates whether a vertex is an articulation point or not. Worst Case Time Complexity: O(|V| + |E|) Auxiliary Space: O(|V|) reference: https://en.wikipedia.org/wiki/Biconnected_component and https://cptalks.quora.com/Cut-Vertex-Articulation-point +2. [`BreadthFirstSearch`](./graph/breadthfirstsearch.go#L9): BreadthFirstSearch is an algorithm for traversing and searching graph data structures. It starts at an arbitrary node of a graph, and explores all of the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level. Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) reference: https://en.wikipedia.org/wiki/Breadth-first_search +3. [`DepthFirstSearch`](./graph/depthfirstsearch.go#L53): No description provided. +4. [`DepthFirstSearchHelper`](./graph/depthfirstsearch.go#L21): No description provided. +5. [`FloydWarshall`](./graph/floydwarshall.go#L15): FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm +6. [`GetIdx`](./graph/depthfirstsearch.go#L3): No description provided. +7. [`KruskalMST`](./graph/kruskal.go#L87): KruskalMST will return a minimum spanning tree along with its total cost to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is the number of edges in the graph and n is number of nodes in it. +8. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) +9. [`NewDSU`](./graph/kruskal.go#L34): NewDSU will return an initialised DSU using the value of n which will be treated as the number of elements out of which the DSU is being made +10. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. +11. [`Topological`](./graph/topological.go#L7): Assumes that graph given is valid and possible to get a topo ordering. constraints are array of []int{a, b}, representing an edge going from a to b --- ##### Types @@ -605,6 +606,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`IsPalindrome`](./strings/palindrome/ispalindrome.go#L26): No description provided. +2. [`IsPalindromeRecursive`](./strings/palindrome/ispalindrome.go#L39): No description provided. ---
@@ -836,14 +838,15 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 4. [`HeapSort`](./sort/heapsort.go#L121): No description provided. 5. [`ImprovedSimpleSort`](./sort/simplesort.go#L25): ImprovedSimpleSort is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort 6. [`InsertionSort`](./sort/insertionsort.go#L3): No description provided. -7. [`Mergesort`](./sort/mergesort.go#L35): Mergesort Perform mergesort on a slice of ints -8. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. -9. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array -10. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array -11. [`RadixSort`](./sort/radixsort.go#L35): No description provided. -12. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. -13. [`ShellSort`](./sort/shellsort.go#L3): No description provided. -14. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. +7. [`MergeIter`](./sort/mergesort.go#L51): No description provided. +8. [`Mergesort`](./sort/mergesort.go#L37): Mergesort Perform mergesort on a slice of ints +9. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. +10. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array +11. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array +12. [`RadixSort`](./sort/radixsort.go#L35): No description provided. +13. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. +14. [`ShellSort`](./sort/shellsort.go#L3): No description provided. +15. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. --- ##### Types diff --git a/graph/articulationpoints.go b/graph/articulationpoints.go new file mode 100644 index 000000000..8c295d639 --- /dev/null +++ b/graph/articulationpoints.go @@ -0,0 +1,100 @@ +package graph + +import "github.com/TheAlgorithms/Go/math/min" + +type apHelper struct { + is_ap []bool + visited []bool + child_cnt []int + discovery_time []int + earliest_discovery []int +} + +// ArticulationPoint is a function to identify articulation points in a graph. +// The function takes the graph as an argument and returns a boolean slice +// which indicates whether a vertex is an articulation point or not. +// Worst Case Time Complexity: O(|V| + |E|) +// Auxiliary Space: O(|V|) +// reference: https://en.wikipedia.org/wiki/Biconnected_component and https://cptalks.quora.com/Cut-Vertex-Articulation-point +func ArticulationPoint(graph *Graph) []bool { + // time variable to keep track of the time of discovery_time of a vertex + time := 0 + + //initialize all the variables + apHelperInstance := &apHelper{ + is_ap: make([]bool, graph.vertices), + visited: make([]bool, graph.vertices), + child_cnt: make([]int, graph.vertices), + // integer slice to store the discovery time of a vertex as we traverse + // the graph in a depth first manner + discovery_time: make([]int, graph.vertices), + // integer slice to store the earliest discovered vertex reachable from a vertex + earliest_discovery: make([]int, graph.vertices), + } + articulationPointHelper( + apHelperInstance, + 0, + -1, + &time, + graph, + ) + + if apHelperInstance.child_cnt[0] == 1 { + // if the root has only one child, it is not an articulation point + apHelperInstance.is_ap[0] = false + } + + return apHelperInstance.is_ap +} + +// articulationPointHelper is a recursive function to traverse the graph +// and mark articulation points. Based on the depth first search transversal +// of the graph, however modified to keep track and update the +// `child_cnt`, `discovery_time`` and `earliest_discovery` slices defined above +func articulationPointHelper( + apHelperInstance *apHelper, + vertex int, + parent int, + time *int, + graph *Graph, +) { + apHelperInstance.visited[vertex] = true + + // Mark the time of discovery of a vertex + // set the earliest discovery time to the discovered time + // increment the time + apHelperInstance.discovery_time[vertex] = *time + apHelperInstance.earliest_discovery[vertex] = apHelperInstance.discovery_time[vertex] + *time++ + + for next_vertex := range graph.edges[vertex] { + if next_vertex == parent { + continue + } + + if apHelperInstance.visited[next_vertex] { + apHelperInstance.earliest_discovery[vertex] = min.Int( + apHelperInstance.earliest_discovery[vertex], + apHelperInstance.discovery_time[next_vertex], + ) + continue + } + + apHelperInstance.child_cnt[vertex]++ + articulationPointHelper( + apHelperInstance, + next_vertex, + vertex, + time, + graph, + ) + apHelperInstance.earliest_discovery[vertex] = min.Int( + apHelperInstance.earliest_discovery[vertex], + apHelperInstance.earliest_discovery[next_vertex], + ) + if apHelperInstance.earliest_discovery[next_vertex] >= apHelperInstance.discovery_time[vertex] { + apHelperInstance.is_ap[vertex] = true + } + + } +} diff --git a/graph/articulationpoints_test.go b/graph/articulationpoints_test.go new file mode 100644 index 000000000..a9dca3e6d --- /dev/null +++ b/graph/articulationpoints_test.go @@ -0,0 +1,82 @@ +package graph + +import ( + "reflect" + "testing" +) + +func TestArticulationPoints(t *testing.T) { + var testCases = []struct { + description string + graph Graph + expected []bool + }{ + { + "Linear tree structure", + Graph{ + vertices: 5, + edges: map[int]map[int]int{ + 0: { + 1: 0, + }, + + 1: { + 0: 0, + 2: 0, + }, + + 2: { + 1: 0, + 3: 0, + }, + + 3: { + 2: 0, + 4: 0, + }, + }, + }, + []bool{false, true, true, true, false}, + }, { + "A complete graph", + Graph{ + vertices: 4, + edges: map[int]map[int]int{ + 0: { + 1: 0, + 2: 0, + 3: 0, + }, + + 1: { + 0: 0, + 2: 0, + 3: 0, + }, + + 2: { + 0: 0, + 1: 0, + 3: 0, + }, + + 3: { + 0: 0, + 1: 0, + 2: 0, + }, + }, + }, + []bool{false, false, false, false}, + }, + } + + for _, test := range testCases { + t.Run(test.description, func(t *testing.T) { + is_ap := ArticulationPoint(&test.graph) + if !reflect.DeepEqual(is_ap, test.expected) { + t.Logf("FAIL: %s", test.description) + } + }) + } +} From 63bca76880283598d5a98764f501a0aa906d62d4 Mon Sep 17 00:00:00 2001 From: qzQi <62093728+qzQi@users.noreply.github.com> Date: Mon, 24 Jan 2022 17:07:00 +0800 Subject: [PATCH 314/488] merge: Update singlylinkedlist.go (#463) fix int -->interface{} --- structure/linkedlist/singlylinkedlist.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structure/linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go index 5dd92e335..5b9d71787 100644 --- a/structure/linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -29,7 +29,7 @@ func (ll *Singly) AddAtBeg(val interface{}) { } // AddAtEnd adds a new snode with given value at the end of the list. -func (ll *Singly) AddAtEnd(val int) { +func (ll *Singly) AddAtEnd(val interface{}) { n := NewNode(val) if ll.Head == nil { From 331446cfd3fccf460ee7b27f972069f644127c3b Mon Sep 17 00:00:00 2001 From: Simon Berndtsson Date: Sat, 5 Feb 2022 20:48:57 +0100 Subject: [PATCH 315/488] Simplify BreadthFirstSearch.go (#465) Remove redundant if clause which condition is always met at line of execution --- graph/breadthfirstsearch.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/graph/breadthfirstsearch.go b/graph/breadthfirstsearch.go index 93d29f9e4..7325c06a3 100644 --- a/graph/breadthfirstsearch.go +++ b/graph/breadthfirstsearch.go @@ -13,9 +13,7 @@ func BreadthFirstSearch(start, end, nodes int, edges [][]int) (isConnected bool, queue = append(queue, start) for len(queue) > 0 { v := queue[0] - if len(queue) > 0 { - queue = queue[1:] - } + queue = queue[1:] for i := 0; i < len(edges[v]); i++ { if discovered[i] == 0 && edges[v][i] > 0 { if i == end { From 30292322c165952c32f0e2d981540363f6cfe848 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 10 Feb 2022 16:01:27 +0300 Subject: [PATCH 316/488] merge: CRC8 algo (#469) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * feat: abs algo * Updated Documentation in README.md * fix: add comment * Updated Documentation in README.md * fix: new comment * Updated Documentation in README.md * fix: rename func and remove package * Updated Documentation in README.md * Update math/abs.go Co-authored-by: Taj * Updated Documentation in README.md * Update math/binary/abs.go Co-authored-by: Taj * Updated Documentation in README.md * fix: rename func and move binary test * feat: crc8 algorithm * Updated Documentation in README.md * fix test * fix after review * Updated Documentation in README.md * fix after review Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- README.md | 19 +++++++++++ checksum/crc/crc8.go | 66 +++++++++++++++++++++++++++++++++++++++ checksum/crc/crc8_test.go | 59 ++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 checksum/crc/crc8.go create mode 100644 checksum/crc/crc8_test.go diff --git a/README.md b/README.md index 0743c1981..fbb464a0a 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,25 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 8. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. 9. [`RomanToInteger`](./conversion/romantointeger.go#L40): RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. +--- +
+ crc + +--- + +##### Package crc describes algorithms for finding various CRC checksums + +--- +##### Functions: + +1. [`CalculateCRC8`](./checksum/crc/crc8.go#L26): CalculateCRC8 This function calculate CRC8 checksum. + +--- +##### Types + +1. [`CRCModel`](./checksum/crc/crc8.go#L16): No description provided. + + ---
diffiehellman diff --git a/checksum/crc/crc8.go b/checksum/crc/crc8.go new file mode 100644 index 000000000..3c69aeec2 --- /dev/null +++ b/checksum/crc/crc8.go @@ -0,0 +1,66 @@ +// crc8.go +// description: Calculate CRC8 +// details: +// A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks +// and storage devices to detect accidental changes to raw data. +// See more [CRC](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) +// author(s) [red_byte](https://github.com/i-redbyte) +// see crc8_test.go + +// Package crc describes algorithms for finding various CRC checksums +package crc + +import "math/bits" + +// CRCModel contains the necessary parameters for calculating the DRC algorithm +type CRCModel struct { + Poly uint8 + Init uint8 + RefIn bool + RefOut bool + XorOut uint8 + Name string +} + +// CalculateCRC8 This function calculate CRC8 checksum. +func CalculateCRC8(data []byte, model CRCModel) uint8 { + table := getTable(model) + crcResult := model.Init + crcResult = addBytes(data, model, crcResult, table) + if model.RefOut { + crcResult = bits.Reverse8(crcResult) + } + return crcResult ^ model.XorOut +} + +// This function get the result of adding the bytes in data to the crc +func addBytes(data []byte, model CRCModel, crcResult uint8, table []uint8) uint8 { + if model.RefIn { + for _, d := range data { + d = bits.Reverse8(d) + crcResult = table[crcResult^d] + } + return crcResult + } + for _, d := range data { + crcResult = table[crcResult^d] + } + return crcResult +} + +// This function get 256-byte (256x8) table for efficient processing. +func getTable(model CRCModel) []uint8 { + table := make([]uint8, 256) + for i := 0; i < 256; i++ { + crc := uint8(i) + for j := 0; j < 8; j++ { + isSetBit := (crc & 0x80) != 0 + crc <<= 1 + if isSetBit { + crc ^= model.Poly + } + } + table[i] = crc + } + return table +} diff --git a/checksum/crc/crc8_test.go b/checksum/crc/crc8_test.go new file mode 100644 index 000000000..ee6ac2188 --- /dev/null +++ b/checksum/crc/crc8_test.go @@ -0,0 +1,59 @@ +// crc8_test.go +// description: Test for calculate crc8 +// author(s) [red_byte](https://github.com/i-redbyte) +// see crc8.go + +package crc + +import ( + "fmt" + "testing" +) + +var ( + CRC8 = CRCModel{0x07, 0x00, false, false, 0x00, "CRC-8"} + CRC8CDMA2000 = CRCModel{0x9B, 0xFF, false, false, 0x00, "CRC-8/CDMA2000"} + CRC8DARC = CRCModel{0x39, 0x00, true, true, 0x00, "CRC-8/DARC"} + CRC8DVBS2 = CRCModel{0xD5, 0x00, false, false, 0x00, "CRC-8/DVB-S2"} + CRC8EBU = CRCModel{0x1D, 0xFF, true, true, 0x00, "CRC-8/EBU"} + CRC8ICODE = CRCModel{0x1D, 0xFD, false, false, 0x00, "CRC-8/I-CODE"} + CRC8ITU = CRCModel{0x07, 0x00, false, false, 0x55, "CRC-8/ITU"} + CRC8MAXIM = CRCModel{0x31, 0x00, true, true, 0x00, "CRC-8/MAXIM"} + CRC8ROHC = CRCModel{0x07, 0xFF, true, true, 0x00, "CRC-8/ROHC"} + CRC8WCDMA = CRCModel{0x9B, 0x00, true, true, 0x00, "CRC-8/WCDMA"} +) + +func TestCalculateCRC8(t *testing.T) { + data := []byte("123456789") + tests := []struct { + name string + data []byte + model CRCModel + want uint8 + }{ + {CRC8.Name, data, CRC8, 0xF4}, + {CRC8CDMA2000.Name, data, CRC8CDMA2000, 0xDA}, + {CRC8DARC.Name, data, CRC8DARC, 0x15}, + {CRC8DVBS2.Name, data, CRC8DVBS2, 0xBC}, + {CRC8EBU.Name, data, CRC8EBU, 0x97}, + {CRC8ICODE.Name, data, CRC8ICODE, 0x7E}, + {CRC8ITU.Name, data, CRC8ITU, 0xA1}, + {CRC8MAXIM.Name, data, CRC8MAXIM, 0xA1}, + {CRC8ROHC.Name, data, CRC8ROHC, 0xD0}, + {CRC8WCDMA.Name, data, CRC8WCDMA, 0x25}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fmt.Println(CalculateCRC8(test.data, test.model)) + if got := CalculateCRC8(test.data, test.model); got != test.want { + t.Errorf("CalculateCRC8() = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkCalculateCRC8(b *testing.B) { + for i := 0; i < b.N; i++ { + CalculateCRC8([]byte("123456789"), CRC8) + } +} From 2cc5f5a27da9e56a7303f3a0e0010fc15dc2047e Mon Sep 17 00:00:00 2001 From: Aniruddha Bhattacharjee Date: Fri, 11 Feb 2022 13:55:20 +0530 Subject: [PATCH 317/488] merge: Longest increasing subsequence greedy (#466) * Initial commit for the greedy implementation of the longest increasing subsequence question * Updated Documentation in README.md * Minor naming changes * Add test for longest increasing subsequence function * Change the lowerBound function * Remove extraneous blank lines * Updated Documentation in README.md * Reorganize files and use existing tests for longest increasing subsequence * Updated Documentation in README.md * Edit description * Updated Documentation in README.md * Refactor test for longest increasing subsequence * Updated Documentation in README.md * Unexport utility test function * Updated Documentation in README.md Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Rak Laptudirm --- README.md | 15 ++++--- dynamic/longestincreasingsubsequence_test.go | 12 +++++- dynamic/longestincreasingsubsequencegreedy.go | 43 +++++++++++++++++++ 3 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 dynamic/longestincreasingsubsequencegreedy.go diff --git a/README.md b/README.md index fbb464a0a..a608159be 100644 --- a/README.md +++ b/README.md @@ -275,13 +275,14 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 7. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit 8. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L8): LongestCommonSubsequence function 9. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order -10. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function -11. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function -12. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function -13. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function -14. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate -15. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) -16. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number +10. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ +11. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function +12. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function +13. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function +14. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function +15. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate +16. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) +17. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number ---
diff --git a/dynamic/longestincreasingsubsequence_test.go b/dynamic/longestincreasingsubsequence_test.go index ed021db1e..81ea2fcde 100644 --- a/dynamic/longestincreasingsubsequence_test.go +++ b/dynamic/longestincreasingsubsequence_test.go @@ -7,7 +7,7 @@ import ( "github.com/TheAlgorithms/Go/dynamic" ) -func TestLongestIncreasingSubsequence(t *testing.T) { +func longestIncreasingSubsequenceTest(t *testing.T, algorithm func(nums []int) int) { td := []struct { elements []int expectedLen int @@ -21,10 +21,18 @@ func TestLongestIncreasingSubsequence(t *testing.T) { } for _, tc := range td { t.Run(fmt.Sprint("test with", tc.elements), func(t *testing.T) { - actualLen := dynamic.LongestIncreasingSubsequence(tc.elements) + actualLen := algorithm(tc.elements) if tc.expectedLen != actualLen { t.Fatalf("expecting a sequence of len %d to be found but the actual len was %d; input: %v", tc.expectedLen, actualLen, tc.elements) } }) } } + +func TestLongestIncreasingSubsequence(t *testing.T) { + longestIncreasingSubsequenceTest(t, dynamic.LongestIncreasingSubsequence) +} + +func TestLongestIncreasingSubsequenceGreedy(t *testing.T) { + longestIncreasingSubsequenceTest(t, dynamic.LongestIncreasingSubsequenceGreedy) +} diff --git a/dynamic/longestincreasingsubsequencegreedy.go b/dynamic/longestincreasingsubsequencegreedy.go new file mode 100644 index 000000000..438836527 --- /dev/null +++ b/dynamic/longestincreasingsubsequencegreedy.go @@ -0,0 +1,43 @@ +package dynamic + +// LongestIncreasingSubsequenceGreedy is a function to find the longest increasing +// subsequence in a given array using a greedy approach. +// The dynamic programming approach is implemented alongside this one. +// Worst Case Time Complexity: O(nlogn) +// Auxiliary Space: O(n), where n is the length of the array(slice). +// Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ +func LongestIncreasingSubsequenceGreedy(nums []int) int { + longestIncreasingSubsequnce := make([]int, 0) + + for _, num := range nums { + // find the leftmost index in longestIncreasingSubsequnce with value >= num + leftmostIndex := lowerBound(longestIncreasingSubsequnce, num) + + if leftmostIndex == len(longestIncreasingSubsequnce) { + longestIncreasingSubsequnce = append(longestIncreasingSubsequnce, num) + } else { + longestIncreasingSubsequnce[leftmostIndex] = num + } + } + + return len(longestIncreasingSubsequnce) +} + +// Function to find the leftmost index in arr with value >= val, mimicking the inbuild lower_bound function in C++ +// Time Complexity: O(logn) +// Auxiliary Space: O(1) +func lowerBound(arr []int, val int) int { + searchWindowLeft, searchWindowRight := 0, len(arr)-1 + + for searchWindowLeft <= searchWindowRight { + middle := (searchWindowLeft + searchWindowRight) / 2 + + if arr[middle] < val { + searchWindowLeft = middle + 1 + } else { + searchWindowRight = middle - 1 + } + } + + return searchWindowRight + 1 +} From 4f29592b5402d834ee6eccfcafe946124902fdb9 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Fri, 11 Mar 2022 07:24:43 +0300 Subject: [PATCH 318/488] merge: Added Square root algorithm using fast inverse square root (#471) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * feat: abs algo * Updated Documentation in README.md * fix: add comment * Updated Documentation in README.md * fix: new comment * Updated Documentation in README.md * fix: rename func and remove package * Updated Documentation in README.md * Update math/abs.go Co-authored-by: Taj * Updated Documentation in README.md * Update math/binary/abs.go Co-authored-by: Taj * Updated Documentation in README.md * fix: rename func and move binary test * feat: bitwise sqrt * Updated Documentation in README.md * add comment * fix after review * fix: bitwise sqrt and test Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- README.md | 3 ++- math/binary/sqrt.go | 24 +++++++++++++++++++ math/binary/sqrt_test.go | 50 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 math/binary/sqrt.go create mode 100644 math/binary/sqrt_test.go diff --git a/README.md b/README.md index a608159be..4521e550b 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 6. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift 7. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. 8. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n -9. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence +9. [`Sqrt`](./math/binary/sqrt.go#L16): No description provided. +10. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---
diff --git a/math/binary/sqrt.go b/math/binary/sqrt.go new file mode 100644 index 000000000..4d352ed49 --- /dev/null +++ b/math/binary/sqrt.go @@ -0,0 +1,24 @@ +// sqrt.go +// description: Square root calculation +// details: +// Calculating the square root using binary operations and a magic number 0x5f3759df [See more](https://en.wikipedia.org/wiki/Fast_inverse_square_root) +// author(s) [red_byte](https://github.com/i-redbyte) +// see sqrt_test.go + +package binary + +import ( + "math" +) + +const threeHalves = 1.5 + +func Sqrt(number float32) float32 { + var halfHumber, y float32 + halfHumber = number * 0.5 + z := math.Float32bits(number) + z = 0x5f3759df - (z >> 1) // floating point bit level hacking + y = math.Float32frombits(z) + y = y * (threeHalves - (halfHumber * y * y)) // Newton's approximation + return 1 / y +} diff --git a/math/binary/sqrt_test.go b/math/binary/sqrt_test.go new file mode 100644 index 000000000..426794fd2 --- /dev/null +++ b/math/binary/sqrt_test.go @@ -0,0 +1,50 @@ +// sqrt_test.go +// description: Test for square root calculation +// author(s) [red_byte](https://github.com/i-redbyte) +// see sqrt.go + +package binary + +import ( + "math" + "testing" +) + +const epsilon = 0.2 + +func TestSquareRootCalculation(t *testing.T) { + tests := []struct { + name string + number float32 + want float64 + }{ + {"sqrt(1)", 1, 1}, + {"sqrt(9)", 9, 3}, + {"sqrt(25)", 25, 5}, + {"sqrt(121)", 121, 11}, + {"sqrt(10000)", 10000, 100}, + {"sqrt(169)", 169, 13}, + {"sqrt(0)", 0, 0}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := Sqrt(test.number) + delta := math.Abs(test.want - float64(got)) + if delta > epsilon { + t.Errorf("Sqrt() = %v, want %v delta %v", got, test.want, delta) + } + }) + } +} + +func BenchmarkSquareRootCalculation(b *testing.B) { + for i := 0; i < b.N; i++ { + Sqrt(225) + } +} + +func BenchmarkMathSqrt(b *testing.B) { + for i := 0; i < b.N; i++ { + math.Sqrt(225) + } +} From b875ba70940e17418904f25b0c6ad08b674a19aa Mon Sep 17 00:00:00 2001 From: XU ZHIWEI Date: Fri, 11 Mar 2022 19:10:34 +0800 Subject: [PATCH 319/488] feat: implementation of find kth element in array (#472) (#473) * feat: implementation of find kth element in array (#472) * feat: implementation of find kth element in array * feat: implementation of find kth element in array * Updated Documentation in README.md Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Rak Laptudirm --- README.md | 21 +++++---- math/kthnumber.go | 43 +++++++++++++++++ math/kthnumber_test.go | 104 +++++++++++++++++++++++++++++++++++++++++ sort/quicksort.go | 4 +- 4 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 math/kthnumber.go create mode 100644 math/kthnumber_test.go diff --git a/README.md b/README.md index 4521e550b..8b3a9287c 100644 --- a/README.md +++ b/README.md @@ -545,8 +545,10 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Abs`](./math/abs.go#L11): Abs returns absolute value -2. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -3. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +2. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +3. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +4. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +5. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. ---
@@ -861,13 +863,14 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 6. [`InsertionSort`](./sort/insertionsort.go#L3): No description provided. 7. [`MergeIter`](./sort/mergesort.go#L51): No description provided. 8. [`Mergesort`](./sort/mergesort.go#L37): Mergesort Perform mergesort on a slice of ints -9. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. -10. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array -11. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array -12. [`RadixSort`](./sort/radixsort.go#L35): No description provided. -13. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. -14. [`ShellSort`](./sort/shellsort.go#L3): No description provided. -15. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. +9. [`Partition`](./sort/quicksort.go#L10): No description provided. +10. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. +11. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array +12. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array +13. [`RadixSort`](./sort/radixsort.go#L35): No description provided. +14. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. +15. [`ShellSort`](./sort/shellsort.go#L3): No description provided. +16. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. --- ##### Types diff --git a/math/kthnumber.go b/math/kthnumber.go new file mode 100644 index 000000000..802e2cf50 --- /dev/null +++ b/math/kthnumber.go @@ -0,0 +1,43 @@ +package math + +import ( + "github.com/TheAlgorithms/Go/search" + "github.com/TheAlgorithms/Go/sort" +) + +// FindKthMax returns the kth large element given an integer slice +// with nil `error` if found and returns -1 with `error` `search.ErrNotFound` +// if not found. NOTE: The `nums` slice gets mutated in the process. +func FindKthMax(nums []int, k int) (int, error) { + index := len(nums) - k + return kthNumber(nums, index) +} + +// FindKthMin returns kth small element given an integer slice +// with nil `error` if found and returns -1 with `error` `search.ErrNotFound` +// if not found. NOTE: The `nums` slice gets mutated in the process. +func FindKthMin(nums []int, k int) (int, error) { + index := k - 1 + return kthNumber(nums, index) +} + +// kthNumber use the selection algorithm (based on the partition method - the same one as used in quicksort). +func kthNumber(nums []int, k int) (int, error) { + if k < 0 || k >= len(nums) { + return -1, search.ErrNotFound + } + start := 0 + end := len(nums) - 1 + for start <= end { + pivot := sort.Partition(nums, start, end) + if k == pivot { + return nums[pivot], nil + } + if k > pivot { + start = pivot + 1 + continue + } + end = pivot - 1 + } + return -1, search.ErrNotFound +} diff --git a/math/kthnumber_test.go b/math/kthnumber_test.go new file mode 100644 index 000000000..558cf2240 --- /dev/null +++ b/math/kthnumber_test.go @@ -0,0 +1,104 @@ +package math + +import ( + "github.com/TheAlgorithms/Go/search" + "testing" +) + +func TestFindKthMax(t *testing.T) { + sortTests := []struct { + input []int + k int + expected int + err error + name string + }{ + { + input: []int{6, 7, 0, -1, 10, 70, 8, 22, 3, 9}, + k: 3, + expected: 10, + name: "3th largest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + k: 3, + expected: -1, + name: "3th largest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1}, + k: 7, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + { + input: []int{}, + k: 1, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + } + for _, test := range sortTests { + t.Run(test.name, func(t *testing.T) { + actual, err := FindKthMax(test.input, test.k) + if err != test.err { + t.Errorf("name:%v FindKthMax() = %v, want err: %v", test.name, err, test.err) + } + if actual != test.expected { + t.Errorf("test %s failed", test.name) + t.Errorf("actual %v expected %v", actual, test.expected) + } + }) + } +} + +func TestFindKthMin(t *testing.T) { + sortTests := []struct { + input []int + k int + expected int + err error + name string + }{ + { + input: []int{6, 7, 0, -1, 10, 70, 8, 22, 3, 9}, + k: 3, + expected: 3, + name: "3th smallest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + k: 3, + expected: -1, + name: "3th smallest number", + }, + { + input: []int{-1, -1, -1, -1, -1, -1}, + k: 7, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + { + input: []int{}, + k: 1, + expected: -1, + err: search.ErrNotFound, + name: "This should be an error", + }, + } + for _, test := range sortTests { + t.Run(test.name, func(t *testing.T) { + actual, err := FindKthMin(test.input, test.k) + if err != test.err { + t.Errorf("name:%v FindKthMin() = %v, want err: %v", test.name, err, test.err) + } + if actual != test.expected { + t.Errorf("test %s failed", test.name) + t.Errorf("actual %v expected %v", actual, test.expected) + } + }) + } +} diff --git a/sort/quicksort.go b/sort/quicksort.go index 6ecbac20e..36319cbea 100644 --- a/sort/quicksort.go +++ b/sort/quicksort.go @@ -7,7 +7,7 @@ package sort -func partition(arr []int, low, high int) int { +func Partition(arr []int, low, high int) int { index := low - 1 pivotElement := arr[high] for i := low; i < high; i++ { @@ -27,7 +27,7 @@ func QuickSortRange(arr []int, low, high int) { } if low < high { - pivot := partition(arr, low, high) + pivot := Partition(arr, low, high) QuickSortRange(arr, low, pivot-1) QuickSortRange(arr, pivot+1, high) } From 3c6401000f114f9b370df952ee6ae890f77ce3f6 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 17 Mar 2022 22:42:33 +0300 Subject: [PATCH 320/488] package name geometry (#474) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * feat: abs algo * Updated Documentation in README.md * fix: add comment * Updated Documentation in README.md * fix: new comment * Updated Documentation in README.md * fix: rename func and remove package * Updated Documentation in README.md * Update math/abs.go Co-authored-by: Taj * Updated Documentation in README.md * Update math/binary/abs.go Co-authored-by: Taj * Updated Documentation in README.md * fix: rename func and move binary test * add package description and add function name to comment * Updated Documentation in README.md * rename Intercept method to YIntercept * Updated Documentation in README.md * fix strings * Updated Documentation in README.md Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- README.md | 21 ++++++++++++--------- math/geometry/straightlines.go | 19 ++++++++++--------- math/geometry/straightlines_test.go | 4 ++-- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 8b3a9287c..4d97baa6f 100644 --- a/README.md +++ b/README.md @@ -382,22 +382,25 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- +##### Package geometry contains geometric algorithms + +--- ##### Functions: -1. [`Distance`](./math/geometry/straightlines.go#L17): Calculates the shortest distance between two points. -2. [`Intercept`](./math/geometry/straightlines.go#L36): Calculates the Y-Intercept of a line from a specific Point. -3. [`IsParallel`](./math/geometry/straightlines.go#L41): Checks if two lines are parallel or not. -4. [`IsPerpendicular`](./math/geometry/straightlines.go#L46): Checks if two lines are perpendicular or not. -5. [`PointDistance`](./math/geometry/straightlines.go#L52): Calculates the distance of a given Point from a given line. The slice should contain the coefficiet of x, the coefficient of y and the constant in the respective order. -6. [`Section`](./math/geometry/straightlines.go#L23): Calculates the Point that divides a line in specific ratio. DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. -7. [`Slope`](./math/geometry/straightlines.go#L31): Calculates the slope (gradient) of a line. +1. [`Distance`](./math/geometry/straightlines.go#L18): Distance calculates the shortest distance between two points. +2. [`IsParallel`](./math/geometry/straightlines.go#L42): IsParallel checks if two lines are parallel or not. +3. [`IsPerpendicular`](./math/geometry/straightlines.go#L47): IsPerpendicular checks if two lines are perpendicular or not. +4. [`PointDistance`](./math/geometry/straightlines.go#L53): PointDistance calculates the distance of a given Point from a given line. The slice should contain the coefficiet of x, the coefficient of y and the constant in the respective order. +5. [`Section`](./math/geometry/straightlines.go#L24): Section calculates the Point that divides a line in specific ratio. DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. +6. [`Slope`](./math/geometry/straightlines.go#L32): Slope calculates the slope (gradient) of a line. +7. [`YIntercept`](./math/geometry/straightlines.go#L37): YIntercept calculates the Y-Intercept of a line from a specific Point. --- ##### Types -1. [`Line`](./math/geometry/straightlines.go#L12): No description provided. +1. [`Line`](./math/geometry/straightlines.go#L13): No description provided. -2. [`Point`](./math/geometry/straightlines.go#L8): No description provided. +2. [`Point`](./math/geometry/straightlines.go#L9): No description provided. --- diff --git a/math/geometry/straightlines.go b/math/geometry/straightlines.go index 355263581..cf1951b07 100644 --- a/math/geometry/straightlines.go +++ b/math/geometry/straightlines.go @@ -1,10 +1,11 @@ +// Package geometry contains geometric algorithms package geometry import ( "math" ) -// Defines a point with x and y coordinates. +// Point defines a point with x and y coordinates. type Point struct { X, Y float64 } @@ -13,12 +14,12 @@ type Line struct { P1, P2 Point } -// Calculates the shortest distance between two points. +// Distance calculates the shortest distance between two points. func Distance(a, b *Point) float64 { return math.Sqrt(math.Pow(a.X-b.X, 2) + math.Pow(a.Y-b.Y, 2)) } -// Calculates the Point that divides a line in specific ratio. +// Section calculates the Point that divides a line in specific ratio. // DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. func Section(p1, p2 *Point, r float64) Point { var point Point @@ -27,27 +28,27 @@ func Section(p1, p2 *Point, r float64) Point { return point } -// Calculates the slope (gradient) of a line. +// Slope calculates the slope (gradient) of a line. func Slope(l *Line) float64 { return (l.P2.Y - l.P1.Y) / (l.P2.X - l.P1.X) } -// Calculates the Y-Intercept of a line from a specific Point. -func Intercept(p *Point, slope float64) float64 { +// YIntercept calculates the Y-Intercept of a line from a specific Point. +func YIntercept(p *Point, slope float64) float64 { return p.Y - (slope * p.X) } -// Checks if two lines are parallel or not. +// IsParallel checks if two lines are parallel or not. func IsParallel(l1, l2 *Line) bool { return Slope(l1) == Slope(l2) } -// Checks if two lines are perpendicular or not. +// IsPerpendicular checks if two lines are perpendicular or not. func IsPerpendicular(l1, l2 *Line) bool { return Slope(l1)*Slope(l2) == -1 } -// Calculates the distance of a given Point from a given line. +// PointDistance calculates the distance of a given Point from a given line. // The slice should contain the coefficiet of x, the coefficient of y and the constant in the respective order. func PointDistance(p *Point, equation [3]float64) float64 { return math.Abs(equation[0]*p.X+equation[1]*p.Y+equation[2]) / math.Sqrt(math.Pow(equation[0], 2)+math.Pow(equation[1], 2)) diff --git a/math/geometry/straightlines_test.go b/math/geometry/straightlines_test.go index 262bc3147..d71a78e5a 100644 --- a/math/geometry/straightlines_test.go +++ b/math/geometry/straightlines_test.go @@ -37,9 +37,9 @@ func TestIntercept(t *testing.T) { p := Point{0, 3} var slope float64 = -5 var wantedIntercept float64 = 3 - var calculatedIntercept float64 = Intercept(&p, slope) + var calculatedIntercept float64 = YIntercept(&p, slope) if calculatedIntercept != wantedIntercept { - t.Fatalf("Failed to calculate Intercept.") + t.Fatalf("Failed to calculate YIntercept.") } } From 096521a617e96802dee5a2a0d90cd1ed17ed9b22 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Sun, 20 Mar 2022 22:32:55 +0300 Subject: [PATCH 321/488] Feat/cos (#475) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * feat: abs algo * Updated Documentation in README.md * fix: add comment * Updated Documentation in README.md * fix: new comment * Updated Documentation in README.md * fix: rename func and remove package * Updated Documentation in README.md * Update math/abs.go Co-authored-by: Taj * Updated Documentation in README.md * Update math/binary/abs.go Co-authored-by: Taj * Updated Documentation in README.md * fix: rename func and move binary test * add package description and add function name to comment * Updated Documentation in README.md * rename Intercept method to YIntercept * Updated Documentation in README.md * fix strings * Updated Documentation in README.md * fix commit * added Cosine function * Updated Documentation in README.md * fix after review * Updated Documentation in README.md * fixes * fix: doc comment Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- README.md | 9 +++++---- math/cos.go | 17 +++++++++++++++++ math/cos_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 math/cos.go create mode 100644 math/cos_test.go diff --git a/README.md b/README.md index 4d97baa6f..676a85def 100644 --- a/README.md +++ b/README.md @@ -548,10 +548,11 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Abs`](./math/abs.go#L11): Abs returns absolute value -2. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -3. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -4. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -5. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +2. [`Cos`](./math/cos.go#L10): Cos returns the cosine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) [Based on the idea of Bhaskara approximation of cos(x)](https://math.stackexchange.com/questions/3886552/bhaskara-approximation-of-cosx) +3. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +4. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +5. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +6. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. ---
diff --git a/math/cos.go b/math/cos.go new file mode 100644 index 000000000..369cd588c --- /dev/null +++ b/math/cos.go @@ -0,0 +1,17 @@ +// author(s) [red_byte](https://github.com/i-redbyte) +// see cos_test.go + +package math + +import "math" + +// Cos returns the cosine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +// [Based on the idea of Bhaskara approximation of cos(x)](https://math.stackexchange.com/questions/3886552/bhaskara-approximation-of-cosx) +func Cos(x float64) float64 { + tp := 1.0 / (2.0 * math.Pi) + x *= tp + x -= 0.25 + math.Floor(x+0.25) + x *= 16.0 * (math.Abs(x) - 0.5) + x += 0.225 * x * (math.Abs(x) - 1.0) //Extra precision + return x +} diff --git a/math/cos_test.go b/math/cos_test.go new file mode 100644 index 000000000..c1df66b8d --- /dev/null +++ b/math/cos_test.go @@ -0,0 +1,45 @@ +package math + +import ( + "math" + "testing" +) + +const epsilon = 0.001 + +func TestCos(t *testing.T) { + tests := []struct { + name string + n float64 + want float64 + }{ + {"cos(0)", 0, 1}, + {"cos(90)", 90, -0.447}, + {"cos(180)", 180, -0.598}, + {"cos(1)", 1, 0.540}, + {"cos(1)", math.Pi, -1}, + {"cos(1)", math.Pi / 2, 0}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := Cos(test.n) + if math.Abs(got-test.want) >= epsilon { + t.Errorf("Cos() = %v, want %v", got, test.want) + t.Errorf("MATH Cos() = %v", math.Cos(test.n)) + } + }) + } +} + +func BenchmarkCos(b *testing.B) { + for i := 0; i < b.N; i++ { + Cos(180) + } +} + +// BenchmarkMathCos is slower because the standard library `math.Cos` calculates a more accurate value. +func BenchmarkMathCos(b *testing.B) { + for i := 0; i < b.N; i++ { + math.Cos(180) + } +} From 322859fc50fb1a2b1014919222bae869cdf5389c Mon Sep 17 00:00:00 2001 From: Taj Date: Sat, 26 Mar 2022 19:35:51 +0000 Subject: [PATCH 322/488] fix: [generic + sort] All ready for generics (#483) * fix: [generic + sort] All ready for generics * GoDocMD support for Go 1.18 * Bump Go version in workflow * Updated Documentation in README.md * bump go version in GoLangCI lint action * fix: [generic + sort] review feedback * Updated Documentation in README.md * empty commit: stuck github action Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- .github/workflows/godocmd.yml | 4 +- .github/workflows/golang_lint_and_test.yml | 2 + README.md | 33 ++++++------ constraints/contraints.go | 40 ++++++++++++++ go.mod | 2 +- sort/bubblesort.go | 5 +- sort/combSort.go | 5 +- sort/countingsort.go | 6 ++- sort/exchangesort.go | 4 +- sort/insertionsort.go | 4 +- sort/mergesort.go | 19 ++++--- sort/quicksort.go | 18 ++++--- sort/selectionsort.go | 3 +- sort/shellsort.go | 4 +- sort/simplesort.go | 8 +-- sort/sorts_test.go | 63 +++++++++++----------- 16 files changed, 143 insertions(+), 77 deletions(-) create mode 100644 constraints/contraints.go diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index 3b4f0ef4c..b69bf13d9 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -9,10 +9,10 @@ jobs: fetch-depth: 0 - uses: actions/setup-go@v2 with: - go-version: '^1.17' + go-version: '^1.18' - name: Install GoDocMD run: | - go install github.com/tjgurwara99/godocmd@v0.1.2 + go install github.com/tjgurwara99/godocmd@v0.1.3 - name: Configure Github Action run: | git config --global user.name github-action diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index 4cb59f712..29a2a9283 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -15,6 +15,8 @@ jobs: skip: "go.mod,go.sum" - name: Setup Go uses: actions/setup-go@v2 + with: + go-version: '^1.18' - name: Run Golang CI Lint uses: golangci/golangci-lint-action@v2 with: diff --git a/README.md b/README.md index 676a85def..da8fb416b 100644 --- a/README.md +++ b/README.md @@ -859,22 +859,23 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`Comb`](./sort/combSort.go#L14): No description provided. -2. [`Count`](./sort/countingsort.go#L9): No description provided. -3. [`Exchange`](./sort/exchangesort.go#L6): No description provided. -4. [`HeapSort`](./sort/heapsort.go#L121): No description provided. -5. [`ImprovedSimpleSort`](./sort/simplesort.go#L25): ImprovedSimpleSort is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort -6. [`InsertionSort`](./sort/insertionsort.go#L3): No description provided. -7. [`MergeIter`](./sort/mergesort.go#L51): No description provided. -8. [`Mergesort`](./sort/mergesort.go#L37): Mergesort Perform mergesort on a slice of ints -9. [`Partition`](./sort/quicksort.go#L10): No description provided. -10. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. -11. [`QuickSort`](./sort/quicksort.go#L37): QuickSort Sorts the entire array -12. [`QuickSortRange`](./sort/quicksort.go#L24): QuickSortRange Sorts the specified range within the array -13. [`RadixSort`](./sort/radixsort.go#L35): No description provided. -14. [`SelectionSort`](./sort/selectionsort.go#L3): No description provided. -15. [`ShellSort`](./sort/shellsort.go#L3): No description provided. -16. [`SimpleSort`](./sort/simplesort.go#L11): No description provided. +1. [`Bubble`](./sort/bubblesort.go#L9): Bubble is a simple generic definition of Bubble sort algorithm. +2. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. +3. [`Count`](./sort/countingsort.go#L11): No description provided. +4. [`Exchange`](./sort/exchangesort.go#L8): No description provided. +5. [`HeapSort`](./sort/heapsort.go#L121): No description provided. +6. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort +7. [`Insertion`](./sort/insertionsort.go#L5): No description provided. +8. [`Merge`](./sort/mergesort.go#L40): Merge Perform merge sort on a slice +9. [`MergeIter`](./sort/mergesort.go#L54): No description provided. +10. [`Partition`](./sort/quicksort.go#L12): No description provided. +11. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. +12. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array +13. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array +14. [`RadixSort`](./sort/radixsort.go#L35): No description provided. +15. [`Selection`](./sort/selectionsort.go#L5): No description provided. +16. [`Shell`](./sort/shellsort.go#L5): No description provided. +17. [`Simple`](./sort/simplesort.go#L13): No description provided. --- ##### Types diff --git a/constraints/contraints.go b/constraints/contraints.go new file mode 100644 index 000000000..ca902cec5 --- /dev/null +++ b/constraints/contraints.go @@ -0,0 +1,40 @@ +// Package constraints has some useful generic type constraints defined which is very similar to +// [golang.org/x/exp/constraints](https://pkg.go.dev/golang.org/x/exp/constraints) package. +// We refrained from using that until it gets placed into the standard library - currently +// there are some questions regarding this package [ref](https://github.com/golang/go/issues/50792). +package constraints + +// Signed is a generic type constraint for all signed integers. +type Signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// Unsigned is a generic type constraint for all unsigned integers. +type Unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 +} + +// Integer is a generic type constraint for all integers (signed and unsigned.) +type Integer interface { + Signed | Unsigned +} + +// Float is a generic type constraint for all floating point types. +type Float interface { + ~float32 | ~float64 +} + +// Number is a generic type constraint for all numeric types in Go except Complex types. +type Number interface { + Integer | Float +} + +// Ordered is a generic type constraint for all ordered data types in Go. +// Loosely speaking, in mathematics a field is an ordered field if there is a "total +// order" (a binary relation - in this case `<` symbol) such that we will always have +// if a < b then a + c < b + c and if 0 < a, 0 < b then 0 < a.b +// The idea in Go is quite similar, though only limited to Go standard types +// not user defined types. +type Ordered interface { + Integer | ~string | Float +} diff --git a/go.mod b/go.mod index e7de82f0c..23f37df27 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/TheAlgorithms/Go -go 1.17 +go 1.18 diff --git a/sort/bubblesort.go b/sort/bubblesort.go index 83242e5c5..4c40678b7 100644 --- a/sort/bubblesort.go +++ b/sort/bubblesort.go @@ -3,7 +3,10 @@ package sort -func bubbleSort(arr []int) []int { +import "github.com/TheAlgorithms/Go/constraints" + +// Bubble is a simple generic definition of Bubble sort algorithm. +func Bubble[T constraints.Ordered](arr []T) []T { swapped := true for swapped { swapped = false diff --git a/sort/combSort.go b/sort/combSort.go index fa7b173d9..76e523e34 100644 --- a/sort/combSort.go +++ b/sort/combSort.go @@ -3,6 +3,8 @@ package sort +import "github.com/TheAlgorithms/Go/constraints" + func getNextGap(gap int) int { gap = (gap * 10) / 13 if gap < 1 { @@ -11,7 +13,8 @@ func getNextGap(gap int) int { return gap } -func Comb(data []int) []int { +// Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. +func Comb[T constraints.Ordered](data []T) []T { n := len(data) gap := n swapped := true diff --git a/sort/countingsort.go b/sort/countingsort.go index 3dae5934a..6961efff8 100644 --- a/sort/countingsort.go +++ b/sort/countingsort.go @@ -6,11 +6,13 @@ package sort -func Count(data []int) []int { +import "github.com/TheAlgorithms/Go/constraints" + +func Count[T constraints.Number](data []int) []int { var aMin, aMax = -1000, 1000 count := make([]int, aMax-aMin+1) for _, x := range data { - count[x-aMin]++ + count[x-aMin]++ // this is the reason for having only Number constraint instead of Ordered. } z := 0 for i, c := range count { diff --git a/sort/exchangesort.go b/sort/exchangesort.go index b901490cb..cbf6b9b00 100644 --- a/sort/exchangesort.go +++ b/sort/exchangesort.go @@ -3,7 +3,9 @@ package sort -func Exchange(arr []int) []int { +import "github.com/TheAlgorithms/Go/constraints" + +func Exchange[T constraints.Ordered](arr []T) []T { for i := 0; i < len(arr)-1; i++ { for j := i + 1; j < len(arr); j++ { if arr[i] > arr[j] { diff --git a/sort/insertionsort.go b/sort/insertionsort.go index 11f0cd922..b51bc5379 100644 --- a/sort/insertionsort.go +++ b/sort/insertionsort.go @@ -1,6 +1,8 @@ package sort -func InsertionSort(arr []int) []int { +import "github.com/TheAlgorithms/Go/constraints" + +func Insertion[T constraints.Ordered](arr []T) []T { for currentIndex := 1; currentIndex < len(arr); currentIndex++ { temporary := arr[currentIndex] iterator := currentIndex diff --git a/sort/mergesort.go b/sort/mergesort.go index 45c17ab04..babff39f1 100644 --- a/sort/mergesort.go +++ b/sort/mergesort.go @@ -1,10 +1,13 @@ package sort -import "github.com/TheAlgorithms/Go/math/min" +import ( + "github.com/TheAlgorithms/Go/constraints" + "github.com/TheAlgorithms/Go/math/min" +) -func merge(a []int, b []int) []int { +func merge[T constraints.Ordered](a []T, b []T) []T { - var r = make([]int, len(a)+len(b)) + var r = make([]T, len(a)+len(b)) var i = 0 var j = 0 @@ -33,8 +36,8 @@ func merge(a []int, b []int) []int { } -//Mergesort Perform mergesort on a slice of ints -func Mergesort(items []int) []int { +// Merge Perform merge sort on a slice +func Merge[T constraints.Ordered](items []T) []T { if len(items) < 2 { return items @@ -42,13 +45,13 @@ func Mergesort(items []int) []int { } var middle = len(items) / 2 - var a = Mergesort(items[:middle]) - var b = Mergesort(items[middle:]) + var a = Merge(items[:middle]) + var b = Merge(items[middle:]) return merge(a, b) } -func MergeIter(items []int) []int { +func MergeIter[T constraints.Ordered](items []T) []T { for step := 1; step < len(items); step += step { for i := 0; i+step < len(items); i += 2 * step { tmp := merge(items[i:i+step], items[i+step:min.Int(i+2*step, len(items))]) diff --git a/sort/quicksort.go b/sort/quicksort.go index 36319cbea..576db395a 100644 --- a/sort/quicksort.go +++ b/sort/quicksort.go @@ -7,7 +7,9 @@ package sort -func Partition(arr []int, low, high int) int { +import "github.com/TheAlgorithms/Go/constraints" + +func Partition[T constraints.Ordered](arr []T, low, high int) int { index := low - 1 pivotElement := arr[high] for i := low; i < high; i++ { @@ -20,21 +22,21 @@ func Partition(arr []int, low, high int) int { return index + 1 } -// QuickSortRange Sorts the specified range within the array -func QuickSortRange(arr []int, low, high int) { +// QuicksortRange Sorts the specified range within the array +func QuicksortRange[T constraints.Ordered](arr []T, low, high int) { if len(arr) <= 1 { return } if low < high { pivot := Partition(arr, low, high) - QuickSortRange(arr, low, pivot-1) - QuickSortRange(arr, pivot+1, high) + QuicksortRange(arr, low, pivot-1) + QuicksortRange(arr, pivot+1, high) } } -// QuickSort Sorts the entire array -func QuickSort(arr []int) []int { - QuickSortRange(arr, 0, len(arr)-1) +// Quicksort Sorts the entire array +func Quicksort[T constraints.Ordered](arr []T) []T { + QuicksortRange(arr, 0, len(arr)-1) return arr } diff --git a/sort/selectionsort.go b/sort/selectionsort.go index 95fd4ffa1..b86000a9b 100644 --- a/sort/selectionsort.go +++ b/sort/selectionsort.go @@ -1,7 +1,8 @@ package sort -func SelectionSort(arr []int) []int { +import "github.com/TheAlgorithms/Go/constraints" +func Selection[T constraints.Ordered](arr []T) []T { for i := 0; i < len(arr); i++ { min := i for j := i + 1; j < len(arr); j++ { diff --git a/sort/shellsort.go b/sort/shellsort.go index 28f76dcae..fb04f6f7c 100644 --- a/sort/shellsort.go +++ b/sort/shellsort.go @@ -1,6 +1,8 @@ package sort -func ShellSort(arr []int) []int { +import "github.com/TheAlgorithms/Go/constraints" + +func Shell[T constraints.Ordered](arr []T) []T { for d := int(len(arr) / 2); d > 0; d /= 2 { for i := d; i < len(arr); i++ { for j := i; j >= d && arr[j-d] > arr[j]; j -= d { diff --git a/sort/simplesort.go b/sort/simplesort.go index 39f3a55f9..ec54c1db0 100644 --- a/sort/simplesort.go +++ b/sort/simplesort.go @@ -8,7 +8,9 @@ package sort -func SimpleSort(arr []int) []int { +import "github.com/TheAlgorithms/Go/constraints" + +func Simple[T constraints.Ordered](arr []T) []T { for i := 0; i < len(arr); i++ { for j := 0; j < len(arr); j++ { if arr[i] < arr[j] { @@ -20,9 +22,9 @@ func SimpleSort(arr []int) []int { return arr } -// ImprovedSimpleSort is a improve SimpleSort by skipping an unnecessary comparison of the first and last. +// ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. // This improved version is more similar to implementation of insertion sort -func ImprovedSimpleSort(arr []int) []int { +func ImprovedSimple[T constraints.Ordered](arr []T) []T { for i := 1; i < len(arr); i++ { for j := 0; j < len(arr)-1; j++ { if arr[i] < arr[j] { diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 828b907cb..08b6a716d 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -1,6 +1,7 @@ -package sort +package sort_test import ( + "github.com/TheAlgorithms/Go/sort" "reflect" "testing" ) @@ -75,63 +76,63 @@ func testFramework(t *testing.T, sortingFunction func([]int) []int) { //BEGIN TESTS func TestBubble(t *testing.T) { - testFramework(t, bubbleSort) + testFramework(t, sort.Bubble[int]) } func TestExchange(t *testing.T) { - testFramework(t, Exchange) + testFramework(t, sort.Exchange[int]) } func TestInsertion(t *testing.T) { - testFramework(t, InsertionSort) + testFramework(t, sort.Insertion[int]) } func TestMerge(t *testing.T) { - testFramework(t, Mergesort) + testFramework(t, sort.Merge[int]) } func TestMergeIter(t *testing.T) { - testFramework(t, MergeIter) + testFramework(t, sort.MergeIter[int]) } func TestHeap(t *testing.T) { - testFramework(t, HeapSort) + testFramework(t, sort.HeapSort) } func TestCount(t *testing.T) { - testFramework(t, Count) + testFramework(t, sort.Count[int]) } func TestQuick(t *testing.T) { - testFramework(t, QuickSort) + testFramework(t, sort.Quicksort[int]) } func TestShell(t *testing.T) { - testFramework(t, ShellSort) + testFramework(t, sort.Shell[int]) } func TestRadix(t *testing.T) { - testFramework(t, RadixSort) + testFramework(t, sort.RadixSort) } func TestSimple(t *testing.T) { - testFramework(t, SimpleSort) + testFramework(t, sort.Simple[int]) } func TestImprovedSimple(t *testing.T) { - testFramework(t, ImprovedSimpleSort) + testFramework(t, sort.ImprovedSimple[int]) } func TestSelection(t *testing.T) { - testFramework(t, SelectionSort) + testFramework(t, sort.Selection[int]) } func TestComb(t *testing.T) { - testFramework(t, Comb) + testFramework(t, sort.Comb[int]) } func TestPigeonhole(t *testing.T) { - testFramework(t, Pigeonhole) + testFramework(t, sort.Pigeonhole) } //END TESTS @@ -176,62 +177,62 @@ func benchmarkFramework(b *testing.B, f func(arr []int) []int) { //BEGIN BENCHMARKS func BenchmarkBubble(b *testing.B) { - benchmarkFramework(b, bubbleSort) + benchmarkFramework(b, sort.Bubble[int]) } func BenchmarkExchange(b *testing.B) { - benchmarkFramework(b, Exchange) + benchmarkFramework(b, sort.Exchange[int]) } func BenchmarkInsertion(b *testing.B) { - benchmarkFramework(b, InsertionSort) + benchmarkFramework(b, sort.Insertion[int]) } func BenchmarkMerge(b *testing.B) { - benchmarkFramework(b, Mergesort) + benchmarkFramework(b, sort.Merge[int]) } func BenchmarkMergeIter(b *testing.B) { - benchmarkFramework(b, MergeIter) + benchmarkFramework(b, sort.MergeIter[int]) } func BenchmarkHeap(b *testing.B) { - benchmarkFramework(b, HeapSort) + benchmarkFramework(b, sort.HeapSort) } func BenchmarkCount(b *testing.B) { - benchmarkFramework(b, Count) + benchmarkFramework(b, sort.Count[int]) } func BenchmarkQuick(b *testing.B) { - benchmarkFramework(b, QuickSort) + benchmarkFramework(b, sort.Quicksort[int]) } func BenchmarkShell(b *testing.B) { - benchmarkFramework(b, ShellSort) + benchmarkFramework(b, sort.Shell[int]) } func BenchmarkRadix(b *testing.B) { - benchmarkFramework(b, RadixSort) + benchmarkFramework(b, sort.RadixSort) } func BenchmarkSimple(b *testing.B) { - benchmarkFramework(b, SimpleSort) + benchmarkFramework(b, sort.Simple[int]) } func BenchmarkImprovedSimple(b *testing.B) { - benchmarkFramework(b, ImprovedSimpleSort) + benchmarkFramework(b, sort.ImprovedSimple[int]) } // Very Slow, consider commenting func BenchmarkSelection(b *testing.B) { - benchmarkFramework(b, SelectionSort) + benchmarkFramework(b, sort.Selection[int]) } func BenchmarkComb(b *testing.B) { - benchmarkFramework(b, Comb) + benchmarkFramework(b, sort.Comb[int]) } func BenchmarkPigeonhole(b *testing.B) { - benchmarkFramework(b, Pigeonhole) + benchmarkFramework(b, sort.Pigeonhole) } From 5e4bc7eeab0236ddc990185e18f2a8e3325db805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BA=84=E5=85=A8=E8=9B=8B?= Date: Sun, 27 Mar 2022 14:38:55 +0800 Subject: [PATCH 323/488] merge: Add LowerBound and UpperBound algorithms (#482) * feat:add LowerBound and UpperBound * fix:gofmt -s -w binary.go * enhancement:for iterate 0,len(array)-1 instead of pass lowIndex,highIndex Co-authored-by: zhuangyongxin Co-authored-by: Rak Laptudirm --- search/binary.go | 50 ++++++++++++++++++++++++++++++++++++++++--- search/binary_test.go | 44 +++++++++++++++++++++++++++++++++++-- search/testcases.go | 28 ++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 5 deletions(-) diff --git a/search/binary.go b/search/binary.go index 7692813d7..c30e4b291 100644 --- a/search/binary.go +++ b/search/binary.go @@ -20,9 +20,9 @@ func Binary(array []int, target int, lowIndex int, highIndex int) (int, error) { // BinaryIterative search for target within a sorted array by repeatedly dividing the array in half and comparing the midpoint with the target. // Unlike Binary, this function uses iterative method and not recursive. // If a target is found, the index of the target is returned. Else the function return -1 and ErrNotFound. -func BinaryIterative(array []int, target int, lowIndex int, highIndex int) (int, error) { - startIndex := lowIndex - endIndex := highIndex +func BinaryIterative(array []int, target int) (int, error) { + startIndex := 0 + endIndex := len(array) - 1 var mid int for startIndex <= endIndex { mid = int(startIndex + (endIndex-startIndex)/2) @@ -36,3 +36,47 @@ func BinaryIterative(array []int, target int, lowIndex int, highIndex int) (int, } return -1, ErrNotFound } + +//Returns index to the first element in the range [0, len(array)-1] that is not less than (i.e. greater or equal to) target. +//return -1 and ErrNotFound if no such element is found. +func LowerBound(array []int, target int) (int, error) { + startIndex := 0 + endIndex := len(array) - 1 + var mid int + for startIndex <= endIndex { + mid = int(startIndex + (endIndex-startIndex)/2) + if array[mid] < target { + startIndex = mid + 1 + } else { + endIndex = mid - 1 + } + } + + //when target greater than every element in array, startIndex will out of bounds + if startIndex >= len(array) { + return -1, ErrNotFound + } + return startIndex, nil +} + +//Returns index to the first element in the range [lowIndex, len(array)-1] that is greater than target. +//return -1 and ErrNotFound if no such element is found. +func UpperBound(array []int, target int) (int, error) { + startIndex := 0 + endIndex := len(array) - 1 + var mid int + for startIndex <= endIndex { + mid = int(startIndex + (endIndex-startIndex)/2) + if array[mid] > target { + endIndex = mid - 1 + } else { + startIndex = mid + 1 + } + } + + //when target greater or equal than every element in array, startIndex will out of bounds + if startIndex >= len(array) { + return -1, ErrNotFound + } + return startIndex, nil +} diff --git a/search/binary_test.go b/search/binary_test.go index ec3e563cc..ea77bf817 100644 --- a/search/binary_test.go +++ b/search/binary_test.go @@ -16,7 +16,31 @@ func TestBinary(t *testing.T) { func TestBinaryIterative(t *testing.T) { for _, test := range searchTests { - actualValue, actualError := BinaryIterative(test.data, test.key, 0, len(test.data)-1) + actualValue, actualError := BinaryIterative(test.data, test.key) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) + } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) + } + } +} + +func TestLowerBound(t *testing.T) { + for _, test := range lowerBoundTests { + actualValue, actualError := LowerBound(test.data, test.key) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) + } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) + } + } +} + +func TestUpperBound(t *testing.T) { + for _, test := range uppperBoundTests { + actualValue, actualError := UpperBound(test.data, test.key) if actualValue != test.expected { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) } @@ -38,6 +62,22 @@ func BenchmarkBinaryIterative(b *testing.B) { testCase := generateBenchmarkTestCase() b.ResetTimer() // this is important because the generateBenchmarkTestCase() is expensive for i := 0; i < b.N; i++ { - _, _ = BinaryIterative(testCase, i, 0, len(testCase)-1) + _, _ = BinaryIterative(testCase, i) + } +} + +func BenchmarkLowerBound(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // this is important because the generateBenchmarkTestCase() is expensive + for i := 0; i < b.N; i++ { + _, _ = LowerBound(testCase, i) + } +} + +func BenchmarkUpperBound(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // this is important because the generateBenchmarkTestCase() is expensive + for i := 0; i < b.N; i++ { + _, _ = UpperBound(testCase, i) } } diff --git a/search/testcases.go b/search/testcases.go index eacbaeb4f..7e02bc5c8 100644 --- a/search/testcases.go +++ b/search/testcases.go @@ -29,6 +29,34 @@ var searchTests = []searchTest{ {[]int{}, 2, -1, ErrNotFound, "Empty"}, } +var lowerBoundTests = []searchTest{ + //Sanity + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, -25, 0, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, nil, "Sanity"}, + {[]int{1, 2, 2, 2, 2, 6, 7, 8, 9, 10}, 2, 1, nil, "Sanity"}, + {[]int{2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 2, 0, nil, "Sanity"}, + //Absent + {[]int{1, 4, 5, 6, 7, 10}, 25, -1, ErrNotFound, "Absent"}, + //Empty slice + {[]int{}, 2, -1, ErrNotFound, "Empty"}, +} + +var uppperBoundTests = []searchTest{ + //Sanity + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, -25, 0, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 1, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 5, nil, "Sanity"}, + {[]int{1, 2, 2, 2, 2, 6, 7, 8, 9, 10}, 2, 5, nil, "Sanity"}, + //Absent + {[]int{2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 2, -1, ErrNotFound, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, -1, ErrNotFound, "Sanity"}, + {[]int{1, 4, 5, 6, 7, 10}, 25, -1, ErrNotFound, "Absent"}, + //Empty slice + {[]int{}, 2, -1, ErrNotFound, "Empty"}, +} + // This function generate consistent testcase for benchmark test. func generateBenchmarkTestCase() []int { var testCase []int From f15028bcf4f66d0dd38bc5eadb5ebf48a6cc55a9 Mon Sep 17 00:00:00 2001 From: Paul Leydier <75126792+paul-leydier@users.noreply.github.com> Date: Tue, 29 Mar 2022 08:34:21 +0200 Subject: [PATCH 324/488] feat: Fuzzing test on Base64 encoding and decoding (#486) --- conversion/base64_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/conversion/base64_test.go b/conversion/base64_test.go index ed882634c..96342695a 100644 --- a/conversion/base64_test.go +++ b/conversion/base64_test.go @@ -109,3 +109,15 @@ func TestBase64EncodeDecodeInverse(t *testing.T) { } } } + +func FuzzBase64Encode(f *testing.F) { + f.Add([]byte("hello")) + f.Fuzz(func(t *testing.T, input []byte) { + result := Base64Decode(Base64Encode(input)) + for i := 0; i < len(input); i++ { + if result[i] != input[i] { + t.Fatalf("with input '%s' - expected '%s', got '%s' (mismatch at position %d)", input, input, result, i) + } + } + }) +} From bd8e6d52ba9f340761b6dc061fe43a5e5b7bbfd6 Mon Sep 17 00:00:00 2001 From: Taj Date: Wed, 30 Mar 2022 18:38:44 +0100 Subject: [PATCH 325/488] Fix: restructure checksum package (#485) * fix: [generic + sort] All ready for generics * GoDocMD support for Go 1.18 * Bump Go version in workflow * Updated Documentation in README.md * bump go version in GoLangCI lint action * fix: [generic + sort] review feedback * Updated Documentation in README.md * empty commit: stuck github action * fix: restructuring checksum package * Updated Documentation in README.md Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 39 +++++++++--------------- checksum/crc/crc8_test.go | 59 ------------------------------------ checksum/{crc => }/crc8.go | 7 ++--- checksum/crc8_test.go | 61 ++++++++++++++++++++++++++++++++++++++ checksum/luhn.go | 4 +-- checksum/luhn_test.go | 30 +++++++++++-------- 6 files changed, 97 insertions(+), 103 deletions(-) delete mode 100644 checksum/crc/crc8_test.go rename checksum/{crc => }/crc8.go (88%) create mode 100644 checksum/crc8_test.go diff --git a/README.md b/README.md index da8fb416b..f9f798a61 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,14 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`LuhnAlgorithm`](./checksum/luhn.go#L11): LuhnAlgorithm This function calculates the checksum using the Luna algorithm +1. [`CRC8`](./checksum/crc8.go#L25): CRC8 calculates CRC8 checksum of the given data. +2. [`Luhn`](./checksum/luhn.go#L11): Luhn validates the provided data using the Luhn algorithm. + +--- +##### Types + +1. [`CRCModel`](./checksum/crc8.go#L15): No description provided. + ---
@@ -217,30 +224,12 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 2. [`Base64Encode`](./conversion/base64.go#L19): Base64Encode encodes the received input bytes slice into a base64 string. The implementation follows the RFC4648 standard, which is documented at https://datatracker.ietf.org/doc/html/rfc4648#section-4 3. [`BinaryToDecimal`](./conversion/binarytodecimal.go#L25): BinaryToDecimal() function that will take Binary number as string, and return it's Decimal equivalent as integer. 4. [`DecimalToBinary`](./conversion/decimaltobinary.go#L32): DecimalToBinary() function that will take Decimal number as int, and return it's Binary equivalent as string. -5. [`HEXToRGB`](./conversion/rgbhex.go#L10): HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) into the individual components: red, green and blue -6. [`IntToRoman`](./conversion/integertoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. -7. [`RGBToHEX`](./conversion/rgbhex.go#L41): RGBToHEX does exactly the opposite of HEXToRGB: it combines the three components red, green and blue to an RGB value, which can be converted to e.g. Hex -8. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. -9. [`RomanToInteger`](./conversion/romantointeger.go#L40): RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. - ---- -
- crc - ---- - -##### Package crc describes algorithms for finding various CRC checksums - ---- -##### Functions: - -1. [`CalculateCRC8`](./checksum/crc/crc8.go#L26): CalculateCRC8 This function calculate CRC8 checksum. - ---- -##### Types - -1. [`CRCModel`](./checksum/crc/crc8.go#L16): No description provided. - +5. [`FuzzBase64Encode`](./conversion/base64_test.go#L113): No description provided. +6. [`HEXToRGB`](./conversion/rgbhex.go#L10): HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) into the individual components: red, green and blue +7. [`IntToRoman`](./conversion/integertoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. +8. [`RGBToHEX`](./conversion/rgbhex.go#L41): RGBToHEX does exactly the opposite of HEXToRGB: it combines the three components red, green and blue to an RGB value, which can be converted to e.g. Hex +9. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. +10. [`RomanToInteger`](./conversion/romantointeger.go#L40): RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. ---
diff --git a/checksum/crc/crc8_test.go b/checksum/crc/crc8_test.go deleted file mode 100644 index ee6ac2188..000000000 --- a/checksum/crc/crc8_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// crc8_test.go -// description: Test for calculate crc8 -// author(s) [red_byte](https://github.com/i-redbyte) -// see crc8.go - -package crc - -import ( - "fmt" - "testing" -) - -var ( - CRC8 = CRCModel{0x07, 0x00, false, false, 0x00, "CRC-8"} - CRC8CDMA2000 = CRCModel{0x9B, 0xFF, false, false, 0x00, "CRC-8/CDMA2000"} - CRC8DARC = CRCModel{0x39, 0x00, true, true, 0x00, "CRC-8/DARC"} - CRC8DVBS2 = CRCModel{0xD5, 0x00, false, false, 0x00, "CRC-8/DVB-S2"} - CRC8EBU = CRCModel{0x1D, 0xFF, true, true, 0x00, "CRC-8/EBU"} - CRC8ICODE = CRCModel{0x1D, 0xFD, false, false, 0x00, "CRC-8/I-CODE"} - CRC8ITU = CRCModel{0x07, 0x00, false, false, 0x55, "CRC-8/ITU"} - CRC8MAXIM = CRCModel{0x31, 0x00, true, true, 0x00, "CRC-8/MAXIM"} - CRC8ROHC = CRCModel{0x07, 0xFF, true, true, 0x00, "CRC-8/ROHC"} - CRC8WCDMA = CRCModel{0x9B, 0x00, true, true, 0x00, "CRC-8/WCDMA"} -) - -func TestCalculateCRC8(t *testing.T) { - data := []byte("123456789") - tests := []struct { - name string - data []byte - model CRCModel - want uint8 - }{ - {CRC8.Name, data, CRC8, 0xF4}, - {CRC8CDMA2000.Name, data, CRC8CDMA2000, 0xDA}, - {CRC8DARC.Name, data, CRC8DARC, 0x15}, - {CRC8DVBS2.Name, data, CRC8DVBS2, 0xBC}, - {CRC8EBU.Name, data, CRC8EBU, 0x97}, - {CRC8ICODE.Name, data, CRC8ICODE, 0x7E}, - {CRC8ITU.Name, data, CRC8ITU, 0xA1}, - {CRC8MAXIM.Name, data, CRC8MAXIM, 0xA1}, - {CRC8ROHC.Name, data, CRC8ROHC, 0xD0}, - {CRC8WCDMA.Name, data, CRC8WCDMA, 0x25}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - fmt.Println(CalculateCRC8(test.data, test.model)) - if got := CalculateCRC8(test.data, test.model); got != test.want { - t.Errorf("CalculateCRC8() = %v, want %v", got, test.want) - } - }) - } -} - -func BenchmarkCalculateCRC8(b *testing.B) { - for i := 0; i < b.N; i++ { - CalculateCRC8([]byte("123456789"), CRC8) - } -} diff --git a/checksum/crc/crc8.go b/checksum/crc8.go similarity index 88% rename from checksum/crc/crc8.go rename to checksum/crc8.go index 3c69aeec2..fc73a9a40 100644 --- a/checksum/crc/crc8.go +++ b/checksum/crc8.go @@ -7,8 +7,7 @@ // author(s) [red_byte](https://github.com/i-redbyte) // see crc8_test.go -// Package crc describes algorithms for finding various CRC checksums -package crc +package checksum import "math/bits" @@ -22,8 +21,8 @@ type CRCModel struct { Name string } -// CalculateCRC8 This function calculate CRC8 checksum. -func CalculateCRC8(data []byte, model CRCModel) uint8 { +// CRC8 calculates CRC8 checksum of the given data. +func CRC8(data []byte, model CRCModel) uint8 { table := getTable(model) crcResult := model.Init crcResult = addBytes(data, model, crcResult, table) diff --git a/checksum/crc8_test.go b/checksum/crc8_test.go new file mode 100644 index 000000000..15e93e453 --- /dev/null +++ b/checksum/crc8_test.go @@ -0,0 +1,61 @@ +// crc8_test.go +// description: Test for calculate crc8 +// author(s) [red_byte](https://github.com/i-redbyte) +// see crc8.go + +package checksum_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/checksum" +) + +var ( + CRC8 = checksum.CRCModel{0x07, 0x00, false, false, 0x00, "CRC-8"} + CRC8CDMA2000 = checksum.CRCModel{0x9B, 0xFF, false, false, 0x00, "CRC-8/CDMA2000"} + CRC8DARC = checksum.CRCModel{0x39, 0x00, true, true, 0x00, "CRC-8/DARC"} + CRC8DVBS2 = checksum.CRCModel{0xD5, 0x00, false, false, 0x00, "CRC-8/DVB-S2"} + CRC8EBU = checksum.CRCModel{0x1D, 0xFF, true, true, 0x00, "CRC-8/EBU"} + CRC8ICODE = checksum.CRCModel{0x1D, 0xFD, false, false, 0x00, "CRC-8/I-CODE"} + CRC8ITU = checksum.CRCModel{0x07, 0x00, false, false, 0x55, "CRC-8/ITU"} + CRC8MAXIM = checksum.CRCModel{0x31, 0x00, true, true, 0x00, "CRC-8/MAXIM"} + CRC8ROHC = checksum.CRCModel{0x07, 0xFF, true, true, 0x00, "CRC-8/ROHC"} + CRC8WCDMA = checksum.CRCModel{0x9B, 0x00, true, true, 0x00, "CRC-8/WCDMA"} +) + +func TestCalculateCRC8(t *testing.T) { + data := []byte("123456789") + tests := []struct { + name string + data []byte + model checksum.CRCModel + want uint8 + }{ + {CRC8.Name, data, CRC8, 0xF4}, + {CRC8CDMA2000.Name, data, CRC8CDMA2000, 0xDA}, + {CRC8DARC.Name, data, CRC8DARC, 0x15}, + {CRC8DVBS2.Name, data, CRC8DVBS2, 0xBC}, + {CRC8EBU.Name, data, CRC8EBU, 0x97}, + {CRC8ICODE.Name, data, CRC8ICODE, 0x7E}, + {CRC8ITU.Name, data, CRC8ITU, 0xA1}, + {CRC8MAXIM.Name, data, CRC8MAXIM, 0xA1}, + {CRC8ROHC.Name, data, CRC8ROHC, 0xD0}, + {CRC8WCDMA.Name, data, CRC8WCDMA, 0x25}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fmt.Println(checksum.CRC8(test.data, test.model)) + if got := checksum.CRC8(test.data, test.model); got != test.want { + t.Errorf("CalculateCRC8() = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkCalculateCRC8(b *testing.B) { + for i := 0; i < b.N; i++ { + checksum.CRC8([]byte("123456789"), CRC8) + } +} diff --git a/checksum/luhn.go b/checksum/luhn.go index f3e230ead..e9f7dd6b1 100644 --- a/checksum/luhn.go +++ b/checksum/luhn.go @@ -7,8 +7,8 @@ // Package checksum describes algorithms for finding various checksums package checksum -// LuhnAlgorithm This function calculates the checksum using the Luna algorithm -func LuhnAlgorithm(s []rune) bool { +// Luhn validates the provided data using the Luhn algorithm. +func Luhn(s []byte) bool { n := len(s) number := 0 result := 0 diff --git a/checksum/luhn_test.go b/checksum/luhn_test.go index e928e51b6..e81560a64 100644 --- a/checksum/luhn_test.go +++ b/checksum/luhn_test.go @@ -3,27 +3,31 @@ // author(s) [red_byte](https://github.com/i-redbyte) // see luhn.go -package checksum +package checksum_test -import "testing" +import ( + "testing" -func TestLuhnAlgorithm(t *testing.T) { + "github.com/TheAlgorithms/Go/checksum" +) + +func TestLuhn(t *testing.T) { tests := []struct { name string - s []rune + s []byte want bool }{ - {"check 4242424242424242", []rune("4242424242424242"), true}, - {"check 6200000000000005", []rune("6200000000000005"), true}, - {"check 5534200028533164", []rune("5534200028533164"), true}, - {"check 36227206271667", []rune("36227206271667"), true}, - {"check 471629309440", []rune("471629309440"), false}, - {"check 1111", []rune("1111"), false}, - {"check 12345674", []rune("12345674"), true}, + {"check 4242424242424242", []byte("4242424242424242"), true}, + {"check 6200000000000005", []byte("6200000000000005"), true}, + {"check 5534200028533164", []byte("5534200028533164"), true}, + {"check 36227206271667", []byte("36227206271667"), true}, + {"check 471629309440", []byte("471629309440"), false}, + {"check 1111", []byte("1111"), false}, + {"check 12345674", []byte("12345674"), true}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - if got := LuhnAlgorithm(test.s); got != test.want { + if got := checksum.Luhn(test.s); got != test.want { t.Errorf("LuhnAlgorithm() = %v, want %v", got, test.want) } }) @@ -32,6 +36,6 @@ func TestLuhnAlgorithm(t *testing.T) { func BenchmarkBruteForceFactorial(b *testing.B) { for i := 0; i < b.N; i++ { - LuhnAlgorithm([]rune("4242424242424242")) + checksum.Luhn([]byte("4242424242424242")) } } From 628336b7d752df8cb13d4961a30daf552acf3e02 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 31 Mar 2022 09:33:21 +0300 Subject: [PATCH 326/488] Feat/sin (#476) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * feat: abs algo * Updated Documentation in README.md * fix: add comment * Updated Documentation in README.md * fix: new comment * Updated Documentation in README.md * fix: rename func and remove package * Updated Documentation in README.md * Update math/abs.go Co-authored-by: Taj * Updated Documentation in README.md * Update math/binary/abs.go Co-authored-by: Taj * Updated Documentation in README.md * fix: rename func and move binary test * add package description and add function name to comment * Updated Documentation in README.md * rename Intercept method to YIntercept * Updated Documentation in README.md * fix strings * Updated Documentation in README.md * fix commit * fix name cos tests and rename epsilon to epsilonCos * feat: sin * Updated Documentation in README.md * fix test for sin * fix epsilon * rename package to test * fix afte review Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- README.md | 1 + math/cos_test.go | 19 ++++++++++--------- math/sin.go | 11 +++++++++++ math/sin_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 math/sin.go create mode 100644 math/sin_test.go diff --git a/README.md b/README.md index f9f798a61..7e41257dd 100644 --- a/README.md +++ b/README.md @@ -542,6 +542,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 4. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. 5. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. 6. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +7. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) ---
diff --git a/math/cos_test.go b/math/cos_test.go index c1df66b8d..16110c855 100644 --- a/math/cos_test.go +++ b/math/cos_test.go @@ -1,7 +1,8 @@ -package math +package math_test import ( - "math" + algmath "github.com/TheAlgorithms/Go/math" + stdmath "math" "testing" ) @@ -17,15 +18,15 @@ func TestCos(t *testing.T) { {"cos(90)", 90, -0.447}, {"cos(180)", 180, -0.598}, {"cos(1)", 1, 0.540}, - {"cos(1)", math.Pi, -1}, - {"cos(1)", math.Pi / 2, 0}, + {"cos(π)", stdmath.Pi, -1}, + {"cos(π/2)", stdmath.Pi / 2, 0}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got := Cos(test.n) - if math.Abs(got-test.want) >= epsilon { + got := algmath.Cos(test.n) + if stdmath.Abs(got-test.want) >= epsilon { t.Errorf("Cos() = %v, want %v", got, test.want) - t.Errorf("MATH Cos() = %v", math.Cos(test.n)) + t.Errorf("MATH Cos() = %v", stdmath.Cos(test.n)) } }) } @@ -33,13 +34,13 @@ func TestCos(t *testing.T) { func BenchmarkCos(b *testing.B) { for i := 0; i < b.N; i++ { - Cos(180) + algmath.Cos(180) } } // BenchmarkMathCos is slower because the standard library `math.Cos` calculates a more accurate value. func BenchmarkMathCos(b *testing.B) { for i := 0; i < b.N; i++ { - math.Cos(180) + stdmath.Cos(180) } } diff --git a/math/sin.go b/math/sin.go new file mode 100644 index 000000000..e9713cf5e --- /dev/null +++ b/math/sin.go @@ -0,0 +1,11 @@ +// author(s) [red_byte](https://github.com/i-redbyte) +// see sin_test.go + +package math + +import "math" + +// Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +func Sin(x float64) float64 { + return Cos((math.Pi / 2) - x) +} diff --git a/math/sin_test.go b/math/sin_test.go new file mode 100644 index 000000000..0dc89428f --- /dev/null +++ b/math/sin_test.go @@ -0,0 +1,43 @@ +package math_test + +import ( + algmath "github.com/TheAlgorithms/Go/math" + stdmath "math" + "testing" +) + +func TestSin(t *testing.T) { + tests := []struct { + name string + n float64 + want float64 + }{ + {"sin(0)", 0, 0}, + {"sin(3π/2)", (3 * stdmath.Pi) / 2, -1}, + {"sin(π/2)", stdmath.Pi / 2, 1}, + {"sin(π/6)", stdmath.Pi / 6, 0.5}, + {"sin(90)", 90, 0.893996663600558}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := algmath.Sin(test.n) + if stdmath.Abs(got-test.want) >= epsilon { + t.Errorf("Sin() = %v, want %v", got, test.want) + t.Errorf("MATH Sin() = %v", stdmath.Sin(test.n)) + } + }) + } +} + +func BenchmarkSin(b *testing.B) { + for i := 0; i < b.N; i++ { + algmath.Sin(180) + } +} + +// BenchmarkMathSin is slower because the standard library `math.Sin` calculates a more accurate value. +func BenchmarkMathSin(b *testing.B) { + for i := 0; i < b.N; i++ { + stdmath.Sin(180) + } +} From f38fdca30a5786e41952d35464399ee62fbe5d7c Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Mon, 4 Apr 2022 14:18:26 +0530 Subject: [PATCH 327/488] Add Deterministic Miller-Rabin Primality Test (#484) * feat: add deterministic miller-rabin test * feat: refactor and commenting Tasks: - Refactored code. - Added some more witness groups. - Commented code. * chore: run `gofmt` * fix: remove old code * chore: update tests * fix: deterministic function test * chore: run `gofmt` * chore: update function name in doc comment Co-authored-by: Taj * chore: separate tests for the two versions * chore: `isTrivial` follows the `, ok` idiom * chore: add named returns for better docs * chore: use named returns to make code more concise Co-authored-by: Taj --- math/prime/millerrabinprimalitytest.go | 140 +++++++++++++++----- math/prime/millerrabinprimalitytest_test.go | 60 ++++++--- 2 files changed, 148 insertions(+), 52 deletions(-) diff --git a/math/prime/millerrabinprimalitytest.go b/math/prime/millerrabinprimalitytest.go index 2b358774d..76cb27578 100644 --- a/math/prime/millerrabinprimalitytest.go +++ b/math/prime/millerrabinprimalitytest.go @@ -1,10 +1,11 @@ -// millerrabinprimalitytest.go -// description: An implementation of Miller-Rabin primality test -// details: -// A simple implementation of Miller-Rabin Primality Test -// [Miller-Rabin primality test Wiki](https://en.wikipedia.org/wiki/Miller–Rabin_primality_test) -// author(s) [Taj](https://github.com/tjgurwara99) -// see millerrabinprimalitytest_test.go +// This file implements two versions of the Miller-Rabin primality test. +// One of the implementations is deterministic and the other is probabilistic. +// The Miller-Rabin test is one of the simplest and fastest known primality +// tests and is widely used. +// +// Authors: +// [Taj](https://github.com/tjgurwara99) +// [Rak](https://github.com/raklaptudirm) package prime @@ -14,25 +15,40 @@ import ( "github.com/TheAlgorithms/Go/math/modular" ) -// findD accepts a number and returns the -// odd number d such that num = 2^r * d - 1 -func findRD(num int64) (int64, int64) { - r := int64(0) - d := num - 1 +// formatNum accepts a number and returns the +// odd number d such that num = 2^s * d + 1 +func formatNum(num int64) (d int64, s int64) { + d = num - 1 for num%2 == 0 { d /= 2 - r++ + s++ } - return d, r + return } -// MillerTest This is the intermediate step that repeats within the -// miller rabin primality test for better probabilitic chances of -// receiving the correct result. -func MillerTest(d, num int64) (bool, error) { - random := rand.Int63n(num-1) + 2 +// isTrivial checks if num's primality is easy to determine. +// If it is, it returns true and num's primality. Otherwise +// it returns false and false. +func isTrivial(num int64) (prime bool, trivial bool) { + if num <= 4 { + // 2 and 3 are primes + prime = num == 2 || num == 3 + trivial = true + } else { + prime = false + // number is trivial prime if + // it is divisible by 2 + trivial = num%2 == 0 + } - res, err := modular.Exponentiation(random, d, num) + return +} + +// MillerTest tests whether num is a strong probable prime to a witness. +// Formally: a^d ≡ 1 (mod n) or a^(2^r * d) ≡ -1 (mod n), 0 <= r <= s +func MillerTest(num, witness int64) (bool, error) { + d, _ := formatNum(num) + res, err := modular.Exponentiation(witness, d, num) if err != nil { return false, err @@ -55,21 +71,41 @@ func MillerTest(d, num int64) (bool, error) { return false, nil } -// MillerRabinTest Probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin. -func MillerRabinTest(num, rounds int64) (bool, error) { - if num <= 4 { - if num == 2 || num == 3 { - return true, nil +// MillerRandomTest This is the intermediate step that repeats within the +// miller rabin primality test for better probabilitic chances of +// receiving the correct result with random witnesses. +func MillerRandomTest(num int64) (bool, error) { + random := rand.Int63n(num-1) + 2 + return MillerTest(num, random) +} + +// MillerTestMultiple is like MillerTest but runs the test for multiple +// witnesses. +func MillerTestMultiple(num int64, witnesses ...int64) (bool, error) { + for _, witness := range witnesses { + prime, err := MillerTest(num, witness) + if err != nil { + return false, err + } + + if !prime { + return false, nil } - return false, nil } - if num%2 == 0 { - return false, nil + + return true, nil +} + +// MillerRabinProbabilistic is a probabilistic test for primality +// of an integer based of the algorithm devised by Miller and Rabin. +func MillerRabinProbabilistic(num, rounds int64) (bool, error) { + if prime, trivial := isTrivial(num); trivial { + // num is a trivial number + return prime, nil } - d, _ := findRD(num) for i := int64(0); i < rounds; i++ { - val, err := MillerTest(d, num) + val, err := MillerRandomTest(num) if err != nil { return false, err } @@ -79,3 +115,47 @@ func MillerRabinTest(num, rounds int64) (bool, error) { } return true, nil } + +// MillerRabinDeterministic is a Deterministic version of the Miller-Rabin +// test, which returns correct results for all valid int64 numbers. +func MillerRabinDeterministic(num int64) (bool, error) { + if prime, trivial := isTrivial(num); trivial { + // num is a trivial number + return prime, nil + } + + switch { + case num < 2047: + // witness 2 can determine the primality of any number less than 2047 + return MillerTest(num, 2) + case num < 1_373_653: + // witnesses 2 and 3 can determine the primality + // of any number less than 1,373,653 + return MillerTestMultiple(num, 2, 3) + case num < 9_080_191: + // witnesses 31 and 73 can determine the primality + // of any number less than 9,080,191 + return MillerTestMultiple(num, 31, 73) + case num < 25_326_001: + // witnesses 2, 3, and 5 can determine the + // primality of any number less than 25,326,001 + return MillerTestMultiple(num, 2, 3, 5) + case num < 1_122_004_669_633: + // witnesses 2, 13, 23, and 1,662,803 can determine the + // primality of any number less than 1,122,004,669,633 + return MillerTestMultiple(num, 2, 13, 23, 1_662_803) + case num < 2_152_302_898_747: + // witnesses 2, 3, 5, 7, and 11 can determine the primality + // of any number less than 2,152,302,898,747 + return MillerTestMultiple(num, 2, 3, 5, 7, 11) + case num < 341_550_071_728_321: + // witnesses 2, 3, 5, 7, 11, 13, and 17 can determine the + // primality of any number less than 341,550,071,728,321 + return MillerTestMultiple(num, 2, 3, 5, 7, 11, 13, 17) + default: + // witnesses 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, and 37 can determine + // the primality of any number less than 318,665,857,834,031,151,167,461 + // which is well above the max int64 9,223,372,036,854,775,807 + return MillerTestMultiple(num, 2, 3, 5, 7, 11, 13, 17, 19, 23, 31, 37) + } +} diff --git a/math/prime/millerrabinprimalitytest_test.go b/math/prime/millerrabinprimalitytest_test.go index 0773b1149..b4a4ed34f 100644 --- a/math/prime/millerrabinprimalitytest_test.go +++ b/math/prime/millerrabinprimalitytest_test.go @@ -1,29 +1,25 @@ -// millerrabinprimality_test.go -// description: Test for Miller-Rabin Primality Test -// author(s) [Taj](https://github.com/tjgurwara99) -// see millerrabinprimalitytest.go - package prime import "testing" -func TestMillerRabinTest(t *testing.T) { - var tests = []struct { - name string - input int64 - expected bool - rounds int64 - err error - }{ - {"smallest prime", 2, true, 5, nil}, - {"random prime", 3, true, 5, nil}, - {"neither prime nor composite", 1, false, 5, nil}, - {"random non-prime", 10, false, 5, nil}, - {"another random prime", 23, true, 5, nil}, - } +var tests = []struct { + name string + input int64 + expected bool + rounds int64 + err error +}{ + {"smallest prime", 2, true, 5, nil}, + {"random prime", 3, true, 5, nil}, + {"neither prime nor composite", 1, false, 5, nil}, + {"random non-prime", 10, false, 5, nil}, + {"another random prime", 23, true, 5, nil}, +} + +func TestMillerRabinProbabilistic(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - output, err := MillerRabinTest(test.input, test.rounds) + output, err := MillerRabinProbabilistic(test.input, test.rounds) if err != test.err { t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err) } @@ -34,8 +30,28 @@ func TestMillerRabinTest(t *testing.T) { } } -func BenchmarkMillerRabinPrimalityTest(b *testing.B) { +func TestMillerRabinDeterministic(t *testing.T) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + output, err := MillerRabinDeterministic(test.input) + if err != test.err { + t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err) + } + if output != test.expected { + t.Errorf("For input: %d, expected %v", test.input, output) + } + }) + } +} + +func BenchmarkMillerRabinProbabilistic(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = MillerRabinProbabilistic(23, 5) + } +} + +func BenchmarkMillerRabinDeterministic(b *testing.B) { for i := 0; i < b.N; i++ { - _, _ = MillerRabinTest(23, 5) + _, _ = MillerRabinDeterministic(23) } } From 397284b7d13cc9e6ec099ce964e642150a90ccba Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 5 Apr 2022 10:32:20 +0200 Subject: [PATCH 328/488] merge: Remove cclauss from CODEOWNERS (#489) --- .github/CODEOWNERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4a0788d2e..fd1f63e16 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,5 +7,4 @@ # Order is important. The last matching pattern has the most precedence. -* @siriak @raklaptudirm @tjgurwara99 -/.* @cclauss +* @siriak @raklaptudirm @tjgurwara99 @yanglbme From 028fe09c5ce1198aad665ca3dfbb69ab346406cc Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Wed, 6 Apr 2022 21:25:46 +0530 Subject: [PATCH 329/488] Update repository workflows (#488) --- .../{golang_lint_and_test.yml => ci.yml} | 26 ++++++++++++++----- .github/workflows/godocmd.yml | 9 +++++-- 2 files changed, 26 insertions(+), 9 deletions(-) rename .github/workflows/{golang_lint_and_test.yml => ci.yml} (61%) diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/ci.yml similarity index 61% rename from .github/workflows/golang_lint_and_test.yml rename to .github/workflows/ci.yml index 29a2a9283..40ebab4a1 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,21 @@ # https://github.com/golangci/golangci-lint -name: golang_lint_and_test -on: [push, pull_request] +name: Continuous Integration +on: + push: + # prevent duplication of tests with + # `pull_request` event + branches: + - master + pull_request: + jobs: golang_lint_and_test: + name: Code style and tests runs-on: ubuntu-latest strategy: fail-fast: false steps: - uses: actions/checkout@v2 - - name: Codespell - uses: codespell-project/actions-codespell@master - with: - ignore_words_list: "actualy,nwe" - skip: "go.mod,go.sum" - name: Setup Go uses: actions/setup-go@v2 with: @@ -24,3 +27,12 @@ jobs: args: -E gofmt - name: Run tests run: go test ./... + codespell: + name: Check for spelling errors + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: codespell-project/actions-codespell@master + with: + ignore_words_list: "actualy,nwe" + skip: "go.mod,go.sum" diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index b69bf13d9..2ed6aec61 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -1,7 +1,12 @@ -name: godocmd -on: [push] +name: Generate Documentation +on: + push: + branches: + - master + jobs: generate_readme: + name: Markdown Generation runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 From 38dee1373a094b6313c700bb71ea4d62084e9810 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Thu, 7 Apr 2022 23:17:23 +0530 Subject: [PATCH 330/488] chore: set-up Code Scanning (#491) --- .github/workflows/codeql-analysis.yml | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..f1a89f3d2 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '33 2 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 From 30c24e8a134ebab170f789d44f38f04ef52b5774 Mon Sep 17 00:00:00 2001 From: Yassin Achengli <79287426+89453728@users.noreply.github.com> Date: Wed, 13 Apr 2022 19:05:08 +0200 Subject: [PATCH 331/488] Add Parenthesis Checking Algorithm (#492) --- strings/parenthesis/parenthesis.go | 27 +++++++++++++ strings/parenthesis/parenthesis_test.go | 53 +++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 strings/parenthesis/parenthesis.go create mode 100644 strings/parenthesis/parenthesis_test.go diff --git a/strings/parenthesis/parenthesis.go b/strings/parenthesis/parenthesis.go new file mode 100644 index 000000000..2ae49a641 --- /dev/null +++ b/strings/parenthesis/parenthesis.go @@ -0,0 +1,27 @@ +package parenthesis + +// Parenthesis algorithm checks if every opened parenthesis +// is closed correctly + +// when parcounter is less than 0 is because a closing +// parenthesis is detected without an opening parenthesis +// that surrounds it + +// parcounter will be 0 if all open parenthesis are closed +// correctly +func Parenthesis(text string) bool { + parcounter := 0 + + for _, r := range text { + switch r { + case '(': + parcounter++ + case ')': + parcounter-- + } + if parcounter < 0 { + return false + } + } + return parcounter == 0 +} diff --git a/strings/parenthesis/parenthesis_test.go b/strings/parenthesis/parenthesis_test.go new file mode 100644 index 000000000..b7f5abd6c --- /dev/null +++ b/strings/parenthesis/parenthesis_test.go @@ -0,0 +1,53 @@ +package parenthesis + +import ( + "testing" +) + +var parenthesisTestCases = []struct { + name string + text string + expected bool +}{ + { + "simple test with one level deep", + "(3*9-2)+(3/7^3)", + true, + }, + { + "three nested pharentesis with three deep level", + "(-1*(5+2^(3-4)*(7.44-12)+6.66/(3.43-(1+2)))*(sqrt(3-4)))", + true, + }, + { + "one opened pharentesis without be closed", + "(2*9-17)*((7+3/3)*2*(-1+4)", + false, + }, + { + "one open pharentesis for each close one but not in pairs", + "(4*(39.22-7.4)/6.77))(", + false, + }, + { + "6 deep level", + "(5+33.2)*((8.04-6.5)*(1 - (1^(2-1.22*5.44+(4.33*7.2^(0.34*(-1.23+2)))))))", + true, + }, + { + "inverted pharentesis", + ")()()()()(", + false, + }, +} + +func TestParenthesis(t *testing.T) { + for _, tc := range parenthesisTestCases { + t.Run(tc.name, func(t *testing.T) { + actual := Parenthesis(tc.text) + if actual != tc.expected { + t.Errorf("Expected %t value from test %s with input %s\n", tc.expected, tc.name, tc.text) + } + }) + } +} From 8befb60cbea14d877f4898c9556bbc091fbd3d60 Mon Sep 17 00:00:00 2001 From: hugokung <49091849+hugokung@users.noreply.github.com> Date: Thu, 21 Apr 2022 00:46:14 +0800 Subject: [PATCH 332/488] Fix: segmenttree algorithm bug (#497) --- structure/segmenttree/segmenttree.go | 12 +++++++----- structure/segmenttree/segmenttree_test.go | 8 ++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/structure/segmenttree/segmenttree.go b/structure/segmenttree/segmenttree.go index acdae7b35..2799c5537 100644 --- a/structure/segmenttree/segmenttree.go +++ b/structure/segmenttree/segmenttree.go @@ -11,7 +11,7 @@ import ( "github.com/TheAlgorithms/Go/math/min" ) -const emptyLazyNode = -1 +const emptyLazyNode = 0 //SegmentTree with original Array and the Segment Tree Array type SegmentTree struct { @@ -29,11 +29,12 @@ func (s *SegmentTree) Propagate(node int, leftNode int, rightNode int) { if leftNode == rightNode { //leaf node - s.Array[leftNode] = s.LazyTree[node] + s.Array[leftNode] += s.LazyTree[node] } else { //propagate lazy node value for children nodes - s.LazyTree[2*node] = s.LazyTree[node] - s.LazyTree[2*node+1] = s.LazyTree[node] + //may propagate multiple times, children nodes should accumulate lazy node value + s.LazyTree[2*node] += s.LazyTree[node] + s.LazyTree[2*node+1] += s.LazyTree[node] } //clear lazy node @@ -81,7 +82,8 @@ func (s *SegmentTree) Update(node int, leftNode int, rightNode int, firstIndex i if (leftNode >= firstIndex) && (rightNode <= lastIndex) { //inside the interval - s.LazyTree[node] = value + //accumulate the lazy node value + s.LazyTree[node] += value s.Propagate(node, leftNode, rightNode) } else { //update left and right nodes diff --git a/structure/segmenttree/segmenttree_test.go b/structure/segmenttree/segmenttree_test.go index c8e2c9e45..b1e21da6c 100644 --- a/structure/segmenttree/segmenttree_test.go +++ b/structure/segmenttree/segmenttree_test.go @@ -60,6 +60,14 @@ func TestSegmentTree(t *testing.T) { queries: []query{{0, 5}, {0, 2}, {2, 4}}, expected: []int{31, 14, 24}, }, + { + description: "test array with size 11 and range updates", + array: []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + updates: []update{{firstIndex: 2, lastIndex: 8, value: 2}, + {firstIndex: 2, lastIndex: 8, value: 2}}, + queries: []query{{3, 5}, {7, 8}, {4, 5}, {8, 8}}, + expected: []int{15, 10, 10, 5}, + }, } for _, test := range segmentTreeTestData { t.Run(test.description, func(t *testing.T) { From 45cbe015a65a882885f8562c4c39022c0eb6330d Mon Sep 17 00:00:00 2001 From: nursyah21 <64634372+nursyah21@users.noreply.github.com> Date: Thu, 21 Apr 2022 19:37:21 +0700 Subject: [PATCH 333/488] added implementation coinchange (#496) * added implementation coinchange * Update coinchange.go * Update coinchange_test.go * Update coinchange_test.go * Update coinchange.go * Update coinchange_test.go --- dynamic/coinchange.go | 17 +++++++++++++++++ dynamic/coinchange_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 dynamic/coinchange.go create mode 100644 dynamic/coinchange_test.go diff --git a/dynamic/coinchange.go b/dynamic/coinchange.go new file mode 100644 index 000000000..1098ea4e1 --- /dev/null +++ b/dynamic/coinchange.go @@ -0,0 +1,17 @@ +package dynamic + +// CoinChange finds the number of possible combinations of coins +// of different values which can get to the target amount. +func CoinChange(coins []int32, amount int32) int32 { + combination := make([]int32, amount) + combination[0] = 1 + + for _, c := range coins { + for i := c; i < amount; i++ { + + combination[i] += combination[i-c] + } + } + + return combination[amount-1] +} diff --git a/dynamic/coinchange_test.go b/dynamic/coinchange_test.go new file mode 100644 index 000000000..174a702f8 --- /dev/null +++ b/dynamic/coinchange_test.go @@ -0,0 +1,31 @@ +package dynamic_test + +import ( + "fmt" + "github.com/TheAlgorithms/Go/dynamic" + "testing" +) + +func TestCoinChange(t *testing.T) { + coinCombination := []int32{1, 2, 5, 10} + targets := []struct { + target int32 + expected int32 + }{ + {4, 2}, + {5, 3}, + {10, 8}, + {15, 19}, + {20, 34}, + } + + for _, v := range targets { + t.Run(fmt.Sprintf("target: %d ", v.target), func(t *testing.T) { + result := dynamic.CoinChange(coinCombination, v.target) + if result != v.expected { + t.Errorf("target: %d Expected %d, got %d", v.target, v.expected, result) + } + }) + } + +} From 4043a4b4cb67873f54854a3008976788a1b9f599 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Wed, 27 Apr 2022 14:37:20 +0530 Subject: [PATCH 334/488] merge: segmenttree: format test file with `gofmt` (#501) --- structure/segmenttree/segmenttree_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/structure/segmenttree/segmenttree_test.go b/structure/segmenttree/segmenttree_test.go index b1e21da6c..142104b87 100644 --- a/structure/segmenttree/segmenttree_test.go +++ b/structure/segmenttree/segmenttree_test.go @@ -62,10 +62,10 @@ func TestSegmentTree(t *testing.T) { }, { description: "test array with size 11 and range updates", - array: []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + array: []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, updates: []update{{firstIndex: 2, lastIndex: 8, value: 2}, {firstIndex: 2, lastIndex: 8, value: 2}}, - queries: []query{{3, 5}, {7, 8}, {4, 5}, {8, 8}}, + queries: []query{{3, 5}, {7, 8}, {4, 5}, {8, 8}}, expected: []int{15, 10, 10, 5}, }, } From ff2211355cc67fb7ce106c53e8f40269628bc8a6 Mon Sep 17 00:00:00 2001 From: Daesar Lau Date: Wed, 27 Apr 2022 21:51:31 +0800 Subject: [PATCH 335/488] insertion sort: make sorting stable (#499) --- go.sum | 0 sort/insertionsort.go | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 go.sum diff --git a/go.sum b/go.sum deleted file mode 100644 index e69de29bb..000000000 diff --git a/sort/insertionsort.go b/sort/insertionsort.go index b51bc5379..13e45eeb9 100644 --- a/sort/insertionsort.go +++ b/sort/insertionsort.go @@ -6,7 +6,7 @@ func Insertion[T constraints.Ordered](arr []T) []T { for currentIndex := 1; currentIndex < len(arr); currentIndex++ { temporary := arr[currentIndex] iterator := currentIndex - for ; iterator > 0 && arr[iterator-1] >= temporary; iterator-- { + for ; iterator > 0 && arr[iterator-1] > temporary; iterator-- { arr[iterator] = arr[iterator-1] } arr[iterator] = temporary From 603f2fdd88e85c0b882a2817e955559bb0d4250c Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 28 Apr 2022 10:45:27 +0300 Subject: [PATCH 336/488] merge: algorithm: Bitwise log base 2 (#503) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition * feat: added description to some functions * Updated Documentation in README.md * fix: change descriptions * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * feat: abs algo * Updated Documentation in README.md * fix: add comment * Updated Documentation in README.md * fix: new comment * Updated Documentation in README.md * fix: rename func and remove package * Updated Documentation in README.md * Update math/abs.go Co-authored-by: Taj * Updated Documentation in README.md * Update math/binary/abs.go Co-authored-by: Taj * Updated Documentation in README.md * fix: rename func and move binary test * add package description and add function name to comment * Updated Documentation in README.md * rename Intercept method to YIntercept * Updated Documentation in README.md * fix strings * Updated Documentation in README.md * fix commit * fix name cos tests and rename epsilon to epsilonCos * feat: sin * Updated Documentation in README.md * fix test for sin * fix epsilon * rename package to test * fix afte review * Updated Documentation in README.md * Updated Documentation in README.md * Updated Documentation in README.md * @feat bitwise logarithm * @fix: rename function name to LogBase2 Co-authored-by: Rak Laptudirm Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- README.md | 58 ++++++++++++++++++++++------------- math/binary/logarithm.go | 18 +++++++++++ math/binary/logarithm_test.go | 48 +++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 22 deletions(-) create mode 100644 math/binary/logarithm.go create mode 100644 math/binary/logarithm_test.go diff --git a/README.md b/README.md index 7e41257dd..0fc3d96e5 100644 --- a/README.md +++ b/README.md @@ -257,22 +257,23 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Bin2`](./dynamic/binomialcoefficient.go#L21): Bin2 function -2. [`CutRodDp`](./dynamic/rodcutting.go#L21): CutRodDp solve the same problem using dynamic programming -3. [`CutRodRec`](./dynamic/rodcutting.go#L8): CutRodRec solve the problem recursively: initial approach -4. [`EditDistanceDP`](./dynamic/editdistance.go#L35): EditDistanceDP is an optimised implementation which builds on the ideas of the recursive implementation. We use dynamic programming to compute the DP table where dp[i][j] denotes the edit distance value of first[0..i-1] and second[0..j-1]. Time complexity is O(m * n) where m and n are lengths of the strings, first and second respectively. -5. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity. -6. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided. -7. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit -8. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L8): LongestCommonSubsequence function -9. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order -10. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ -11. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function -12. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function -13. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function -14. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function -15. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate -16. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) -17. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number +2. [`CoinChange`](./dynamic/coinchange.go#L5): CoinChange finds the number of possible combinations of coins of different values which can get to the target amount. +3. [`CutRodDp`](./dynamic/rodcutting.go#L21): CutRodDp solve the same problem using dynamic programming +4. [`CutRodRec`](./dynamic/rodcutting.go#L8): CutRodRec solve the problem recursively: initial approach +5. [`EditDistanceDP`](./dynamic/editdistance.go#L35): EditDistanceDP is an optimised implementation which builds on the ideas of the recursive implementation. We use dynamic programming to compute the DP table where dp[i][j] denotes the edit distance value of first[0..i-1] and second[0..j-1]. Time complexity is O(m * n) where m and n are lengths of the strings, first and second respectively. +6. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity. +7. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided. +8. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit +9. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L8): LongestCommonSubsequence function +10. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order +11. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ +12. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function +13. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function +14. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function +15. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function +16. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate +17. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) +18. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number ---
@@ -635,6 +636,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`IsPangram`](./strings/pangram/ispangram.go#L21): No description provided. +--- +
+ parenthesis + +--- + +##### Functions: + +1. [`Parenthesis`](./strings/parenthesis/parenthesis.go#L12): parcounter will be 0 if all open parenthesis are closed correctly + ---
pascal @@ -727,11 +738,14 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Factorize`](./math/prime/primefactorization.go#L5): Factorize is a function that computes the exponents of each prime in the prime factorization of n 2. [`Generate`](./math/prime/sieve.go#L26): Generate returns a int slice of prime numbers up to the limit 3. [`GenerateChannel`](./math/prime/sieve.go#L9): Generate generates the sequence of integers starting at 2 and sends it to the channel `ch` -4. [`MillerRabinTest`](./math/prime/millerrabinprimalitytest.go#L59): MillerRabinTest Probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin. -5. [`MillerTest`](./math/prime/millerrabinprimalitytest.go#L32): MillerTest This is the intermediate step that repeats within the miller rabin primality test for better probabilitic chances of receiving the correct result. -6. [`NaiveApproach`](./math/prime/primecheck.go#L8): NaiveApproach checks if an integer is prime or not. Returns a bool. -7. [`PairApproach`](./math/prime/primecheck.go#L22): PairApproach checks primality of an integer and returns a bool. More efficient than the naive approach as number of iterations are less. -8. [`Sieve`](./math/prime/sieve.go#L16): Sieve Sieving the numbers that are not prime from the channel - basically removing them from the channels +4. [`MillerRabinDeterministic`](./math/prime/millerrabinprimalitytest.go#L121): MillerRabinDeterministic is a Deterministic version of the Miller-Rabin test, which returns correct results for all valid int64 numbers. +5. [`MillerRabinProbabilistic`](./math/prime/millerrabinprimalitytest.go#L101): MillerRabinProbabilistic is a probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin. +6. [`MillerRandomTest`](./math/prime/millerrabinprimalitytest.go#L77): MillerRandomTest This is the intermediate step that repeats within the miller rabin primality test for better probabilitic chances of receiving the correct result with random witnesses. +7. [`MillerTest`](./math/prime/millerrabinprimalitytest.go#L49): MillerTest tests whether num is a strong probable prime to a witness. Formally: a^d ≡ 1 (mod n) or a^(2^r * d) ≡ -1 (mod n), 0 <= r <= s +8. [`MillerTestMultiple`](./math/prime/millerrabinprimalitytest.go#L84): MillerTestMultiple is like MillerTest but runs the test for multiple witnesses. +9. [`NaiveApproach`](./math/prime/primecheck.go#L8): NaiveApproach checks if an integer is prime or not. Returns a bool. +10. [`PairApproach`](./math/prime/primecheck.go#L22): PairApproach checks primality of an integer and returns a bool. More efficient than the naive approach as number of iterations are less. +11. [`Sieve`](./math/prime/sieve.go#L16): Sieve Sieving the numbers that are not prime from the channel - basically removing them from the channels ---
@@ -807,7 +821,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`NewSegmentTree`](./structure/segmenttree/segmenttree.go#L114): No description provided. +1. [`NewSegmentTree`](./structure/segmenttree/segmenttree.go#L116): No description provided. --- ##### Types diff --git a/math/binary/logarithm.go b/math/binary/logarithm.go new file mode 100644 index 000000000..205b0235b --- /dev/null +++ b/math/binary/logarithm.go @@ -0,0 +1,18 @@ +// author(s) [red_byte](https://github.com/i-redbyte) +// see logarithm_test.go + +package binary + +// LogBase2 Finding the exponent of n = 2**x using bitwise operations (logarithm in base 2 of n) [See more](https://en.wikipedia.org/wiki/Logarithm) +func LogBase2(n uint32) uint32 { + base := [5]uint32{0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000} + exponents := [5]uint32{1, 2, 4, 8, 16} + var result uint32 + for i := 4; i >= 0; i-- { + if n&base[i] != 0 { + n >>= exponents[i] + result |= exponents[i] + } + } + return result +} diff --git a/math/binary/logarithm_test.go b/math/binary/logarithm_test.go new file mode 100644 index 000000000..8aaaabe72 --- /dev/null +++ b/math/binary/logarithm_test.go @@ -0,0 +1,48 @@ +// logarithm_test.go +// description: Test for finding the exponent of n = 2**x using bitwise operations (logarithm in base 2 of n) +// author(s) [red_byte](https://github.com/i-redbyte) +// see logarithm.go + +package binary + +import ( + "math" + "testing" +) + +func TestLogBase2(t *testing.T) { + tests := []struct { + name string + n uint32 + want uint32 + }{ + {"log2(1) = 0", 1, 0}, + {"log2(2) = 1", 2, 1}, + {"log2(4) = 2", 4, 2}, + {"log2(8) = 3", 8, 3}, + {"log2(16) = 4", 16, 4}, + {"log2(32) = 5", 32, 5}, + {"log2(64) = 6", 64, 6}, + {"log2(128) = 7", 128, 7}, + {"log2(256) = 8", 256, 8}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := LogBase2(test.n); got != test.want { + t.Errorf("LogBase2() = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkBitwiseLogBase2(b *testing.B) { + for i := 0; i < b.N; i++ { + LogBase2(1024) + } +} + +func BenchmarkMathPAckageLogBase2(b *testing.B) { + for i := 0; i < b.N; i++ { + math.Log2(1024) + } +} From d00ee5eef862c2bbf07c7de2d0e2bdfe5d1e1cef Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Thu, 28 Apr 2022 06:27:15 -0700 Subject: [PATCH 337/488] Fix broken link in CONTRIBUTING.md (#500) --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea44b249f..15c29be06 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,9 +6,9 @@ Welcome to [TheAlgorithms/Go](https://github.com/TheAlgorithms/Go)! Before submi ## Contributing -### Maintainer/reviewer +### Maintainers -**Please check the [reviewer code](https://github.com/TheAlgorithms/Go/blob/master/DIRECTORY.md) file for maintainers and reviewers.** +Please check the [`CODEOWNERS`](https://github.com/TheAlgorithms/Go/blob/master/.github/CODEOWNERS) file for a list of repository maintainers. ### Contributor From d696a494f9ac8fe824c52a138cf3359550f6129b Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Mon, 2 May 2022 14:46:59 +0530 Subject: [PATCH 338/488] merge: Consolidate Primality Algorithm testing into single suite (#504) * chore: add testing interface * chore: add benchmark helper * chore: remove individual tests (1) * chore: remove individual tests (2) * chore: add miller rabin test suite * refactor: trial division primality tests * chore: add trial division test suite * refactor: trial division tests now accept `int64` * chore: remove `error` return from `primalityTest` * fix: remove redundant identifier * chore: add function names for debug * chore: fix typo * chore: add explicit type conversions * fix: index out of range in tests * fix: random witness generation --- math/prime/millerrabinprimalitytest_test.go | 57 ----------- ...binprimalitytest.go => millerrabintest.go} | 2 +- math/prime/prime_test.go | 95 +++++++++++++++++++ math/prime/primecheck.go | 34 +++++-- math/prime/primecheck_test.go | 62 ------------ 5 files changed, 121 insertions(+), 129 deletions(-) delete mode 100644 math/prime/millerrabinprimalitytest_test.go rename math/prime/{millerrabinprimalitytest.go => millerrabintest.go} (99%) create mode 100644 math/prime/prime_test.go delete mode 100644 math/prime/primecheck_test.go diff --git a/math/prime/millerrabinprimalitytest_test.go b/math/prime/millerrabinprimalitytest_test.go deleted file mode 100644 index b4a4ed34f..000000000 --- a/math/prime/millerrabinprimalitytest_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package prime - -import "testing" - -var tests = []struct { - name string - input int64 - expected bool - rounds int64 - err error -}{ - {"smallest prime", 2, true, 5, nil}, - {"random prime", 3, true, 5, nil}, - {"neither prime nor composite", 1, false, 5, nil}, - {"random non-prime", 10, false, 5, nil}, - {"another random prime", 23, true, 5, nil}, -} - -func TestMillerRabinProbabilistic(t *testing.T) { - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - output, err := MillerRabinProbabilistic(test.input, test.rounds) - if err != test.err { - t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err) - } - if output != test.expected { - t.Errorf("For input: %d, expected: %v", test.input, output) - } - }) - } -} - -func TestMillerRabinDeterministic(t *testing.T) { - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - output, err := MillerRabinDeterministic(test.input) - if err != test.err { - t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err) - } - if output != test.expected { - t.Errorf("For input: %d, expected %v", test.input, output) - } - }) - } -} - -func BenchmarkMillerRabinProbabilistic(b *testing.B) { - for i := 0; i < b.N; i++ { - _, _ = MillerRabinProbabilistic(23, 5) - } -} - -func BenchmarkMillerRabinDeterministic(b *testing.B) { - for i := 0; i < b.N; i++ { - _, _ = MillerRabinDeterministic(23) - } -} diff --git a/math/prime/millerrabinprimalitytest.go b/math/prime/millerrabintest.go similarity index 99% rename from math/prime/millerrabinprimalitytest.go rename to math/prime/millerrabintest.go index 76cb27578..1f3a2ef72 100644 --- a/math/prime/millerrabinprimalitytest.go +++ b/math/prime/millerrabintest.go @@ -75,7 +75,7 @@ func MillerTest(num, witness int64) (bool, error) { // miller rabin primality test for better probabilitic chances of // receiving the correct result with random witnesses. func MillerRandomTest(num int64) (bool, error) { - random := rand.Int63n(num-1) + 2 + random := rand.Int63n(num-2) + 2 return MillerTest(num, random) } diff --git a/math/prime/prime_test.go b/math/prime/prime_test.go new file mode 100644 index 000000000..e06f4a6de --- /dev/null +++ b/math/prime/prime_test.go @@ -0,0 +1,95 @@ +package prime + +import ( + "fmt" + "testing" +) + +var primeList = []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127} +var testLimit = 127 + +type primalityTest func(int64) bool + +func primalityTestTestingHelper(t *testing.T, name string, f primalityTest) { + arrayIndex := 0 + for i := 1; i <= testLimit; i++ { + isPrime := i == primeList[arrayIndex] + + testName := fmt.Sprintf("%s(%d)", name, i) + t.Run(testName, func(t *testing.T) { + result := f(int64(i)) + + if isPrime { + arrayIndex++ + } + + if result != isPrime { + t.Errorf("%d: %s function returned %v\n", i, name, result) + } + }) + } +} + +func primalityTestBenchmarkHelper(b *testing.B, f primalityTest) { + for i := 0; i < b.N; i++ { + f(104729) + } +} + +// Miller-Rabin Probabilistic test + +func millerRabinProbabilisticTester(n int64) bool { + result, err := MillerRabinProbabilistic(n, 40) + if err != nil { + panic(err) + } + + return result +} + +func TestMillerRabinProbabilistic(t *testing.T) { + primalityTestTestingHelper(t, "Miller-Rabin Probabilistic", millerRabinProbabilisticTester) +} + +func BenchmarkMillerRabinProbabilistic(b *testing.B) { + primalityTestBenchmarkHelper(b, millerRabinProbabilisticTester) +} + +// Miller-Rabin deterministic test + +func millerRabinDeterministicTester(n int64) bool { + result, err := MillerRabinDeterministic(n) + if err != nil { + panic(err) + } + + return result +} + +func TestMillerRabinDeterministic(t *testing.T) { + primalityTestTestingHelper(t, "Miller-Rabin Deterministic", millerRabinDeterministicTester) +} + +func BenchmarkMillerRabinDeterministic(b *testing.B) { + primalityTestBenchmarkHelper(b, millerRabinDeterministicTester) +} + +// Trial Division test + +func TestTrialDivision(t *testing.T) { + primalityTestTestingHelper(t, "Trial Division", TrialDivision) +} + +func BenchmarkTrialDivision(b *testing.B) { + primalityTestBenchmarkHelper(b, TrialDivision) +} + +// Trial Division (optimized) + +func TestOptimizedTrialDivision(t *testing.T) { + primalityTestTestingHelper(t, "Trial Division (optimized)", OptimizedTrialDivision) +} + +func BenchmarkOptimizedTrialDivision(b *testing.B) { + primalityTestBenchmarkHelper(b, OptimizedTrialDivision) +} diff --git a/math/prime/primecheck.go b/math/prime/primecheck.go index e6b4f96c2..3e2a97280 100644 --- a/math/prime/primecheck.go +++ b/math/prime/primecheck.go @@ -1,15 +1,17 @@ package prime -// A primality test is an algorithm for determining whether an input number is prime.Among other fields of mathematics, it is used for cryptography. -//Unlike integer factorization, primality tests do not generally give prime factors, only stating whether the input number is prime or not. -//Source - Wikipedia https://en.wikipedia.org/wiki/Primality_test +// A primality test is an algorithm for determining whether an input number is prime. Among other +// fields of mathematics, it is used for cryptography. Unlike integer factorization, primality +// tests do not generally give prime factors, only stating whether the input number is prime or not. +// Source - Wikipedia https://en.wikipedia.org/wiki/Primality_test -// NaiveApproach checks if an integer is prime or not. Returns a bool. -func NaiveApproach(n int) bool { +// TrialDivision tests whether a number is prime by trying to divide it by the numbers less than it. +func TrialDivision(n int64) bool { if n < 2 { return false } - for i := 2; i < n; i++ { + + for i := int64(2); i < n; i++ { if n%i == 0 { return false @@ -18,12 +20,26 @@ func NaiveApproach(n int) bool { return true } -// PairApproach checks primality of an integer and returns a bool. More efficient than the naive approach as number of iterations are less. -func PairApproach(n int) bool { +// OptimizedTrialDivision checks primality of an integer using an optimized trial division method. +// The optimizations include not checking divisibility by the even numbers and only checking up to +// the square root of the given number. +func OptimizedTrialDivision(n int64) bool { + // 0 and 1 are not prime if n < 2 { return false } - for i := 2; i*i <= n; i++ { + + // 2 and 3 are prime + if n < 4 { + return true + } + + // all numbers divisible by 2 except 2 are not prime + if n%2 == 0 { + return false + } + + for i := int64(3); i*i <= n; i += 2 { if n%i == 0 { return false } diff --git a/math/prime/primecheck_test.go b/math/prime/primecheck_test.go deleted file mode 100644 index 0cbe310f7..000000000 --- a/math/prime/primecheck_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package prime - -import ( - "testing" -) - -func TestTableNaiveApproach(t *testing.T) { - var tests = []struct { - name string - input int - expected bool - }{ - {"smallest prime", 2, true}, - {"random prime", 3, true}, - {"neither prime nor composite", 1, false}, - {"random non-prime", 10, false}, - {"another random prime", 23, true}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if output := NaiveApproach(test.input); output != test.expected { - t.Errorf("For input: %d, expected: %v, but got: %v", test.input, test.expected, output) - } - }) - } - -} -func TestTablePairApproach(t *testing.T) { - var tests = []struct { - name string - input int - expected bool - }{ - {"smallest prime", 2, true}, - {"random prime", 3, true}, - {"neither prime nor composite", 1, false}, - {"random non-prime", 10, false}, - {"another random prime", 23, true}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - if output := NaiveApproach(test.input); output != test.expected { - t.Errorf("For input: %d, expected: %v, but got: %v", test.input, test.expected, output) - } - }) - } - -} - -func BenchmarkNaiveApproach(b *testing.B) { - for i := 0; i < b.N; i++ { - NaiveApproach(23) - } -} - -func BenchmarkPairApproach(b *testing.B) { - for i := 0; i < b.N; i++ { - PairApproach(23) - } -} From db857821c21bd53224a85343c7edfaa1524e936a Mon Sep 17 00:00:00 2001 From: Ritik Bhandari Date: Sun, 8 May 2022 13:05:48 +0530 Subject: [PATCH 339/488] merge: replaced 'interface{}' with 'any' using new go1.18 alias (#506) --- CONTRIBUTING.md | 2 +- graph/dijkstra.go | 2 +- sort/heapsort.go | 4 +-- structure/dynamicarray/dynamicarray.go | 12 ++++----- structure/dynamicarray/dynamicarray_test.go | 4 +-- structure/hashmap/hashmap.go | 18 ++++++------- structure/hashmap/hashmap_test.go | 2 +- structure/linkedlist/cyclic.go | 2 +- structure/linkedlist/cyclic_test.go | 4 +-- structure/linkedlist/doubly.go | 10 +++---- structure/linkedlist/shared.go | 4 +-- structure/linkedlist/singlylinkedlist.go | 8 +++--- structure/linkedlist/singlylinkedlist_test.go | 20 +++++++------- structure/queue/queue_test.go | 4 +-- structure/queue/queuearray.go | 10 +++---- structure/queue/queuelinkedlist.go | 10 +++---- structure/queue/queuelinklistwithlist.go | 6 ++--- structure/set/set.go | 26 +++++++++---------- structure/stack/stack_test.go | 6 ++--- structure/stack/stackarray.go | 10 +++---- structure/stack/stacklinkedlist.go | 10 +++---- structure/stack/stacklinkedlistwithlist.go | 6 ++--- 22 files changed, 90 insertions(+), 90 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 15c29be06..1d7b39624 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,7 +93,7 @@ import ( // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. // It returns the number of bytes written, and any write error encountered. -func Fprint(w io.Writer, a ...interface{}) (n int, err error) { +func Fprint(w io.Writer, a ...any) (n int, err error) { ... } diff --git a/graph/dijkstra.go b/graph/dijkstra.go index 26b2becbc..685cf02e8 100644 --- a/graph/dijkstra.go +++ b/graph/dijkstra.go @@ -7,7 +7,7 @@ type Item struct { dist int } -func (a Item) More(b interface{}) bool { +func (a Item) More(b any) bool { // reverse direction for minheap return a.dist < b.(Item).dist } diff --git a/sort/heapsort.go b/sort/heapsort.go index 0c44eb515..07a5d9547 100644 --- a/sort/heapsort.go +++ b/sort/heapsort.go @@ -107,11 +107,11 @@ func (h MaxHeap) heapifyDown(i int) { type Comparable interface { Idx() int - More(interface{}) bool + More(any) bool } type Int int -func (a Int) More(b interface{}) bool { +func (a Int) More(b any) bool { return a > b.(Int) } func (a Int) Idx() int { diff --git a/structure/dynamicarray/dynamicarray.go b/structure/dynamicarray/dynamicarray.go index 66822be70..948cf71fc 100644 --- a/structure/dynamicarray/dynamicarray.go +++ b/structure/dynamicarray/dynamicarray.go @@ -21,11 +21,11 @@ var defaultCapacity = 10 type DynamicArray struct { Size int Capacity int - ElementData []interface{} + ElementData []any } // Put function is change/update the value in array with the index and new value -func (da *DynamicArray) Put(index int, element interface{}) error { +func (da *DynamicArray) Put(index int, element any) error { err := da.CheckRangeFromIndex(index) if err != nil { @@ -38,7 +38,7 @@ func (da *DynamicArray) Put(index int, element interface{}) error { } // Add function is add new element to our array -func (da *DynamicArray) Add(element interface{}) { +func (da *DynamicArray) Add(element any) { if da.Size == da.Capacity { da.NewCapacity() } @@ -64,7 +64,7 @@ func (da *DynamicArray) Remove(index int) error { } // Get function is return one element with the index of array -func (da *DynamicArray) Get(index int) (interface{}, error) { +func (da *DynamicArray) Get(index int) (any, error) { err := da.CheckRangeFromIndex(index) if err != nil { @@ -80,7 +80,7 @@ func (da *DynamicArray) IsEmpty() bool { } // GetData function return all value of array -func (da *DynamicArray) GetData() []interface{} { +func (da *DynamicArray) GetData() []any { return da.ElementData[:da.Size] } @@ -100,7 +100,7 @@ func (da *DynamicArray) NewCapacity() { da.Capacity = da.Capacity << 1 } - newDataElement := make([]interface{}, da.Capacity) + newDataElement := make([]any, da.Capacity) copy(newDataElement, da.ElementData) diff --git a/structure/dynamicarray/dynamicarray_test.go b/structure/dynamicarray/dynamicarray_test.go index 976370ba8..e6b30b2b1 100644 --- a/structure/dynamicarray/dynamicarray_test.go +++ b/structure/dynamicarray/dynamicarray_test.go @@ -26,7 +26,7 @@ func TestDynamicArray(t *testing.T) { if numbers.IsEmpty() != false { t.Errorf("Expected be false but got %v", numbers.IsEmpty()) } - var res []interface{} + var res []any res = append(res, 10) res = append(res, 20) res = append(res, 30) @@ -43,7 +43,7 @@ func TestDynamicArray(t *testing.T) { if numbers.IsEmpty() != false { t.Errorf("Expected be false but got %v", numbers.IsEmpty()) } - var res []interface{} + var res []any res = append(res, 10) res = append(res, 30) res = append(res, 40) diff --git a/structure/hashmap/hashmap.go b/structure/hashmap/hashmap.go index 1665a50c7..b0f5dbb1d 100644 --- a/structure/hashmap/hashmap.go +++ b/structure/hashmap/hashmap.go @@ -8,8 +8,8 @@ import ( var defaultCapacity uint64 = 1 << 10 type node struct { - key interface{} - value interface{} + key any + value any next *node } @@ -38,7 +38,7 @@ func Make(size, capacity uint64) HashMap { } // Get returns value associated with given key -func (hm *HashMap) Get(key interface{}) interface{} { +func (hm *HashMap) Get(key any) any { node := hm.getNodeByHash(hm.hash(key)) if node != nil { @@ -49,17 +49,17 @@ func (hm *HashMap) Get(key interface{}) interface{} { } // Put puts new key value in hashmap -func (hm *HashMap) Put(key interface{}, value interface{}) interface{} { +func (hm *HashMap) Put(key any, value any) any { return hm.putValue(hm.hash(key), key, value) } // Contains checks if given key is stored in hashmap -func (hm *HashMap) Contains(key interface{}) bool { +func (hm *HashMap) Contains(key any) bool { node := hm.getNodeByHash(hm.hash(key)) return node != nil } -func (hm *HashMap) putValue(hash uint64, key interface{}, value interface{}) interface{} { +func (hm *HashMap) putValue(hash uint64, key any, value any) any { if hm.capacity == 0 { hm.capacity = defaultCapacity hm.table = make([]*node, defaultCapacity) @@ -106,14 +106,14 @@ func (hm *HashMap) resize() { } } -func newNode(key interface{}, value interface{}) *node { +func newNode(key any, value any) *node { return &node{ key: key, value: value, } } -func newNodeWithNext(key interface{}, value interface{}, next *node) *node { +func newNodeWithNext(key any, value any, next *node) *node { return &node{ key: key, value: value, @@ -121,7 +121,7 @@ func newNodeWithNext(key interface{}, value interface{}, next *node) *node { } } -func (hm *HashMap) hash(key interface{}) uint64 { +func (hm *HashMap) hash(key any) uint64 { h := fnv.New64a() _, _ = h.Write([]byte(fmt.Sprintf("%v", key))) diff --git a/structure/hashmap/hashmap_test.go b/structure/hashmap/hashmap_test.go index 2b0030b7e..1699f8c25 100644 --- a/structure/hashmap/hashmap_test.go +++ b/structure/hashmap/hashmap_test.go @@ -59,7 +59,7 @@ func TestHashMap(t *testing.T) { }) t.Run("Test 7: Checking if the key does not exist Get func returns nil", func(t *testing.T) { - want := interface{}(nil) + want := any(nil) got := mp.Get(2) if got != want { t.Errorf("Key '2' does not exists in the map but it says otherwise") diff --git a/structure/linkedlist/cyclic.go b/structure/linkedlist/cyclic.go index cf0ab22df..d0ef8c4b6 100644 --- a/structure/linkedlist/cyclic.go +++ b/structure/linkedlist/cyclic.go @@ -17,7 +17,7 @@ func NewCyclic() *Cyclic { // point to itself. For other cases, the node will be added // to the end of the list. End of the list is Prev field of // current item. Complexity O(1). -func (cl *Cyclic) Add(val interface{}) { +func (cl *Cyclic) Add(val any) { n := NewNode(val) cl.Size++ if cl.Head == nil { diff --git a/structure/linkedlist/cyclic_test.go b/structure/linkedlist/cyclic_test.go index 162f9d0a1..41e925a95 100644 --- a/structure/linkedlist/cyclic_test.go +++ b/structure/linkedlist/cyclic_test.go @@ -15,8 +15,8 @@ func TestAdd(t *testing.T) { list := NewCyclic() fillList(list, 3) - want := []interface{}{1, 2, 3} - var got []interface{} + want := []any{1, 2, 3} + var got []any var start *Node start = list.Head diff --git a/structure/linkedlist/doubly.go b/structure/linkedlist/doubly.go index 5a76e7cf9..42d24935f 100644 --- a/structure/linkedlist/doubly.go +++ b/structure/linkedlist/doubly.go @@ -24,7 +24,7 @@ func NewDoubly() *Doubly { } // AddAtBeg Add a node to the beginning of the linkedlist -func (ll *Doubly) AddAtBeg(val interface{}) { +func (ll *Doubly) AddAtBeg(val any) { n := NewNode(val) n.Next = ll.Head @@ -37,7 +37,7 @@ func (ll *Doubly) AddAtBeg(val interface{}) { } // AddAtEnd Add a node at the end of the linkedlist -func (ll *Doubly) AddAtEnd(val interface{}) { +func (ll *Doubly) AddAtEnd(val any) { n := NewNode(val) if ll.Head == nil { @@ -53,7 +53,7 @@ func (ll *Doubly) AddAtEnd(val interface{}) { } // DelAtBeg Delete the node at the beginning of the linkedlist -func (ll *Doubly) DelAtBeg() interface{} { +func (ll *Doubly) DelAtBeg() any { if ll.Head == nil { return -1 } @@ -68,7 +68,7 @@ func (ll *Doubly) DelAtBeg() interface{} { } // DetAtEnd Delete a node at the end of the linkedlist -func (ll *Doubly) DelAtEnd() interface{} { +func (ll *Doubly) DelAtEnd() any { // no item if ll.Head == nil { return -1 @@ -90,7 +90,7 @@ func (ll *Doubly) DelAtEnd() interface{} { } // Count Number of nodes in the linkedlist -func (ll *Doubly) Count() interface{} { +func (ll *Doubly) Count() any { var ctr int = 0 for cur := ll.Head; cur != nil; cur = cur.Next { diff --git a/structure/linkedlist/shared.go b/structure/linkedlist/shared.go index de92a8fcb..c09e9fe8a 100644 --- a/structure/linkedlist/shared.go +++ b/structure/linkedlist/shared.go @@ -3,12 +3,12 @@ package linkedlist // Node Structure representing the linkedlist node. // This node is shared across different implementations. type Node struct { - Val interface{} + Val any Prev *Node Next *Node } // Create new node. -func NewNode(val interface{}) *Node { +func NewNode(val any) *Node { return &Node{val, nil, nil} } diff --git a/structure/linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go index 5b9d71787..f8662408a 100644 --- a/structure/linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -21,7 +21,7 @@ func NewSingly() *Singly { } // AddAtBeg adds a new snode with given value at the beginning of the list. -func (ll *Singly) AddAtBeg(val interface{}) { +func (ll *Singly) AddAtBeg(val any) { n := NewNode(val) n.Next = ll.Head ll.Head = n @@ -29,7 +29,7 @@ func (ll *Singly) AddAtBeg(val interface{}) { } // AddAtEnd adds a new snode with given value at the end of the list. -func (ll *Singly) AddAtEnd(val interface{}) { +func (ll *Singly) AddAtEnd(val any) { n := NewNode(val) if ll.Head == nil { @@ -46,7 +46,7 @@ func (ll *Singly) AddAtEnd(val interface{}) { } // DelAtBeg deletes the snode at the head(beginning) of the list and returns its value. Returns -1 if the list is empty. -func (ll *Singly) DelAtBeg() interface{} { +func (ll *Singly) DelAtBeg() any { if ll.Head == nil { return -1 } @@ -59,7 +59,7 @@ func (ll *Singly) DelAtBeg() interface{} { } // DelAtEnd deletes the snode at the tail(end) of the list and returns its value. Returns -1 if the list is empty. -func (ll *Singly) DelAtEnd() interface{} { +func (ll *Singly) DelAtEnd() any { if ll.Head == nil { return -1 } diff --git a/structure/linkedlist/singlylinkedlist_test.go b/structure/linkedlist/singlylinkedlist_test.go index b5c615403..df8004aa0 100644 --- a/structure/linkedlist/singlylinkedlist_test.go +++ b/structure/linkedlist/singlylinkedlist_test.go @@ -12,8 +12,8 @@ func TestSingly(t *testing.T) { list.AddAtBeg(3) t.Run("Test AddAtBeg()", func(t *testing.T) { - want := []interface{}{3, 2, 1} - got := []interface{}{} + want := []any{3, 2, 1} + got := []any{} current := list.Head got = append(got, current.Val) for current.Next != nil { @@ -28,8 +28,8 @@ func TestSingly(t *testing.T) { list.AddAtEnd(4) t.Run("Test AddAtEnd()", func(t *testing.T) { - want := []interface{}{3, 2, 1, 4} - got := []interface{}{} + want := []any{3, 2, 1, 4} + got := []any{} current := list.Head got = append(got, current.Val) for current.Next != nil { @@ -42,7 +42,7 @@ func TestSingly(t *testing.T) { }) t.Run("Test DelAtBeg()", func(t *testing.T) { - want := interface{}(3) + want := any(3) got := list.DelAtBeg() if got != want { t.Errorf("got: %v, want: %v", got, want) @@ -50,7 +50,7 @@ func TestSingly(t *testing.T) { }) t.Run("Test DelAtEnd()", func(t *testing.T) { - want := interface{}(4) + want := any(4) got := list.DelAtEnd() if got != want { t.Errorf("got: %v, want: %v", got, want) @@ -74,8 +74,8 @@ func TestSingly(t *testing.T) { list2.AddAtBeg(6) t.Run("Test Reverse()", func(t *testing.T) { - want := []interface{}{1, 2, 3, 4, 5, 6} - got := []interface{}{} + want := []any{1, 2, 3, 4, 5, 6} + got := []any{} list2.Reverse() current := list2.Head got = append(got, current.Val) @@ -89,8 +89,8 @@ func TestSingly(t *testing.T) { }) t.Run("Test ReversePartition()", func(t *testing.T) { - want := []interface{}{1, 5, 4, 3, 2, 6} - got := []interface{}{} + want := []any{1, 5, 4, 3, 2, 6} + got := []any{} err := list2.ReversePartition(2, 5) if err != nil { diff --git a/structure/queue/queue_test.go b/structure/queue/queue_test.go index 469fede41..11cda8ca6 100644 --- a/structure/queue/queue_test.go +++ b/structure/queue/queue_test.go @@ -109,7 +109,7 @@ func TestQueue(t *testing.T) { } }) - ListQueue = []interface{}{} + ListQueue = []any{} t.Run("Test Queue isEmpty", func(t *testing.T) { @@ -125,7 +125,7 @@ func TestQueue(t *testing.T) { } }) - ListQueue = []interface{}{} + ListQueue = []any{} t.Run("Test Queue Length", func(t *testing.T) { if LenQueue() != 0 { t.Errorf("Test Queue Length is wrong the result must be %v but got %v", 0, LenQueue()) diff --git a/structure/queue/queuearray.go b/structure/queue/queuearray.go index 27d0cf609..f1813c8e6 100644 --- a/structure/queue/queuearray.go +++ b/structure/queue/queuearray.go @@ -9,27 +9,27 @@ package queue -var ListQueue []interface{} +var ListQueue []any // EnQueue it will be added new value into our list -func EnQueue(n interface{}) { +func EnQueue(n any) { ListQueue = append(ListQueue, n) } // DeQueue it will be removed the first value that added into the list -func DeQueue() interface{} { +func DeQueue() any { data := ListQueue[0] ListQueue = ListQueue[1:] return data } // FrontQueue return the Front value -func FrontQueue() interface{} { +func FrontQueue() any { return ListQueue[0] } // BackQueue return the Back value -func BackQueue() interface{} { +func BackQueue() any { return ListQueue[len(ListQueue)-1] } diff --git a/structure/queue/queuelinkedlist.go b/structure/queue/queuelinkedlist.go index 7c7dbc4d1..18c04d3f5 100644 --- a/structure/queue/queuelinkedlist.go +++ b/structure/queue/queuelinkedlist.go @@ -11,7 +11,7 @@ package queue // Node will be store the value and the next node as well type Node struct { - Data interface{} + Data any Next *Node } @@ -23,7 +23,7 @@ type Queue struct { } // enqueue it will be added new value into queue -func (ll *Queue) enqueue(n interface{}) { +func (ll *Queue) enqueue(n any) { var newNode Node // create new Node newNode.Data = n // set the data @@ -40,7 +40,7 @@ func (ll *Queue) enqueue(n interface{}) { } // dequeue it will be removed the first value into queue (First In First Out) -func (ll *Queue) dequeue() interface{} { +func (ll *Queue) dequeue() any { if ll.isEmpty() { return -1 // if is empty return -1 } @@ -67,11 +67,11 @@ func (ll *Queue) len() int { } // frontQueue it will return the front data -func (ll *Queue) frontQueue() interface{} { +func (ll *Queue) frontQueue() any { return ll.head.Data } // backQueue it will return the back data -func (ll *Queue) backQueue() interface{} { +func (ll *Queue) backQueue() any { return ll.tail.Data } diff --git a/structure/queue/queuelinklistwithlist.go b/structure/queue/queuelinklistwithlist.go index c1216c3a9..c27bb8bef 100644 --- a/structure/queue/queuelinklistwithlist.go +++ b/structure/queue/queuelinklistwithlist.go @@ -22,7 +22,7 @@ type LQueue struct { } // Enqueue will be added new value -func (lq *LQueue) Enqueue(value interface{}) { +func (lq *LQueue) Enqueue(value any) { lq.queue.PushBack(value) } @@ -40,7 +40,7 @@ func (lq *LQueue) Dequeue() error { } // Front it will return the front value -func (lq *LQueue) Front() (interface{}, error) { +func (lq *LQueue) Front() (any, error) { if !lq.Empty() { val := lq.queue.Front().Value return val, nil @@ -50,7 +50,7 @@ func (lq *LQueue) Front() (interface{}, error) { } // Back it will return the back value -func (lq *LQueue) Back() (interface{}, error) { +func (lq *LQueue) Back() (any, error) { if !lq.Empty() { val := lq.queue.Back().Value return val, nil diff --git a/structure/set/set.go b/structure/set/set.go index 00ffd0629..9adef5c48 100644 --- a/structure/set/set.go +++ b/structure/set/set.go @@ -4,9 +4,9 @@ package set // New gives new set. -func New(items ...interface{}) Set { +func New(items ...any) Set { st := set{ - elements: make(map[interface{}]bool), + elements: make(map[any]bool), } for _, item := range items { st.Add(item) @@ -17,15 +17,15 @@ func New(items ...interface{}) Set { // Set is an interface of possible methods on 'set'. type Set interface { // Add: adds new element to the set - Add(item interface{}) + Add(item any) // Delete: deletes the passed element from the set if present - Delete(item interface{}) + Delete(item any) // Len: gives the length of the set (total no. of elements in set) Len() int - // GetItems: gives the array( []interface{} ) of elements of the set. - GetItems() []interface{} + // GetItems: gives the array( []any ) of elements of the set. + GetItems() []any // In: checks whether item is present in set or not. - In(item interface{}) bool + In(item any) bool // IsSubsetOf: checks whether set is subset of set2 or not. IsSubsetOf(set2 Set) bool // IsSupersetOf: checks whether set is superset of set2 or not. @@ -45,19 +45,19 @@ type Set interface { } type set struct { - elements map[interface{}]bool + elements map[any]bool } -func (st *set) Add(value interface{}) { +func (st *set) Add(value any) { st.elements[value] = true } -func (st *set) Delete(value interface{}) { +func (st *set) Delete(value any) { delete(st.elements, value) } -func (st *set) GetItems() []interface{} { - keys := make([]interface{}, 0, len(st.elements)) +func (st *set) GetItems() []any { + keys := make([]any, 0, len(st.elements)) for k := range st.elements { keys = append(keys, k) } @@ -68,7 +68,7 @@ func (st *set) Len() int { return len(st.elements) } -func (st *set) In(value interface{}) bool { +func (st *set) In(value any) bool { if _, in := st.elements[value]; in { return true } diff --git a/structure/stack/stack_test.go b/structure/stack/stack_test.go index 6bc01ed79..e5a77e70b 100644 --- a/structure/stack/stack_test.go +++ b/structure/stack/stack_test.go @@ -24,7 +24,7 @@ func TestStackLinkedList(t *testing.T) { t.Run("Stack Push", func(t *testing.T) { result := newStack.show() - expected := []interface{}{2, 1} + expected := []any{2, 1} for x := range result { if result[x] != expected[x] { t.Errorf("Stack Push is not work, got %v but expected %v", result, expected) @@ -73,8 +73,8 @@ func TestStackArray(t *testing.T) { stackPush(3) t.Run("Stack Push", func(t *testing.T) { - if !reflect.DeepEqual([]interface{}{3, 2}, stackArray) { - t.Errorf("Stack Push is not work we expected %v but got %v", []interface{}{3, 2}, stackArray) + if !reflect.DeepEqual([]any{3, 2}, stackArray) { + t.Errorf("Stack Push is not work we expected %v but got %v", []any{3, 2}, stackArray) } }) diff --git a/structure/stack/stackarray.go b/structure/stack/stackarray.go index 197871cd6..5aba01cf4 100644 --- a/structure/stack/stackarray.go +++ b/structure/stack/stackarray.go @@ -9,11 +9,11 @@ package stack -var stackArray []interface{} +var stackArray []any // stackPush push to first index of array -func stackPush(n interface{}) { - stackArray = append([]interface{}{n}, stackArray...) +func stackPush(n any) { + stackArray = append([]any{n}, stackArray...) } // stackLength return length of array @@ -22,7 +22,7 @@ func stackLength() int { } // stackPeak return last input of array -func stackPeak() interface{} { +func stackPeak() any { return stackArray[0] } @@ -32,7 +32,7 @@ func stackEmpty() bool { } // stackPop return last input and remove it in array -func stackPop() interface{} { +func stackPop() any { pop := stackArray[0] stackArray = stackArray[1:] return pop diff --git a/structure/stack/stacklinkedlist.go b/structure/stack/stacklinkedlist.go index 9148cc7ad..4c4973884 100644 --- a/structure/stack/stacklinkedlist.go +++ b/structure/stack/stacklinkedlist.go @@ -11,7 +11,7 @@ package stack // Node structure type Node struct { - Val interface{} + Val any Next *Node } @@ -22,7 +22,7 @@ type Stack struct { } // push add value to last index -func (ll *Stack) push(n interface{}) { +func (ll *Stack) push(n any) { newStack := &Node{} // new node newStack.Val = n @@ -33,7 +33,7 @@ func (ll *Stack) push(n interface{}) { } // pop remove last item as first output -func (ll *Stack) pop() interface{} { +func (ll *Stack) pop() any { result := ll.top.Val if ll.top.Next == nil { ll.top = nil @@ -56,12 +56,12 @@ func (ll *Stack) len() int { } // peak return last input value -func (ll *Stack) peak() interface{} { +func (ll *Stack) peak() any { return ll.top.Val } // show all value as an interface array -func (ll *Stack) show() (in []interface{}) { +func (ll *Stack) show() (in []any) { current := ll.top for current != nil { diff --git a/structure/stack/stacklinkedlistwithlist.go b/structure/stack/stacklinkedlistwithlist.go index 6afb778f8..0a758d8c6 100644 --- a/structure/stack/stacklinkedlistwithlist.go +++ b/structure/stack/stacklinkedlistwithlist.go @@ -20,12 +20,12 @@ type SList struct { } // Push add a value into our stack -func (sl *SList) Push(val interface{}) { +func (sl *SList) Push(val any) { sl.stack.PushFront(val) } // Peak is return last value that insert into our stack -func (sl *SList) Peak() (interface{}, error) { +func (sl *SList) Peak() (any, error) { if !sl.Empty() { element := sl.stack.Front() return element.Value, nil @@ -35,7 +35,7 @@ func (sl *SList) Peak() (interface{}, error) { // Pop is return last value that insert into our stack //also it will remove it in our stack -func (sl *SList) Pop() (interface{}, error) { +func (sl *SList) Pop() (any, error) { if !sl.Empty() { // get last element that insert into stack element := sl.stack.Front() From 07eee88553943ed548d6c7d7c62e25e4e72b62cf Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Tue, 10 May 2022 22:46:29 +0530 Subject: [PATCH 340/488] chore: remove codeql workflow (#507) --- .github/workflows/codeql-analysis.yml | 70 --------------------------- 1 file changed, 70 deletions(-) delete mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index f1a89f3d2..000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,70 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '33 2 * * 6' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 From 94ee68a86581a8cc55a5fd6d4bc5f2116205eabe Mon Sep 17 00:00:00 2001 From: duongoku Date: Sun, 22 May 2022 03:17:06 +0700 Subject: [PATCH 341/488] add abbreviation problem in dynamic (#508) --- dynamic/abbreviation.go | 45 ++++++++++++++++++++++++++++++++++++ dynamic/abbreviation_test.go | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 dynamic/abbreviation.go create mode 100644 dynamic/abbreviation_test.go diff --git a/dynamic/abbreviation.go b/dynamic/abbreviation.go new file mode 100644 index 000000000..ebfe92171 --- /dev/null +++ b/dynamic/abbreviation.go @@ -0,0 +1,45 @@ +// File: abbreviation.go +// Description: Abbreviation problem +// Details: +// https://www.hackerrank.com/challenges/abbr/problem +// Problem description (from hackerrank): +// You can perform the following operations on the string, a: +// 1. Capitalize zero or more of a's lowercase letters. +// 2. Delete all of the remaining lowercase letters in a. +// Given 2 strings a and b, determine if it's possible to make a equal to be using above operations. +// Example: +// Given a = "ABcde" and b = "ABCD" +// We can capitalize "c" and "d" in a to get "ABCde" then delete all the lowercase letters (which is only "e") in a to get "ABCD" which equals b. +// Author: [duongoku](https://github.com/duongoku) +// See abbreviation_test.go for test cases + +package dynamic + +// strings for getting uppercases and lowercases +import ( + "strings" +) + +// Returns true if it is possible to make a equals b (if b is an abbreviation of a), returns false otherwise +func Abbreviation(a string, b string) bool { + dp := make([][]bool, len(a)+1) + for i := range dp { + dp[i] = make([]bool, len(b)+1) + } + dp[0][0] = true + + for i := 0; i < len(a); i++ { + for j := 0; j <= len(b); j++ { + if dp[i][j] { + if j < len(b) && strings.ToUpper(string(a[i])) == string(b[j]) { + dp[i+1][j+1] = true + } + if string(a[i]) == strings.ToLower(string(a[i])) { + dp[i+1][j] = true + } + } + } + } + + return dp[len(a)][len(b)] +} diff --git a/dynamic/abbreviation_test.go b/dynamic/abbreviation_test.go new file mode 100644 index 000000000..38824d33a --- /dev/null +++ b/dynamic/abbreviation_test.go @@ -0,0 +1,41 @@ +package dynamic + +import ( + "fmt" + "testing" +) + +func TestAbbreviation(t *testing.T) { + tests := []struct { + a string + b string + expected bool + }{ + {"uOHlGMdUBc", "uOalGMdUBCasdcavsdf", false}, + {"kotgDIUagj", "DIU", true}, + {"WPTffVkSNl", "WPTVSN", true}, + {"CoJsPURrVX", "CPUVX", false}, + {"xasreDHndqvCnFfX", "DHndqvCnFX", false}, + {"XFEaWCxpeepGjOnCCsFh", "XFEAWCPEPGOCCSF", true}, + {"", "", true}, + {"a", "", true}, + {"a", "b", false}, + {"a", "a", false}, + {"A", "A", true}, + } + count := len(tests) + for i := 0; i < count; i++ { + name := fmt.Sprintf( + "Test case #%d: string a = \"%s\", string b = \"%s\"", + i+1, + tests[i].a, + tests[i].b, + ) + t.Run(name, func(t *testing.T) { + result := Abbreviation(tests[i].a, tests[i].b) + if result != tests[i].expected { + t.Errorf("Expected the %t, got %t", tests[i].expected, result) + } + }) + } +} From 3a41a76f0cae4cb677334a34714c129ec05cf5ad Mon Sep 17 00:00:00 2001 From: Taj Date: Mon, 27 Jun 2022 06:18:30 +0100 Subject: [PATCH 342/488] merge: manually disabled the problematic linters for Go 1.18 (#509) * fix: manually disabled the problematic linters * chore: add trailing newline Co-authored-by: Rak Laptudirm --- .golangci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..aa9001693 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,8 @@ +run: + go: 1.18 +linters: + disable: + - gosimple + - staticcheck + - structcheck + - unused From d05e0135ac4a778d262d312103b7449d9121b027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Ti=E1=BA=BFn=20=C4=90=E1=BA=A1t?= Date: Thu, 7 Jul 2022 09:12:26 +0700 Subject: [PATCH 343/488] feat: Lowest Common Ancestor (LCA) algorithm (#512) --- README.md | 84 +++++----- graph/lowestcommonancestor.go | 121 ++++++++++++++ graph/lowestcommonancestor_test.go | 250 +++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+), 37 deletions(-) create mode 100644 graph/lowestcommonancestor.go create mode 100644 graph/lowestcommonancestor_test.go diff --git a/README.md b/README.md index 0fc3d96e5..8eee9e312 100644 --- a/README.md +++ b/README.md @@ -93,12 +93,13 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 2. [`BitCounter`](./math/binary/bitcounter.go#L11): BitCounter - The function returns the number of set bits for an unsigned integer number 3. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. 4. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 -5. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations -6. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift -7. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. -8. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n -9. [`Sqrt`](./math/binary/sqrt.go#L16): No description provided. -10. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence +5. [`LogBase2`](./math/binary/logarithm.go#L7): LogBase2 Finding the exponent of n = 2**x using bitwise operations (logarithm in base 2 of n) [See more](https://en.wikipedia.org/wiki/Logarithm) +6. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations +7. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift +8. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. +9. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n +10. [`Sqrt`](./math/binary/sqrt.go#L16): No description provided. +11. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---
@@ -256,24 +257,25 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`Bin2`](./dynamic/binomialcoefficient.go#L21): Bin2 function -2. [`CoinChange`](./dynamic/coinchange.go#L5): CoinChange finds the number of possible combinations of coins of different values which can get to the target amount. -3. [`CutRodDp`](./dynamic/rodcutting.go#L21): CutRodDp solve the same problem using dynamic programming -4. [`CutRodRec`](./dynamic/rodcutting.go#L8): CutRodRec solve the problem recursively: initial approach -5. [`EditDistanceDP`](./dynamic/editdistance.go#L35): EditDistanceDP is an optimised implementation which builds on the ideas of the recursive implementation. We use dynamic programming to compute the DP table where dp[i][j] denotes the edit distance value of first[0..i-1] and second[0..j-1]. Time complexity is O(m * n) where m and n are lengths of the strings, first and second respectively. -6. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity. -7. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided. -8. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit -9. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L8): LongestCommonSubsequence function -10. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order -11. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ -12. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function -13. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function -14. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function -15. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function -16. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate -17. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) -18. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number +1. [`Abbreviation`](./dynamic/abbreviation.go#L24): Returns true if it is possible to make a equals b (if b is an abbreviation of a), returns false otherwise +2. [`Bin2`](./dynamic/binomialcoefficient.go#L21): Bin2 function +3. [`CoinChange`](./dynamic/coinchange.go#L5): CoinChange finds the number of possible combinations of coins of different values which can get to the target amount. +4. [`CutRodDp`](./dynamic/rodcutting.go#L21): CutRodDp solve the same problem using dynamic programming +5. [`CutRodRec`](./dynamic/rodcutting.go#L8): CutRodRec solve the problem recursively: initial approach +6. [`EditDistanceDP`](./dynamic/editdistance.go#L35): EditDistanceDP is an optimised implementation which builds on the ideas of the recursive implementation. We use dynamic programming to compute the DP table where dp[i][j] denotes the edit distance value of first[0..i-1] and second[0..j-1]. Time complexity is O(m * n) where m and n are lengths of the strings, first and second respectively. +7. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity. +8. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided. +9. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit +10. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L8): LongestCommonSubsequence function +11. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order +12. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ +13. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function +14. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function +15. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function +16. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function +17. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate +18. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) +19. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number ---
@@ -411,10 +413,12 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 5. [`FloydWarshall`](./graph/floydwarshall.go#L15): FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm 6. [`GetIdx`](./graph/depthfirstsearch.go#L3): No description provided. 7. [`KruskalMST`](./graph/kruskal.go#L87): KruskalMST will return a minimum spanning tree along with its total cost to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is the number of edges in the graph and n is number of nodes in it. -8. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) -9. [`NewDSU`](./graph/kruskal.go#L34): NewDSU will return an initialised DSU using the value of n which will be treated as the number of elements out of which the DSU is being made -10. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. -11. [`Topological`](./graph/topological.go#L7): Assumes that graph given is valid and possible to get a topo ordering. constraints are array of []int{a, b}, representing an edge going from a to b +8. [`LowestCommonAncestor`](./graph/lowestcommonancestor.go#L111): For each node, we will precompute its ancestor above him, its ancestor two nodes above, its ancestor four nodes above, etc. Let's call `jump[j][u]` is the `2^j`-th ancestor above the node `u` with `u` in range `[0, numbersVertex)`, `j` in range `[0,MAXLOG)`. These information allow us to jump from any node to any ancestor above it in `O(MAXLOG)` time. +9. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) +10. [`NewDSU`](./graph/kruskal.go#L34): NewDSU will return an initialised DSU using the value of n which will be treated as the number of elements out of which the DSU is being made +11. [`NewTree`](./graph/lowestcommonancestor.go#L84): No description provided. +12. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. +13. [`Topological`](./graph/topological.go#L7): Assumes that graph given is valid and possible to get a topo ordering. constraints are array of []int{a, b}, representing an edge going from a to b --- ##### Types @@ -429,7 +433,13 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 5. [`Item`](./graph/dijkstra.go#L5): No description provided. -6. [`WeightedGraph`](./graph/floydwarshall.go#L9): No description provided. +6. [`Query`](./graph/lowestcommonancestor_test.go#L9): No description provided. + +7. [`Tree`](./graph/lowestcommonancestor.go#L25): No description provided. + +8. [`TreeEdge`](./graph/lowestcommonancestor.go#L12): No description provided. + +9. [`WeightedGraph`](./graph/floydwarshall.go#L9): No description provided. --- @@ -738,14 +748,14 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Factorize`](./math/prime/primefactorization.go#L5): Factorize is a function that computes the exponents of each prime in the prime factorization of n 2. [`Generate`](./math/prime/sieve.go#L26): Generate returns a int slice of prime numbers up to the limit 3. [`GenerateChannel`](./math/prime/sieve.go#L9): Generate generates the sequence of integers starting at 2 and sends it to the channel `ch` -4. [`MillerRabinDeterministic`](./math/prime/millerrabinprimalitytest.go#L121): MillerRabinDeterministic is a Deterministic version of the Miller-Rabin test, which returns correct results for all valid int64 numbers. -5. [`MillerRabinProbabilistic`](./math/prime/millerrabinprimalitytest.go#L101): MillerRabinProbabilistic is a probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin. -6. [`MillerRandomTest`](./math/prime/millerrabinprimalitytest.go#L77): MillerRandomTest This is the intermediate step that repeats within the miller rabin primality test for better probabilitic chances of receiving the correct result with random witnesses. -7. [`MillerTest`](./math/prime/millerrabinprimalitytest.go#L49): MillerTest tests whether num is a strong probable prime to a witness. Formally: a^d ≡ 1 (mod n) or a^(2^r * d) ≡ -1 (mod n), 0 <= r <= s -8. [`MillerTestMultiple`](./math/prime/millerrabinprimalitytest.go#L84): MillerTestMultiple is like MillerTest but runs the test for multiple witnesses. -9. [`NaiveApproach`](./math/prime/primecheck.go#L8): NaiveApproach checks if an integer is prime or not. Returns a bool. -10. [`PairApproach`](./math/prime/primecheck.go#L22): PairApproach checks primality of an integer and returns a bool. More efficient than the naive approach as number of iterations are less. -11. [`Sieve`](./math/prime/sieve.go#L16): Sieve Sieving the numbers that are not prime from the channel - basically removing them from the channels +4. [`MillerRabinDeterministic`](./math/prime/millerrabintest.go#L121): MillerRabinDeterministic is a Deterministic version of the Miller-Rabin test, which returns correct results for all valid int64 numbers. +5. [`MillerRabinProbabilistic`](./math/prime/millerrabintest.go#L101): MillerRabinProbabilistic is a probabilistic test for primality of an integer based of the algorithm devised by Miller and Rabin. +6. [`MillerRandomTest`](./math/prime/millerrabintest.go#L77): MillerRandomTest This is the intermediate step that repeats within the miller rabin primality test for better probabilitic chances of receiving the correct result with random witnesses. +7. [`MillerTest`](./math/prime/millerrabintest.go#L49): MillerTest tests whether num is a strong probable prime to a witness. Formally: a^d ≡ 1 (mod n) or a^(2^r * d) ≡ -1 (mod n), 0 <= r <= s +8. [`MillerTestMultiple`](./math/prime/millerrabintest.go#L84): MillerTestMultiple is like MillerTest but runs the test for multiple witnesses. +9. [`OptimizedTrialDivision`](./math/prime/primecheck.go#L26): OptimizedTrialDivision checks primality of an integer using an optimized trial division method. The optimizations include not checking divisibility by the even numbers and only checking up to the square root of the given number. +10. [`Sieve`](./math/prime/sieve.go#L16): Sieve Sieving the numbers that are not prime from the channel - basically removing them from the channels +11. [`TrialDivision`](./math/prime/primecheck.go#L9): TrialDivision tests whether a number is prime by trying to divide it by the numbers less than it. ---
diff --git a/graph/lowestcommonancestor.go b/graph/lowestcommonancestor.go new file mode 100644 index 000000000..8ce575187 --- /dev/null +++ b/graph/lowestcommonancestor.go @@ -0,0 +1,121 @@ +// lowestcommonancestor.go +// description: Implementation of Lowest common ancestor (LCA) algorithm. +// detail: +// Let `T` be a tree. The LCA of `u` and `v` in T is the shared ancestor of `u` and `v` +// that is located farthest from the root. +// references: [cp-algorithms](https://cp-algorithms.com/graph/lca_binary_lifting.html) +// author(s) [Dat](https://github.com/datbeohbbh) +// see lowestcommonancestor_test.go for a test implementation. + +package graph + +type TreeEdge struct { + from int + to int +} + +type ITree interface { + dfs(int, int) + addEdge(int, int) + GetDepth(int) int + GetDad(int) int + GetLCA(int, int) int +} + +type Tree struct { + numbersVertex int + root int + MAXLOG int + depth []int + dad []int + jump [][]int + edges [][]int +} + +func (tree *Tree) addEdge(u, v int) { + tree.edges[u] = append(tree.edges[u], v) + tree.edges[v] = append(tree.edges[v], u) +} + +func (tree *Tree) dfs(u, par int) { + tree.jump[0][u] = par + tree.dad[u] = par + for _, v := range tree.edges[u] { + if v != par { + tree.depth[v] = tree.depth[u] + 1 + tree.dfs(v, u) + } + } +} + +func (tree *Tree) GetDepth(u int) int { + return tree.depth[u] +} + +func (tree *Tree) GetDad(u int) int { + return tree.dad[u] +} + +func (tree *Tree) GetLCA(u, v int) int { + if tree.GetDepth(u) < tree.GetDepth(v) { + u, v = v, u + } + + for j := tree.MAXLOG - 1; j >= 0; j-- { + if tree.GetDepth(tree.jump[j][u]) >= tree.GetDepth(v) { + u = tree.jump[j][u] + } + } + + if u == v { + return u + } + + for j := tree.MAXLOG - 1; j >= 0; j-- { + if tree.jump[j][u] != tree.jump[j][v] { + u = tree.jump[j][u] + v = tree.jump[j][v] + } + } + + return tree.jump[0][u] +} + +func NewTree(numbersVertex, root int, edges []TreeEdge) (tree *Tree) { + tree = new(Tree) + tree.numbersVertex, tree.root, tree.MAXLOG = numbersVertex, root, 0 + tree.depth = make([]int, numbersVertex) + tree.dad = make([]int, numbersVertex) + + for (1 << tree.MAXLOG) <= numbersVertex { + (tree.MAXLOG) += 1 + } + (tree.MAXLOG) += 1 + + tree.jump = make([][]int, tree.MAXLOG) + for j := 0; j < tree.MAXLOG; j++ { + tree.jump[j] = make([]int, numbersVertex) + } + + tree.edges = make([][]int, numbersVertex) + for _, e := range edges { + tree.addEdge(e.from, e.to) + } + + return tree +} + +// For each node, we will precompute its ancestor above him, its ancestor two nodes above, its ancestor four nodes above, etc. +// Let's call `jump[j][u]` is the `2^j`-th ancestor above the node `u` with `u` in range `[0, numbersVertex)`, `j` in range `[0,MAXLOG)`. +// These information allow us to jump from any node to any ancestor above it in `O(MAXLOG)` time. +func LowestCommonAncestor(tree *Tree) { + // call dfs to compute depth from the root to each node and the parent of each node. + tree.dfs(tree.root, tree.root) + + // compute jump[j][u] + for j := 1; j < tree.MAXLOG; j++ { + for u := 0; u < tree.numbersVertex; u++ { + tree.jump[j][u] = tree.jump[j-1][tree.jump[j-1][u]] + } + } +} diff --git a/graph/lowestcommonancestor_test.go b/graph/lowestcommonancestor_test.go new file mode 100644 index 000000000..c7149e46e --- /dev/null +++ b/graph/lowestcommonancestor_test.go @@ -0,0 +1,250 @@ +package graph + +import ( + "math/rand" + "testing" + "time" +) + +type Query struct { + u int + v int + expected int +} + +func TestLCA(t *testing.T) { + testSuites := []struct { + numbersVertex int + root int + edges []TreeEdge + queries []Query + }{ + { + numbersVertex: 2, + root: 0, + edges: []TreeEdge{ + { + from: 0, + to: 1, + }, + }, + queries: []Query{ + { + u: 0, + v: 0, + expected: 0, + }, + { + u: 0, + v: 1, + expected: 0, + }, + { + u: 1, + v: 1, + expected: 1, + }, + }, + }, { + numbersVertex: 1, + root: 0, + edges: []TreeEdge{}, + queries: []Query{ + { + u: 0, + v: 0, + expected: 0, + }, + }, + }, { + numbersVertex: 9, + root: 7, + edges: []TreeEdge{ + { + from: 0, + to: 1, + }, + { + from: 0, + to: 2, + }, + { + from: 2, + to: 3, + }, + { + from: 2, + to: 4, + }, + { + from: 2, + to: 6, + }, + { + from: 3, + to: 5, + }, + { + from: 6, + to: 7, + }, + { + from: 6, + to: 8, + }, + }, + queries: []Query{ + { + u: 1, + v: 0, + expected: 0, + }, + { + u: 8, + v: 2, + expected: 6, + }, + { + u: 1, + v: 5, + expected: 2, + }, + { + u: 4, + v: 7, + expected: 7, + }, + { + u: 0, + v: 8, + expected: 6, + }, + }, + }, + } + // Test #2: + // 7 + // / + // 6 + // / \ + // 2 8 + // / | \ + // 0 3 4 + // / | + // 1 5 + for idx, test := range testSuites { + tree := NewTree(test.numbersVertex, test.root, test.edges) + LowestCommonAncestor(tree) + + for qi, query := range test.queries { + actual := tree.GetLCA(query.u, query.v) + expected := query.expected + if actual != expected { + t.Errorf("\nTest #%d:\nQuery #%d: u = %d, v = %d\nExpected %d, but actual %d", idx, qi, query.u, query.v, expected, actual) + } + } + } +} + +func generateTree() *Tree { + rand.Seed(time.Now().UnixNano()) + + const MAXVERTEX int = 2000 + var numbersVertex int = rand.Intn(MAXVERTEX) + 1 + var root int = rand.Intn(numbersVertex) + var edges []TreeEdge + + var fullGraph []TreeEdge + for u := 0; u < numbersVertex; u++ { + for v := 0; v < numbersVertex; v++ { + fullGraph = append(fullGraph, TreeEdge{ + from: u, + to: v, + }) + } + } + rand.Shuffle(len(fullGraph), func(i, j int) { + fullGraph[i], fullGraph[j] = fullGraph[j], fullGraph[i] + }) + + par := make([]int, numbersVertex) + for u := 0; u < numbersVertex; u++ { + par[u] = u + } + + var findp func(int) int + findp = func(u int) int { + if u == par[u] { + return u + } else { + par[u] = findp(par[u]) + return par[u] + } + } + + join := func(u, v int) bool { + u, v = findp(u), findp(v) + if u == v { + return false + } + par[v] = u + return true + } + + for _, e := range fullGraph { + if join(e.from, e.to) == true { + edges = append(edges, e) + } + } + + return NewTree(numbersVertex, root, edges) +} + +func generateQuery(tree *Tree) []Query { + rand.Seed(time.Now().UnixNano()) + const MAXQUERY = 50 + var queries []Query + + bruteforceLCA := func(u, v int) int { + for u != v { + if tree.GetDepth(u) > tree.GetDepth(v) { + u = tree.GetDad(u) + } else { + v = tree.GetDad(v) + } + } + return u + } + + for q := 1; q <= MAXQUERY; q++ { + u := rand.Intn(tree.numbersVertex) + v := rand.Intn(tree.numbersVertex) + queries = append(queries, Query{ + u: u, + v: v, + expected: bruteforceLCA(u, v), + }) + } + + return queries +} + +// Test with the tree with up to 2000 vertices. +func TestLCAWithLargeTree(t *testing.T) { + const MAXTEST int = 20 + + for test := 1; test <= MAXTEST; test++ { + tree := generateTree() + LowestCommonAncestor(tree) + + queries := generateQuery(tree) + + for qi, query := range queries { + actual := tree.GetLCA(query.u, query.v) + expected := query.expected + if actual != expected { + t.Errorf("\nTest #%d:\nQuery #%d: u = %d, v = %d\nExpected %d, but actual %d", test, qi, query.u, query.v, expected, actual) + } + } + } +} From b419e51309d680766e05f72621228ecc08faf6c5 Mon Sep 17 00:00:00 2001 From: AFMahmuda Date: Tue, 26 Jul 2022 04:30:51 +0800 Subject: [PATCH 344/488] fix CONTRIBUTING.md (#514) * fix: CONTRIBUTING.md markdown styling Co-authored-by: Arif Fathur Mahmuda --- CONTRIBUTING.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d7b39624..738f6cb7f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,10 +7,12 @@ Welcome to [TheAlgorithms/Go](https://github.com/TheAlgorithms/Go)! Before submi ## Contributing ### Maintainers +--- Please check the [`CODEOWNERS`](https://github.com/TheAlgorithms/Go/blob/master/.github/CODEOWNERS) file for a list of repository maintainers. ### Contributor +--- Being a contributor at The Algorithms, we request you to follow the points mentioned below: @@ -19,13 +21,18 @@ Being a contributor at The Algorithms, we request you to follow the points menti - Your work will be distributed under the [MIT License](https://github.com/TheAlgorithms/Go/blob/master/LICENSE) once your pull request has been merged. - Please follow the repository guidelines and standards mentioned below. -**New implementation** New implementations are welcome! +#### New implementation -You can add new algorithms or data structures that are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs, or in any other reasonable sense) +- New implementations are welcome! -**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers. +- You can add new algorithms or data structures that are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs, or in any other reasonable sense) + +#### Issues + +- Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers. ### Making Changes +--- #### Code @@ -56,6 +63,7 @@ You can add new algorithms or data structures that are **not present in the repo - Please try to add one or more `Test` functions that will invoke the algorithm implementation on random test data with the expected output. ### Benchmark +--- - Make sure to add examples and benchmark cases in your `filename_test.go` or `filename_bench.go` if you want separated test and benchmark files. - If you find an algorithm or document without benchmarks, please feel free to create a pull request or issue describing suggested changes. @@ -158,6 +166,7 @@ Common prefixes: - test: Correct existing tests or add new ones ### For New Gophers +--- #### Installing Go @@ -192,6 +201,7 @@ go build . ``` ### Pull Requests +--- - Check out our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.md ) From 14aa19417f8ca1fdeb4bb28c9cb62f9c80a5c79b Mon Sep 17 00:00:00 2001 From: Samuel NTA Gyamfi <49637763+Onlyartist9@users.noreply.github.com> Date: Thu, 4 Aug 2022 11:50:05 +0000 Subject: [PATCH 345/488] Fixed typo in name of algorithm. (#516) --- cipher/diffiehellman/diffiehellmankeyexchange.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cipher/diffiehellman/diffiehellmankeyexchange.go b/cipher/diffiehellman/diffiehellmankeyexchange.go index ae26b1f09..2621e3cca 100644 --- a/cipher/diffiehellman/diffiehellmankeyexchange.go +++ b/cipher/diffiehellman/diffiehellmankeyexchange.go @@ -1,4 +1,4 @@ -// Package diffiehellman implements Deffie Hellman Key Exchange Algorithm +// Package diffiehellman implements Diffie-Hellman Key Exchange Algorithm // for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI package diffiehellman From b913b5e40e95b8c47d085070fed56c8d3f240a5b Mon Sep 17 00:00:00 2001 From: Taj Date: Sat, 6 Aug 2022 05:24:06 +0100 Subject: [PATCH 346/488] bump: go 1.19 and fix: fmt issues (#519) --- .golangci.yml | 2 +- go.mod | 2 +- graph/articulationpoints.go | 2 +- graph/floydwarshall_test.go | 6 +++--- math/binary/checkisnumberpoweroftwo.go | 8 +++++--- math/pythagoras/pythagoras.go | 4 ++-- math/pythagoras/pythagoras_test.go | 2 +- other/nested/nestedbrackets.go | 6 +++--- search/binary.go | 8 ++++---- search/interpolation.go | 11 +++++++---- structure/segmenttree/segmenttree.go | 20 ++++++++++---------- structure/segmenttree/segmenttree_test.go | 2 +- structure/stack/stacklinkedlistwithlist.go | 2 +- 13 files changed, 40 insertions(+), 35 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index aa9001693..b334bee16 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,5 @@ run: - go: 1.18 + go: 1.19 linters: disable: - gosimple diff --git a/go.mod b/go.mod index 23f37df27..5a3e15ba4 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/TheAlgorithms/Go -go 1.18 +go 1.19 diff --git a/graph/articulationpoints.go b/graph/articulationpoints.go index 8c295d639..618107890 100644 --- a/graph/articulationpoints.go +++ b/graph/articulationpoints.go @@ -50,7 +50,7 @@ func ArticulationPoint(graph *Graph) []bool { // articulationPointHelper is a recursive function to traverse the graph // and mark articulation points. Based on the depth first search transversal // of the graph, however modified to keep track and update the -// `child_cnt`, `discovery_time`` and `earliest_discovery` slices defined above +// `child_cnt`, `discovery_time` and `earliest_discovery` slices defined above func articulationPointHelper( apHelperInstance *apHelper, vertex int, diff --git a/graph/floydwarshall_test.go b/graph/floydwarshall_test.go index 17d82930e..a4a28aae5 100644 --- a/graph/floydwarshall_test.go +++ b/graph/floydwarshall_test.go @@ -7,13 +7,13 @@ import ( const float64EqualityThreshold = 1e-9 -//almostEqual subtracts two float64 variables and returns true if they differ less then float64EqualityThreshold -//reference: https://stackoverflow.com/a/47969546 +// almostEqual subtracts two float64 variables and returns true if they differ less then float64EqualityThreshold +// reference: https://stackoverflow.com/a/47969546 func almostEqual(a, b float64) bool { return math.Abs(a-b) <= float64EqualityThreshold } -//IsAlmostEqualTo verifies if two WeightedGraphs can be considered almost equal +// IsAlmostEqualTo verifies if two WeightedGraphs can be considered almost equal func (a *WeightedGraph) IsAlmostEqualTo(b WeightedGraph) bool { if len(*a) != len(b) { return false diff --git a/math/binary/checkisnumberpoweroftwo.go b/math/binary/checkisnumberpoweroftwo.go index 46c459cf8..63ecc6e3b 100644 --- a/math/binary/checkisnumberpoweroftwo.go +++ b/math/binary/checkisnumberpoweroftwo.go @@ -11,9 +11,11 @@ package binary // like 10...0 in binary, and numbers one less than the power of 2 // are represented like 11...1. // Therefore, using the and function: -// 10...0 -// & 01...1 -// 00...0 -> 0 +// +// 10...0 +// & 01...1 +// 00...0 -> 0 +// // This is also true for 0, which is not a power of 2, for which we // have to add and extra condition. func IsPowerOfTwo(x int) bool { diff --git a/math/pythagoras/pythagoras.go b/math/pythagoras/pythagoras.go index fb3c51c4c..54e6ef0ca 100644 --- a/math/pythagoras/pythagoras.go +++ b/math/pythagoras/pythagoras.go @@ -4,14 +4,14 @@ import ( "math" ) -//Vector defines a tuple with 3 values in 3d-space +// Vector defines a tuple with 3 values in 3d-space type Vector struct { x float64 y float64 z float64 } -//Distance calculates the distance between to vectors with the Pythagoras theorem +// Distance calculates the distance between to vectors with the Pythagoras theorem func Distance(a, b Vector) float64 { res := math.Pow(b.x-a.x, 2.0) + math.Pow(b.y-a.y, 2.0) + math.Pow(b.z-a.z, 2.0) return math.Sqrt(res) diff --git a/math/pythagoras/pythagoras_test.go b/math/pythagoras/pythagoras_test.go index 1ae7e1185..3365c4a31 100644 --- a/math/pythagoras/pythagoras_test.go +++ b/math/pythagoras/pythagoras_test.go @@ -18,7 +18,7 @@ var distanceTest = []struct { {"random short vectors", Vector{1, 1, 1}, Vector{2, 2, 2}, 1.73}, } -//TestDistance tests the Function Distance with 2 vectors +// TestDistance tests the Function Distance with 2 vectors func TestDistance(t *testing.T) { t.Parallel() // marks TestDistance as capable of running in parallel with other tests for _, tt := range distanceTest { diff --git a/other/nested/nestedbrackets.go b/other/nested/nestedbrackets.go index f127acc93..ec912938c 100644 --- a/other/nested/nestedbrackets.go +++ b/other/nested/nestedbrackets.go @@ -8,9 +8,9 @@ package nested // // A sequence of brackets `s` is considered properly nested // if any of the following conditions are true: -// - `s` is empty; -// - `s` has the form (U) or [U] or {U} where U is a properly nested string; -// - `s` has the form VW where V and W are properly nested strings. +// - `s` is empty; +// - `s` has the form (U) or [U] or {U} where U is a properly nested string; +// - `s` has the form VW where V and W are properly nested strings. // // For example, the string "()()[()]" is properly nested but "[(()]" is not. // diff --git a/search/binary.go b/search/binary.go index c30e4b291..3b9241af6 100644 --- a/search/binary.go +++ b/search/binary.go @@ -37,8 +37,8 @@ func BinaryIterative(array []int, target int) (int, error) { return -1, ErrNotFound } -//Returns index to the first element in the range [0, len(array)-1] that is not less than (i.e. greater or equal to) target. -//return -1 and ErrNotFound if no such element is found. +// Returns index to the first element in the range [0, len(array)-1] that is not less than (i.e. greater or equal to) target. +// return -1 and ErrNotFound if no such element is found. func LowerBound(array []int, target int) (int, error) { startIndex := 0 endIndex := len(array) - 1 @@ -59,8 +59,8 @@ func LowerBound(array []int, target int) (int, error) { return startIndex, nil } -//Returns index to the first element in the range [lowIndex, len(array)-1] that is greater than target. -//return -1 and ErrNotFound if no such element is found. +// Returns index to the first element in the range [lowIndex, len(array)-1] that is greater than target. +// return -1 and ErrNotFound if no such element is found. func UpperBound(array []int, target int) (int, error) { startIndex := 0 endIndex := len(array) - 1 diff --git a/search/interpolation.go b/search/interpolation.go index 963e68000..722d77e2a 100644 --- a/search/interpolation.go +++ b/search/interpolation.go @@ -4,11 +4,14 @@ package search // if the entity is present, it will return the index of the entity, if not -1 will be returned. // see: https://en.wikipedia.org/wiki/Interpolation_search // Complexity -// Worst: O(N) -// Average: O(log(log(N)) if the elements are uniformly distributed -// Best: O(1) +// +// Worst: O(N) +// Average: O(log(log(N)) if the elements are uniformly distributed +// Best: O(1) +// // Example -// fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) +// +// fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) func Interpolation(sortedData []int, guess int) (int, error) { if len(sortedData) == 0 { return -1, ErrNotFound diff --git a/structure/segmenttree/segmenttree.go b/structure/segmenttree/segmenttree.go index 2799c5537..b55f69f0e 100644 --- a/structure/segmenttree/segmenttree.go +++ b/structure/segmenttree/segmenttree.go @@ -13,14 +13,14 @@ import ( const emptyLazyNode = 0 -//SegmentTree with original Array and the Segment Tree Array +// SegmentTree with original Array and the Segment Tree Array type SegmentTree struct { Array []int SegmentTree []int LazyTree []int } -//Propagate lazy tree node values +// Propagate lazy tree node values func (s *SegmentTree) Propagate(node int, leftNode int, rightNode int) { if s.LazyTree[node] != emptyLazyNode { //add lazy node value multiplied by (right-left+1), which represents all interval @@ -42,8 +42,8 @@ func (s *SegmentTree) Propagate(node int, leftNode int, rightNode int) { } } -//Query on interval [firstIndex, leftIndex] -//node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +// Query on interval [firstIndex, leftIndex] +// node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 func (s *SegmentTree) Query(node int, leftNode int, rightNode int, firstIndex int, lastIndex int) int { if (firstIndex > lastIndex) || (leftNode > rightNode) { //outside the interval @@ -67,10 +67,10 @@ func (s *SegmentTree) Query(node int, leftNode int, rightNode int, firstIndex in return leftNodeSum + rightNodeSum } -//Update Segment Tree -//node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 -//index is the Array index that you want to update -//value is the value that you want to override +// Update Segment Tree +// node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +// index is the Array index that you want to update +// value is the value that you want to override func (s *SegmentTree) Update(node int, leftNode int, rightNode int, firstIndex int, lastIndex int, value int) { //propagate lazy tree s.Propagate(node, leftNode, rightNode) @@ -96,8 +96,8 @@ func (s *SegmentTree) Update(node int, leftNode int, rightNode int, firstIndex i } } -//Build Segment Tree -//node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +// Build Segment Tree +// node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 func (s *SegmentTree) Build(node int, left int, right int) { if left == right { //leaf node diff --git a/structure/segmenttree/segmenttree_test.go b/structure/segmenttree/segmenttree_test.go index 142104b87..33bfef546 100644 --- a/structure/segmenttree/segmenttree_test.go +++ b/structure/segmenttree/segmenttree_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -//Query interval +// Query interval type query struct { firstIndex int lastIndex int diff --git a/structure/stack/stacklinkedlistwithlist.go b/structure/stack/stacklinkedlistwithlist.go index 0a758d8c6..ba3ce6580 100644 --- a/structure/stack/stacklinkedlistwithlist.go +++ b/structure/stack/stacklinkedlistwithlist.go @@ -34,7 +34,7 @@ func (sl *SList) Peak() (any, error) { } // Pop is return last value that insert into our stack -//also it will remove it in our stack +// also it will remove it in our stack func (sl *SList) Pop() (any, error) { if !sl.Empty() { // get last element that insert into stack From 16c92748a3db40d1c6f916e390342d02e21c22d0 Mon Sep 17 00:00:00 2001 From: Paulden Date: Sat, 6 Aug 2022 19:23:37 +0800 Subject: [PATCH 347/488] add patience sorting algorithm (#517) * add patience sorting algorithm * fix: fix patience sorting code style * fix:fix patience sorting formatting error --- sort/patiencesort.go | 67 ++++++++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 8 ++++++ 2 files changed, 75 insertions(+) create mode 100644 sort/patiencesort.go diff --git a/sort/patiencesort.go b/sort/patiencesort.go new file mode 100644 index 000000000..efae67ff0 --- /dev/null +++ b/sort/patiencesort.go @@ -0,0 +1,67 @@ +// Package sort +// Patience sorting is a sorting algorithm inspired by the card game patience. +// +// For more details check out those links below here: +// GeeksForGeeks article : https://www.geeksforgeeks.org/patience-sorting/ +// Wikipedia article: https://en.wikipedia.org/wiki/Patience_sorting +// authors [guuzaa](https://github.com/guuzaa) +// see patiencesort.go +package sort + +import "github.com/TheAlgorithms/Go/constraints" + +func Patience[T constraints.Ordered](arr []T) []T { + if len(arr) <= 1 { + return arr + } + + var piles [][]T + + for _, card := range arr { + left, right := 0, len(piles) + for left < right { + mid := left + (right-left)/2 + if piles[mid][len(piles[mid])-1] >= card { + right = mid + } else { + left = mid + 1 + } + } + + if left == len(piles) { + piles = append(piles, []T{card}) + } else { + piles[left] = append(piles[left], card) + } + } + + return mergePiles(piles) +} + +func mergePiles[T constraints.Ordered](piles [][]T) []T { + var ret []T + + for len(piles) > 0 { + minID := 0 + minValue := piles[minID][len(piles[minID])-1] + + for i := 1; i < len(piles); i++ { + if minValue <= piles[i][len(piles[i])-1] { + continue + } + + minValue = piles[i][len(piles[i])-1] + minID = i + } + + ret = append(ret, minValue) + + piles[minID] = piles[minID][:len(piles[minID])-1] + + if len(piles[minID]) == 0 { + piles = append(piles[:minID], piles[minID+1:]...) + } + } + + return ret +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 08b6a716d..467d054ce 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -135,6 +135,10 @@ func TestPigeonhole(t *testing.T) { testFramework(t, sort.Pigeonhole) } +func TestPatience(t *testing.T) { + testFramework(t, sort.Patience[int]) +} + //END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { @@ -236,3 +240,7 @@ func BenchmarkComb(b *testing.B) { func BenchmarkPigeonhole(b *testing.B) { benchmarkFramework(b, sort.Pigeonhole) } + +func BenchmarkPatience(b *testing.B) { + benchmarkFramework(b, sort.Patience[int]) +} From 2ad5f9c0a3f13791c291fc5d3d9be973312e8327 Mon Sep 17 00:00:00 2001 From: Jason07311 <52784322+Jason07311@users.noreply.github.com> Date: Sun, 7 Aug 2022 23:24:24 +0800 Subject: [PATCH 348/488] merge: Added mean algorithm and test code (#521) * Added mean algorithm and test code Mean algorithm 4 test cases included with test codes * Implement Suggestions from tjgurwara99 fix: Removed the print message under validation fix: Removed print message under validating condition for empty array fix: The first letter of function name is capitalized fix: Added another test cases with no values fix: Added Generics docs: Moved the mean.go and mean_test.go to be directly under maths package docs: Added comment to indicate the validating condition for empty array in the algorithm * Implement Next Suggestion & Bug Fixes fix: Fixed the typo of package name in both files fix: Replace the import of constraints with github existing constraints fix: Simplified the return codes docs: Removed unnecessary comments docs: Removed extra folder of mean and files within * Removed the useless codes of interface fix: Implemented the embedded constraints within github/TheAlogithm/Go and removed the extra codes * Updated the package of mean_test.go fix: Updated the package to math_test fix: Updated the access of Mean to math.Mean fix: Added github path for math --- math/mean.go | 21 +++++++++++++++++++ math/mean_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 math/mean.go create mode 100644 math/mean_test.go diff --git a/math/mean.go b/math/mean.go new file mode 100644 index 000000000..4bd0e40ed --- /dev/null +++ b/math/mean.go @@ -0,0 +1,21 @@ +package math + +import ( + "github.com/TheAlgorithms/Go/constraints" +) + +func Mean[T constraints.Number](values []T) float64 { + + if len(values) == 0 { + return 0 + } + + var summation float64 = 0 + + for _, singleValue := range values { + summation += float64(singleValue) + } + + return summation / float64(len(values)) + +} diff --git a/math/mean_test.go b/math/mean_test.go new file mode 100644 index 000000000..8f74511ef --- /dev/null +++ b/math/mean_test.go @@ -0,0 +1,52 @@ +package math_test + +import ( + "github.com/TheAlgorithms/Go/math" + "testing" +) + +func TestMean(t *testing.T) { + testCases := []struct { + name string + testValues []float64 + average float64 + }{ + { + name: "All 0s", + testValues: []float64{0, 0, 0, 0, 0}, + average: 0, + }, + { + name: "With integer values", + testValues: []float64{1, 2, 3, 4, 5}, + average: 3.0, + }, + { + name: "With negative values", + testValues: []float64{-1, 2, -3, 4, 5}, + average: 1.4, + }, + { + name: "With floating values", + testValues: []float64{1.1, 2.2, 3.3, 4.4, 5.5}, + average: 3.3, + }, + { + name: "With no values", + testValues: []float64{}, + average: 0, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + returnedAverage := math.Mean(test.testValues) + if returnedAverage != test.average { + t.Errorf("\nFailed test: %s\ntestValues: %v\naverage: %v\nbut received: %v\n", + test.name, test.testValues, test.average, returnedAverage) + } + + }) + } + +} From aaf7fd89269659fa0d3ad54fe75a033cb9a0f00d Mon Sep 17 00:00:00 2001 From: jo3zeph <86296674+jo3zeph@users.noreply.github.com> Date: Mon, 8 Aug 2022 14:36:19 +0800 Subject: [PATCH 349/488] Added median.go (#522) * Added Roundoff Simple showcase of Roundoff operation in GoLang feat: add roundoff.go test: add roundoff_test.go docs: added comments on both roundoff.go and roundoff_test.go * Revert "Added Roundoff" This reverts commit c50fa899d619c7954259c6e5112a58a16b503166. * Added median.go feat: added median.go test: added median_test.go docs: added comments on both median.go and median_test.go * Performed suggested fixes and improvements on median.go and median_test.go fix median.go on using switch case, formatting, applied generics fix median_test.go on formatting and using edge case doc median_test.go on comments for test cases * Update to math/median.go Co-authored-by: Taj * Revert "Update to math/median.go" This reverts commit 7c7c4f561a3a75a0158f26050db00c4ea070db61. * Fix median.go Fix: median.go (import local packages and rectify newly affected issues) * Update median.go Fix: median.go removed redundant codes * Fix: median.go and median_test.go Fix: median.go (removed all deemed irrelevant comments) Fix: median.go (removed all deemed irrelevant comments and changed package + fixed newly affected issues) * Update median.go fix: median.go (return values directly) Co-authored-by: Taj --- go.sum | 0 math/median.go | 28 +++++++++++++++++++++++ math/median_test.go | 56 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 go.sum create mode 100644 math/median.go create mode 100644 math/median_test.go diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..e69de29bb diff --git a/math/median.go b/math/median.go new file mode 100644 index 000000000..d8cd02796 --- /dev/null +++ b/math/median.go @@ -0,0 +1,28 @@ +// author(s) [jo3zeph](https://github.com/jo3zeph) +// description: Find the median from a set of values +// see median_test.go + +package math + +import ( + "github.com/TheAlgorithms/Go/constraints" + "github.com/TheAlgorithms/Go/sort" +) + +func Median[T constraints.Number](values []T) float64 { + + sort.Bubble(values) + + l := len(values) + + switch { + case l == 0: + return 0 + + case l%2 == 0: + return float64((values[l/2-1] + values[l/2]) / 2) + + default: + return float64(values[l/2]) + } +} diff --git a/math/median_test.go b/math/median_test.go new file mode 100644 index 000000000..5210caec4 --- /dev/null +++ b/math/median_test.go @@ -0,0 +1,56 @@ +// author(s) [jo3zeph](https://github.com/jo3zeph) +// median_test.go +// see median.go + +package math_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math" +) + +func TestMedian(t *testing.T) { + testCases := []struct { + name string + testValues []float64 + answer float64 + }{ + + { + name: "Series of numbers in ascending order", + testValues: []float64{12, 14, 16, 18, 19}, + answer: 16, + }, + + { + name: "Series of numbers in random order", + testValues: []float64{21, 10, 22, 33, 11, 88}, + answer: 21.5, + }, + + { + name: "Series of decimals in random order", + testValues: []float64{11.2, 32.5, 2.5, 37.8, 21.8, 5.2}, + answer: 16.5, + }, + + { + testValues: []float64{}, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + + returnedMedian := math.Median(test.testValues) + + t.Log(test.testValues, " ", returnedMedian) + + if returnedMedian != test.answer { + t.Errorf("Test failed. Median should have been %v but received %v", + test.answer, returnedMedian) + } + }) + } +} From feb2246c4605f9c9b4e00a491b2930524bbda2be Mon Sep 17 00:00:00 2001 From: CalvinNJK <87193669+CalvinNJK@users.noreply.github.com> Date: Tue, 9 Aug 2022 13:49:08 +0800 Subject: [PATCH 350/488] Added mode.go & mode_test.go (#523) --- math/mode.go | 49 ++++++++++++++++++++++++ math/mode_test.go | 94 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 math/mode.go create mode 100644 math/mode_test.go diff --git a/math/mode.go b/math/mode.go new file mode 100644 index 000000000..c0745c33d --- /dev/null +++ b/math/mode.go @@ -0,0 +1,49 @@ +// mode.go +// author(s): [CalvinNJK] (https://github.com/CalvinNJK) +// description: Finding Mode Value In an Array +// see mode.go + +package math + +import ( + "errors" + + "github.com/TheAlgorithms/Go/constraints" +) + +// ErrEmptySlice is the error returned by functions in math package when +// an empty slice is provided to it as argument when the function expects +// a non-empty slice. +var ErrEmptySlice = errors.New("empty slice provided") + +func Mode[T constraints.Number](numbers []T) (T, error) { + + countMap := make(map[T]int) + + n := len(numbers) + + if n == 0 { + return 0, ErrEmptySlice + } + + for _, number := range numbers { + if _, check := countMap[number]; check { + countMap[number]++ + } else { + countMap[number] = 1 + } + } + + var mode T + count := 0 + + for k, v := range countMap { + if v > count { + count = v + mode = k + } + } + + return mode, nil + +} diff --git a/math/mode_test.go b/math/mode_test.go new file mode 100644 index 000000000..5db0eb5df --- /dev/null +++ b/math/mode_test.go @@ -0,0 +1,94 @@ +// mode.go +// author(s): [CalvinNJK] (https://github.com/CalvinNJK) +// description: Test for Finding Mode Value In an Array + +package math_test + +import ( + "errors" + "testing" + + "github.com/TheAlgorithms/Go/constraints" + "github.com/TheAlgorithms/Go/math" +) + +type testCase[T constraints.Number] struct { + name string + numbers []T + mode T + err error +} + +func testModeFramework[T constraints.Number](t *testing.T, testCases []testCase[T]) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + returnMode, err := math.Mode(test.numbers) + if returnMode != test.mode { + t.Errorf("\n Failed test %s,\n Numbers: %v,\n Correct Mode: %v,\n Returned Mode: %v\n", + test.name, test.numbers, test.mode, returnMode) + } + if !errors.Is(err, test.err) { + t.Errorf("\n Failed test %s,\n Numbers: %v,\n Correct Error: %v,\n Returned Error: %v\n", + test.name, test.numbers, test.err, err) + } + }) + } +} +func TestMode(t *testing.T) { + // test cases for integer values + intTestCases := []testCase[int]{ + { + name: "An array of positive whole numbers", + numbers: []int{10, 52, 10, 92, 10, 75, 60, 10, 44, 29}, + mode: 10, + err: nil, + }, + { + name: "An array of negative whole numbers", + numbers: []int{-19, -12, -74, -19, -22, -56, -19, -19, -68, -93}, + mode: -19, + err: nil, + }, + { + name: "An array of positive & negative whole numbers", + numbers: []int{18, -28, 33, -28, 2, 39, 48, -49, -87, 78, -28}, + mode: -28, + err: nil, + }, + { + name: "If array has no value", + numbers: []int{}, + mode: 0, + err: math.ErrEmptySlice, + }, + } + testModeFramework(t, intTestCases) + // test cases for float64 values + floatTestCases := []testCase[float64]{ + { + name: "An array of positive real numbers", + numbers: []float64{1.5, 2.88, 84.4, 77.2, 29.8, 46.2, 33.7, 88.4, 88.4}, + mode: 88.4, + err: nil, + }, + { + name: "An array of negative real numbers", + numbers: []float64{-98.1, -26.8, -54.45, -26.8, -1.5, -26.8, -33, -19.5, -26.8}, + mode: -26.8, + err: nil, + }, + { + name: "An array of positive and negative real numbers", + numbers: []float64{-17, 28.9, -5.2, -19.5, 77.3, -5.2, 39.3, 28.5, -59.77, -5.2}, + mode: -5.2, + err: nil, + }, + { + name: "If array has no value", + numbers: []float64{}, + mode: 0, + err: math.ErrEmptySlice, + }, + } + testModeFramework(t, floatTestCases) +} From 251f3404e1ec22329985e432635ae34e0cf2bd1b Mon Sep 17 00:00:00 2001 From: Vaishnavi Amira Yada <108050528+Vaishnaviamirayada@users.noreply.github.com> Date: Sun, 21 Aug 2022 01:58:16 +0530 Subject: [PATCH 351/488] doc: Add a useful resource (#525) --- structure/linkedlist/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structure/linkedlist/Readme.md b/structure/linkedlist/Readme.md index 32f784c96..cb6c1f6e7 100644 --- a/structure/linkedlist/Readme.md +++ b/structure/linkedlist/Readme.md @@ -2,7 +2,7 @@ *** ## What is it? *** -Linked list is a data structure that is a linear chain of data elements whose order is not given by their phyisical placement in memory. This structure is built up of nodes which point to the element ahead or behind this particular node (depending on the type of Linked List). +[Linked list](https://www.scaler.com/topics/linked-list/) is a data structure that is a linear chain of data elements whose order is not given by their phyisical placement in memory. This structure is built up of nodes which point to the element ahead or behind this particular node (depending on the type of Linked List). # Types of Linked List implemented within this repository From 93434be9df4441004814d96d571863f5c481c146 Mon Sep 17 00:00:00 2001 From: Taj Date: Sun, 28 Aug 2022 06:29:40 +0100 Subject: [PATCH 352/488] fix: spellcheck (#527) --- README.md | 36 +++++++++++++++++------------- other/password/generator.go | 4 ++-- structure/linkedlist/doc.go | 2 +- structure/trie/trie_bench_test.go | 37 +------------------------------ 4 files changed, 24 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 8eee9e312..19c15407d 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Abs`](./math/binary/abs.go#L10): Abs returns absolute value using binary operation Principle of operation: 1) Get the mask by right shift by the base 2) Base is the size of an integer variable in bits, for example, for int32 it will be 32, for int64 it will be 64 3) For negative numbers, above step sets mask as 1 1 1 1 1 1 1 1 and 0 0 0 0 0 0 0 0 for positive numbers. 4) Add the mask to the given number. 5) XOR of mask + n and mask gives the absolute value. 2. [`BitCounter`](./math/binary/bitcounter.go#L11): BitCounter - The function returns the number of set bits for an unsigned integer number -3. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L19): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. -4. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L26): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 +3. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L21): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. +4. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L28): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 5. [`LogBase2`](./math/binary/logarithm.go#L7): LogBase2 Finding the exponent of n = 2**x using bitwise operations (logarithm in base 2 of n) [See more](https://en.wikipedia.org/wiki/Logarithm) 6. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations 7. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift @@ -238,7 +238,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### Package diffiehellman implements Deffie Hellman Key Exchange Algorithm for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI +##### Package diffiehellman implements Diffie-Hellman Key Exchange Algorithm for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI --- ##### Functions: @@ -501,7 +501,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### Package linkedlist demonstates different implementations on linkedlists. +##### Package linkedlist demonstrates different implementations on linkedlists. --- ##### Functions: @@ -552,8 +552,11 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 3. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. 4. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. 5. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -6. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. -7. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +6. [`Mean`](./math/mean.go#L7): No description provided. +7. [`Median`](./math/median.go#L12): No description provided. +8. [`Mode`](./math/mode.go#L19): No description provided. +9. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +10. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) ---
@@ -623,7 +626,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`IsBalanced`](./other/nested/nestedbrackets.go#L20): IsBalanced returns true if provided input string is properly nested. Input is a sequence of brackets: '(', ')', '[', ']', '{', '}'. A sequence of brackets `s` is considered properly nested if any of the following conditions are true: - `s` is empty; - `s` has the form (U) or [U] or {U} where U is a properly nested string; - `s` has the form VW where V and W are properly nested strings. For example, the string "()()[()]" is properly nested but "[(()]" is not. **Note** Providing characters other then brackets would return false, despite brackets sequence in the string. Make sure to filter input before usage. +1. [`IsBalanced`](./other/nested/nestedbrackets.go#L20): IsBalanced returns true if provided input string is properly nested. Input is a sequence of brackets: '(', ')', '[', ']', '{', '}'. A sequence of brackets `s` is considered properly nested if any of the following conditions are true: - `s` is empty; - `s` has the form (U) or [U] or {U} where U is a properly nested string; - `s` has the form VW where V and W are properly nested strings. For example, the string "()()[()]" is properly nested but "[(()]" is not. **Note** Providing characters other then brackets would return false, despite brackets sequence in the string. Make sure to filter input before usage. ---
@@ -765,7 +768,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`Distance`](./math/pythagoras/pythagoras.go#L15): Distance calculates the distance between to vectors with the Pythagoras theorem +1. [`Distance`](./math/pythagoras/pythagoras.go#L15): Distance calculates the distance between to vectors with the Pythagoras theorem --- ##### Types @@ -868,7 +871,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### Package sort a package for demonstrating sorting algorithms in Go +##### Package sort a package for demonstrating sorting algorithms in Go Package sort Patience sorting is a sorting algorithm inspired by the card game patience. For more details check out those links below here: GeeksForGeeks article : https://www.geeksforgeeks.org/patience-sorting/ Wikipedia article: https://en.wikipedia.org/wiki/Patience_sorting authors [guuzaa](https://github.com/guuzaa) see patiencesort.go --- ##### Functions: @@ -883,13 +886,14 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 8. [`Merge`](./sort/mergesort.go#L40): Merge Perform merge sort on a slice 9. [`MergeIter`](./sort/mergesort.go#L54): No description provided. 10. [`Partition`](./sort/quicksort.go#L12): No description provided. -11. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. -12. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array -13. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array -14. [`RadixSort`](./sort/radixsort.go#L35): No description provided. -15. [`Selection`](./sort/selectionsort.go#L5): No description provided. -16. [`Shell`](./sort/shellsort.go#L5): No description provided. -17. [`Simple`](./sort/simplesort.go#L13): No description provided. +11. [`Patience`](./sort/patiencesort.go#L13): No description provided. +12. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. +13. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array +14. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array +15. [`RadixSort`](./sort/radixsort.go#L35): No description provided. +16. [`Selection`](./sort/selectionsort.go#L5): No description provided. +17. [`Shell`](./sort/shellsort.go#L5): No description provided. +18. [`Simple`](./sort/simplesort.go#L13): No description provided. --- ##### Types diff --git a/other/password/generator.go b/other/password/generator.go index 0a8023c26..46237364f 100644 --- a/other/password/generator.go +++ b/other/password/generator.go @@ -25,7 +25,7 @@ func Generate(minLength int, maxLength int) string { newPassword := make([]byte, intLength) randomData := make([]byte, intLength+intLength/4) - clen := byte(len(chars)) + charLen := byte(len(chars)) maxrb := byte(256 - (256 % len(chars))) i := 0 for { @@ -36,7 +36,7 @@ func Generate(minLength int, maxLength int) string { if c >= maxrb { continue } - newPassword[i] = chars[c%clen] + newPassword[i] = chars[c%charLen] i++ if i == intLength { return string(newPassword) diff --git a/structure/linkedlist/doc.go b/structure/linkedlist/doc.go index 580adf068..d4c56c0e1 100644 --- a/structure/linkedlist/doc.go +++ b/structure/linkedlist/doc.go @@ -1,2 +1,2 @@ -// Package linkedlist demonstates different implementations on linkedlists. +// Package linkedlist demonstrates different implementations on linkedlists. package linkedlist diff --git a/structure/trie/trie_bench_test.go b/structure/trie/trie_bench_test.go index f3af3aaa1..be59496ee 100644 --- a/structure/trie/trie_bench_test.go +++ b/structure/trie/trie_bench_test.go @@ -6,42 +6,15 @@ import ( "testing" ) -// CAUTION : make sure to limit the benchamrks to 3000 iterations, +// CAUTION : make sure to limit the benchmarks to 3000 iterations, // or removal will mostly process an empty Trie, giving absurd results. -// go test -v -bench=. -benchmem -benchtime=3000x - -// === RUN TestTrieInsert -// --- PASS: TestTrieInsert (0.00s) -// === RUN TestTrieRemove -// --- PASS: TestTrieRemove (0.00s) -// === RUN ExampleNode -// --- PASS: ExampleNode (0.00s) -// goos: linux -// goarch: amd64 -// pkg: github.com/TheAlgorithms/Go/structure/trie -// BenchmarkTrie_Insert -// BenchmarkTrie_Insert-8 3000 1559881 ns/op 1370334 B/op 25794 allocs/op -// BenchmarkTrie_Find_non_existant -// BenchmarkTrie_Find_non_existant-8 3000 59.1 ns/op 0 B/op 0 allocs/op -// BenchmarkTrie_Find_existant -// BenchmarkTrie_Find_existant-8 3000 238 ns/op 0 B/op 0 allocs/op -// BenchmarkTrie_Remove_lazy -// BenchmarkTrie_Remove_lazy-8 3000 126 ns/op 0 B/op 0 allocs/op -// BenchmarkTrie_Remove_and_Compact -// BenchmarkTrie_Remove_and_Compact-8 3000 213945 ns/op 0 B/op 0 allocs/op -// PASS -// ok github.com/TheAlgorithms/Go/structure/trie 5.355s - func BenchmarkTrie_Insert(b *testing.B) { - - // prepare random words for insertion insert := make([]string, 3000) for i := 0; i < len(insert); i++ { insert[i] = fmt.Sprintf("%f", rand.Float64()) } - // Reset timer and run benchmark for insertion b.ResetTimer() for i := 0; i < b.N; i++ { n := NewNode() @@ -51,7 +24,6 @@ func BenchmarkTrie_Insert(b *testing.B) { func BenchmarkTrie_Find_non_existant(b *testing.B) { - // prepare random words for insertion insert := make([]string, 3000) for i := 0; i < len(insert); i++ { insert[i] = fmt.Sprintf("%f", rand.Float64()) @@ -59,7 +31,6 @@ func BenchmarkTrie_Find_non_existant(b *testing.B) { n := NewNode() n.Insert(insert...) - // Reset timer and run benchmark for finding non existing b.ResetTimer() for i := 0; i < b.N; i++ { n.Find("0.3213213244346546546546565465465") // does not exists @@ -67,7 +38,6 @@ func BenchmarkTrie_Find_non_existant(b *testing.B) { } func BenchmarkTrie_Find_existant(b *testing.B) { - // prepare and insert random words insert := make([]string, 3000) for i := 0; i < len(insert); i++ { insert[i] = fmt.Sprintf("%f", rand.Float64()) @@ -75,7 +45,6 @@ func BenchmarkTrie_Find_existant(b *testing.B) { n := NewNode() n.Insert(insert...) - // Reset timer and run benchmark for finding existing words b.ResetTimer() for i := 0; i < b.N; i++ { n.Find(insert[i%3000]) // always exists ! @@ -83,7 +52,6 @@ func BenchmarkTrie_Find_existant(b *testing.B) { } func BenchmarkTrie_Remove_lazy(b *testing.B) { - // prepare and insert random words insert := make([]string, 3000) for i := 0; i < len(insert); i++ { insert[i] = fmt.Sprintf("%f", rand.Float64()) @@ -91,7 +59,6 @@ func BenchmarkTrie_Remove_lazy(b *testing.B) { n := NewNode() n.Insert(insert...) - // Reset timer and run benchmark for lazily removing words b.ResetTimer() for i := 0; i < b.N; i++ { n.Remove(insert[i%3000]) // exists, at least until removed ... @@ -99,7 +66,6 @@ func BenchmarkTrie_Remove_lazy(b *testing.B) { } func BenchmarkTrie_Remove_and_Compact(b *testing.B) { - // prepare and insert random words insert := make([]string, 3000) for i := 0; i < len(insert); i++ { insert[i] = fmt.Sprintf("%f", rand.Float64()) @@ -107,7 +73,6 @@ func BenchmarkTrie_Remove_and_Compact(b *testing.B) { n := NewNode() n.Insert(insert...) - // Reset timer and run benchmark for removing words and immediately compacting b.ResetTimer() for i := 0; i < b.N; i++ { n.Remove(insert[i%3000]) From 72ff3a7f4f0fdb9ce9ac810eb0807c6a0cab9df7 Mon Sep 17 00:00:00 2001 From: Moein Halvaei <50274938+mo1ein@users.noreply.github.com> Date: Sun, 28 Aug 2022 14:15:02 +0430 Subject: [PATCH 353/488] merge: Add char-occurrence algorithm (#526) * feat: Add char-occurrence algorithm * fix: test package name * fix: clean code style * fix: remove extra value for print * fix: change package name to strings * fix: use short var names * fix: put testCases inside test func * fix: add documentation comment * fix: import strings package * fix: clear documention * fix: fix typo * fix: clear description * fix: remove details --- strings/charoccurrence.go | 21 ++++++++++++++++++ strings/charoccurrence_test.go | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 strings/charoccurrence.go create mode 100644 strings/charoccurrence_test.go diff --git a/strings/charoccurrence.go b/strings/charoccurrence.go new file mode 100644 index 000000000..71c3056b1 --- /dev/null +++ b/strings/charoccurrence.go @@ -0,0 +1,21 @@ +// charoccurrence.go +// description: An algorithm which counts the number +// of times a character occurred in a string. +// author(s) [Moein](https://github.com/mo1ein) +// see charoccurrence_test.go + +package strings + +// CountChars counts the number of a times a character +// has occurred in the provided string argument and +// returns a map with `rune` as keys and the count as value. +func CountChars(text string) map[rune]int { + charMap := make(map[rune]int, 0) + for _, c := range text { + if _, ok := charMap[c]; !ok { + charMap[c] = 0 + } + charMap[c]++ + } + return charMap +} diff --git a/strings/charoccurrence_test.go b/strings/charoccurrence_test.go new file mode 100644 index 000000000..0f284acda --- /dev/null +++ b/strings/charoccurrence_test.go @@ -0,0 +1,39 @@ +package strings_test + +import ( + "github.com/TheAlgorithms/Go/strings" + "reflect" + "testing" +) + +func TestCountChars(t *testing.T) { + var testCases = []struct { + name string + input string + expected map[rune]int + }{ + { + "english text", + "hello world!", + map[rune]int{32: 1, 33: 1, 100: 1, 101: 1, 104: 1, 108: 3, 111: 2, 114: 1, 119: 1}, + }, + { + "chinese text", + " 世界 ", + map[rune]int{32: 2, 19990: 1, 30028: 1}, + }, + { + "persian text", + "سلام دنیا!", + map[rune]int{32: 1, 33: 1, 1575: 2, 1583: 1, 1587: 1, 1604: 1, 1605: 1, 1606: 1, 1740: 1}, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + funcResult := strings.CountChars(test.input) + if !reflect.DeepEqual(test.expected, funcResult) { + t.Errorf("expected: %v, got %v", test.expected, funcResult) + } + }) + } +} From f850556d904a8b7126e2705cf0ca2cd5402ad926 Mon Sep 17 00:00:00 2001 From: Akshay Dubey <38462415+itsAkshayDubey@users.noreply.github.com> Date: Fri, 9 Sep 2022 21:36:10 +0530 Subject: [PATCH 354/488] feat: Add mobius function (#532) --- math/mobius.go | 38 ++++++++++++++++++++++++++++++++++++++ math/mobius_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 math/mobius.go create mode 100644 math/mobius_test.go diff --git a/math/mobius.go b/math/mobius.go new file mode 100644 index 000000000..76b50da14 --- /dev/null +++ b/math/mobius.go @@ -0,0 +1,38 @@ +// mobius.go +// description: Returns μ(n) +// details: +// For any positive integer n, define μ(n) as the sum of the primitive nth roots of unity. +// It has values in {−1, 0, 1} depending on the factorization of n into prime factors: +// μ(n) = +1 if n is a square-free positive integer with an even number of prime factors. +// μ(n) = −1 if n is a square-free positive integer with an odd number of prime factors. +// μ(n) = 0 if n has a squared prime factor. +// wikipedia: https://en.wikipedia.org/wiki/M%C3%B6bius_function +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see mobius_test.go + +package math + +import ( + "github.com/TheAlgorithms/Go/math/prime" +) + +// Mu is the Mobius function +// This function returns μ(n) for given number +func Mu(n int) int { + if n <= 1 { + return 1 + } + var primeFactorCount int + for i := 1; i <= n; i++ { + if n%i == 0 && prime.OptimizedTrialDivision(int64(i)) { + if n%(i*i) == 0 { + return 0 + } + primeFactorCount += 1 + } + } + if primeFactorCount%2 == 0 { + return 1 + } + return -1 +} diff --git a/math/mobius_test.go b/math/mobius_test.go new file mode 100644 index 000000000..271b9c74f --- /dev/null +++ b/math/mobius_test.go @@ -0,0 +1,41 @@ +// mobius_test.go +// description: Returns μ(n) +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see mobius.go + +package math_test + +import ( + "testing" + + algmath "github.com/TheAlgorithms/Go/math" +) + +func TestMu(t *testing.T) { + var tests = []struct { + n int + expected int + }{ + {-1, 1}, + {0, 1}, + {2, -1}, + {3, -1}, + {95, 1}, + {97, -1}, + {98, 0}, + {99, 0}, + {100, 0}, + } + for _, test := range tests { + result := algmath.Mu(test.n) + t.Log(test.n, " ", result) + if result != test.expected { + t.Errorf("Wrong result! Expected:%v, returned:%v ", test.expected, result) + } + } +} +func BenchmarkMu(b *testing.B) { + for i := 0; i < b.N; i++ { + algmath.Mu(65536) + } +} From 6c8e82210656cb1b341ab00fc59682dff2418514 Mon Sep 17 00:00:00 2001 From: crunchypi <53178205+crunchypi@users.noreply.github.com> Date: Fri, 9 Sep 2022 18:06:27 +0200 Subject: [PATCH 355/488] add generics (#528) --- structure/linkedlist/cyclic.go | 26 +++++----- structure/linkedlist/cyclic_test.go | 16 +++---- structure/linkedlist/doubly.go | 38 ++++++++------- structure/linkedlist/doubly_test.go | 30 +++++++----- structure/linkedlist/shared.go | 12 ++--- structure/linkedlist/singlylinkedlist.go | 48 ++++++++++--------- structure/linkedlist/singlylinkedlist_test.go | 14 ++++-- 7 files changed, 101 insertions(+), 83 deletions(-) diff --git a/structure/linkedlist/cyclic.go b/structure/linkedlist/cyclic.go index d0ef8c4b6..14bc518cc 100644 --- a/structure/linkedlist/cyclic.go +++ b/structure/linkedlist/cyclic.go @@ -3,21 +3,21 @@ package linkedlist import "fmt" // Cyclic Struct which cycles the linked list in this implementation. -type Cyclic struct { +type Cyclic[T any] struct { Size int - Head *Node + Head *Node[T] } // Create new list. -func NewCyclic() *Cyclic { - return &Cyclic{0, nil} +func NewCyclic[T any]() *Cyclic[T] { + return &Cyclic[T]{} } // Inserting the first node is a special case. It will // point to itself. For other cases, the node will be added // to the end of the list. End of the list is Prev field of // current item. Complexity O(1). -func (cl *Cyclic) Add(val any) { +func (cl *Cyclic[T]) Add(val T) { n := NewNode(val) cl.Size++ if cl.Head == nil { @@ -46,7 +46,7 @@ func (cl *Cyclic) Add(val any) { // places is the same as moving N - P places back. // Therefore, if P > N / 2, you can turn the list by N-P places back. // Complexity O(n). -func (cl *Cyclic) Rotate(places int) { +func (cl *Cyclic[T]) Rotate(places int) { if cl.Size > 0 { if places < 0 { multiple := cl.Size - 1 - places/cl.Size @@ -71,9 +71,9 @@ func (cl *Cyclic) Rotate(places int) { } // Delete the current item. -func (cl *Cyclic) Delete() bool { +func (cl *Cyclic[T]) Delete() bool { var deleted bool - var prevItem, thisItem, nextItem *Node + var prevItem, thisItem, nextItem *Node[T] if cl.Size == 0 { return deleted @@ -97,15 +97,15 @@ func (cl *Cyclic) Delete() bool { } // Destroy all items in the list. -func (cl *Cyclic) Destroy() { +func (cl *Cyclic[T]) Destroy() { for cl.Delete() { continue } } // Show list body. -func (cl *Cyclic) Walk() *Node { - var start *Node +func (cl *Cyclic[T]) Walk() *Node[T] { + var start *Node[T] start = cl.Head for i := 0; i < cl.Size; i++ { @@ -117,13 +117,13 @@ func (cl *Cyclic) Walk() *Node { // https://en.wikipedia.org/wiki/Josephus_problem // This is a struct-based solution for Josephus problem. -func JosephusProblem(cl *Cyclic, k int) int { +func JosephusProblem(cl *Cyclic[int], k int) int { for cl.Size > 1 { cl.Rotate(k) cl.Delete() cl.Rotate(-1) } - retval := cl.Head.Val.(int) + retval := cl.Head.Val cl.Destroy() return retval } diff --git a/structure/linkedlist/cyclic_test.go b/structure/linkedlist/cyclic_test.go index 41e925a95..882dbd8ad 100644 --- a/structure/linkedlist/cyclic_test.go +++ b/structure/linkedlist/cyclic_test.go @@ -5,19 +5,19 @@ import ( "testing" ) -func fillList(list *Cyclic, n int) { +func fillList(list *Cyclic[int], n int) { for i := 1; i <= n; i++ { list.Add(i) } } func TestAdd(t *testing.T) { - list := NewCyclic() + list := NewCyclic[int]() fillList(list, 3) want := []any{1, 2, 3} var got []any - var start *Node + var start *Node[int] start = list.Head for i := 0; i < list.Size; i++ { @@ -30,7 +30,7 @@ func TestAdd(t *testing.T) { } func TestWalk(t *testing.T) { - list := NewCyclic() + list := NewCyclic[int]() fillList(list, 3) want := 1 @@ -46,7 +46,7 @@ func TestRotate(t *testing.T) { param int wantToReturn int } - list := NewCyclic() + list := NewCyclic[int]() fillList(list, 3) testCases := []testCase{ @@ -69,7 +69,7 @@ func TestRotate(t *testing.T) { } func TestDelete(t *testing.T) { - list := NewCyclic() + list := NewCyclic[int]() fillList(list, 3) want := 2 @@ -85,7 +85,7 @@ func TestDelete(t *testing.T) { } func TestDestroy(t *testing.T) { - list := NewCyclic() + list := NewCyclic[int]() fillList(list, 3) wantSize := 0 list.Destroy() @@ -119,7 +119,7 @@ func TestJosephusProblem(t *testing.T) { } for _, tCase := range testCases { - list := NewCyclic() + list := NewCyclic[int]() fillList(list, tCase.listCount) got := JosephusProblem(list, tCase.param) if got != tCase.wantToReturn { diff --git a/structure/linkedlist/doubly.go b/structure/linkedlist/doubly.go index 42d24935f..0550ddba1 100644 --- a/structure/linkedlist/doubly.go +++ b/structure/linkedlist/doubly.go @@ -15,16 +15,16 @@ import "fmt" // `import "github.com/TheAlgorithms/Go/structure/linkedlist"` // // and call linkedlist.Doubly to create a new doubly linked list. -type Doubly struct { - Head *Node +type Doubly[T any] struct { + Head *Node[T] } -func NewDoubly() *Doubly { - return &Doubly{nil} +func NewDoubly[T any]() *Doubly[T] { + return &Doubly[T]{} } // AddAtBeg Add a node to the beginning of the linkedlist -func (ll *Doubly) AddAtBeg(val any) { +func (ll *Doubly[T]) AddAtBeg(val T) { n := NewNode(val) n.Next = ll.Head @@ -37,7 +37,7 @@ func (ll *Doubly) AddAtBeg(val any) { } // AddAtEnd Add a node at the end of the linkedlist -func (ll *Doubly) AddAtEnd(val any) { +func (ll *Doubly[T]) AddAtEnd(val T) { n := NewNode(val) if ll.Head == nil { @@ -53,9 +53,10 @@ func (ll *Doubly) AddAtEnd(val any) { } // DelAtBeg Delete the node at the beginning of the linkedlist -func (ll *Doubly) DelAtBeg() any { +func (ll *Doubly[T]) DelAtBeg() (T, bool) { if ll.Head == nil { - return -1 + var r T + return r, false } cur := ll.Head @@ -64,14 +65,15 @@ func (ll *Doubly) DelAtBeg() any { if ll.Head != nil { ll.Head.Prev = nil } - return cur.Val + return cur.Val, true } // DetAtEnd Delete a node at the end of the linkedlist -func (ll *Doubly) DelAtEnd() any { +func (ll *Doubly[T]) DelAtEnd() (T, bool) { // no item if ll.Head == nil { - return -1 + var r T + return r, false } // only one item @@ -86,11 +88,11 @@ func (ll *Doubly) DelAtEnd() any { retval := cur.Next.Val cur.Next = nil - return retval + return retval, true } // Count Number of nodes in the linkedlist -func (ll *Doubly) Count() any { +func (ll *Doubly[T]) Count() int { var ctr int = 0 for cur := ll.Head; cur != nil; cur = cur.Next { @@ -101,8 +103,8 @@ func (ll *Doubly) Count() any { } // Reverse Reverse the order of the linkedlist -func (ll *Doubly) Reverse() { - var Prev, Next *Node +func (ll *Doubly[T]) Reverse() { + var Prev, Next *Node[T] cur := ll.Head for cur != nil { @@ -117,7 +119,7 @@ func (ll *Doubly) Reverse() { } // Display display the linked list -func (ll *Doubly) Display() { +func (ll *Doubly[T]) Display() { for cur := ll.Head; cur != nil; cur = cur.Next { fmt.Print(cur.Val, " ") } @@ -126,11 +128,11 @@ func (ll *Doubly) Display() { } // DisplayReverse Display the linkedlist in reverse order -func (ll *Doubly) DisplayReverse() { +func (ll *Doubly[T]) DisplayReverse() { if ll.Head == nil { return } - var cur *Node + var cur *Node[T] for cur = ll.Head; cur.Next != nil; cur = cur.Next { } diff --git a/structure/linkedlist/doubly_test.go b/structure/linkedlist/doubly_test.go index b48eda812..e30663dda 100644 --- a/structure/linkedlist/doubly_test.go +++ b/structure/linkedlist/doubly_test.go @@ -6,7 +6,7 @@ import ( ) func TestDoubly(t *testing.T) { - newList := NewDoubly() + newList := NewDoubly[int]() newList.AddAtBeg(1) newList.AddAtBeg(2) @@ -20,11 +20,11 @@ func TestDoubly(t *testing.T) { // check from Next address current := newList.Head - got = append(got, current.Val.(int)) + got = append(got, current.Val) for current.Next != nil { current = current.Next - got = append(got, current.Val.(int)) + got = append(got, current.Val) } if !reflect.DeepEqual(got, wantNext) { @@ -33,11 +33,11 @@ func TestDoubly(t *testing.T) { // check from Prev address got = []int{} - got = append(got, current.Val.(int)) + got = append(got, current.Val) for current.Prev != nil { current = current.Prev - got = append(got, current.Val.(int)) + got = append(got, current.Val) } if !reflect.DeepEqual(got, wantPrev) { @@ -51,10 +51,10 @@ func TestDoubly(t *testing.T) { want := []int{3, 2, 1, 4} got := []int{} current := newList.Head - got = append(got, current.Val.(int)) + got = append(got, current.Val) for current.Next != nil { current = current.Next - got = append(got, current.Val.(int)) + got = append(got, current.Val) } if !reflect.DeepEqual(got, want) { t.Errorf("got: %v, want: %v", got, want) @@ -63,7 +63,10 @@ func TestDoubly(t *testing.T) { t.Run("Test DelAtBeg", func(t *testing.T) { want := 3 - got := newList.DelAtBeg() + got, ok := newList.DelAtBeg() + if !ok { + t.Error("unexpected not-ok") + } if got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -71,7 +74,10 @@ func TestDoubly(t *testing.T) { t.Run("Test DelAtEnd", func(t *testing.T) { want := 4 - got := newList.DelAtEnd() + got, ok := newList.DelAtEnd() + if !ok { + t.Error("unexpected not-ok") + } if got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -85,7 +91,7 @@ func TestDoubly(t *testing.T) { } }) - newList2 := NewDoubly() + newList2 := NewDoubly[int]() newList2.AddAtBeg(1) newList2.AddAtBeg(2) newList2.AddAtBeg(3) @@ -94,10 +100,10 @@ func TestDoubly(t *testing.T) { got := []int{} newList2.Reverse() current := newList2.Head - got = append(got, current.Val.(int)) + got = append(got, current.Val) for current.Next != nil { current = current.Next - got = append(got, current.Val.(int)) + got = append(got, current.Val) } if !reflect.DeepEqual(got, want) { t.Errorf("got: %v, want: %v", got, want) diff --git a/structure/linkedlist/shared.go b/structure/linkedlist/shared.go index c09e9fe8a..03e52f7bf 100644 --- a/structure/linkedlist/shared.go +++ b/structure/linkedlist/shared.go @@ -2,13 +2,13 @@ package linkedlist // Node Structure representing the linkedlist node. // This node is shared across different implementations. -type Node struct { - Val any - Prev *Node - Next *Node +type Node[T any] struct { + Val T + Prev *Node[T] + Next *Node[T] } // Create new node. -func NewNode(val any) *Node { - return &Node{val, nil, nil} +func NewNode[T any](val T) *Node[T] { + return &Node[T]{val, nil, nil} } diff --git a/structure/linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go index f8662408a..18d661799 100644 --- a/structure/linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -7,29 +7,29 @@ import ( ) // Singly structure with length of the list and its head -type Singly struct { +type Singly[T any] struct { length int // Note that Node here holds both Next and Prev Node // however only the Next node is used in Singly methods. - Head *Node + Head *Node[T] } // NewSingly returns a new instance of a linked list -func NewSingly() *Singly { - return &Singly{} +func NewSingly[T any]() *Singly[T] { + return &Singly[T]{} } // AddAtBeg adds a new snode with given value at the beginning of the list. -func (ll *Singly) AddAtBeg(val any) { - n := NewNode(val) +func (ll *Singly[T]) AddAtBeg(val T) { + n := NewNode[T](val) n.Next = ll.Head ll.Head = n ll.length++ } // AddAtEnd adds a new snode with given value at the end of the list. -func (ll *Singly) AddAtEnd(val any) { +func (ll *Singly[T]) AddAtEnd(val T) { n := NewNode(val) if ll.Head == nil { @@ -45,23 +45,27 @@ func (ll *Singly) AddAtEnd(val any) { ll.length++ } -// DelAtBeg deletes the snode at the head(beginning) of the list and returns its value. Returns -1 if the list is empty. -func (ll *Singly) DelAtBeg() any { +// DelAtBeg deletes the snode at the head(beginning) of the list +// and returns its value. Returns false if the list is empty. +func (ll *Singly[T]) DelAtBeg() (T, bool) { if ll.Head == nil { - return -1 + var r T + return r, false } cur := ll.Head ll.Head = cur.Next ll.length-- - return cur.Val + return cur.Val, true } -// DelAtEnd deletes the snode at the tail(end) of the list and returns its value. Returns -1 if the list is empty. -func (ll *Singly) DelAtEnd() any { +// DelAtEnd deletes the snode at the tail(end) of the list +// and returns its value. Returns false if the list is empty. +func (ll *Singly[T]) DelAtEnd() (T, bool) { if ll.Head == nil { - return -1 + var r T + return r, false } if ll.Head.Next == nil { @@ -76,18 +80,18 @@ func (ll *Singly) DelAtEnd() any { retval := cur.Next.Val cur.Next = nil ll.length-- - return retval + return retval, true } // Count returns the current size of the list. -func (ll *Singly) Count() int { +func (ll *Singly[T]) Count() int { return ll.length } // Reverse reverses the list. -func (ll *Singly) Reverse() { - var prev, Next *Node +func (ll *Singly[T]) Reverse() { + var prev, Next *Node[T] cur := ll.Head for cur != nil { @@ -101,12 +105,12 @@ func (ll *Singly) Reverse() { } // ReversePartition Reverse the linked list from the ath to the bth node -func (ll *Singly) ReversePartition(left, right int) error { +func (ll *Singly[T]) ReversePartition(left, right int) error { err := ll.CheckRangeFromIndex(left, right) if err != nil { return err } - tmpNode := NewNode(-1) + tmpNode := &Node[T]{} tmpNode.Next = ll.Head pre := tmpNode for i := 0; i < left-1; i++ { @@ -122,7 +126,7 @@ func (ll *Singly) ReversePartition(left, right int) error { ll.Head = tmpNode.Next return nil } -func (ll *Singly) CheckRangeFromIndex(left, right int) error { +func (ll *Singly[T]) CheckRangeFromIndex(left, right int) error { if left > right { return errors.New("left boundary must smaller than right") } else if left < 1 { @@ -134,7 +138,7 @@ func (ll *Singly) CheckRangeFromIndex(left, right int) error { } // Display prints out the elements of the list. -func (ll *Singly) Display() { +func (ll *Singly[T]) Display() { for cur := ll.Head; cur != nil; cur = cur.Next { fmt.Print(cur.Val, " ") } diff --git a/structure/linkedlist/singlylinkedlist_test.go b/structure/linkedlist/singlylinkedlist_test.go index df8004aa0..705770d9c 100644 --- a/structure/linkedlist/singlylinkedlist_test.go +++ b/structure/linkedlist/singlylinkedlist_test.go @@ -6,7 +6,7 @@ import ( ) func TestSingly(t *testing.T) { - list := NewSingly() + list := NewSingly[int]() list.AddAtBeg(1) list.AddAtBeg(2) list.AddAtBeg(3) @@ -43,7 +43,10 @@ func TestSingly(t *testing.T) { t.Run("Test DelAtBeg()", func(t *testing.T) { want := any(3) - got := list.DelAtBeg() + got, ok := list.DelAtBeg() + if !ok { + t.Error("unexpected not-ok") + } if got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -51,7 +54,10 @@ func TestSingly(t *testing.T) { t.Run("Test DelAtEnd()", func(t *testing.T) { want := any(4) - got := list.DelAtEnd() + got, ok := list.DelAtEnd() + if !ok { + t.Error("unexpected not-ok") + } if got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -65,7 +71,7 @@ func TestSingly(t *testing.T) { } }) - list2 := Singly{} + list2 := Singly[int]{} list2.AddAtBeg(1) list2.AddAtBeg(2) list2.AddAtBeg(3) From 94e8490ea0a1620c6b70a91846043f2c16cd5b48 Mon Sep 17 00:00:00 2001 From: Akshay Dubey <38462415+itsAkshayDubey@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:39:00 +0530 Subject: [PATCH 356/488] algorithm: binomial coefficient (#539) * feat: Add binomial coefficient implementation * test: Add tests for binomial coefficient * fix: Fix typing error in binomialcoefficient.go * fix: Add linter fixes to BenchmarkBinomialCoefficient() * fix: Fix import statement in binomialcoefficient_test.go * fix: Fix return statement * test: Add detailed unit tests for binomial coefficient * fix: Replace all occurrences of C with Combinations * fix: Move error variable outside Combinations function * refactor: Add t.Run block * refactor: Remove log statement * refactor: Refactor unit tests * fix: Change error variable name from error to err --- math/binomialcoefficient.go | 33 +++++++++++++++++++++++++ math/binomialcoefficient_test.go | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 math/binomialcoefficient.go create mode 100644 math/binomialcoefficient_test.go diff --git a/math/binomialcoefficient.go b/math/binomialcoefficient.go new file mode 100644 index 000000000..d3c123a6f --- /dev/null +++ b/math/binomialcoefficient.go @@ -0,0 +1,33 @@ +// binomialcoefficient.go +// description: Returns C(n, k) +// details: +// a binomial coefficient C(n,k) gives number ways +// in which k objects can be chosen from n objects. +// wikipedia: https://en.wikipedia.org/wiki/Binomial_coefficient +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see binomialcoefficient_test.go + +package math + +import ( + "errors" +) + +var ErrPosArgsOnly error = errors.New("arguments must be positive") + +// C is Binomial Coefficient function +// This function returns C(n, k) for given n and k +func Combinations(n int, k int) (int, error) { + if n < 0 || k < 0 { + return -1, ErrPosArgsOnly + } + if k > (n - k) { + k = n - k + } + res := 1 + for i := 0; i < k; i++ { + res *= (n - i) + res /= (i + 1) + } + return res, nil +} diff --git a/math/binomialcoefficient_test.go b/math/binomialcoefficient_test.go new file mode 100644 index 000000000..20b9c4373 --- /dev/null +++ b/math/binomialcoefficient_test.go @@ -0,0 +1,42 @@ +// binomialcoefficient_test.go +// description: Returns C(n, k) +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see binomialcoefficient.go + +package math_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math" +) + +func TestCombinations(t *testing.T) { + var tests = []struct { + name string + n int + k int + expectedValue int + expectedError error + }{ + {"n = 5, k = 2", 5, 2, 10, nil}, + {"n = 7, k = 4", 7, 4, 35, nil}, + {"n = 0, k = 0", 0, 0, 1, nil}, + {"n = -1, k = 1", -1, 1, -1, math.ErrPosArgsOnly}, + {"n = 1, k = -1", 1, -1, -1, math.ErrPosArgsOnly}, + {"n = -1, k = -1", -1, -1, -1, math.ErrPosArgsOnly}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := math.Combinations(test.n, test.k) + if result != test.expectedValue || test.expectedError != err { + t.Errorf("expected error: %s, got: %s; expected value: %v, got: %v", test.expectedError, err, test.expectedValue, result) + } + }) + } +} +func BenchmarkCombinations(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = math.Combinations(65536, 65536) + } +} From 1acfe4c456b79b7d50482d0ce38f84de9a4adc56 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Fri, 16 Sep 2022 10:23:43 +0300 Subject: [PATCH 357/488] Add Pollard's Rho Factorization algorithm (#530) --- README.md | 13 ++++++++ math/pollard.go | 43 ++++++++++++++++++++++++ math/pollard_test.go | 79 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 math/pollard.go create mode 100644 math/pollard_test.go diff --git a/README.md b/README.md index 19c15407d..6dc6e9f1f 100644 --- a/README.md +++ b/README.md @@ -920,6 +920,19 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 3. [`Stack`](./structure/stack/stacklinkedlist.go#L19): No description provided. +--- +
+ strings + +--- + +##### Package strings is a package that contains all algorithms that are used to analyse and manipulate strings. + +--- +##### Functions: + +1. [`CountChars`](./strings/charoccurrence.go#L12): CountChars counts the number of a times a character has occurred in the provided string argument and returns a map with `rune` as keys and the count as value. + ---
transposition diff --git a/math/pollard.go b/math/pollard.go new file mode 100644 index 000000000..434a0f24f --- /dev/null +++ b/math/pollard.go @@ -0,0 +1,43 @@ +// pollard.go +// description: Pollard's rho algorithm +// details: +// implementation of Pollard's rho algorithm for integer factorization-[Pollard's rho algorithm](https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm) +// author(s) [red_byte](https://github.com/i-redbyte) +// see pollard_test.go + +package math + +import ( + "errors" + "math/big" +) + +// DefaultPolynomial is the commonly used polynomial g(x) = (x^2 + 1) mod n +func DefaultPolynomial(n *big.Int) func(*big.Int) *big.Int { + bigOne := big.NewInt(1) + bigTwo := big.NewInt(2) + return func(x *big.Int) *big.Int { + xSquared := new(big.Int).Exp(x, bigTwo, n) // see: https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm#Core_ideas + xSquared.Add(xSquared, bigOne) + xSquared.Mod(xSquared, n) + return xSquared + } +} + +// PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm +// using the default parameters x = y = 2 +func PollardsRhoFactorization(n *big.Int, f func(n *big.Int) func(x *big.Int) *big.Int) (*big.Int, error) { + x, y, d := big.NewInt(2), big.NewInt(2), big.NewInt(1) + bigOne := big.NewInt(1) + g := f(n) + for d.Cmp(bigOne) == 0 { + x = g(x) + y = g(g(y)) + sub := new(big.Int).Sub(x, y) + d.GCD(nil, nil, sub.Abs(sub), n) + } + if d.Cmp(n) == 0 { + return nil, errors.New("factorization failed") + } + return d, nil +} diff --git a/math/pollard_test.go b/math/pollard_test.go new file mode 100644 index 000000000..d77d81b22 --- /dev/null +++ b/math/pollard_test.go @@ -0,0 +1,79 @@ +// pollard_test.go +// description: Test for Pollard's rho algorithm +// author(s) [red_byte](https://github.com/i-redbyte) +// see pollard.go + +package math + +import ( + "math/big" + "reflect" + "testing" +) + +func TestDefaultPolynomial(t *testing.T) { + tests := []struct { + name string + x *big.Int + n *big.Int + want *big.Int + }{ + {"Polynomial for n = 1772; x = 535", big.NewInt(535), big.NewInt(1772), big.NewInt(934)}, + {"Polynomial for n = 666; x = 53135", big.NewInt(53135), big.NewInt(666), big.NewInt(380)}, + {"Polynomial for n = 666; x = 13", big.NewInt(13), big.NewInt(666), big.NewInt(170)}, + {"Polynomial for n = 1917; x = 2510", big.NewInt(2510), big.NewInt(1917), big.NewInt(839)}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := DefaultPolynomial(test.n)(test.x); !reflect.DeepEqual(got, test.want) { + t.Errorf("DefaultPolynomial() = %v, want %v", got, test.want) + } + }) + } +} + +func TestRho(t *testing.T) { + tests := []struct { + name string + n *big.Int + g func(n *big.Int) func(*big.Int) *big.Int + want *big.Int + wantErr bool + }{ + {"Factor of n: 11235 ", big.NewInt(11235), DefaultPolynomial, big.NewInt(21), false}, + {"Factor of n: 111155 ", big.NewInt(111155), DefaultPolynomial, big.NewInt(11), false}, + {"Factor of n: 8080 ", big.NewInt(8080), DefaultPolynomial, big.NewInt(16), false}, + {"Factor of n: 8536 ", big.NewInt(8536), DefaultPolynomial, big.NewInt(88), false}, + {"Factor of n: 666 ", big.NewInt(666), DefaultPolynomial, big.NewInt(3), false}, + {"Factor of n: 2 ", big.NewInt(2), DefaultPolynomial, big.NewInt(2), true}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got, err := PollardsRhoFactorization(test.n, test.g) + if err != nil && !test.wantErr { + t.Errorf("PollardsRhoFactorization() error = %v, wantErr %v", err, test.wantErr) + return + } else if err != nil && test.wantErr { + return + } + if !reflect.DeepEqual(got, test.want) { + t.Errorf("PollardsRhoFactorization() got = %v, want %v", got, test.want) + } + }) + } +} + +func BenchmarkDefaultPolynomial(b *testing.B) { + for i := 0; i < b.N; i++ { + DefaultPolynomial(big.NewInt(535))(big.NewInt(11235)) + } +} + +func BenchmarkRho(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := PollardsRhoFactorization(big.NewInt(535), DefaultPolynomial) + if err != nil { + return + } + } +} From 6a99cd70c53ce155cfe812909525b74628d63779 Mon Sep 17 00:00:00 2001 From: Akshay Dubey <38462415+itsAkshayDubey@users.noreply.github.com> Date: Wed, 21 Sep 2022 00:14:34 +0530 Subject: [PATCH 358/488] algorithm: Liouville lambda function (#540) --- math/liouville.go | 35 +++++++++++++++++++++++++++++++++++ math/liouville_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 math/liouville.go create mode 100644 math/liouville_test.go diff --git a/math/liouville.go b/math/liouville.go new file mode 100644 index 000000000..908a4deac --- /dev/null +++ b/math/liouville.go @@ -0,0 +1,35 @@ +// liouville.go +// description: Returns λ(n) +// details: +// For any positive integer n, define λ(n) as the sum of the primitive nth roots of unity. +// It has values in {−1, 1} depending on the factorization of n into prime factors: +// λ(n) = +1 if n is a positive integer with an even number of prime factors. +// λ(n) = −1 if n is a positive integer with an odd number of prime factors. +// wikipedia: https://en.wikipedia.org/wiki/Liouville_function +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see liouville_test.go + +package math + +import ( + "errors" + + "github.com/TheAlgorithms/Go/math/prime" +) + +var ErrNonZeroArgsOnly error = errors.New("arguments cannot be zero") + +// Lambda is the liouville function +// This function returns λ(n) for given number +func LiouvilleLambda(n int) (int, error) { + switch { + case n < 0: + return 0, ErrPosArgsOnly + case n == 0: + return 0, ErrNonZeroArgsOnly + case len(prime.Factorize(int64(n)))%2 == 0: + return 1, nil + default: + return -1, nil + } +} diff --git a/math/liouville_test.go b/math/liouville_test.go new file mode 100644 index 000000000..41d327c3e --- /dev/null +++ b/math/liouville_test.go @@ -0,0 +1,39 @@ +// liouville_test.go +// description: Returns λ(n) +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see liouville.go + +package math_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math" +) + +func TestLiouvilleLambda(t *testing.T) { + var tests = []struct { + name string + n int + expectedValue int + expectedError error + }{ + {"n = 10", 10, 1, nil}, + {"n = 11", 11, -1, nil}, + {"n = -1", -1, 0, math.ErrPosArgsOnly}, + {"n = 0", 0, 0, math.ErrNonZeroArgsOnly}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := math.LiouvilleLambda(test.n) + if result != test.expectedValue || test.expectedError != err { + t.Errorf("expected error: %s, got: %s; expected value: %v, got: %v", test.expectedError, err, test.expectedValue, result) + } + }) + } +} +func BenchmarkLiouvilleLambda(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = math.LiouvilleLambda(65536) + } +} From eaa2be2ffe9295b9eb996ec49af6e0e2e6381595 Mon Sep 17 00:00:00 2001 From: Taj Date: Fri, 23 Sep 2022 09:44:50 +0100 Subject: [PATCH 359/488] feat: re-enable all linters (#541) * Updated Documentation in README.md * fix: golangci-lint disabled linters and checks * Updated Documentation in README.md * fix: documentation comment issue * Updated Documentation in README.md Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- .golangci.yml | 6 ------ README.md | 25 +++++++++++++++---------- math/mode.go | 6 +----- sort/patiencesort.go | 2 +- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b334bee16..586ace461 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,8 +1,2 @@ run: go: 1.19 -linters: - disable: - - gosimple - - staticcheck - - structcheck - - unused diff --git a/README.md b/README.md index 6dc6e9f1f..66de9cad0 100644 --- a/README.md +++ b/README.md @@ -548,15 +548,20 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Abs`](./math/abs.go#L11): Abs returns absolute value -2. [`Cos`](./math/cos.go#L10): Cos returns the cosine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) [Based on the idea of Bhaskara approximation of cos(x)](https://math.stackexchange.com/questions/3886552/bhaskara-approximation-of-cosx) -3. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -4. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -5. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -6. [`Mean`](./math/mean.go#L7): No description provided. -7. [`Median`](./math/median.go#L12): No description provided. -8. [`Mode`](./math/mode.go#L19): No description provided. -9. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. -10. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +2. [`Combinations`](./math/binomialcoefficient.go#L20): C is Binomial Coefficient function This function returns C(n, k) for given n and k +3. [`Cos`](./math/cos.go#L10): Cos returns the cosine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) [Based on the idea of Bhaskara approximation of cos(x)](https://math.stackexchange.com/questions/3886552/bhaskara-approximation-of-cosx) +4. [`DefaultPolynomial`](./math/pollard.go#L16): DefaultPolynomial is the commonly used polynomial g(x) = (x^2 + 1) mod n +5. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +6. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +7. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +8. [`LiouvilleLambda`](./math/liouville.go#L24): Lambda is the liouville function This function returns λ(n) for given number +9. [`Mean`](./math/mean.go#L7): No description provided. +10. [`Median`](./math/median.go#L12): No description provided. +11. [`Mode`](./math/mode.go#L19): No description provided. +12. [`Mu`](./math/mobius.go#L21): Mu is the Mobius function This function returns μ(n) for given number +13. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +14. [`PollardsRhoFactorization`](./math/pollard.go#L29): PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm using the default parameters x = y = 2 +15. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) ---
@@ -871,7 +876,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### Package sort a package for demonstrating sorting algorithms in Go Package sort Patience sorting is a sorting algorithm inspired by the card game patience. For more details check out those links below here: GeeksForGeeks article : https://www.geeksforgeeks.org/patience-sorting/ Wikipedia article: https://en.wikipedia.org/wiki/Patience_sorting authors [guuzaa](https://github.com/guuzaa) see patiencesort.go +##### Package sort a package for demonstrating sorting algorithms in Go --- ##### Functions: diff --git a/math/mode.go b/math/mode.go index c0745c33d..164084bb6 100644 --- a/math/mode.go +++ b/math/mode.go @@ -27,11 +27,7 @@ func Mode[T constraints.Number](numbers []T) (T, error) { } for _, number := range numbers { - if _, check := countMap[number]; check { - countMap[number]++ - } else { - countMap[number] = 1 - } + countMap[number]++ } var mode T diff --git a/sort/patiencesort.go b/sort/patiencesort.go index efae67ff0..746c84931 100644 --- a/sort/patiencesort.go +++ b/sort/patiencesort.go @@ -1,4 +1,3 @@ -// Package sort // Patience sorting is a sorting algorithm inspired by the card game patience. // // For more details check out those links below here: @@ -6,6 +5,7 @@ // Wikipedia article: https://en.wikipedia.org/wiki/Patience_sorting // authors [guuzaa](https://github.com/guuzaa) // see patiencesort.go + package sort import "github.com/TheAlgorithms/Go/constraints" From 4d9b1e48789f24959739ef03b52b26d074a98de8 Mon Sep 17 00:00:00 2001 From: Abel Date: Mon, 3 Oct 2022 21:46:09 +0800 Subject: [PATCH 360/488] feat: add fuzzing for cipher/xor (#546) --- cipher/xor/xor_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cipher/xor/xor_test.go b/cipher/xor/xor_test.go index 999755188..5f98964e1 100644 --- a/cipher/xor/xor_test.go +++ b/cipher/xor/xor_test.go @@ -1,6 +1,7 @@ package xor import ( + "bytes" "fmt" "reflect" "testing" @@ -103,3 +104,14 @@ func TestXorCipherDecrypt(t *testing.T) { }) } } + +func FuzzXOR(f *testing.F) { + f.Add([]byte("The Quick Brown Fox Jumps over the Lazy Dog."), byte('X')) + f.Fuzz(func(t *testing.T, input []byte, key byte) { + cipherText := Encrypt(key, input) + result := Decrypt(key, cipherText) + if !bytes.Equal(input, result) { + t.Errorf("Before: %s, after: %s, key: %d", input, result, key) + } + }) +} From 51f0485f9289676e23d4c7cbf4a868e4704a27d6 Mon Sep 17 00:00:00 2001 From: safesuk Date: Fri, 7 Oct 2022 18:50:57 +0700 Subject: [PATCH 361/488] feat: add lerp (#545) * add lerp * fix: add description --- math/lerp.go | 8 ++++++++ math/lerp_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 math/lerp.go create mode 100644 math/lerp_test.go diff --git a/math/lerp.go b/math/lerp.go new file mode 100644 index 000000000..1d2b59908 --- /dev/null +++ b/math/lerp.go @@ -0,0 +1,8 @@ +package math + +// Lerp or Linear interpolation +// This function will return new value in 't' percentage between 'v0' and 'v1' +func Lerp(v0, v1, t float64) float64 { + // see: https://en.wikipedia.org/wiki/Linear_interpolation + return (1-t)*v0 + t*v1 +} diff --git a/math/lerp_test.go b/math/lerp_test.go new file mode 100644 index 000000000..3a6ac25fd --- /dev/null +++ b/math/lerp_test.go @@ -0,0 +1,29 @@ +package math_test + +import ( + "testing" + + algmath "github.com/TheAlgorithms/Go/math" +) + +func TestLerp(t *testing.T) { + tests := []struct { + name string + testValues []float64 + answer float64 + }{ + {"Lerp(1,1,1)", []float64{1, 1, 1}, 1}, + {"Lerp(0,1,1)", []float64{0, 1, 1}, 1}, + {"Lerp(0,1,0.5)", []float64{0, 1, 0.5}, 0.5}, + {"Lerp(0,1,0.1)", []float64{0, 1, 0.1}, 0.1}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := algmath.Lerp(test.testValues[0], test.testValues[1], test.testValues[2]) + if got != test.answer { + t.Errorf("Lerp(%f,%f,%f) = %v, want %v", got, test.testValues[0], + test.testValues[1], test.testValues[2], test.answer) + } + }) + } +} From af1519c2041b5dc5e6efcb9d9a96ed6d9d26659e Mon Sep 17 00:00:00 2001 From: Akshay Dubey <38462415+itsAkshayDubey@users.noreply.github.com> Date: Sun, 9 Oct 2022 17:48:52 +0530 Subject: [PATCH 362/488] algorithm: Twin prime (#550) --- math/prime/twin.go | 20 ++++++++++++++++++++ math/prime/twin_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 math/prime/twin.go create mode 100644 math/prime/twin_test.go diff --git a/math/prime/twin.go b/math/prime/twin.go new file mode 100644 index 000000000..1326746e4 --- /dev/null +++ b/math/prime/twin.go @@ -0,0 +1,20 @@ +// twin.go +// description: Returns Twin Prime of n +// details: +// For any integer n, twin prime is (n + 2) +// if and only if both n and (n + 2) both are prime +// wikipedia: https://en.wikipedia.org/wiki/Twin_prime +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see twin_test.go + +package prime + +// This function returns twin prime for given number +// returns (n + 2) if both n and (n + 2) are prime +// -1 otherwise +func Twin(n int) (int, bool) { + if OptimizedTrialDivision(int64(n)) && OptimizedTrialDivision(int64(n+2)) { + return n + 2, true + } + return -1, false +} diff --git a/math/prime/twin_test.go b/math/prime/twin_test.go new file mode 100644 index 000000000..7c1923dcb --- /dev/null +++ b/math/prime/twin_test.go @@ -0,0 +1,39 @@ +// twin_test.go +// description: Returns Twin Prime of n +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see twin.go + +package prime_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/prime" +) + +func TestTwin(t *testing.T) { + var tests = []struct { + name string + n int + expectedValue int + hasTwin bool + }{ + {"n = 3, should return 5", 3, 5, true}, + {"n = 4, should return -1", 4, -1, false}, + {"n = 5, should return 7", 5, 7, true}, + {"n = 17, should return 19", 17, 19, true}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, hasTwin := prime.Twin(test.n) + if result != test.expectedValue || hasTwin != test.hasTwin { + t.Errorf("expected value: %v and %v, got: %v and %v", test.expectedValue, test.hasTwin, result, hasTwin) + } + }) + } +} +func BenchmarkTwin(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = prime.Twin(65536) + } +} From 44b39e09ddf43a23fde630679c9bad20948b422b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C5=A9=20H=E1=BA=A3i=20L=C3=A2m?= Date: Wed, 12 Oct 2022 11:51:00 +0700 Subject: [PATCH 363/488] feat: Use generic for pigeonholesort and max min Int (#565) --- math/max/max.go | 4 +++- math/min/min.go | 4 +++- sort/pigeonholesort.go | 9 ++++++--- sort/sorts_test.go | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/math/max/max.go b/math/max/max.go index 0449a2d6b..d93aa5601 100644 --- a/math/max/max.go +++ b/math/max/max.go @@ -1,7 +1,9 @@ package max +import "github.com/TheAlgorithms/Go/constraints" + // Int is a function which returns the maximum of all the integers provided as arguments. -func Int(values ...int) int { +func Int[T constraints.Integer](values ...T) T { max := values[0] for _, value := range values { if value > max { diff --git a/math/min/min.go b/math/min/min.go index 03fd090ba..3ef21272b 100644 --- a/math/min/min.go +++ b/math/min/min.go @@ -1,7 +1,9 @@ package min +import "github.com/TheAlgorithms/Go/constraints" + // Int is a function which returns the minimum of all the integers provided as arguments. -func Int(values ...int) int { +func Int[T constraints.Integer](values ...T) T { min := values[0] for _, value := range values { if value < min { diff --git a/sort/pigeonholesort.go b/sort/pigeonholesort.go index bfc20244e..12941cdc9 100644 --- a/sort/pigeonholesort.go +++ b/sort/pigeonholesort.go @@ -4,12 +4,15 @@ package sort import ( + "github.com/TheAlgorithms/Go/constraints" "github.com/TheAlgorithms/Go/math/max" "github.com/TheAlgorithms/Go/math/min" ) // Pigeonhole sorts a slice using pigeonhole sorting algorithm. -func Pigeonhole(arr []int) []int { +// NOTE: To maintain time complexity O(n + N), this is the reason for having +// only Integer constraint instead of Ordered. +func Pigeonhole[T constraints.Integer](arr []T) []T { if len(arr) == 0 { return arr } @@ -19,7 +22,7 @@ func Pigeonhole(arr []int) []int { size := max - min + 1 - holes := make([]int, size) + holes := make([]T, size) for _, element := range arr { holes[element-min]++ @@ -27,7 +30,7 @@ func Pigeonhole(arr []int) []int { i := 0 - for j := 0; j < size; j++ { + for j := T(0); j < size; j++ { for holes[j] > 0 { holes[j]-- arr[i] = j + min diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 467d054ce..1c07ddb2b 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -132,7 +132,7 @@ func TestComb(t *testing.T) { } func TestPigeonhole(t *testing.T) { - testFramework(t, sort.Pigeonhole) + testFramework(t, sort.Pigeonhole[int]) } func TestPatience(t *testing.T) { @@ -238,7 +238,7 @@ func BenchmarkComb(b *testing.B) { } func BenchmarkPigeonhole(b *testing.B) { - benchmarkFramework(b, sort.Pigeonhole) + benchmarkFramework(b, sort.Pigeonhole[int]) } func BenchmarkPatience(b *testing.B) { From 873b9eca0aaad59bdf7b18ffed9db8f08fd71d37 Mon Sep 17 00:00:00 2001 From: VictorAssunc Date: Wed, 12 Oct 2022 08:02:46 -0300 Subject: [PATCH 364/488] feat(cipher/caesar): add fuzzy test to caesar cipher (#559) --- cipher/caesar/caesar.go | 10 +++++----- cipher/caesar/caesar_test.go | 13 +++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/cipher/caesar/caesar.go b/cipher/caesar/caesar.go index 21da4f5a9..8c1cb47f7 100644 --- a/cipher/caesar/caesar.go +++ b/cipher/caesar/caesar.go @@ -9,12 +9,12 @@ func Encrypt(input string, key int) string { key8 := byte(key%26+26) % 26 var outputBuffer []byte - // r is a rune, which is the equivalent of uint32. - for _, r := range input { - newByte := byte(r) - if 'A' <= r && r <= 'Z' { + // b is a byte, which is the equivalent of uint8. + for _, b := range []byte(input) { + newByte := b + if 'A' <= b && b <= 'Z' { outputBuffer = append(outputBuffer, 'A'+(newByte-'A'+key8)%26) - } else if 'a' <= r && r <= 'z' { + } else if 'a' <= b && b <= 'z' { outputBuffer = append(outputBuffer, 'a'+(newByte-'a'+key8)%26) } else { outputBuffer = append(outputBuffer, newByte) diff --git a/cipher/caesar/caesar_test.go b/cipher/caesar/caesar_test.go index e28a3fe11..4d03ea3ec 100644 --- a/cipher/caesar/caesar_test.go +++ b/cipher/caesar/caesar_test.go @@ -2,7 +2,9 @@ package caesar import ( "fmt" + "math/rand" "testing" + "time" ) func TestEncrypt(t *testing.T) { @@ -152,3 +154,14 @@ func Example() { // Encrypt=> key: 10, input: The Quick Brown Fox Jumps over the Lazy Dog., encryptedText: Dro Aesmu Lbygx Pyh Tewzc yfob dro Vkji Nyq. // Decrypt=> key: 10, input: Dro Aesmu Lbygx Pyh Tewzc yfob dro Vkji Nyq., decryptedText: The Quick Brown Fox Jumps over the Lazy Dog. } + +func FuzzCaesar(f *testing.F) { + rand.Seed(time.Now().Unix()) + f.Add("The Quick Brown Fox Jumps over the Lazy Dog.") + f.Fuzz(func(t *testing.T, input string) { + key := rand.Intn(26) + if result := Decrypt(Encrypt(input, key), key); result != input { + t.Fatalf("With input: '%s' and key: %d\n\tExpected: '%s'\n\tGot: '%s'", input, key, input, result) + } + }) +} From c86b40dda9255444137460674c0e237f51f4459d Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Thu, 13 Oct 2022 05:04:21 +0200 Subject: [PATCH 365/488] test: add tests for longestcommonsubsequence.go (#556) --- dynamic/longestcommonsubsequence_test.go | 55 ++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 dynamic/longestcommonsubsequence_test.go diff --git a/dynamic/longestcommonsubsequence_test.go b/dynamic/longestcommonsubsequence_test.go new file mode 100644 index 000000000..361f2b004 --- /dev/null +++ b/dynamic/longestcommonsubsequence_test.go @@ -0,0 +1,55 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseLCS struct { + stringA string + stringB string + expected int +} + +func getLCSTestCases() []testCaseLCS { + return []testCaseLCS{ + {"ABCDGH", "AEDFHR", 3}, + {"AGGTAB", "GXTXAYB", 4}, + {"programming", "gaming", 6}, + {"physics", "smartphone", 2}, + {"computer", "food", 1}, + {"123", "12345", 3}, + {"XYZ", "XYZ", 3}, + {"XYZ", "XYZa", 3}, + {"XYZ", "aXYZ", 3}, + {"0123", "abc", 0}, + {"abcdef", "aXbXcXXXdeXXf", 6}, + {"", "abc", 0}, + {"", "", 0}, + } +} + +func TestLongestCommonSubsequence(t *testing.T) { + t.Run("Simple test", func(t *testing.T) { + for _, tc := range getLCSTestCases() { + actual := dynamic.LongestCommonSubsequence( + tc.stringA, tc.stringB, + len(tc.stringA), len(tc.stringB)) + if actual != tc.expected { + t.Errorf("expected: %d, but got: %d", tc.expected, actual) + } + } + }) + + t.Run("Symmetry test", func(t *testing.T) { + for _, tc := range getLCSTestCases() { + actual := dynamic.LongestCommonSubsequence( + tc.stringB, tc.stringA, + len(tc.stringB), len(tc.stringA)) + if actual != tc.expected { + t.Errorf("expected: %d, but got: %d", tc.expected, actual) + } + } + }) +} From 746173e57fe169ebdb00fed1bf8b7dd2e44d30c1 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Thu, 13 Oct 2022 05:05:07 +0200 Subject: [PATCH 366/488] test: add tests for rodcutting.go (#555) --- dynamic/rodcutting_test.go | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 dynamic/rodcutting_test.go diff --git a/dynamic/rodcutting_test.go b/dynamic/rodcutting_test.go new file mode 100644 index 000000000..96321df40 --- /dev/null +++ b/dynamic/rodcutting_test.go @@ -0,0 +1,39 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type rodCuttingTestCase struct { + price []int + length int + expected int +} + +func getRodCuttingTestCases() []rodCuttingTestCase { + return []rodCuttingTestCase{ + {[]int{0, 1, 5, 8, 9}, 4, 10}, + {[]int{0, 2, 5, 7, 8, 0}, 5, 12}, + {[]int{0, 1, 5, 8, 9, 10, 17, 17, 20}, 8, 22}, + {[]int{0, 3, 5, 8, 9, 10, 17, 17, 20}, 8, 24}, + } +} + +func cutRodSolTestFunc(t *testing.T, cutRodSolFunc func([]int, int) int) { + for _, tc := range getRodCuttingTestCases() { + actual := cutRodSolFunc(tc.price, tc.length) + if actual != tc.expected { + t.Errorf("expected: %d, got: %d", tc.expected, actual) + } + } +} + +func TestCutRodRec(t *testing.T) { + cutRodSolTestFunc(t, dynamic.CutRodRec) +} + +func TestCutRodDp(t *testing.T) { + cutRodSolTestFunc(t, dynamic.CutRodDp) +} From ae98d523dd3889afb06da7c762a414c00f063043 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Thu, 13 Oct 2022 05:07:06 +0200 Subject: [PATCH 367/488] feat: add perfectnumber (#554) --- math/perfectnumber.go | 36 +++++++++ math/perfectnumber_test.go | 151 +++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 math/perfectnumber.go create mode 100644 math/perfectnumber_test.go diff --git a/math/perfectnumber.go b/math/perfectnumber.go new file mode 100644 index 000000000..e21c89b64 --- /dev/null +++ b/math/perfectnumber.go @@ -0,0 +1,36 @@ +// perfectnumber.go +// description: provides the function IsPerfectNumber and related utilities +// details: +// provides the functions +// - IsPerfectNumber which checks if the input is a perfect number, +// - SumOfProperDivisors which returns the sum of proper divisors of the input. +// A number is called perfect, if it is a sum of its proper divisors, +// cf. https://en.wikipedia.org/wiki/Perfect_number, +// https://mathworld.wolfram.com/PerfectNumber.html +// https://oeis.org/A000396 +// author(s) [Piotr Idzik](https://github.com/vil02) +// see perfectnumber_test.go + +package math + +// Returns the sum of proper divisors of inNumber. +func SumOfProperDivisors(inNumber uint) uint { + var res = uint(0) + if inNumber > 1 { + res = uint(1) + } + for curDivisor := uint(2); curDivisor*curDivisor <= inNumber; curDivisor++ { + if inNumber%curDivisor == 0 { + res += curDivisor + if curDivisor*curDivisor != inNumber { + res += inNumber / curDivisor + } + } + } + return res +} + +// Checks if inNumber is a perfect number +func IsPerfectNumber(inNumber uint) bool { + return inNumber > 0 && SumOfProperDivisors(inNumber) == inNumber +} diff --git a/math/perfectnumber_test.go b/math/perfectnumber_test.go new file mode 100644 index 000000000..c0041d0ae --- /dev/null +++ b/math/perfectnumber_test.go @@ -0,0 +1,151 @@ +package math_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math" +) + +type testCaseSumOfProperDivisors struct { + input uint + expected uint +} + +// getSumOfProperDivisorsTestCases returns an array of test data +// for the tests of the function SumOfProperDivisors. +// Data was verified using [A001065]. +// [A001065]: https://oeis.org/A001065/b001065.txt +func getSumOfProperDivisorsTestCases() []testCaseSumOfProperDivisors { + return []testCaseSumOfProperDivisors{ + {0, 0}, + {1, 0}, + {2, 1}, + {3, 1}, + {4, 3}, + {5, 1}, + {6, 6}, + {7, 1}, + {8, 7}, + {9, 4}, + {10, 8}, + {11, 1}, + {12, 16}, + {13, 1}, + {14, 10}, + {15, 9}, + {16, 15}, + {17, 1}, + {18, 21}, + {19, 1}, + {20, 22}, + {21, 11}, + {22, 14}, + {23, 1}, + {24, 36}, + {25, 6}, + {26, 16}, + {27, 13}, + {28, 28}, + {29, 1}, + {30, 42}, + {31, 1}, + {32, 31}, + {33, 15}, + {34, 20}, + {35, 13}, + {36, 55}, + {37, 1}, + {38, 22}, + {39, 17}, + {40, 50}, + {41, 1}, + {42, 54}, + {43, 1}, + {44, 40}, + {45, 33}, + {46, 26}, + {47, 1}, + {48, 76}, + {49, 8}, + {50, 43}, + {51, 21}, + {52, 46}, + {53, 1}, + {54, 66}, + {55, 17}, + {56, 64}, + {57, 23}, + {58, 32}, + {59, 1}, + {60, 108}, + {800, 1153}, + {8204, 8260}, + {9646, 8498}, + {9756, 14996}, + {9829, 1}, + {9954, 15006}, + {10000, 14211}, + } +} + +func TestSumOfProperDivisors(t *testing.T) { + for _, tc := range getSumOfProperDivisorsTestCases() { + actual := math.SumOfProperDivisors(tc.input) + if actual != tc.expected { + t.Errorf( + "Expected SumOfProperDivisors(%d) to be: %d, but got: %d", + tc.input, tc.expected, actual) + } + } +} + +func BenchmarkSumOfProperDivisors(b *testing.B) { + for i := 0; i < b.N; i++ { + math.SumOfProperDivisors(800) + } +} + +type isPerfectNumberTestCase struct { + number uint + isPerfect bool +} + +// getIsPerfectNumberTestCases returns an array of test data +// for the tests of the function IsPerfectNumber +// Data was verified using [A000396]. +// [A000396]: https://oeis.org/A000396 +func getIsPerfectNumberTestCases() []isPerfectNumberTestCase { + return []isPerfectNumberTestCase{ + {6, true}, + {28, true}, + {496, true}, + {8128, true}, + {33550336, true}, + {0, false}, + {1, false}, + {2, false}, + {3, false}, + {4, false}, + {5, false}, + {7, false}, + {100, false}, + {219, false}, + {997, false}, + {33550335, false}, + {33550337, false}, + } +} + +func TestIsPerfectNumber(t *testing.T) { + for _, tc := range getIsPerfectNumberTestCases() { + if math.IsPerfectNumber(tc.number) != tc.isPerfect { + t.Errorf("Unexpected output for %d", tc.number) + } + } +} + +func BenchmarkIsPerfectNumber(b *testing.B) { + for i := 0; i < b.N; i++ { + math.IsPerfectNumber(8128) + } +} From e2332789099665ac40e83d0c30d964e41a97d692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C5=A9=20H=E1=BA=A3i=20L=C3=A2m?= Date: Thu, 13 Oct 2022 10:07:42 +0700 Subject: [PATCH 368/488] feat:Use generic for radixsort (#566) --- sort/radixsort.go | 22 +++++++++++++++------- sort/sorts_test.go | 4 ++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/sort/radixsort.go b/sort/radixsort.go index 7b731cdb1..4dbd21d64 100644 --- a/sort/radixsort.go +++ b/sort/radixsort.go @@ -1,10 +1,18 @@ +// radixsort.go +// description: Implementation of in-place radixsort algorithm +// details: +// A simple in-place quicksort algorithm implementation. [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort) + package sort -import "github.com/TheAlgorithms/Go/math/max" +import ( + "github.com/TheAlgorithms/Go/constraints" + "github.com/TheAlgorithms/Go/math/max" +) -func countSort(arr []int, exp int) []int { +func countSort[T constraints.Integer](arr []T, exp T) []T { var digits [10]int - var output = make([]int, len(arr)) + var output = make([]T, len(arr)) for _, item := range arr { digits[(item/exp)%10]++ @@ -21,22 +29,22 @@ func countSort(arr []int, exp int) []int { return output } -func unsignedRadixSort(arr []int) []int { +func unsignedRadixSort[T constraints.Integer](arr []T) []T { if len(arr) == 0 { return arr } maxElement := max.Int(arr...) - for exp := 1; maxElement/exp > 0; exp *= 10 { + for exp := T(1); maxElement/exp > 0; exp *= 10 { arr = countSort(arr, exp) } return arr } -func RadixSort(arr []int) []int { +func RadixSort[T constraints.Integer](arr []T) []T { if len(arr) < 1 { return arr } - var negatives, nonNegatives []int + var negatives, nonNegatives []T for _, item := range arr { if item < 0 { diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 1c07ddb2b..34f2966e2 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -112,7 +112,7 @@ func TestShell(t *testing.T) { } func TestRadix(t *testing.T) { - testFramework(t, sort.RadixSort) + testFramework(t, sort.RadixSort[int]) } func TestSimple(t *testing.T) { @@ -217,7 +217,7 @@ func BenchmarkShell(b *testing.B) { } func BenchmarkRadix(b *testing.B) { - benchmarkFramework(b, sort.RadixSort) + benchmarkFramework(b, sort.RadixSort[int]) } func BenchmarkSimple(b *testing.B) { From 3e2af4fc317c1fe3b9807ce0030e3744536fae62 Mon Sep 17 00:00:00 2001 From: Corentin Giaufer Saubert <43623834+CorentinGS@users.noreply.github.com> Date: Thu, 13 Oct 2022 05:08:03 +0200 Subject: [PATCH 369/488] feat: Parallel MergeSort using goroutines (#558) --- sort/mergesort.go | 26 ++++++++++++++++++++++++++ sort/sorts_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/sort/mergesort.go b/sort/mergesort.go index babff39f1..9a875b428 100644 --- a/sort/mergesort.go +++ b/sort/mergesort.go @@ -3,6 +3,7 @@ package sort import ( "github.com/TheAlgorithms/Go/constraints" "github.com/TheAlgorithms/Go/math/min" + "sync" ) func merge[T constraints.Ordered](a []T, b []T) []T { @@ -60,3 +61,28 @@ func MergeIter[T constraints.Ordered](items []T) []T { } return items } + +// ParallelMerge Perform merge sort on a slice using goroutines +func ParallelMerge[T constraints.Ordered](items []T) []T { + if len(items) < 2 { + return items + } + + if len(items) < 2048 { + return Merge(items) + } + + var wg sync.WaitGroup + wg.Add(1) + + var middle = len(items) / 2 + var a []T + go func() { + defer wg.Done() + a = ParallelMerge(items[:middle]) + }() + var b = ParallelMerge(items[middle:]) + + wg.Wait() + return merge(a, b) +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 34f2966e2..3c7e89caa 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -2,8 +2,10 @@ package sort_test import ( "github.com/TheAlgorithms/Go/sort" + "math/rand" "reflect" "testing" + "time" ) func testFramework(t *testing.T, sortingFunction func([]int) []int) { @@ -95,6 +97,26 @@ func TestMergeIter(t *testing.T) { testFramework(t, sort.MergeIter[int]) } +func TestMergeParallel(t *testing.T) { + testFramework(t, sort.ParallelMerge[int]) + + // Test parallel merge sort with a large slice + t.Run("ParallelMerge on large slice", func(t *testing.T) { + rand.Seed(time.Now().UnixNano()) + size := 100000 + randomLargeSlice := make([]int, size) + for i := range randomLargeSlice { + randomLargeSlice[i] = rand.Intn(size) + } + sortedSlice := sort.ParallelMerge[int](randomLargeSlice) + for i := 0; i < len(sortedSlice)-1; i++ { + if sortedSlice[i] > sortedSlice[i+1] { + t.Errorf("ParallelMerge failed") + } + } + }) +} + func TestHeap(t *testing.T) { testFramework(t, sort.HeapSort) } @@ -200,6 +222,10 @@ func BenchmarkMergeIter(b *testing.B) { benchmarkFramework(b, sort.MergeIter[int]) } +func BenchmarkMergeParallel(b *testing.B) { + benchmarkFramework(b, sort.ParallelMerge[int]) +} + func BenchmarkHeap(b *testing.B) { benchmarkFramework(b, sort.HeapSort) } From 942a6885da7710ca79e31fb3abbca1c2f62b03a7 Mon Sep 17 00:00:00 2001 From: Chanwit Piromplad Date: Thu, 13 Oct 2022 16:37:53 +0700 Subject: [PATCH 370/488] feat: add lru cache (#547) * feat: add lru cache * fix: double linkedlist for support LRU cache * fix: move to cache folder * fix: rename function to NewLRU * fix: head in double linkedlist to pointer * Apply suggestions from code review Co-authored-by: Taj Co-authored-by: Taj --- cache/lru.go | 65 +++++++++++++ cache/lru_test.go | 59 ++++++++++++ structure/linkedlist/doubly.go | 143 +++++++++++++++++++--------- structure/linkedlist/doubly_test.go | 14 +-- 4 files changed, 227 insertions(+), 54 deletions(-) create mode 100644 cache/lru.go create mode 100644 cache/lru_test.go diff --git a/cache/lru.go b/cache/lru.go new file mode 100644 index 000000000..d937118f9 --- /dev/null +++ b/cache/lru.go @@ -0,0 +1,65 @@ +package cache + +import ( + "github.com/TheAlgorithms/Go/structure/linkedlist" +) + +type item struct { + key string + value any +} + +type LRU struct { + dl *linkedlist.Doubly[any] + capacity int + maxCapacity int + storage map[string]*linkedlist.Node[any] +} + +// NewLRU represent initiate lru cache with capacity +func NewLRU(capacity int) LRU { + return LRU{ + dl: linkedlist.NewDoubly[any](), + storage: make(map[string]*linkedlist.Node[any], capacity), + capacity: 0, + maxCapacity: capacity, + } +} + +// Get value from lru +// if not found, return nil +func (c *LRU) Get(key string) any { + v, ok := c.storage[key] + if ok { + c.dl.MoveToBack(v) + return v.Val.(item).value + } + + return nil +} + +// Put cache with key and value to lru +func (c *LRU) Put(key string, value any) { + e, ok := c.storage[key] + if ok { + n := e.Val.(item) + n.value = value + e.Val = n + c.dl.MoveToBack(e) + return + } + + if c.capacity >= c.maxCapacity { + e := c.dl.Front() + dk := e.Val.(item).key + c.dl.Remove(e) + delete(c.storage, dk) + c.capacity-- + } + + n := item{key: key, value: value} + c.dl.AddAtEnd(n) + ne := c.dl.Back() + c.storage[key] = ne + c.capacity++ +} diff --git a/cache/lru_test.go b/cache/lru_test.go new file mode 100644 index 000000000..34ab3752b --- /dev/null +++ b/cache/lru_test.go @@ -0,0 +1,59 @@ +package cache_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/cache" +) + +func TestLRU(t *testing.T) { + cache := cache.NewLRU(3) + + t.Run("Test 1: Put number and Get is correct", func(t *testing.T) { + key, value := "1", 1 + cache.Put(key, value) + got := cache.Get(key) + + if got != value { + t.Errorf("expected: %v, got: %v", value, got) + } + }) + + t.Run("Test 2: Get data not stored in cache should return nil", func(t *testing.T) { + got := cache.Get("2") + if got != nil { + t.Errorf("expected: nil, got: %v", got) + } + }) + + t.Run("Test 3: Put data over capacity and Get should return nil", func(t *testing.T) { + cache.Put("2", 2) + cache.Put("3", 3) + cache.Put("4", 4) + + got := cache.Get("1") + if got != nil { + t.Errorf("expected: nil, got: %v", got) + } + }) + + t.Run("test 4: Put key over capacity but recent key exists", func(t *testing.T) { + cache.Put("4", 4) + cache.Put("3", 3) + cache.Put("2", 2) + cache.Put("1", 1) + + got := cache.Get("4") + if got != nil { + t.Errorf("expected: nil, got: %v", got) + } + + expected := 3 + got = cache.Get("3") + + if got != expected { + t.Errorf("expected: %v, got: %v", expected, got) + } + + }) +} diff --git a/structure/linkedlist/doubly.go b/structure/linkedlist/doubly.go index 0550ddba1..a14513751 100644 --- a/structure/linkedlist/doubly.go +++ b/structure/linkedlist/doubly.go @@ -19,83 +19,97 @@ type Doubly[T any] struct { Head *Node[T] } -func NewDoubly[T any]() *Doubly[T] { - return &Doubly[T]{} +// Init initializes double linked list +func (ll *Doubly[T]) Init() *Doubly[T] { + ll.Head = &Node[T]{} + ll.Head.Next = ll.Head + ll.Head.Prev = ll.Head + + return ll } -// AddAtBeg Add a node to the beginning of the linkedlist -func (ll *Doubly[T]) AddAtBeg(val T) { - n := NewNode(val) - n.Next = ll.Head +func NewDoubly[T any]() *Doubly[T] { + return new(Doubly[T]).Init() +} - if ll.Head != nil { - ll.Head.Prev = n +// lazyInit lazily initializes a zero List value. +func (ll *Doubly[T]) lazyInit() { + if ll.Head.Next == nil { + ll.Init() } +} - ll.Head = n +func (ll *Doubly[T]) insert(n, at *Node[T]) *Node[T] { + n.Prev = at + n.Next = at.Next + n.Prev.Next = n + n.Next.Prev = n + return n +} + +func (ll *Doubly[T]) insertValue(val T, at *Node[T]) *Node[T] { + return ll.insert(NewNode(val), at) +} + +// AddAtBeg Add a node to the beginning of the linkedlist +func (ll *Doubly[T]) AddAtBeg(val T) { + ll.lazyInit() + ll.insertValue(val, ll.Head) } // AddAtEnd Add a node at the end of the linkedlist func (ll *Doubly[T]) AddAtEnd(val T) { - n := NewNode(val) + ll.lazyInit() + ll.insertValue(val, ll.Head.Prev) +} - if ll.Head == nil { - ll.Head = n - return - } +func (ll *Doubly[T]) Remove(n *Node[T]) T { + n.Prev.Next = n.Next + n.Next.Prev = n.Prev + n.Next = nil + n.Prev = nil - cur := ll.Head - for ; cur.Next != nil; cur = cur.Next { - } - cur.Next = n - n.Prev = cur + return n.Val } // DelAtBeg Delete the node at the beginning of the linkedlist func (ll *Doubly[T]) DelAtBeg() (T, bool) { - if ll.Head == nil { + // no item + if ll.Head.Next == nil { var r T return r, false } - cur := ll.Head - ll.Head = cur.Next - - if ll.Head != nil { - ll.Head.Prev = nil - } - return cur.Val, true + n := ll.Head.Next + val := n.Val + ll.Remove(n) + return val, true } // DetAtEnd Delete a node at the end of the linkedlist func (ll *Doubly[T]) DelAtEnd() (T, bool) { // no item - if ll.Head == nil { + if ll.Head.Prev == nil { var r T return r, false } - // only one item - if ll.Head.Next == nil { - return ll.DelAtBeg() - } - - // more than one, go to second last - cur := ll.Head - for ; cur.Next.Next != nil; cur = cur.Next { - } - - retval := cur.Next.Val - cur.Next = nil - return retval, true + n := ll.Head.Prev + val := n.Val + ll.Remove(n) + return val, true } // Count Number of nodes in the linkedlist func (ll *Doubly[T]) Count() int { var ctr int = 0 - for cur := ll.Head; cur != nil; cur = cur.Next { + if ll.Head.Next == nil { + return 0 + } + + for cur := ll.Head.Next; cur != ll.Head; cur = cur.Next { ctr += 1 } @@ -120,7 +134,7 @@ func (ll *Doubly[T]) Reverse() { // Display display the linked list func (ll *Doubly[T]) Display() { - for cur := ll.Head; cur != nil; cur = cur.Next { + for cur := ll.Head.Next; cur != ll.Head; cur = cur.Next { fmt.Print(cur.Val, " ") } @@ -133,12 +147,47 @@ func (ll *Doubly[T]) DisplayReverse() { return } var cur *Node[T] - for cur = ll.Head; cur.Next != nil; cur = cur.Next { - } - - for ; cur != nil; cur = cur.Prev { + for cur = ll.Head.Prev; cur != ll.Head; cur = cur.Prev { fmt.Print(cur.Val, " ") } fmt.Print("\n") } + +func (ll *Doubly[T]) Front() *Node[T] { + if ll.Count() == 0 { + return nil + } + + return ll.Head.Next +} + +func (ll *Doubly[T]) Back() *Node[T] { + if ll.Count() == 0 { + return nil + } + + return ll.Head.Prev +} + +func (ll *Doubly[T]) MoveToBack(n *Node[T]) { + if ll.Head.Prev == n { + return + } + + ll.move(n, ll.Head.Prev) +} + +func (ll *Doubly[T]) move(n, at *Node[T]) { + if n == at { + return + } + + n.Prev.Next = n.Next + n.Next.Prev = n.Prev + + n.Prev = at + n.Next = at.Next + n.Prev.Next = n + n.Next.Prev = n +} diff --git a/structure/linkedlist/doubly_test.go b/structure/linkedlist/doubly_test.go index e30663dda..4778be74e 100644 --- a/structure/linkedlist/doubly_test.go +++ b/structure/linkedlist/doubly_test.go @@ -18,11 +18,11 @@ func TestDoubly(t *testing.T) { got := []int{} // check from Next address - current := newList.Head + current := newList.Head.Next got = append(got, current.Val) - for current.Next != nil { + for current.Next != newList.Head { current = current.Next got = append(got, current.Val) } @@ -35,7 +35,7 @@ func TestDoubly(t *testing.T) { got = []int{} got = append(got, current.Val) - for current.Prev != nil { + for current.Prev != newList.Head { current = current.Prev got = append(got, current.Val) } @@ -50,9 +50,9 @@ func TestDoubly(t *testing.T) { t.Run("Test AddAtEnd", func(t *testing.T) { want := []int{3, 2, 1, 4} got := []int{} - current := newList.Head + current := newList.Head.Next got = append(got, current.Val) - for current.Next != nil { + for current.Next != newList.Head { current = current.Next got = append(got, current.Val) } @@ -99,9 +99,9 @@ func TestDoubly(t *testing.T) { want := []int{1, 2, 3} got := []int{} newList2.Reverse() - current := newList2.Head + current := newList2.Head.Next got = append(got, current.Val) - for current.Next != nil { + for current.Next != newList2.Head { current = current.Next got = append(got, current.Val) } From 57d49d59cf8f4d0c494f92c0465cacc66f9316e2 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 15 Oct 2022 11:09:27 +0200 Subject: [PATCH 371/488] refactor: simplity signature of `LongestCommonSubsequence` (#567) * refactor: simplity signature of LongestCommonSubsequence * style: use camelCase * style: remove commented-out code --- dynamic/longestcommonsubsequence.go | 32 +++++++++++------------- dynamic/longestcommonsubsequence_test.go | 9 +++---- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/dynamic/longestcommonsubsequence.go b/dynamic/longestcommonsubsequence.go index 447af9f7f..8ca739811 100644 --- a/dynamic/longestcommonsubsequence.go +++ b/dynamic/longestcommonsubsequence.go @@ -4,19 +4,24 @@ package dynamic +import ( + "unicode/utf8" +) + // LongestCommonSubsequence function -func LongestCommonSubsequence(a string, b string, m int, n int) int { - // m is the length of string a and n is the length of string b +func LongestCommonSubsequence(a string, b string) int { + var aLen = utf8.RuneCountInString(a) + var bLen = utf8.RuneCountInString(b) - // here we are making a 2d slice of size (m+1)*(n+1) - lcs := make([][]int, m+1) - for i := 0; i <= m; i++ { - lcs[i] = make([]int, n+1) + // here we are making a 2d slice of size (aLen+1)*(bLen+1) + lcs := make([][]int, aLen+1) + for i := 0; i <= aLen; i++ { + lcs[i] = make([]int, bLen+1) } // block that implements LCS - for i := 0; i <= m; i++ { - for j := 0; j <= n; j++ { + for i := 0; i <= aLen; i++ { + for j := 0; j <= bLen; j++ { if i == 0 || j == 0 { lcs[i][j] = 0 } else if a[i-1] == b[j-1] { @@ -27,14 +32,5 @@ func LongestCommonSubsequence(a string, b string, m int, n int) int { } } // returning the length of longest common subsequence - return lcs[m][n] + return lcs[aLen][bLen] } - -// func main(){ -// // declaring two strings and asking for input - -// var a,b string -// fmt.Scan(&a, &b) -// // calling the LCS function -// fmt.Println("The length of longest common subsequence is:", longestCommonSubsequence(a,b, len(a), len(b))) -// } diff --git a/dynamic/longestcommonsubsequence_test.go b/dynamic/longestcommonsubsequence_test.go index 361f2b004..1c102c3be 100644 --- a/dynamic/longestcommonsubsequence_test.go +++ b/dynamic/longestcommonsubsequence_test.go @@ -27,15 +27,14 @@ func getLCSTestCases() []testCaseLCS { {"abcdef", "aXbXcXXXdeXXf", 6}, {"", "abc", 0}, {"", "", 0}, + {"££", "££", 2}, } } func TestLongestCommonSubsequence(t *testing.T) { t.Run("Simple test", func(t *testing.T) { for _, tc := range getLCSTestCases() { - actual := dynamic.LongestCommonSubsequence( - tc.stringA, tc.stringB, - len(tc.stringA), len(tc.stringB)) + actual := dynamic.LongestCommonSubsequence(tc.stringA, tc.stringB) if actual != tc.expected { t.Errorf("expected: %d, but got: %d", tc.expected, actual) } @@ -44,9 +43,7 @@ func TestLongestCommonSubsequence(t *testing.T) { t.Run("Symmetry test", func(t *testing.T) { for _, tc := range getLCSTestCases() { - actual := dynamic.LongestCommonSubsequence( - tc.stringB, tc.stringA, - len(tc.stringB), len(tc.stringA)) + actual := dynamic.LongestCommonSubsequence(tc.stringB, tc.stringA) if actual != tc.expected { t.Errorf("expected: %d, but got: %d", tc.expected, actual) } From 03c8ce84d6b45153b4709997c4c1e7d54d5792c4 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 15 Oct 2022 21:50:08 +0200 Subject: [PATCH 372/488] tests: Modular Inverse (#570) * test: add missing test cases * fix: handle the case b == 0 * style: fix typos * style: remove duplicated code * style: rename b to m * style: remove misleading comment --- math/modular/inverse.go | 9 ++++--- math/modular/inverse_test.go | 46 ++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/math/modular/inverse.go b/math/modular/inverse.go index e0aa73b1a..819ffda8d 100644 --- a/math/modular/inverse.go +++ b/math/modular/inverse.go @@ -13,15 +13,14 @@ import ( "github.com/TheAlgorithms/Go/math/gcd" ) -// ErrorIntOverflow For asserting that the values do not overflow in Int64 var ErrorInverse = errors.New("no Modular Inverse exists") // Inverse Modular function -func Inverse(a, b int64) (int64, error) { - gcd, x, _ := gcd.Extended(a, b) - if gcd != 1 { +func Inverse(a, m int64) (int64, error) { + gcd, x, _ := gcd.Extended(a, m) + if gcd != 1 || m == 0 { return 0, ErrorInverse } - return ((b + (x % b)) % b), nil // this is necessary because of Go's use of architecture specific instruction for the % operator. + return ((m + (x % m)) % m), nil // this is necessary because of Go's use of architecture specific instruction for the % operator. } diff --git a/math/modular/inverse_test.go b/math/modular/inverse_test.go index e27166dbc..a8025e97c 100644 --- a/math/modular/inverse_test.go +++ b/math/modular/inverse_test.go @@ -6,24 +6,34 @@ package modular import "testing" +import "fmt" func TestInverse(t *testing.T) { - t.Run("Testing a = 3 and m = 11: ", func(t *testing.T) { - inv, err := Inverse(3, 11) - if err != nil { - t.Fatalf("Error was raised when it shouldn't: %v", err) - } - if inv != 4 { - t.Fatalf("Test failed:\n\tExpected values: %v\n\tReturned value: %v", 4, inv) - } - }) - t.Run("Testing a = 10 and m = 17: ", func(t *testing.T) { - inv, err := Inverse(10, 17) - if err != nil { - t.Fatalf("Error was raised when it shouldn't: %v", err) - } - if inv != 12 { - t.Fatalf("Test failed:\n\tExpected values: %v\n\tReturned value: %v", 12, inv) - } - }) + testCases := []struct { + a int64 + m int64 + expectedValue int64 + expectedError error + }{ + {3, 11, 4, nil}, + {10, 17, 12, nil}, + {2, 6, 0, ErrorInverse}, + {1, 0, 0, ErrorInverse}, + } + for _, tc := range testCases { + testName := fmt.Sprintf("Testing a = %d and m = %d: ", tc.a, tc.m) + t.Run(testName, func(t *testing.T) { + inv, err := Inverse(tc.a, tc.m) + if err != tc.expectedError { + if tc.expectedError == nil { + t.Fatalf("Error was raised when it shouldn't: %v", err) + } else { + t.Fatalf("Error was not raised when it should") + } + } + if inv != tc.expectedValue { + t.Fatalf("expected: %d, got: %d", tc.expectedValue, inv) + } + }) + } } From 6e6d4d7b4b94d4bf8c23b1f4bbdbdb71f767352a Mon Sep 17 00:00:00 2001 From: pnr Date: Sun, 16 Oct 2022 03:35:29 +0700 Subject: [PATCH 373/488] refactor heapsort to support generic (#553) * refactor: generic heapsort * revert: remove generic test * revert: max heap * refactor: make max heap more generic * fix: zero index * revert: generic MaxHeap * revert: heapifyDown --- sort/heapsort.go | 75 ++++++++++++++++++++++++---------------------- sort/sorts_test.go | 4 +-- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/sort/heapsort.go b/sort/heapsort.go index 07a5d9547..741b4e4e8 100644 --- a/sort/heapsort.go +++ b/sort/heapsort.go @@ -1,21 +1,13 @@ package sort +import "github.com/TheAlgorithms/Go/constraints" + type MaxHeap struct { slice []Comparable heapSize int indices map[int]int } -func buildMaxHeap(slice0 []int) MaxHeap { - var slice []Comparable - for _, i := range slice0 { - slice = append(slice, Int(i)) - } - h := MaxHeap{} - h.Init(slice) - return h -} - func (h *MaxHeap) Init(slice []Comparable) { if slice == nil { slice = make([]Comparable, 0) @@ -73,6 +65,16 @@ func (h MaxHeap) updateidx(i int) { h.indices[h.slice[i].Idx()] = i } +func (h *MaxHeap) swap(i, j int) { + h.slice[i], h.slice[j] = h.slice[j], h.slice[i] + h.updateidx(i) + h.updateidx(j) +} + +func (h MaxHeap) more(i, j int) bool { + return h.slice[i].More(h.slice[j]) +} + func (h MaxHeap) heapifyUp(i int) { if i == 0 { return @@ -80,28 +82,29 @@ func (h MaxHeap) heapifyUp(i int) { p := i / 2 if h.slice[i].More(h.slice[p]) { - h.slice[i], h.slice[p] = h.slice[p], h.slice[i] - h.updateidx(i) - h.updateidx(p) + h.swap(i, p) h.heapifyUp(p) } } func (h MaxHeap) heapifyDown(i int) { + heapifyDown(h.slice, h.heapSize, i, h.more, h.swap) +} + +func heapifyDown[T any](slice []T, N, i int, moreFunc func(i, j int) bool, swapFunc func(i, j int)) { l, r := 2*i+1, 2*i+2 max := i - if l < h.heapSize && h.slice[l].More(h.slice[max]) { + if l < N && moreFunc(l, max) { max = l } - if r < h.heapSize && h.slice[r].More(h.slice[max]) { + if r < N && moreFunc(r, max) { max = r } if max != i { - h.slice[i], h.slice[max] = h.slice[max], h.slice[i] - h.updateidx(i) - h.updateidx(max) - h.heapifyDown(max) + swapFunc(i, max) + + heapifyDown(slice, N, max, moreFunc, swapFunc) } } @@ -109,26 +112,26 @@ type Comparable interface { Idx() int More(any) bool } -type Int int -func (a Int) More(b any) bool { - return a > b.(Int) -} -func (a Int) Idx() int { - return int(a) -} +func HeapSort[T constraints.Ordered](slice []T) []T { + N := len(slice) -func HeapSort(slice []int) []int { - h := buildMaxHeap(slice) - for i := len(h.slice) - 1; i >= 1; i-- { - h.slice[0], h.slice[i] = h.slice[i], h.slice[0] - h.heapSize-- - h.heapifyDown(0) + moreFunc := func(i, j int) bool { + return slice[i] > slice[j] + } + swapFunc := func(i, j int) { + slice[i], slice[j] = slice[j], slice[i] + } + + // build a maxheap + for i := N/2 - 1; i >= 0; i-- { + heapifyDown(slice, N, i, moreFunc, swapFunc) } - res := []int{} - for _, i := range h.slice { - res = append(res, int(i.(Int))) + for i := N - 1; i > 0; i-- { + slice[i], slice[0] = slice[0], slice[i] + heapifyDown(slice, i, 0, moreFunc, swapFunc) } - return res + + return slice } diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 3c7e89caa..ecee3d33c 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -118,7 +118,7 @@ func TestMergeParallel(t *testing.T) { } func TestHeap(t *testing.T) { - testFramework(t, sort.HeapSort) + testFramework(t, sort.HeapSort[int]) } func TestCount(t *testing.T) { @@ -227,7 +227,7 @@ func BenchmarkMergeParallel(b *testing.B) { } func BenchmarkHeap(b *testing.B) { - benchmarkFramework(b, sort.HeapSort) + benchmarkFramework(b, sort.HeapSort[int]) } func BenchmarkCount(b *testing.B) { From d61cee077bf76f9bc5c16ee4eb88385d1796b03c Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sun, 16 Oct 2022 10:10:28 +0200 Subject: [PATCH 374/488] tests: math/pi/Spigot (#573) --- math/pi/spigotpi_test.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/math/pi/spigotpi_test.go b/math/pi/spigotpi_test.go index ad845da15..c48b7dc24 100644 --- a/math/pi/spigotpi_test.go +++ b/math/pi/spigotpi_test.go @@ -14,12 +14,22 @@ func TestSpigot(t *testing.T) { result string n int }{ + {"314", 3}, + {"31415", 5}, {"314159", 6}, {"31415926535", 11}, {"314159265358", 12}, {"314159265358979323846", 21}, - {"314", 3}, - {"31415", 5}, + {"3141592653589793238462643", 25}, + {"314159265358979323846264338327950", 33}, + {"31415926535897932384626433832795028841971693993751" + + "05820974944592307816406286208998628034825342117067" + + "98214808651328230664709384460955058223172535940812" + + "84811174502841027019385211055596446229489549303819" + + "64428810975665933446128475648233786783165271201909" + + "14564856692346034861045432664821339360726024914127" + + "37245870066063155881748815209209628292540917153643" + + "678925903600", 362}, } for _, tv := range tests { t.Run(strconv.Itoa(tv.n)+":"+tv.result, func(t *testing.T) { From e63fa32e97b8207f52bc0b2a7fc84855880c3fc0 Mon Sep 17 00:00:00 2001 From: Paulden Date: Wed, 19 Oct 2022 19:26:52 +0800 Subject: [PATCH 375/488] Add Red-Black Tree (#551) --- README.md | 87 ++- structure/avl/avl.go | 220 -------- structure/avl/avl_test.go | 277 ---------- structure/binarysearchtree/bstree.go | 179 ------- structure/binarysearchtree/bstree_test.go | 235 -------- structure/binarysearchtree/node.go | 13 - structure/tree/avl.go | 188 +++++++ structure/tree/avl_test.go | 275 ++++++++++ structure/tree/bstree.go | 78 +++ structure/tree/bstree_test.go | 149 +++++ structure/tree/rbtree.go | 353 ++++++++++++ structure/tree/rbtree_test.go | 220 ++++++++ structure/tree/tree.go | 283 ++++++++++ structure/tree/tree_test.go | 626 ++++++++++++++++++++++ 14 files changed, 2210 insertions(+), 973 deletions(-) delete mode 100644 structure/avl/avl.go delete mode 100644 structure/avl/avl_test.go delete mode 100644 structure/binarysearchtree/bstree.go delete mode 100644 structure/binarysearchtree/bstree_test.go delete mode 100644 structure/binarysearchtree/node.go create mode 100644 structure/tree/avl.go create mode 100644 structure/tree/avl_test.go create mode 100644 structure/tree/bstree.go create mode 100644 structure/tree/bstree_test.go create mode 100644 structure/tree/rbtree.go create mode 100644 structure/tree/rbtree_test.go create mode 100644 structure/tree/tree.go create mode 100644 structure/tree/tree_test.go diff --git a/README.md b/README.md index 66de9cad0..04ef156d0 100644 --- a/README.md +++ b/README.md @@ -56,28 +56,6 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`IsArmstrong`](./math/armstrong/isarmstrong.go#L14): No description provided. ---- -
- avl - ---- - -##### Package avl is a Adelson-Velskii and Landis tree implemnation avl is self-balancing tree, i.e for all node in a tree, height difference between its left and right child will not exceed 1 more information : https://en.wikipedia.org/wiki/AVL_tree - ---- -##### Functions: - -1. [`Delete`](./structure/avl/avl.go#L72): Delete : remove given key from the tree -2. [`Get`](./structure/avl/avl.go#L20): Get : return node with given key -3. [`Insert`](./structure/avl/avl.go#L35): Insert a new item -4. [`NewTree`](./structure/avl/avl.go#L15): NewTree create a new AVL tree - ---- -##### Types - -1. [`Node`](./structure/avl/avl.go#L8): No description provided. - - ---
binary @@ -101,33 +79,6 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 10. [`Sqrt`](./math/binary/sqrt.go#L16): No description provided. 11. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---- -
- binarytree - ---- - -##### Functions: - -1. [`AccessNodesByLayer`](./structure/binarysearchtree/bstree.go#L145): AccessNodesByLayer Function that access nodes layer by layer instead of printing the results as one line. -2. [`BstDelete`](./structure/binarysearchtree/bstree.go#L44): BstDelete removes the node -3. [`InOrder`](./structure/binarysearchtree/bstree.go#L79): Travers the tree in the following order left --> root --> right -4. [`InOrderSuccessor`](./structure/binarysearchtree/bstree.go#L35): InOrderSuccessor Goes to the left -5. [`Insert`](./structure/binarysearchtree/bstree.go#L17): Insert a value in the BSTree -6. [`LevelOrder`](./structure/binarysearchtree/bstree.go#L138): No description provided. -7. [`Max`](./structure/binarysearchtree/bstree.go#L174): Max Function that returns max of two numbers - possibly already declared. -8. [`NewNode`](./structure/binarysearchtree/node.go#L11): NewNode Returns a new pointer to an empty Node -9. [`PostOrder`](./structure/binarysearchtree/bstree.go#L113): Travers the tree in the following order left --> right --> root -10. [`PreOrder`](./structure/binarysearchtree/bstree.go#L96): Travers the tree in the following order root --> left --> right - ---- -##### Types - -1. [`BSTree`](./structure/binarysearchtree/bstree.go#L4): No description provided. - -2. [`Node`](./structure/binarysearchtree/node.go#L4): No description provided. - - ---
caesar @@ -957,6 +908,43 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 2. [`NoTextToEncryptError`](./cipher/transposition/transposition.go#L15): No description provided. +--- +
+ tree + +--- + +##### For more details check out those links below here: Wikipedia article: https://en.wikipedia.org/wiki/Binary_search_tree authors [guuzaa](https://github.com/guuzaa) + +--- +##### Functions: + +1. [`NewAVL`](./structure/tree/avl.go#L13): NewAVL create a novel AVL tree +2. [`NewBinarySearch`](./structure/tree/bstree.go#L18): NewBinarySearch create a novel Binary-Search tree +3. [`NewRB`](./structure/tree/rbtree.go#L23): Create a new Red-Black Tree + +--- +##### Types + +1. [`AVL`](./structure/tree/avl.go#L8): No description provided. + +2. [`BinarySearch`](./structure/tree/bstree.go#L13): No description provided. + +3. [`Node`](./structure/tree/tree.go#L25): No description provided. + +4. [`RB`](./structure/tree/rbtree.go#L18): No description provided. + + +--- +
+ tree_test + +--- + +##### Functions: + +1. [`FuzzRBTree`](./structure/tree/rbtree_test.go#L90): No description provided. + ---
trie @@ -989,6 +977,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Decrypt`](./cipher/xor/xor.go#L19): Decrypt decrypts with Xor encryption 2. [`Encrypt`](./cipher/xor/xor.go#L10): Encrypt encrypts with Xor encryption after converting each character to byte The returned value might not be readable because there is no guarantee which is within the ASCII range If using other type such as string, []int, or some other types, add the statements for converting the type to []byte. +3. [`FuzzXOR`](./cipher/xor/xor_test.go#L108): No description provided. ---
diff --git a/structure/avl/avl.go b/structure/avl/avl.go deleted file mode 100644 index bdb17c81f..000000000 --- a/structure/avl/avl.go +++ /dev/null @@ -1,220 +0,0 @@ -// Package avl is a Adelson-Velskii and Landis tree implemnation -// avl is self-balancing tree, i.e for all node in a tree, height difference -// between its left and right child will not exceed 1 -// more information : https://en.wikipedia.org/wiki/AVL_tree -package avl - -// Node of a tree -type Node struct { - Key int - Height int - Left, Right *Node -} - -// NewTree create a new AVL tree -func NewTree() *Node { - return nil -} - -// Get : return node with given key -func Get(root *Node, key int) *Node { - if root == nil { - return nil - } - if root.Key == key { - return root - } else if root.Key < key { - root = root.Right - } else { - root = root.Left - } - return Get(root, key) -} - -// Insert a new item -func Insert(root **Node, key int) { - if *root == nil { - *root = &Node{ - Key: key, - Height: 1, - } - return - } - if (*root).Key < key { - Insert(&(*root).Right, key) - } else if (*root).Key > key { - Insert(&(*root).Left, key) - } - - // update height - (*root).Height = height(*root) - - bFactor := balanceFactor(*root) - - if bFactor == 2 { // L - bFactor = balanceFactor((*root).Left) - if bFactor == 1 { // LL - llRotation(root) - } else if bFactor == -1 { // LR - lrRotation(root) - } - } else if bFactor == -2 { // R - bFactor = balanceFactor((*root).Right) - if bFactor == 1 { // RL - rlRotation(root) - } else if bFactor == -1 { // RR - rrRotation(root) - } - } -} - -// Delete : remove given key from the tree -func Delete(root **Node, key int) { - if root == nil { - return - } - if (*root).Key < key { - Delete(&(*root).Right, key) - } else if (*root).Key > key { - Delete(&(*root).Left, key) - } else { - // 3 cases - // 1. No Child - // 2. With One Child - // 3. With Two Child - if (*root).Left == nil && (*root).Right == nil { - *root = nil - } else if (*root).Left == nil { - *root = (*root).Right - } else if (*root).Right == nil { - *root = (*root).Left - } else { - minVal := min((*root).Right) - (*root).Key = minVal - Delete(root, minVal) - } - return - } - - // update height - (*root).Height = height(*root) - - bFactor := balanceFactor(*root) - - if bFactor == 2 { // L - switch balanceFactor((*root).Left) { - case 1: // LL - llRotation(root) - case -1: // LR - lrRotation(root) - case 0: // LL OR LR - llRotation(root) - } - } else if bFactor == -2 { // L - switch balanceFactor((*root).Right) { - case 1: // RL - rlRotation(root) - case -1: // RR - rrRotation(root) - case 0: // RL OR RR - rrRotation(root) - } - } -} - -// rotations -// 1. LL -// 2. LR -// 3. RR -// 4. RL -func llRotation(root **Node) { - b := (*root).Left - br := b.Right - b.Right = *root - (*root).Left = br - (*root).Height = height(*root) - b.Height = height(b) - *root = b -} -func lrRotation(root **Node) { - c := (*root).Left.Right - cl := c.Left - cr := c.Right - - c.Left = (*root).Left - c.Right = (*root) - c.Left.Right = cl - - (*root).Left = cr - - (*root).Height = height(*root) - c.Left.Height = height(c.Left) - c.Height = height(c) - - *root = c - -} -func rrRotation(root **Node) { - b := (*root).Right - bl := b.Left - b.Left = *root - - (*root).Right = bl - (*root).Height = height(*root) - b.Height = height(b) - *root = b - -} -func rlRotation(root **Node) { - c := (*root).Right.Left - cl := c.Left - cr := c.Right - - c.Right = (*root).Right - c.Right.Left = cr - c.Left = *root - (*root).Right = cl - - (*root).Height = height(*root) - c.Right.Height = height(c.Right) - c.Height = height(c) - *root = c -} - -// balanceFactor : -ve balance factor means subtree root is heavy toward left -// and +ve balance factor means subtree root is heavy toward right side -func balanceFactor(root *Node) int { - var leftHeight, rightHeight int - if root.Left != nil { - leftHeight = root.Left.Height - } - if root.Right != nil { - rightHeight = root.Right.Height - } - return leftHeight - rightHeight -} - -func height(root *Node) int { - if root == nil { - return 0 - } - var leftHeight, rightHeight int - if root.Left != nil { - leftHeight = root.Left.Height - } - if root.Right != nil { - rightHeight = root.Right.Height - } - max := leftHeight - if rightHeight > leftHeight { - max = rightHeight - } - return 1 + max -} - -func min(root *Node) int { - if root.Left == nil { - return root.Key - } - return min(root.Left) -} diff --git a/structure/avl/avl_test.go b/structure/avl/avl_test.go deleted file mode 100644 index 199d008e7..000000000 --- a/structure/avl/avl_test.go +++ /dev/null @@ -1,277 +0,0 @@ -package avl - -import ( - "testing" -) - -func TestInsert(t *testing.T) { - t.Run("LLRotaion-Test", func(t *testing.T) { - root := NewTree() - Insert(&root, 5) - Insert(&root, 4) - Insert(&root, 3) - - if root.Key != 4 { - t.Errorf("root should have value = 4") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 3 { - t.Errorf("left child should have value = 3") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 5 { - t.Errorf("right child should have value = 5") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - - }) - t.Run("LRRotaion-Test", func(t *testing.T) { - root := NewTree() - Insert(&root, 5) - Insert(&root, 3) - Insert(&root, 4) - - if root.Key != 4 { - t.Errorf("root should have value = 4") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 3 { - t.Errorf("left child should have value = 3") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 5 { - t.Errorf("right child should have value = 5") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - }) - - t.Run("RRRotaion-Test", func(t *testing.T) { - root := NewTree() - Insert(&root, 3) - Insert(&root, 4) - Insert(&root, 5) - - if root.Key != 4 { - t.Errorf("root should have value = 4") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 3 { - t.Errorf("left child should have value = 3") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 5 { - t.Errorf("right child should have value = 5") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - }) - t.Run("RLRotaion-Test", func(t *testing.T) { - root := NewTree() - Insert(&root, 3) - Insert(&root, 5) - Insert(&root, 4) - - if root.Key != 4 { - t.Errorf("root should have value = 4") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 3 { - t.Errorf("left child should have value = 3") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 5 { - t.Errorf("right child should have value = 5") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - }) -} - -func TestDelete(t *testing.T) { - t.Run("LLRotaion-Test", func(t *testing.T) { - root := NewTree() - - Insert(&root, 5) - Insert(&root, 4) - Insert(&root, 3) - Insert(&root, 2) - - Delete(&root, 5) - - if root.Key != 3 { - t.Errorf("root should have value = 3") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 2 { - t.Errorf("left child should have value = 2") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 4 { - t.Errorf("right child should have value = 5") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - }) - - t.Run("LRRotaion-Test", func(t *testing.T) { - root := NewTree() - - Insert(&root, 10) - Insert(&root, 8) - Insert(&root, 6) - Insert(&root, 7) - - Delete(&root, 10) - - if root.Key != 7 { - t.Errorf("root should have value = 7") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 6 { - t.Errorf("left child should have value = 6") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 8 { - t.Errorf("right child should have value = 8") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - - }) - - t.Run("RRRotaion-Test", func(t *testing.T) { - root := NewTree() - - Insert(&root, 2) - Insert(&root, 3) - Insert(&root, 4) - Insert(&root, 5) - - Delete(&root, 2) - - if root.Key != 4 { - t.Errorf("root should have value = 4") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 3 { - t.Errorf("left child should have value = 3") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 5 { - t.Errorf("right child should have value = 5") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - - }) - - t.Run("RLRotaion-Test", func(t *testing.T) { - root := NewTree() - - Insert(&root, 7) - Insert(&root, 6) - Insert(&root, 9) - Insert(&root, 8) - - Delete(&root, 6) - - if root.Key != 8 { - t.Errorf("root should have value = 8") - } - if root.Height != 2 { - t.Errorf("height of root should be = 2") - } - - if root.Left.Key != 7 { - t.Errorf("left child should have value = 7") - } - if root.Left.Height != 1 { - t.Errorf("height of left child should be 1") - } - - if root.Right.Key != 9 { - t.Errorf("right child should have value = 9") - } - if root.Right.Height != 1 { - t.Errorf("height of right should be 1") - } - - }) -} - -func TestGet(t *testing.T) { - - root := NewTree() - - if Get(root, 5) != nil { - t.Error("no item should exists in newly created AVL tree") - } - - Insert(&root, 5) - Insert(&root, 4) - Insert(&root, 3) - - n := Get(root, 4) - if n.Key != 4 { - t.Error("key should be 4") - } - if n.Right.Key != 5 { - t.Error("right child should have value 5") - } - - if n.Left.Key != 3 { - t.Error("left child should have value 3") - } - -} diff --git a/structure/binarysearchtree/bstree.go b/structure/binarysearchtree/bstree.go deleted file mode 100644 index 0e0b511d9..000000000 --- a/structure/binarysearchtree/bstree.go +++ /dev/null @@ -1,179 +0,0 @@ -package binarytree - -// BSTree Returns a binary search tree structure which contains only a root Node -type BSTree struct { - Root *Node -} - -// calculateDepth helper function for BSTree's depth() -func calculateDepth(n *Node, depth int) int { - if n == nil { - return depth - } - return Max(calculateDepth(n.left, depth+1), calculateDepth(n.right, depth+1)) -} - -// Insert a value in the BSTree -func Insert(root *Node, val int) *Node { - if root == nil { - return NewNode(val) - } - if val < root.val { - root.left = Insert(root.left, val) - } else { - root.right = Insert(root.right, val) - } - return root -} - -// Depth returns the calculated depth of a binary saerch tree -func (t *BSTree) Depth() int { - return calculateDepth(t.Root, 0) -} - -// InOrderSuccessor Goes to the left -func InOrderSuccessor(root *Node) *Node { - cur := root - for cur.left != nil { - cur = cur.left - } - return cur -} - -// BstDelete removes the node -func BstDelete(root *Node, val int) *Node { - if root == nil { - return nil - } - if val < root.val { - root.left = BstDelete(root.left, val) - } else if val > root.val { - root.right = BstDelete(root.right, val) - } else { - // this is the node to delete - // node with one child - if root.left == nil { - return root.right - } else if root.right == nil { - return root.left - } else { - n := root.right - d := InOrderSuccessor(n) - d.left = root.left - return root.right - } - } - return root -} - -// InOrder add's children to a node in order left first then right recursively -func inOrderRecursive(n *Node, traversal *[]int) { - if n != nil { - inOrderRecursive(n.left, traversal) - *traversal = append(*traversal, n.val) - inOrderRecursive(n.right, traversal) - } -} - -// Travers the tree in the following order left --> root --> right -func InOrder(root *Node) []int { - traversal := make([]int, 0) - inOrderRecursive(root, &traversal) - return traversal -} - -// PreOrder Preorder -func preOrderRecursive(n *Node, traversal *[]int) { - if n == nil { - return - } - *traversal = append(*traversal, n.val) - preOrderRecursive(n.left, traversal) - preOrderRecursive(n.right, traversal) -} - -// Travers the tree in the following order root --> left --> right -func PreOrder(root *Node) []int { - traversal := make([]int, 0) - preOrderRecursive(root, &traversal) - return traversal -} - -// PostOrder PostOrder -func postOrderRecursive(n *Node, traversal *[]int) { - if n == nil { - return - } - postOrderRecursive(n.left, traversal) - postOrderRecursive(n.right, traversal) - *traversal = append(*traversal, n.val) -} - -// Travers the tree in the following order left --> right --> root -func PostOrder(root *Node) []int { - traversal := make([]int, 0) - postOrderRecursive(root, &traversal) - return traversal -} - -// LevelOrder LevelOrder -func levelOrderRecursive(root *Node, traversal *[]int) { - var q []*Node // queue - var n *Node // temporary node - - q = append(q, root) - - for len(q) != 0 { - n, q = q[0], q[1:] - *traversal = append(*traversal, n.val) - if n.left != nil { - q = append(q, n.left) - } - if n.right != nil { - q = append(q, n.right) - } - } -} - -func LevelOrder(root *Node) []int { - traversal := make([]int, 0) - levelOrderRecursive(root, &traversal) - return traversal -} - -// AccessNodesByLayer Function that access nodes layer by layer instead of printing the results as one line. -func AccessNodesByLayer(root *Node) [][]int { - var res [][]int - if root == nil { - return res - } - var q []*Node - var n *Node - var idx = 0 - q = append(q, root) - - for len(q) != 0 { - res = append(res, []int{}) - qLen := len(q) - for i := 0; i < qLen; i++ { - n, q = q[0], q[1:] - res[idx] = append(res[idx], n.val) - if n.left != nil { - q = append(q, n.left) - } - if n.right != nil { - q = append(q, n.right) - } - } - idx++ - } - return res -} - -// Max Function that returns max of two numbers - possibly already declared. -func Max(a, b int) int { - if a > b { - return a - } - return b -} diff --git a/structure/binarysearchtree/bstree_test.go b/structure/binarysearchtree/bstree_test.go deleted file mode 100644 index f813063c6..000000000 --- a/structure/binarysearchtree/bstree_test.go +++ /dev/null @@ -1,235 +0,0 @@ -package binarytree - -import ( - "reflect" - "testing" -) - -func TestInsert(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - - if root.val != 90 { - t.Errorf("root should have value = 90") - } - - if root.left.val != 80 { - t.Errorf("left child should have value = 80") - } - - if root.right.val != 100 { - t.Errorf("right child should have value = 100") - } - - if BSTree.Depth() != 2 { - t.Errorf("tree should have depth = 1") - } -} - -func TestDelete(t *testing.T) { - t.Run("Delete a node with no child", func(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - - BstDelete(root, 100) - - if root.val != 90 { - t.Errorf("root should have value = 90") - } - - if root.left.val != 80 { - t.Errorf("left child should have value = 80") - } - - if root.right != nil { - t.Errorf("right child should have value = nil") - } - - if BSTree.Depth() != 2 { - t.Errorf("Depth should have value = 2") - } - }) - - t.Run("Delete a node with one child", func(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - Insert(root, 70) - - BstDelete(root, 80) - - if root.val != 90 { - t.Errorf("root should have value = 90") - } - - if root.right.val != 100 { - t.Errorf("right child should have value = 100") - } - - if root.left.val != 70 { - t.Errorf("left child should have value = 70") - } - - if BSTree.Depth() != 2 { - t.Errorf("Depth should have value = 2") - } - }) - - t.Run("Delete a node with two children", func(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - Insert(root, 70) - Insert(root, 85) - - BstDelete(root, 80) - - if root.val != 90 { - t.Errorf("root should have value = 90") - } - - if root.left.val != 85 { - t.Errorf("left child should have value = 85") - } - - if root.right.val != 100 { - t.Errorf("right child should have value = 100") - } - - if BSTree.Depth() != 3 { - t.Errorf("Depth should have value = 3") - } - }) -} - -func TestInOrder(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - Insert(root, 70) - Insert(root, 85) - Insert(root, 95) - Insert(root, 105) - - a := InOrder(root) - b := []int{70, 80, 85, 90, 95, 100, 105} - - if !reflect.DeepEqual(a, b) { - t.Errorf("Nodes should have value = [70 80 85 90 95 100 105]") - } -} - -func TestPreOrder(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - Insert(root, 70) - Insert(root, 85) - Insert(root, 95) - Insert(root, 105) - - a := PreOrder(root) - b := []int{90, 80, 70, 85, 100, 95, 105} - - if !reflect.DeepEqual(a, b) { - t.Errorf("Nodes should have value = [90 80 70 85 100 95 105]") - } -} - -func TestPostOrder(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - Insert(root, 70) - Insert(root, 85) - Insert(root, 95) - Insert(root, 105) - - a := PostOrder(root) - b := []int{70, 85, 80, 95, 105, 100, 90} - - if !reflect.DeepEqual(a, b) { - t.Errorf("Nodes should have value = [70 85 80 95 105 100 90]") - } -} - -func TestLevelOrder(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - Insert(root, 70) - Insert(root, 85) - Insert(root, 95) - Insert(root, 105) - - a := LevelOrder(root) - b := []int{90, 80, 100, 70, 85, 95, 105} - - if !reflect.DeepEqual(a, b) { - t.Errorf("Nodes should have value = [90 80 100 70 85 95 105]") - } -} - -func TestAccessNodesByLayer(t *testing.T) { - BSTree := BSTree{ - Root: NewNode(90), - } - - root := BSTree.Root - - Insert(root, 80) - Insert(root, 100) - Insert(root, 70) - Insert(root, 85) - Insert(root, 95) - Insert(root, 105) - - a := AccessNodesByLayer(root) - b := [][]int{{90}, {80, 100}, {70, 85, 95, 105}} - - if !reflect.DeepEqual(a, b) { - t.Errorf("Nodes should have value = [[90] [80 100] [70 85 95 105]]") - } -} diff --git a/structure/binarysearchtree/node.go b/structure/binarysearchtree/node.go deleted file mode 100644 index 71d37ac8f..000000000 --- a/structure/binarysearchtree/node.go +++ /dev/null @@ -1,13 +0,0 @@ -package binarytree - -// Node structure for Nodes -type Node struct { - val int - left *Node - right *Node -} - -// NewNode Returns a new pointer to an empty Node -func NewNode(val int) *Node { - return &Node{val, nil, nil} -} diff --git a/structure/tree/avl.go b/structure/tree/avl.go new file mode 100644 index 000000000..7cb62d885 --- /dev/null +++ b/structure/tree/avl.go @@ -0,0 +1,188 @@ +package tree + +import ( + "github.com/TheAlgorithms/Go/constraints" + "github.com/TheAlgorithms/Go/math/max" +) + +type AVL[T constraints.Ordered] struct { + *binaryTree[T] +} + +// NewAVL create a novel AVL tree +func NewAVL[T constraints.Ordered]() *AVL[T] { + return &AVL[T]{ + binaryTree: &binaryTree[T]{ + Root: nil, + NIL: nil, + }, + } +} + +// Push a chain of Node's into the AVL Tree +func (avl *AVL[T]) Push(keys ...T) { + for _, k := range keys { + avl.Root = avl.pushHelper(avl.Root, k) + } +} + +// Delete a Node from the AVL Tree +func (avl *AVL[T]) Delete(key T) bool { + if !avl.Has(key) { + return false + } + + avl.Root = avl.deleteHelper(avl.Root, key) + return true +} + +func (avl *AVL[T]) pushHelper(root *Node[T], key T) *Node[T] { + if root == nil { + return &Node[T]{ + Key: key, + Height: 1, + } + } + + switch { + case key < root.Key: + root.Left = avl.pushHelper(root.Left, key) + case key > root.Key: + root.Right = avl.pushHelper(root.Right, key) + default: + return root + } + + // balance the tree + root.Height = avl.height(root) + bFactor := avl.balanceFactor(root) + if bFactor > 1 { + switch { + case key < root.Left.Key: + return avl.rightRotate(root) + case key > root.Left.Key: + root.Left = avl.leftRotate(root.Left) + return avl.rightRotate(root) + } + } + + if bFactor < -1 { + switch { + case key > root.Right.Key: + return avl.leftRotate(root) + case key < root.Right.Key: + root.Right = avl.rightRotate(root.Right) + return avl.leftRotate(root) + } + } + + return root +} + +func (avl *AVL[T]) deleteHelper(root *Node[T], key T) *Node[T] { + if root == nil { + return root + } + + switch { + case key < root.Key: + root.Left = avl.deleteHelper(root.Left, key) + case key > root.Key: + root.Right = avl.deleteHelper(root.Right, key) + default: + if root.Left == nil || root.Right == nil { + tmp := root.Left + if root.Left != nil { + tmp = root.Right + } + + if tmp == nil { + root = nil + } else { + *root = *tmp + } + } else { + tmp := avl.minimum(root.Right) + root.Key = tmp.Key + root.Right = avl.deleteHelper(root.Right, tmp.Key) + } + } + + if root == nil { + return root + } + + // balance the tree + root.Height = avl.height(root) + bFactor := avl.balanceFactor(root) + switch { + case bFactor > 1: + switch { + case avl.balanceFactor(root.Left) >= 0: + return avl.rightRotate(root) + default: + root.Left = avl.leftRotate(root.Left) + return avl.rightRotate(root) + } + case bFactor < -1: + switch { + case avl.balanceFactor(root.Right) <= 0: + return avl.leftRotate(root) + default: + root.Right = avl.rightRotate(root.Right) + return avl.leftRotate(root) + } + } + + return root +} + +func (avl *AVL[T]) height(root *Node[T]) int { + if root == nil { + return 0 + } + + var leftHeight, rightHeight int + if root.Left != nil { + leftHeight = root.Left.Height + } + if root.Right != nil { + rightHeight = root.Right.Height + } + return 1 + max.Int(leftHeight, rightHeight) +} + +// balanceFactor : negative balance factor means subtree Root is heavy toward Left +// and positive balance factor means subtree Root is heavy toward Right side +func (avl *AVL[T]) balanceFactor(root *Node[T]) int { + var leftHeight, rightHeight int + if root.Left != nil { + leftHeight = root.Left.Height + } + if root.Right != nil { + rightHeight = root.Right.Height + } + return leftHeight - rightHeight +} + +func (avl *AVL[T]) leftRotate(root *Node[T]) *Node[T] { + y := root.Right + yl := y.Left + y.Left = root + root.Right = yl + + root.Height = avl.height(root) + y.Height = avl.height(y) + return y +} + +func (avl *AVL[T]) rightRotate(root *Node[T]) *Node[T] { + y := root.Left + yr := y.Right + y.Right = root + root.Left = yr + + root.Height = avl.height(root) + y.Height = avl.height(y) + return y +} diff --git a/structure/tree/avl_test.go b/structure/tree/avl_test.go new file mode 100644 index 000000000..cbbc3581e --- /dev/null +++ b/structure/tree/avl_test.go @@ -0,0 +1,275 @@ +package tree_test + +import ( + "testing" + + bt "github.com/TheAlgorithms/Go/structure/tree" +) + +func TestAVLPush(t *testing.T) { + t.Run("LLRotation-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + tree.Push(5, 4, 3) + + root := tree.Root + if root.Key != 4 { + t.Errorf("Root should have value = 4, not %v", root.Key) + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2, not %d", root.Height) + } + + if root.Left.Key != 3 { + t.Errorf("Left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("Right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + + }) + t.Run("LRRotation-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + tree.Push(5, 3, 4) + + root := tree.Root + if root.Key != 4 { + t.Errorf("Root should have value = 4") + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("Left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("Right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + }) + + t.Run("RRRotation-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + tree.Push(3) + tree.Push(4) + tree.Push(5) + + root := tree.Root + if root.Key != 4 { + t.Errorf("Root should have value = 4") + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("Left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("Right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + }) + t.Run("RLRotaion-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + tree.Push(3) + tree.Push(5) + tree.Push(4) + + root := tree.Root + if root.Key != 4 { + t.Errorf("Root should have value = 4") + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("Left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("Right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + }) +} + +func TestAVLDelete(t *testing.T) { + t.Run("LLRotation-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + + tree.Push(5) + tree.Push(4) + tree.Push(3) + tree.Push(2) + + if !tree.Delete(5) { + t.Errorf("There is a node, whose value is 5") + } + + if tree.Delete(50) { + t.Errorf("There is no node, whose value is 50") + } + + root := tree.Root + if root.Key != 3 { + t.Errorf("Root should have value = 3") + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2") + } + + if root.Left.Key != 2 { + t.Errorf("Left child should have value = 2") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 4 { + t.Errorf("Right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + }) + + t.Run("LRRotation-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + + tree.Push(10) + tree.Push(8) + tree.Push(6) + tree.Push(7) + + if !tree.Delete(10) { + t.Errorf("There is a node, whose value is 10") + } + + if tree.Delete(5) { + t.Errorf("There is no node, whose value is 5") + } + + root := tree.Root + if root.Key != 7 { + t.Errorf("Root should have value = 7") + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2") + } + + if root.Left.Key != 6 { + t.Errorf("Left child should have value = 6") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 8 { + t.Errorf("Right child should have value = 8") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + + }) + + t.Run("RRRotation-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + + tree.Push(2) + tree.Push(3) + tree.Push(4) + tree.Push(5) + + if !tree.Delete(2) { + t.Errorf("There is a node, whose value is 2") + } + + if tree.Delete(15) { + t.Errorf("There is no node, whose value is 15") + } + + root := tree.Root + if root.Key != 4 { + t.Errorf("Root should have value = 4") + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("Left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("Right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + + }) + + t.Run("RLRotaion-Test", func(t *testing.T) { + tree := bt.NewAVL[int]() + + tree.Push(7) + tree.Push(6) + tree.Push(9) + tree.Push(8) + + tree.Delete(6) + + root := tree.Root + if root.Key != 8 { + t.Errorf("Root should have value = 8") + } + if root.Height != 2 { + t.Errorf("Height of Root should be = 2") + } + + if root.Left.Key != 7 { + t.Errorf("Left child should have value = 7") + } + if root.Left.Height != 1 { + t.Errorf("Height of Left child should be 1") + } + + if root.Right.Key != 9 { + t.Errorf("Right child should have value = 9") + } + if root.Right.Height != 1 { + t.Errorf("Height of Right should be 1") + } + + }) +} diff --git a/structure/tree/bstree.go b/structure/tree/bstree.go new file mode 100644 index 000000000..72c0e4da2 --- /dev/null +++ b/structure/tree/bstree.go @@ -0,0 +1,78 @@ +// Binary search tree. +// +// For more details check out those links below here: +// Wikipedia article: https://en.wikipedia.org/wiki/Binary_search_tree +// see bstree.go + +package tree + +import ( + "github.com/TheAlgorithms/Go/constraints" +) + +type BinarySearch[T constraints.Ordered] struct { + *binaryTree[T] +} + +// NewBinarySearch create a novel Binary-Search tree +func NewBinarySearch[T constraints.Ordered]() *BinarySearch[T] { + return &BinarySearch[T]{ + binaryTree: &binaryTree[T]{ + Root: nil, + NIL: nil, + }, + } +} + +// Push a chain of Node's into the BinarySearch +func (t *BinarySearch[T]) Push(keys ...T) { + for _, key := range keys { + t.Root = t.pushHelper(t.Root, key) + } +} + +// Delete removes the node of val +func (t *BinarySearch[T]) Delete(val T) bool { + if !t.Has(val) { + return false + } + t.deleteHelper(t.Root, val) + return true +} + +func (t *BinarySearch[T]) pushHelper(root *Node[T], val T) *Node[T] { + if root == nil { + return &Node[T]{Key: val, Left: nil, Right: nil} + } + if val < root.Key { + root.Left = t.pushHelper(root.Left, val) + } else { + root.Right = t.pushHelper(root.Right, val) + } + return root +} + +func (t *BinarySearch[T]) deleteHelper(root *Node[T], val T) *Node[T] { + if root == nil { + return nil + } + if val < root.Key { + root.Left = t.deleteHelper(root.Left, val) + } else if val > root.Key { + root.Right = t.deleteHelper(root.Right, val) + } else { + // this is the node to delete + // node with one child + if root.Left == nil { + return root.Right + } else if root.Right == nil { + return root.Left + } else { + n := root.Right + d := t.minimum(n) + d.Left = root.Left + return root.Right + } + } + return root +} diff --git a/structure/tree/bstree_test.go b/structure/tree/bstree_test.go new file mode 100644 index 000000000..094406487 --- /dev/null +++ b/structure/tree/bstree_test.go @@ -0,0 +1,149 @@ +package tree_test + +import ( + "testing" + + bt "github.com/TheAlgorithms/Go/structure/tree" +) + +func TestPush(t *testing.T) { + bst := bt.NewBinarySearch[int]() + + bst.Push(90) + bst.Push(80) + bst.Push(100) + + if bst.Root.Key != 90 { + t.Errorf("Root should have value = 90") + } + + if bst.Root.Left.Key != 80 { + t.Errorf("Left child should have value = 80") + } + + if bst.Root.Right.Key != 100 { + t.Errorf("Right child should have value = 100") + } + + if bst.Depth() != 2 { + t.Errorf("tree should have depth = 1") + } +} + +func TestDelete(t *testing.T) { + t.Run("Delete a node with no child", func(t *testing.T) { + bst := bt.NewBinarySearch[int]() + + bst.Push(90) + bst.Push(80) + bst.Push(100) + + if !bst.Delete(100) { + t.Errorf("There is a node, whose value is 100") + } + + if bst.Delete(105) { + t.Errorf("There is no node, whose value is 105") + } + + root := bst.Root + if root.Key != 90 { + t.Errorf("Root should have value = 90") + } + + if root.Left.Key != 80 { + t.Errorf("Left child should have value = 80") + } + + if root.Right != nil { + t.Errorf("Right child should have value = nil") + } + + if bst.Depth() != 2 { + t.Errorf("Depth should have value = 2") + } + + bst.Delete(80) + + if root.Key != 90 { + t.Errorf("Root should have value = 90") + } + + if root.Left != nil { + t.Errorf("Left child should have value = nil") + } + + if bst.Depth() != 1 { + t.Errorf("Depth should have value = 1") + } + }) + + t.Run("Delete a node with one child", func(t *testing.T) { + bst := bt.NewBinarySearch[int]() + + bst.Push(90) + bst.Push(80) + bst.Push(100) + bst.Push(70) + + if bst.Delete(102) { + t.Errorf("There is no node, whose value is 102") + } + + if !bst.Delete(80) { + t.Errorf("There is a node, whose value is 80") + } + + root := bst.Root + if root.Key != 90 { + t.Errorf("Root should have value = 90") + } + + if root.Right.Key != 100 { + t.Errorf("Right child should have value = 100") + } + + if root.Left.Key != 70 { + t.Errorf("Left child should have value = 70") + } + + if bst.Depth() != 2 { + t.Errorf("Depth should have value = 2") + } + }) + + t.Run("Delete a node with two children", func(t *testing.T) { + bst := bt.NewBinarySearch[int]() + + bst.Push(90) + bst.Push(80) + bst.Push(100) + bst.Push(70) + bst.Push(85) + + if !bst.Delete(80) { + t.Errorf("There is a node, whose value is 80") + } + + if bst.Delete(102) { + t.Errorf("There is no node, whose value is 102") + } + + root := bst.Root + if root.Key != 90 { + t.Errorf("Root should have value = 90") + } + + if root.Left.Key != 85 { + t.Errorf("Left child should have value = 85") + } + + if root.Right.Key != 100 { + t.Errorf("Right child should have value = 100") + } + + if bst.Depth() != 3 { + t.Errorf("Depth should have value = 3") + } + }) +} diff --git a/structure/tree/rbtree.go b/structure/tree/rbtree.go new file mode 100644 index 000000000..252c99930 --- /dev/null +++ b/structure/tree/rbtree.go @@ -0,0 +1,353 @@ +// Red-Black Tree is a kind of self-balancing binary search tree. +// Each node stores "Color" ("red" or "black"), used to ensure that the tree remains balanced during insertions and deletions. +// +// For more details check out those links below here: +// Programiz article : https://www.programiz.com/dsa/red-black-tree +// Wikipedia article: https://en.wikipedia.org/wiki/Red_black_tree +// authors [guuzaa](https://github.com/guuzaa) +// see rbtree.go + +package tree + +import ( + "fmt" + + "github.com/TheAlgorithms/Go/constraints" +) + +type RB[T constraints.Ordered] struct { + *binaryTree[T] +} + +// Create a new Red-Black Tree +func NewRB[T constraints.Ordered]() *RB[T] { + leaf := &Node[T]{Color: Black, Left: nil, Right: nil} + return &RB[T]{ + binaryTree: &binaryTree[T]{ + Root: leaf, + NIL: leaf, + }, + } +} + +// Push a chain of Node's into the Red-Black Tree +func (t *RB[T]) Push(keys ...T) { + for _, key := range keys { + t.pushHelper(t.Root, key) + } +} + +// Delete a node of Red-Black Tree +// Returns false if the node does not exist, otherwise returns true. +func (t *RB[T]) Delete(data T) bool { + return t.deleteHelper(t.Root, data) +} + +// Return the Predecessor of the node of Key +// if there is no predecessor, return default value of type T and false +// otherwise return the Key of predecessor and true +func (t *RB[T]) Predecessor(key T) (T, bool) { + node, ok := t.searchTreeHelper(t.Root, key) + if !ok { + return t.NIL.Key, ok + } + return t.predecessorHelper(node) +} + +// Return the Successor of the node of Key +// if there is no successor, return default value of type T and false +// otherwise return the Key of successor and true +func (t *RB[T]) Successor(key T) (T, bool) { + node, ok := t.searchTreeHelper(t.Root, key) + if !ok { + return t.NIL.Key, ok + } + + return t.successorHelper(node) +} + +func (t *RB[T]) pushHelper(x *Node[T], key T) { + node := &Node[T]{ + Key: key, + Left: t.NIL, + Right: t.NIL, + Parent: nil, + Color: Red, + } + + var y *Node[T] + for !t.isNil(x) { + y = x + if node.Key < x.Key { + x = x.Left + } else { + x = x.Right + } + + } + + node.Parent = y + if y == nil { + t.Root = node + } else if node.Key < y.Key { + y.Left = node + } else { + y.Right = node + } + + if node.Parent == nil { + node.Color = Black + return + } + + if node.Parent.Parent == nil { + return + } + + t.pushFix(node) +} + +func (t *RB[T]) leftRotate(x *Node[T]) { + y := x.Right + x.Right = y.Left + + if !t.isNil(y.Left) { + y.Left.Parent = x + } + + y.Parent = x.Parent + if x.Parent == nil { + t.Root = y + } else if x == x.Parent.Left { + x.Parent.Left = y + } else { + x.Parent.Right = y + } + + y.Left = x + x.Parent = y +} + +func (t *RB[T]) rightRotate(x *Node[T]) { + y := x.Left + x.Left = y.Right + if !t.isNil(y.Right) { + y.Right.Parent = x + } + + y.Parent = x.Parent + if x.Parent == nil { + t.Root = y + } else if x == y.Parent.Right { + y.Parent.Right = y + } else { + y.Parent.Left = y + } + + y.Right = x + x.Parent = y +} + +func (t *RB[T]) pushFix(k *Node[T]) { + var u *Node[T] + for k.Parent.Color == Red { + if k.Parent == k.Parent.Parent.Right { + u = k.Parent.Parent.Left + if u != nil && u.Color == Red { + u.Color = Black + k.Parent.Color = Black + k.Parent.Parent.Color = Red + k = k.Parent.Parent + } else { + if k == k.Parent.Left { + k = k.Parent + t.rightRotate(k) + } + k.Parent.Color = Black + k.Parent.Parent.Color = Red + t.leftRotate(k.Parent.Parent) + } + } else { + u = k.Parent.Parent.Right + if u != nil && u.Color == Red { + u.Color = Black + k.Parent.Color = Black + k.Parent.Parent.Color = Red + k = k.Parent.Parent + } else { + if k == k.Parent.Right { + k = k.Parent + t.leftRotate(k) + } + k.Parent.Color = Black + k.Parent.Parent.Color = Red + t.rightRotate(k.Parent.Parent) + } + } + if k == t.Root { + break + } + } + + t.Root.Color = Black +} + +func (t *RB[T]) deleteHelper(node *Node[T], key T) bool { + z := t.NIL + for !t.isNil(node) { + switch { + case node.Key == key: + z = node + fallthrough + case node.Key <= key: + node = node.Right + case node.Key > key: + node = node.Left + } + } + + if t.isNil(z) { + fmt.Println("Key not found in the tree") + return false + } + + var x *Node[T] + y := z + yOriginColor := y.Color + if t.isNil(z.Left) { + x = z.Right + t.rbTransplant(z, z.Right) + } else if t.isNil(z.Right) { + x = z.Left + t.rbTransplant(z, z.Left) + } else { + y = t.minimum(z.Right) + yOriginColor = y.Color + x = y.Right + if y.Parent == z { + x.Parent = y + } else { + t.rbTransplant(y, y.Right) + y.Right = z.Right + y.Right.Parent = y + } + + t.rbTransplant(z, y) + y.Left = z.Left + y.Left.Parent = y + y.Color = z.Color + } + + if yOriginColor == Black { + t.deleteFix(x) + } + + return true +} + +func (t *RB[T]) deleteFix(x *Node[T]) { + var s *Node[T] + for x != t.Root && x.Color == Black { + if x == x.Parent.Left { + s = x.Parent.Right + if s.Color == Red { + s.Color = Black + x.Parent.Color = Red + t.leftRotate(x.Parent) + s = x.Parent.Right + } + + if s.Left.Color == Black && s.Right.Color == Black { + s.Color = Red + x = x.Parent + } else { + if s.Right.Color == Black { + s.Left.Color = Black + s.Color = Red + t.rightRotate(s) + s = x.Parent.Right + } + + s.Color = x.Parent.Color + x.Parent.Color = Black + s.Right.Color = Black + t.leftRotate(x.Parent) + x = t.Root + } + } else { + s = x.Parent.Left + if s.Color == Red { + s.Color = Black + x.Parent.Color = Red + t.rightRotate(x.Parent) + s = x.Parent.Left + } + + if s.Right.Color == Black && s.Left.Color == Black { + s.Color = Red + x = x.Parent + } else { + if s.Left.Color == Black { + s.Right.Color = Black + s.Color = Red + t.leftRotate(s) + s = x.Parent.Left + } + + s.Color = x.Parent.Color + x.Parent.Color = Black + s.Left.Color = Black + t.rightRotate(x.Parent) + x = t.Root + } + } + } + + x.Color = Black +} + +func (t *RB[T]) rbTransplant(u, v *Node[T]) { + switch { + case u.Parent == nil: + t.Root = v + case u == u.Parent.Left: + u.Parent.Left = v + default: + u.Parent.Right = v + } + v.Parent = u.Parent +} + +func (t *RB[T]) predecessorHelper(node *Node[T]) (T, bool) { + if !t.isNil(node.Left) { + return t.maximum(node.Left).Key, true + } + + p := node.Parent + for p != nil && !t.isNil(p) && node == p.Left { + node = p + p = p.Parent + } + + if p == nil { + return t.NIL.Key, false + } + return p.Key, true +} + +func (t *RB[T]) successorHelper(node *Node[T]) (T, bool) { + if !t.isNil(node.Right) { + return t.minimum(node.Right).Key, true + } + + p := node.Parent + for p != nil && !t.isNil(p) && node == p.Right { + node = p + p = p.Parent + } + + if p == nil { + return t.NIL.Key, false + } + return p.Key, true +} diff --git a/structure/tree/rbtree_test.go b/structure/tree/rbtree_test.go new file mode 100644 index 000000000..25a8c37e1 --- /dev/null +++ b/structure/tree/rbtree_test.go @@ -0,0 +1,220 @@ +package tree_test + +import ( + "math/rand" + "sort" + "testing" + "time" + + bt "github.com/TheAlgorithms/Go/structure/tree" +) + +func TestRBTreePush(t *testing.T) { + tree := bt.NewRB[int]() + + ret := tree.InOrder() + + if !sort.IntsAreSorted(ret) || len(ret) != 0 { + t.Errorf("Error with Push: %v", ret) + } + + if r, ok := tree.Min(); ok { + t.Errorf("Error with Min: %v", r) + } + + if r, ok := tree.Max(); ok { + t.Errorf("Error with Max: %v", r) + } + + nums := []int{10, 8, 88, 888, 4, 1<<63 - 1, -(1 << 62), 188, -188, 4, 88, 1 << 32} + + tree.Push(nums...) + + ret = tree.InOrder() + + if !sort.IntsAreSorted(ret) || len(ret) != len(nums) { + t.Errorf("Error with Push: %v", ret) + } + + if r, ok := tree.Min(); !ok || ret[0] != r { + t.Errorf("Error with Min: %v", r) + } + + if r, ok := tree.Max(); !ok || ret[len(ret)-1] != r { + t.Errorf("Error with Max: %v", r) + } +} + +func TestRBTreeDelete(t *testing.T) { + tree := bt.NewRB[int]() + var ok bool + + nums := []int{10, 8, 88, 888, 4, 1<<63 - 1, -(1 << 62), 188, -188, 4, 88, 1 << 32} + tree.Push(nums...) + + ok = tree.Delete(188) + + if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-1 { + t.Errorf("Error with Delete: %v", ret) + } + + ok = tree.Delete(188) + if ret := tree.InOrder(); ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-1 { + t.Errorf("Error with Delete: %v", ret) + } + + ok = tree.Delete(1<<63 - 1) + if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-2 { + t.Errorf("Error with Delete: %v", ret) + } + + ok = tree.Delete(4) + if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-3 { + t.Errorf("Error with Delete: %v", ret) + } + + ok = tree.Delete(4) + if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-4 { + t.Errorf("Error with Delete: %v", ret) + } + + if ret, ok := tree.Max(); !ok || ret != (1<<32) { + t.Errorf("Error with Delete, max: %v, want: %v", ret, (1 << 32)) + } + + if ret, ok := tree.Min(); !ok || ret != -(1<<62) { + t.Errorf("Error with Delete, min: %v, want: %v", ret, (1 << 32)) + } +} + +func FuzzRBTree(f *testing.F) { + testcases := []int{100, 200, 1000, 10000} + for _, tc := range testcases { + f.Add(tc) + } + + f.Fuzz(func(t *testing.T, a int) { + rand.Seed(time.Now().Unix()) + tree := bt.NewRB[int]() + nums := rand.Perm(a) + tree.Push(nums...) + + rets := tree.InOrder() + if !sort.IntsAreSorted(rets) { + t.Error("Error with Push") + } + + if res, ok := tree.Min(); !ok || res != rets[0] { + t.Errorf("Error with Min, get %d, want: %d", res, rets[0]) + } + + if res, ok := tree.Max(); !ok || res != rets[a-1] { + t.Errorf("Error with Max, get %d, want: %d", res, rets[a-1]) + } + + for i := 0; i < a-1; i++ { + ok := tree.Delete(nums[i]) + rets = tree.InOrder() + if !ok || !sort.IntsAreSorted(rets) { + t.Errorf("Error With Delete") + } + } + }) +} + +func TestRBTreePredecessorAndSuccessor(t *testing.T) { + tree := bt.NewRB[int]() + + nums := []int{10, 8, 88, 888, 4, -1, 100} + tree.Push(nums...) + + if ret, ok := tree.Predecessor(100); !ok && ret == 88 { + t.Errorf("Error with Predecessor") + } + + if _, ok := tree.Predecessor(-1); ok { + t.Errorf("Error with Predecessor") + } + + if _, ok := tree.Predecessor(-12); ok { + t.Errorf("Error with Predecessor") + } + + if ret, ok := tree.Predecessor(4); !ok && ret == -1 { + t.Errorf("Error with Predecessor") + } + + if ret, ok := tree.Successor(4); !ok && ret == 8 { + t.Errorf("Error with Successor") + } + + if ret, ok := tree.Successor(8); !ok && ret == 88 { + t.Errorf("Error with Successor") + } + + if ret, ok := tree.Successor(88); !ok && ret == 100 { + t.Errorf("Error with Successor") + } + + if ret, ok := tree.Successor(100); !ok && ret == 888 { + t.Errorf("Error with Successor") + } + + if ret, ok := tree.Successor(-1); !ok && ret == 4 { + t.Errorf("Error with Successor") + } + + if _, ok := tree.Successor(888); ok { + t.Errorf("Error with Successor") + } + + if _, ok := tree.Successor(188); ok { + t.Errorf("Error with Successor") + } +} + +func TestRBTreeString(t *testing.T) { + tree := bt.NewRB[string]() + + if tree.Has("Golang") { + t.Errorf("Error with Has when T is string.") + } + + strs := []string{"Hello", "World", "Golang", "Python", "Rust", "C", "JavaScript", "Haskell", "Pascal", "ZZ"} + for _, str := range strs { + tree.Push(str) + } + + if !tree.Has("Golang") { + t.Errorf("Error with Has when T is string.") + } + + if tree.Has("Pasc") { + t.Errorf("Error with Has when T is string.") + } + + if ok := tree.Delete("Hello"); !ok { + t.Errorf("Error with Delete when T is string.") + } + + if ok := tree.Delete("Pasc"); ok { + t.Errorf("Error with Delete when T is string.") + } + + if tree.Has("Hello") { + t.Errorf("Error with Has when T is string.") + } + + ret := tree.InOrder() + if !sort.StringsAreSorted(ret) { + t.Errorf("Error with Push when T is string") + } + + if ret, ok := tree.Min(); !ok || ret != "C" { + t.Errorf("Error with Min when T is string") + } + + if ret, ok := tree.Max(); !ok || ret != "ZZ" { + t.Errorf("Error with Max when T is string") + } +} diff --git a/structure/tree/tree.go b/structure/tree/tree.go new file mode 100644 index 000000000..b7ec06fc8 --- /dev/null +++ b/structure/tree/tree.go @@ -0,0 +1,283 @@ +// Binary-Search tree is the tree, with the key of each internal node +// being greater than keys in the respective node's left subtree +// and less than the ones in its right subtree. + +// For more details check out those links below here: +// Wikipedia article: https://en.wikipedia.org/wiki/Binary_search_tree +// authors [guuzaa](https://github.com/guuzaa) +package tree + +import ( + "fmt" + + "github.com/TheAlgorithms/Go/constraints" + "github.com/TheAlgorithms/Go/math/max" +) + +type Color byte + +const ( + Red Color = iota + Black +) + +// Node of a binary tree +type Node[T constraints.Ordered] struct { + Key T + Parent *Node[T] // for Red-Black Tree + Left *Node[T] + Right *Node[T] + Color Color // for Red-Black Tree + Height int // for AVL Tree +} + +// binaryTree is a base-struct for BinarySearch, AVL, RB, etc. +// Note: to avoid instantiation, we make the base struct un-exported. +type binaryTree[T constraints.Ordered] struct { + Root *Node[T] + NIL *Node[T] // NIL denotes the leaf node of Red-Black Tree +} + +// Get a Node from the binary-search Tree +func (t *binaryTree[T]) Get(key T) (*Node[T], bool) { + return t.searchTreeHelper(t.Root, key) +} + +// Determines the tree has the node of Key +func (t *binaryTree[T]) Has(key T) bool { + _, ok := t.searchTreeHelper(t.Root, key) + return ok +} + +// Traverses the tree in the following order Root --> Left --> Right +func (t *binaryTree[T]) PreOrder() []T { + traversal := make([]T, 0) + t.preOrderRecursive(t.Root, &traversal) + return traversal +} + +// Traverses the tree in the following order Left --> Root --> Right +func (t *binaryTree[T]) InOrder() []T { + return t.inOrderHelper(t.Root) +} + +// Traverses the tree in the following order Left --> Right --> Root +func (t *binaryTree[T]) PostOrder() []T { + traversal := make([]T, 0) + t.postOrderRecursive(t.Root, &traversal) + return traversal +} + +// Depth returns the calculated depth of a binary search tree +func (t *binaryTree[T]) Depth() int { + return t.calculateDepth(t.Root, 0) +} + +// Returns the Max value of the tree +func (t *binaryTree[T]) Max() (T, bool) { + ret := t.maximum(t.Root) + if t.isNil(ret) { + return t.NIL.Key, false + } + + return ret.Key, true +} + +// Return the Min value of the tree +func (t *binaryTree[T]) Min() (T, bool) { + ret := t.minimum(t.Root) + if t.isNil(ret) { + return t.NIL.Key, false + } + + return ret.Key, true +} + +// LevelOrder returns the level order traversal of the tree +func (t *binaryTree[T]) LevelOrder() []T { + traversal := make([]T, 0) + t.levelOrderHelper(t.Root, &traversal) + return traversal +} + +// AccessNodesByLayer accesses nodes layer by layer (2-D array), instead of printing the results as 1-D array. +func (t *binaryTree[T]) AccessNodesByLayer() [][]T { + root := t.Root + if t.isNil(root) { + return [][]T{} + } + var q []*Node[T] + var n *Node[T] + var idx = 0 + q = append(q, root) + var res [][]T + + for len(q) != 0 { + res = append(res, []T{}) + qLen := len(q) + for i := 0; i < qLen; i++ { + n, q = q[0], q[1:] + res[idx] = append(res[idx], n.Key) + if !t.isNil(n.Left) { + q = append(q, n.Left) + } + if !t.isNil(n.Right) { + q = append(q, n.Right) + } + } + idx++ + } + return res +} + +// Print the tree horizontally +func (t *binaryTree[T]) Print() { + t.printHelper(t.Root, "", false) +} + +// Determines node is a leaf node +func (t *binaryTree[T]) isNil(node *Node[T]) bool { + return node == t.NIL +} + +func (t *binaryTree[T]) searchTreeHelper(node *Node[T], key T) (*Node[T], bool) { + if node == nil || t.isNil(node) { + return node, false + } + + if key == node.Key { + return node, true + } + + if key < node.Key { + return t.searchTreeHelper(node.Left, key) + } + return t.searchTreeHelper(node.Right, key) +} + +// The iterative inorder; +// The recursive way is similar to the preOrderRecursive +func (t *binaryTree[T]) inOrderHelper(node *Node[T]) []T { + var stack []*Node[T] + var ret []T + + for !t.isNil(node) || len(stack) > 0 { + for !t.isNil(node) { + stack = append(stack, node) + node = node.Left + } + + node = stack[len(stack)-1] + stack = stack[:len(stack)-1] + ret = append(ret, node.Key) + node = node.Right + } + + return ret +} + +func (t *binaryTree[T]) preOrderRecursive(n *Node[T], traversal *[]T) { + if t.isNil(n) { + return + } + + *traversal = append(*traversal, n.Key) + t.preOrderRecursive(n.Left, traversal) + t.preOrderRecursive(n.Right, traversal) +} + +func (t *binaryTree[T]) postOrderRecursive(n *Node[T], traversal *[]T) { + if t.isNil(n) { + return + } + + t.postOrderRecursive(n.Left, traversal) + t.postOrderRecursive(n.Right, traversal) + *traversal = append(*traversal, n.Key) +} + +func (t *binaryTree[T]) calculateDepth(n *Node[T], depth int) int { + if t.isNil(n) { + return depth + } + + return max.Int(t.calculateDepth(n.Left, depth+1), t.calculateDepth(n.Right, depth+1)) +} + +// Returns the minimum value of node of the tree +func (t *binaryTree[T]) minimum(node *Node[T]) *Node[T] { + if t.isNil(node) { + return node + } + + for !t.isNil(node.Left) { + node = node.Left + } + return node +} + +// Returns the maximum value of node of the tree +func (t *binaryTree[T]) maximum(node *Node[T]) *Node[T] { + if t.isNil(node) { + return node + } + + for !t.isNil(node.Right) { + node = node.Right + } + return node +} + +func (t *binaryTree[T]) levelOrderHelper(root *Node[T], traversal *[]T) { + var q []*Node[T] // queue + var tmp *Node[T] + + q = append(q, root) + + for len(q) != 0 { + tmp, q = q[0], q[1:] + *traversal = append(*traversal, tmp.Key) + if !t.isNil(tmp.Left) { + q = append(q, tmp.Left) + } + + if !t.isNil(tmp.Right) { + q = append(q, tmp.Right) + } + } +} + +// Reference: https://stackoverflow.com/a/51730733/15437172 +func (t *binaryTree[T]) printHelper(root *Node[T], indent string, isLeft bool) { + if t.isNil(root) { + return + } + + fmt.Print(indent) + if isLeft { + fmt.Print("├──") + indent += "│ " + } else { + fmt.Print("└──") + indent += " " + } + + if t.isRBTree() { + color := "Black" + if root.Color == Red { + color = "Red" + } + + fmt.Println(root.Key, "(", color, ")") + } else { + fmt.Println(root.Key) + } + + t.printHelper(root.Left, indent, true) + t.printHelper(root.Right, indent, false) +} + +// Determines the tree is RB +func (t *binaryTree[T]) isRBTree() bool { + return t.NIL != nil +} diff --git a/structure/tree/tree_test.go b/structure/tree/tree_test.go new file mode 100644 index 000000000..2426e57e6 --- /dev/null +++ b/structure/tree/tree_test.go @@ -0,0 +1,626 @@ +package tree_test + +import ( + "math/rand" + "reflect" + "sort" + "testing" + + bt "github.com/TheAlgorithms/Go/structure/tree" +) + +func TestTreeGetOrHas(t *testing.T) { + lens := []int{100, 1_000, 10_000, 100_000} + for _, ll := range lens { + nums := rand.Perm(ll) + t.Run("Test Binary Search Tree", func(t *testing.T) { + bsTree := bt.NewBinarySearch[int]() + bsTree.Push(nums...) + for _, num := range nums { + if !bsTree.Has(num) { + t.Errorf("Error with Has or Push method") + } + } + min, _ := bsTree.Min() + max, _ := bsTree.Max() + + if _, ok := bsTree.Get(min - 1); ok { + t.Errorf("Error with Get method") + } + + if _, ok := bsTree.Get(max + 1); ok { + t.Errorf("Error with Get method") + } + }) + + t.Run("Test Red-Black Tree", func(t *testing.T) { + rbTree := bt.NewRB[int]() + rbTree.Push(nums...) + for _, num := range nums { + if !rbTree.Has(num) { + t.Errorf("Error with Has or Push method") + } + } + }) + + t.Run("Test AVL Tree", func(t *testing.T) { + avlTree := bt.NewAVL[int]() + avlTree.Push(nums...) + for _, num := range nums { + if !avlTree.Has(num) { + t.Errorf("Error with Has or Push method") + } + } + }) + } +} + +func TestTreePreOrder(t *testing.T) { + t.Run("Test for Binary-Search Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{90, 80, 70, 85, 100, 95, 105}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, []int{90, 80, 70, 1, 21, 31, 41, 51, 61, 71, 85, 100, 95, 105}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}}, + } + for _, tt := range tests { + tree := bt.NewBinarySearch[int]() + tree.Push(tt.input...) + if ret := tree.PreOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("Error with PreOrder") + } + } + }) + + t.Run("Test for AVL Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{90, 80, 70, 85, 100, 95, 105}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, []int{70, 41, 21, 1, 31, 51, 61, 90, 80, 71, 85, 100, 95, 105}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{7, 3, 2, 1, 5, 4, 6, 9, 8, 10}}, + } + for _, tt := range tests { + tree := bt.NewAVL[int]() + tree.Push(tt.input...) + if ret := tree.PreOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("Error with PreOrder") + } + } + }) + + t.Run("Test for Red-Black Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{90, 80, 70, 85, 100, 95, 105}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, []int{80, 41, 21, 1, 31, 61, 51, 70, 71, 90, 85, 100, 95, 105}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{7, 5, 3, 2, 1, 4, 6, 9, 8, 10}}, + } + for _, tt := range tests { + tree := bt.NewRB[int]() + tree.Push(tt.input...) + if ret := tree.PreOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("Error with PreOrder") + } + } + }) +} + +func TestTreeInOrder(t *testing.T) { + lens := []int{100, 1_000, 10_000, 100_000} + for _, ll := range lens { + nums := rand.Perm(ll) + + t.Run("Test Binary Search Tree", func(t *testing.T) { + bsTree := bt.NewBinarySearch[int]() + bsTree.Push(nums...) + if ret := bsTree.InOrder(); !sort.IntsAreSorted(ret) { + t.Errorf("Error with InOrder") + } + }) + + t.Run("Test Red-Black Tree", func(t *testing.T) { + rbTree := bt.NewRB[int]() + rbTree.Push(nums...) + if ret := rbTree.InOrder(); !sort.IntsAreSorted(ret) { + t.Errorf("Error with InOrder") + } + }) + + t.Run("Test AVL Tree", func(t *testing.T) { + avlTree := bt.NewAVL[int]() + avlTree.Push(nums...) + if ret := avlTree.InOrder(); !sort.IntsAreSorted(ret) { + t.Errorf("Error with InOrder") + } + }) + } +} + +func TestTreePostOrder(t *testing.T) { + t.Run("Test for Binary-Search Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{61, 51, 41, 31, 21, 1, 71, 70, 85, 80, 95, 105, 100, 90}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + } + for i, tt := range tests { + tree := bt.NewBinarySearch[int]() + tree.Push(tt.input...) + if ret := tree.PostOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with Post", i) + } + } + }) + + t.Run("Test for AVL Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{1, 31, 21, 61, 51, 41, 71, 85, 80, 95, 105, 100, 90, 70}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 4, 6, 5, 3, 8, 10, 9, 7}}, + } + for i, tt := range tests { + tree := bt.NewAVL[int]() + tree.Push(tt.input...) + if ret := tree.PostOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with PostOrder", i) + } + } + }) + + t.Run("Test for Red-Black Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{1, 31, 21, 51, 71, 70, 61, 41, 85, 95, 105, 100, 90, 80}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 4, 3, 6, 5, 8, 10, 9, 7}}, + } + for i, tt := range tests { + tree := bt.NewRB[int]() + tree.Push(tt.input...) + if ret := tree.PostOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with PostOrder", i) + } + } + }) +} + +func TestTreeLevelOrder(t *testing.T) { + t.Run("Test for Binary-Search Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{90, 80, 100, 70, 85, 95, 105}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{90, 80, 100, 70, 85, 95, 105, 1, 71, 21, 31, 41, 51, 61}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}}, + } + for i, tt := range tests { + tree := bt.NewBinarySearch[int]() + tree.Push(tt.input...) + if ret := tree.LevelOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with LevelOrder", i) + } + } + }) + + t.Run("Test for AVL Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{90, 80, 100, 70, 85, 95, 105}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{70, 41, 90, 21, 51, 80, 100, 1, 31, 61, 71, 85, 95, 105}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{7, 3, 9, 2, 5, 8, 10, 1, 4, 6}}, + } + for i, tt := range tests { + tree := bt.NewAVL[int]() + tree.Push(tt.input...) + if ret := tree.LevelOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with LevelOrder", i) + } + } + }) + + t.Run("Test for Red-Black Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{90, 80, 100, 70, 85, 95, 105}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{80, 41, 90, 21, 61, 85, 100, 1, 31, 51, 70, 95, 105, 71}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{7, 5, 9, 3, 6, 8, 10, 2, 4, 1}}, + } + for i, tt := range tests { + tree := bt.NewRB[int]() + tree.Push(tt.input...) + if ret := tree.LevelOrder(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with LevelOrder %v", i, ret) + } + } + }) +} + +func TestTreeMinAndMax(t *testing.T) { + lens := []int{500, 1_000, 10_000} + for _, ll := range lens { + nums := rand.Perm(ll) + sort.Ints(nums) + + t.Run("Test Binary Search Tree", func(t *testing.T) { + bsTree := bt.NewBinarySearch[int]() + bsTree.Push(nums...) + if min, ok := bsTree.Min(); !ok || min != nums[0] { + t.Errorf("Error with Min method.") + } + if max, ok := bsTree.Max(); !ok || max != nums[ll-1] { + t.Errorf("Error with Max method.") + } + }) + + t.Run("Test Red-Black Tree", func(t *testing.T) { + rbTree := bt.NewRB[int]() + rbTree.Push(nums...) + if min, ok := rbTree.Min(); !ok || min != nums[0] { + t.Errorf("Error with Min method.") + } + if max, ok := rbTree.Max(); !ok || max != nums[ll-1] { + t.Errorf("Error with Max method.") + } + }) + + t.Run("Test AVL Tree", func(t *testing.T) { + avlTree := bt.NewAVL[int]() + avlTree.Push(nums...) + if min, ok := avlTree.Min(); !ok || min != nums[0] { + t.Errorf("Error with Min method.") + } + + if max, ok := avlTree.Max(); !ok || max != nums[ll-1] { + t.Errorf("Error with Max method.") + } + }) + } +} + +func TestTreeDepth(t *testing.T) { + t.Run("Test for Binary-Search Tree", func(t *testing.T) { + tests := []struct { + input []int + want int + }{ + {[]int{}, 0}, + {[]int{90, 80, 100, 70, 85, 95, 105}, 3}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, 9}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 10}, + } + for _, tt := range tests { + tree := bt.NewBinarySearch[int]() + tree.Push(tt.input...) + if ret := tree.Depth(); ret != tt.want { + t.Errorf("Error with Depth") + } + } + }) + + t.Run("Test for AVL Tree", func(t *testing.T) { + tests := []struct { + input []int + want int + }{ + {[]int{}, 0}, + {[]int{90, 80, 100, 70, 85, 95, 105}, 3}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, 4}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 4}, + } + for i, tt := range tests { + tree := bt.NewAVL[int]() + tree.Push(tt.input...) + if ret := tree.Depth(); ret != tt.want { + t.Errorf("#%d Error with Depth", i) + } + } + }) + + t.Run("Test for Red-Black Tree", func(t *testing.T) { + tests := []struct { + input []int + want int + }{ + {[]int{}, 0}, + {[]int{90, 80, 100, 70, 85, 95, 105}, 3}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, 5}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, 5}, + } + for i, tt := range tests { + tree := bt.NewRB[int]() + tree.Push(tt.input...) + if ret := tree.Depth(); ret != tt.want { + t.Errorf("#%d Error with Depth", i) + } + } + }) +} + +func TestTreePrint(t *testing.T) { + t.Run("Test for Binary-Search Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{61, 51, 41, 31, 21, 1, 71, 70, 85, 80, 95, 105, 100, 90}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + } + for _, tt := range tests { + tree := bt.NewBinarySearch[int]() + t.Log(reflect.TypeOf(tree).String()) + tree.Push(tt.input...) + tree.Print() + } + }) + + t.Run("Test for AVL Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{1, 31, 21, 61, 51, 41, 71, 85, 80, 95, 105, 100, 90, 70}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 4, 6, 5, 3, 8, 10, 9, 7}}, + } + for _, tt := range tests { + tree := bt.NewAVL[int]() + t.Log(reflect.TypeOf(tree).String()) + tree.Push(tt.input...) + tree.Print() + } + }) + + t.Run("Test for Red-Black Tree", func(t *testing.T) { + tests := []struct { + input []int + want []int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + []int{1, 31, 21, 51, 71, 70, 61, 41, 85, 95, 105, 100, 90, 80}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 4, 3, 6, 5, 8, 10, 9, 7}}, + } + for _, tt := range tests { + tree := bt.NewRB[int]() + t.Log(reflect.TypeOf(tree).String() == "*tree.RB[int]") + tree.Push(tt.input...) + tree.Print() + } + }) +} + +func TestTreeAccessNodesByLayer(t *testing.T) { + t.Run("Test for Binary-Search Tree", func(t *testing.T) { + tests := []struct { + input []int + want [][]int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, [][]int{{90}, {80, 100}, {70, 85, 95, 105}}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + [][]int{{90}, {80, 100}, {70, 85, 95, 105}, {1, 71}, {21}, {31}, {41}, {51}, {61}}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, [][]int{{10}, {9}, {8}, {7}, {6}, {5}, {4}, {3}, {2}, {1}}}, + {[]int{}, [][]int{}}, + } + for i, tt := range tests { + tree := bt.NewBinarySearch[int]() + tree.Push(tt.input...) + if ret := tree.AccessNodesByLayer(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with AccessNoedsByLayer", i) + } + } + }) + + t.Run("Test for AVL Tree", func(t *testing.T) { + tests := []struct { + input []int + want [][]int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, [][]int{{90}, {80, 100}, {70, 85, 95, 105}}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + [][]int{{70}, {41, 90}, {21, 51, 80, 100}, {1, 31, 61, 71, 85, 95, 105}}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, [][]int{{7}, {3, 9}, {2, 5, 8, 10}, {1, 4, 6}}}, + {[]int{}, [][]int{}}, + } + for i, tt := range tests { + tree := bt.NewAVL[int]() + tree.Push(tt.input...) + if ret := tree.AccessNodesByLayer(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with AccessNoedsByLayer", i) + } + } + }) + + t.Run("Test for Red-Black Tree", func(t *testing.T) { + tests := []struct { + input []int + want [][]int + }{ + {[]int{90, 80, 100, 70, 85, 95, 105}, [][]int{{90}, {80, 100}, {70, 85, 95, 105}}}, + {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, + [][]int{{80}, {41, 90}, {21, 61, 85, 100}, {1, 31, 51, 70, 95, 105}, {71}}}, + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, [][]int{{7}, {5, 9}, {3, 6, 8, 10}, {2, 4}, {1}}}, + {[]int{}, [][]int{}}, + } + for i, tt := range tests { + tree := bt.NewRB[int]() + t.Log(reflect.TypeOf(tree).String() == "*tree.RB[int]") + tree.Push(tt.input...) + if ret := tree.AccessNodesByLayer(); !reflect.DeepEqual(ret, tt.want) { + t.Errorf("#%d Error with AccessNoedsByLayer, %v", i, ret) + } + } + }) +} + +// Benchmark the comparisons between BST, AVL and RB Tree +const testNum = 10_000 + +func BenchmarkBSTree_Insert(b *testing.B) { + helper := func() { + tree := bt.NewBinarySearch[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} + +func BenchmarkBSTree_Has(b *testing.B) { + helper := func() { + tree := bt.NewBinarySearch[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + + for i := 1; i <= testNum; i++ { + tree.Has(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} + +func BenchmarkBSTree_Delete(b *testing.B) { + helper := func() { + tree := bt.NewBinarySearch[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + + for i := 1; i <= testNum; i++ { + tree.Delete(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} + +func BenchmarkRBTree_Insert(b *testing.B) { + helper := func() { + tree := bt.NewRB[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} + +func BenchmarkRBTree_Has(b *testing.B) { + helper := func() { + tree := bt.NewRB[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + + for i := 1; i <= testNum; i++ { + tree.Has(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} + +func BenchmarkRBTree_Delete(b *testing.B) { + helper := func() { + tree := bt.NewRB[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + + for i := 1; i <= testNum; i++ { + tree.Delete(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} + +func BenchmarkAVLTree_Insert(b *testing.B) { + helper := func() { + tree := bt.NewAVL[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } + +} + +func BenchmarkAVLTree_Has(b *testing.B) { + helper := func() { + tree := bt.NewAVL[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + + for i := 1; i <= testNum; i++ { + tree.Has(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} + +func BenchmarkAVLTree_Delete(b *testing.B) { + helper := func() { + tree := bt.NewAVL[int]() + for i := 1; i <= testNum; i++ { + tree.Push(i) + } + + for i := 1; i <= testNum; i++ { + tree.Delete(i) + } + } + + for i := 0; i < b.N; i++ { + helper() + } +} From ff6275bac67cc1927ece6f999ef99467136d0fa0 Mon Sep 17 00:00:00 2001 From: zafar hussain Date: Thu, 20 Oct 2022 06:22:30 +0500 Subject: [PATCH 376/488] chore: update Discord invite link (#576) Co-authored-by: David Leal --- CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 738f6cb7f..2a2565430 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Before contributing -Welcome to [TheAlgorithms/Go](https://github.com/TheAlgorithms/Go)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/Go/issues/new/choose) or ask in our [Discord server](https://discord.gg/c7MnfGFGa6) / [Gitter](https://gitter.im/TheAlgorithms), and clearly state your concerns. +Welcome to [TheAlgorithms/Go](https://github.com/TheAlgorithms/Go)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/Go/issues/new/choose) or ask in our [Discord server](https://the-algorithms.com/discord/) / [Gitter](https://gitter.im/TheAlgorithms), and clearly state your concerns. ## Contributing diff --git a/README.md b/README.md index 04ef156d0..41d5ee29c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![godocmd](https://github.com/tjgurwara99/Go/workflows/godocmd/badge.svg) ![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  ![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) -[![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square)](https://discord.gg/c7MnfGFGa6)  +[![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square)](https://the-algorithms.com/discord/)  ### Algorithms implemented in Go (for education) From f401e73a692941824e67e5cd24ef8441c196adb5 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Thu, 20 Oct 2022 13:30:37 +0200 Subject: [PATCH 377/488] fix: correct the implementation of `LcsDp` (#577) --- dynamic/longestpalindromicsubsequence.go | 23 +++++------ dynamic/longestpalindromicsubsequence_test.go | 40 +++++++++++++++++++ 2 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 dynamic/longestpalindromicsubsequence_test.go diff --git a/dynamic/longestpalindromicsubsequence.go b/dynamic/longestpalindromicsubsequence.go index 9ec9af31f..bc5df07b6 100644 --- a/dynamic/longestpalindromicsubsequence.go +++ b/dynamic/longestpalindromicsubsequence.go @@ -3,8 +3,7 @@ package dynamic -// LpsRec function -func LpsRec(word string, i, j int) int { +func lpsRec(word string, i, j int) int { if i == j { return 1 } @@ -12,9 +11,14 @@ func LpsRec(word string, i, j int) int { return 0 } if word[i] == word[j] { - return 2 + LpsRec(word, i+1, j-1) + return 2 + lpsRec(word, i+1, j-1) } - return Max(LpsRec(word, i, j-1), LpsRec(word, i+1, j)) + return Max(lpsRec(word, i, j-1), lpsRec(word, i+1, j)) +} + +// LpsRec function +func LpsRec(word string) int { + return lpsRec(word, 0, len(word)-1) } // LpsDp function @@ -43,14 +47,5 @@ func LpsDp(word string) int { } } - return dp[1][N-1] -} - -/* -func main() { - // word := "aaabbbbababbabbabbabf" - word := "aaaabbbba" - fmt.Printf("%d\n", lpsRec(word, 0, len(word)-1)) - fmt.Printf("%d\n", lpsDp(word)) + return dp[0][N-1] } -*/ diff --git a/dynamic/longestpalindromicsubsequence_test.go b/dynamic/longestpalindromicsubsequence_test.go new file mode 100644 index 000000000..34a8f2590 --- /dev/null +++ b/dynamic/longestpalindromicsubsequence_test.go @@ -0,0 +1,40 @@ +package dynamic_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +func lpsTestTemplate(t *testing.T, algorithm func(input string) int) { + testCases := []struct { + input string + expected int + }{ + {"BBABCBCAB", 7}, + {"BBBAB", 4}, + {"ABBD", 2}, + {"GEEKSFORGEEKS", 5}, + {"abcdefgh", 1}, + {"bbbab", 4}, + {"cbbd", 2}, + {"racexyzcxar", 7}, + } + for _, tc := range testCases { + t.Run(fmt.Sprint("test with ", tc.input), func(t *testing.T) { + result := algorithm(tc.input) + if tc.expected != result { + t.Fatalf("expected %d, got %d", tc.expected, result) + } + }) + } +} + +func TestLpsRec(t *testing.T) { + lpsTestTemplate(t, dynamic.LpsRec) +} + +func TestLpsDp(t *testing.T) { + lpsTestTemplate(t, dynamic.LpsDp) +} From 138937e523db90a794326bd9617b5ced161a61dc Mon Sep 17 00:00:00 2001 From: David Leal Date: Sat, 22 Oct 2022 19:30:33 -0500 Subject: [PATCH 378/488] docs: convert issue templates to issue forms (#581) * docs: convert issue templates to issue forms * fix: minor template issues --- .github/ISSUE_TEMPLATE/bug_report.md | 27 ----------- .github/ISSUE_TEMPLATE/bug_report.yml | 45 +++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + .../new-optimize-implementation.md | 20 --------- .github/ISSUE_TEMPLATE/new_implementation.yml | 38 ++++++++++++++++ .github/ISSUE_TEMPLATE/other.yml | 22 +++++++++ 6 files changed, 106 insertions(+), 47 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/new-optimize-implementation.md create mode 100644 .github/ISSUE_TEMPLATE/new_implementation.yml create mode 100644 .github/ISSUE_TEMPLATE/other.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 160740ee5..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..047b3e299 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,45 @@ +name: "Bug report" +description: "Create a report to help us improve" +title: "[BUG]" +labels: ["bug"] +body: + - type: textarea + id: description + attributes: + label: "Description" + description: "A clear and concise description of what the bug is." + validations: + required: true + - type: textarea + id: steps + attributes: + label: "Steps to reproduce" + description: "Steps to reproduce the behavior (if applicable)" + placeholder: | + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: false + - type: textarea + id: exceptedbhv + attributes: + label: "Excepted behavior" + description: "A clear and concise description of what you expected to happen." + validations: + required: true + - type: textarea + id: screenshots + attributes: + label: "Screenshots" + description: "If applicable, add screenshots to help explain your problem." + validations: + required: false + - type: textarea + id: context + attributes: + label: "Additional context" + description: "Add any other context about the problem here." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..3ba13e0ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/new-optimize-implementation.md b/.github/ISSUE_TEMPLATE/new-optimize-implementation.md deleted file mode 100644 index db6cb5224..000000000 --- a/.github/ISSUE_TEMPLATE/new-optimize-implementation.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: New/Optimize implementation -about: Propose an enhancement or a new algorithm implementation. -title: '' -labels: enhancement -assignees: '' - ---- - -**Description** -Provide a clear and concise description of the issue. - -For new implementation: -- Name and problem statement for the algorithm. - -For enhancement: -- Specify what needs to be changed and why. For example: - - Adding tests. - - Optimizing logic. - - Refactoring file and folders for better structure. diff --git a/.github/ISSUE_TEMPLATE/new_implementation.yml b/.github/ISSUE_TEMPLATE/new_implementation.yml new file mode 100644 index 000000000..b2153a022 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new_implementation.yml @@ -0,0 +1,38 @@ +name: "New or optimize implementation" +description: "Propose an enhancement or a new algorithm implementation." +title: "[ENHANCEMENT]" +labels: ["enhancement"] +body: + - type: textarea + id: description + attributes: + label: What would you like to share? + description: Provide a clear and concise explanation of your issue. + validations: + required: true + - type: markdown + attributes: + value: | + " + For new implementations, please specify the name and problem statement for the algorithm. + For algorithm enhancements, specify what needs to be changed and why. For example: + + - Adding tests. + - Optimizing logic. + - Refactoring the file and folders for better structure. + + " + - type: textarea + id: issuedetails + attributes: + label: "Extra issue details" + description: "Write down all the issue/algorithm details mentioned above." + validations: + required: true + - type: textarea + id: extrainfo + attributes: + label: Additional information + description: Is there anything else we should know about this issue? + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/other.yml b/.github/ISSUE_TEMPLATE/other.yml new file mode 100644 index 000000000..14824ba9f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/other.yml @@ -0,0 +1,22 @@ +name: Other +description: Use this for any other issues. Do NOT create blank issues +title: "[OTHER]" +labels: ["awaiting triage"] +body: + - type: markdown + attributes: + value: "# Other issue" + - type: textarea + id: issuedescription + attributes: + label: What would you like to share? + description: Provide a clear and concise explanation of your issue. + validations: + required: true + - type: textarea + id: extrainfo + attributes: + label: Additional information + description: Is there anything else we should know about this issue? + validations: + required: false From b9ee52cb7798050f00af822d01de43402b6defa2 Mon Sep 17 00:00:00 2001 From: AHSKR <87699700+kalyan-arepalle@users.noreply.github.com> Date: Mon, 24 Oct 2022 17:31:38 +0530 Subject: [PATCH 379/488] feat: add sets algorithms for proper subset and proper superset check (#587) * feat: add sets algorithms for proper subset and proper superset check * review changes --- structure/set/set.go | 20 ++++++++++++++++++++ structure/set/set_test.go | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/structure/set/set.go b/structure/set/set.go index 9adef5c48..811ec717e 100644 --- a/structure/set/set.go +++ b/structure/set/set.go @@ -28,8 +28,14 @@ type Set interface { In(item any) bool // IsSubsetOf: checks whether set is subset of set2 or not. IsSubsetOf(set2 Set) bool + // IsProperSubsetOf: checks whether set is proper subset of set2 or not. + // ex: [1,2,3] proper subset of [1,2,3,4] -> true + IsProperSubsetOf(set2 Set) bool // IsSupersetOf: checks whether set is superset of set2 or not. IsSupersetOf(set2 Set) bool + // IsProperSupersetOf: checks whether set is proper superset of set2 or not. + // ex: [1,2,3,4] proper superset of [1,2,3] -> true + IsProperSupersetOf(set2 Set) bool // Union: gives new union set of both sets. // ex: [1,2,3] union [3,4,5] -> [1,2,3,4,5] Union(set2 Set) Set @@ -88,10 +94,24 @@ func (st *set) IsSubsetOf(superSet Set) bool { return true } +func (st *set) IsProperSubsetOf(superSet Set) bool { + if st.Len() == superSet.Len() { + return false + } + return st.IsSubsetOf(superSet) +} + func (st *set) IsSupersetOf(subSet Set) bool { return subSet.IsSubsetOf(st) } +func (st *set) IsProperSupersetOf(subSet Set) bool { + if st.Len() == subSet.Len() { + return false + } + return st.IsSupersetOf(subSet) +} + func (st *set) Union(st2 Set) Set { unionSet := New() for _, item := range st.GetItems() { diff --git a/structure/set/set_test.go b/structure/set/set_test.go index b07fe89a2..4b12a8f55 100644 --- a/structure/set/set_test.go +++ b/structure/set/set_test.go @@ -82,6 +82,16 @@ func TestIsSubsetOf(t *testing.T) { } } +func TestIsProperSubsetOf(t *testing.T) { + s1, s2 := New(1, 2, 3), New(1, 2, 3, 4) + if !s1.IsProperSubsetOf(s2) { + t.Errorf("expecting %v to be a proper subset of %v", s1, s2) + } + if s3 := New(3, 2, 1); s1.IsProperSubsetOf(s3) { + t.Errorf("expecting %v not to be a proper subset of %v", s1, s3) + } +} + func TestIsSupersetOf(t *testing.T) { s1, s2 := New(1, 2, 3), New(1, 2, 3, 4) if !s2.IsSupersetOf(s1) { @@ -95,6 +105,16 @@ func TestIsSupersetOf(t *testing.T) { } } +func TestIsProperSupersetOf(t *testing.T) { + s1, s2 := New(1, 2, 3), New(1, 2, 3, 4) + if !s2.IsProperSupersetOf(s1) { + t.Errorf("expecting %v to be a proper superset of %v", s2, s1) + } + if s3 := New(3, 2, 1); s1.IsProperSupersetOf(s3) { + t.Errorf("expecting %v not to be a proper superset of %v", s1, s3) + } +} + func TestUnion(t *testing.T) { td := []struct { name string From 51c95328394679b58855e134d83babb58d3ef6df Mon Sep 17 00:00:00 2001 From: David Leal Date: Mon, 24 Oct 2022 13:36:07 -0500 Subject: [PATCH 380/488] chore: remove unneeded quotes --- .github/ISSUE_TEMPLATE/new_implementation.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/new_implementation.yml b/.github/ISSUE_TEMPLATE/new_implementation.yml index b2153a022..e8da888e8 100644 --- a/.github/ISSUE_TEMPLATE/new_implementation.yml +++ b/.github/ISSUE_TEMPLATE/new_implementation.yml @@ -13,15 +13,12 @@ body: - type: markdown attributes: value: | - " For new implementations, please specify the name and problem statement for the algorithm. For algorithm enhancements, specify what needs to be changed and why. For example: - Adding tests. - Optimizing logic. - Refactoring the file and folders for better structure. - - " - type: textarea id: issuedetails attributes: From 213cfa61123f0ef71c74a2893679f91b033df618 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Tue, 25 Oct 2022 13:54:46 +0200 Subject: [PATCH 381/488] feat(cipher/rot13): add fuzz test to rot13 cipher (#588) --- README.md | 84 +++++++++++++++++++++++--------------- cipher/rot13/rot13_test.go | 14 ++++++- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 41d5ee29c..2f5ea82cc 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,22 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 10. [`Sqrt`](./math/binary/sqrt.go#L16): No description provided. 11. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence +--- +
+ cache + +--- + +##### Functions: + +1. [`NewLRU`](./cache/lru.go#L20): NewLRU represent initiate lru cache with capacity + +--- +##### Types + +1. [`LRU`](./cache/lru.go#L12): No description provided. + + ---
caesar @@ -92,6 +108,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Decrypt`](./cipher/caesar/caesar.go#L27): Decrypt decrypts by left shift of "key" each character of "input" 2. [`Encrypt`](./cipher/caesar/caesar.go#L6): Encrypt encrypts by right shift of "key" each character of "input" +3. [`FuzzCaesar`](./cipher/caesar/caesar_test.go#L158): No description provided. ---
@@ -217,11 +234,11 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 7. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity. 8. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided. 9. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit -10. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L8): LongestCommonSubsequence function +10. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L12): LongestCommonSubsequence function 11. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order 12. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ -13. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L21): LpsDp function -14. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L7): LpsRec function +13. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L25): LpsDp function +14. [`LpsRec`](./dynamic/longestpalindromicsubsequence.go#L20): LpsRec function 15. [`MatrixChainDp`](./dynamic/matrixmultiplication.go#L24): MatrixChainDp function 16. [`MatrixChainRec`](./dynamic/matrixmultiplication.go#L10): MatrixChainRec function 17. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate @@ -459,7 +476,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`JosephusProblem`](./structure/linkedlist/cyclic.go#L120): https://en.wikipedia.org/wiki/Josephus_problem This is a struct-based solution for Josephus problem. 2. [`NewCyclic`](./structure/linkedlist/cyclic.go#L12): Create new list. -3. [`NewDoubly`](./structure/linkedlist/doubly.go#L22): No description provided. +3. [`NewDoubly`](./structure/linkedlist/doubly.go#L31): No description provided. 4. [`NewNode`](./structure/linkedlist/shared.go#L12): Create new node. 5. [`NewSingly`](./structure/linkedlist/singlylinkedlist.go#L19): NewSingly returns a new instance of a linked list @@ -504,15 +521,18 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 4. [`DefaultPolynomial`](./math/pollard.go#L16): DefaultPolynomial is the commonly used polynomial g(x) = (x^2 + 1) mod n 5. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. 6. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -7. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -8. [`LiouvilleLambda`](./math/liouville.go#L24): Lambda is the liouville function This function returns λ(n) for given number -9. [`Mean`](./math/mean.go#L7): No description provided. -10. [`Median`](./math/median.go#L12): No description provided. -11. [`Mode`](./math/mode.go#L19): No description provided. -12. [`Mu`](./math/mobius.go#L21): Mu is the Mobius function This function returns μ(n) for given number -13. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. -14. [`PollardsRhoFactorization`](./math/pollard.go#L29): PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm using the default parameters x = y = 2 -15. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +7. [`IsPerfectNumber`](./math/perfectnumber.go#L34): Checks if inNumber is a perfect number +8. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +9. [`Lerp`](./math/lerp.go#L5): Lerp or Linear interpolation This function will return new value in 't' percentage between 'v0' and 'v1' +10. [`LiouvilleLambda`](./math/liouville.go#L24): Lambda is the liouville function This function returns λ(n) for given number +11. [`Mean`](./math/mean.go#L7): No description provided. +12. [`Median`](./math/median.go#L12): No description provided. +13. [`Mode`](./math/mode.go#L19): No description provided. +14. [`Mu`](./math/mobius.go#L21): Mu is the Mobius function This function returns μ(n) for given number +15. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +16. [`PollardsRhoFactorization`](./math/pollard.go#L29): PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm using the default parameters x = y = 2 +17. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +18. [`SumOfProperDivisors`](./math/perfectnumber.go#L17): Returns the sum of proper divisors of inNumber. ---
@@ -523,7 +543,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Bitwise`](./math/max/bitwisemax.go#L11): Bitwise computes using bitwise operator the maximum of all the integer input and returns it -2. [`Int`](./math/max/max.go#L4): Int is a function which returns the maximum of all the integers provided as arguments. +2. [`Int`](./math/max/max.go#L6): Int is a function which returns the maximum of all the integers provided as arguments. ---
@@ -547,7 +567,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Bitwise`](./math/min/bitwisemin.go#L11): Bitwise This function returns the minimum integer using bit operations -2. [`Int`](./math/min/min.go#L4): Int is a function which returns the minimum of all the integers provided as arguments. +2. [`Int`](./math/min/min.go#L6): Int is a function which returns the minimum of all the integers provided as arguments. ---
@@ -558,7 +578,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Exponentiation`](./math/modular/exponentiation.go#L22): Exponentiation returns base^exponent % mod -2. [`Inverse`](./math/modular/inverse.go#L20): Inverse Modular function +2. [`Inverse`](./math/modular/inverse.go#L19): Inverse Modular function 3. [`Multiply64BitInt`](./math/modular/exponentiation.go#L51): Multiply64BitInt Checking if the integer multiplication overflows --- @@ -715,6 +735,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 9. [`OptimizedTrialDivision`](./math/prime/primecheck.go#L26): OptimizedTrialDivision checks primality of an integer using an optimized trial division method. The optimizations include not checking divisibility by the even numbers and only checking up to the square root of the given number. 10. [`Sieve`](./math/prime/sieve.go#L16): Sieve Sieving the numbers that are not prime from the channel - basically removing them from the channels 11. [`TrialDivision`](./math/prime/primecheck.go#L9): TrialDivision tests whether a number is prime by trying to divide it by the numbers less than it. +12. [`Twin`](./math/prime/twin.go#L15): This function returns twin prime for given number returns (n + 2) if both n and (n + 2) are prime -1 otherwise ---
@@ -836,29 +857,26 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 2. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. 3. [`Count`](./sort/countingsort.go#L11): No description provided. 4. [`Exchange`](./sort/exchangesort.go#L8): No description provided. -5. [`HeapSort`](./sort/heapsort.go#L121): No description provided. +5. [`HeapSort`](./sort/heapsort.go#L116): No description provided. 6. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort 7. [`Insertion`](./sort/insertionsort.go#L5): No description provided. -8. [`Merge`](./sort/mergesort.go#L40): Merge Perform merge sort on a slice -9. [`MergeIter`](./sort/mergesort.go#L54): No description provided. -10. [`Partition`](./sort/quicksort.go#L12): No description provided. -11. [`Patience`](./sort/patiencesort.go#L13): No description provided. -12. [`Pigeonhole`](./sort/pigeonholesort.go#L12): Pigeonhole sorts a slice using pigeonhole sorting algorithm. -13. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array -14. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array -15. [`RadixSort`](./sort/radixsort.go#L35): No description provided. -16. [`Selection`](./sort/selectionsort.go#L5): No description provided. -17. [`Shell`](./sort/shellsort.go#L5): No description provided. -18. [`Simple`](./sort/simplesort.go#L13): No description provided. +8. [`Merge`](./sort/mergesort.go#L41): Merge Perform merge sort on a slice +9. [`MergeIter`](./sort/mergesort.go#L55): No description provided. +10. [`ParallelMerge`](./sort/mergesort.go#L66): ParallelMerge Perform merge sort on a slice using goroutines +11. [`Partition`](./sort/quicksort.go#L12): No description provided. +12. [`Patience`](./sort/patiencesort.go#L13): No description provided. +13. [`Pigeonhole`](./sort/pigeonholesort.go#L15): Pigeonhole sorts a slice using pigeonhole sorting algorithm. NOTE: To maintain time complexity O(n + N), this is the reason for having only Integer constraint instead of Ordered. +14. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array +15. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array +16. [`RadixSort`](./sort/radixsort.go#L43): No description provided. +17. [`Selection`](./sort/selectionsort.go#L5): No description provided. +18. [`Shell`](./sort/shellsort.go#L5): No description provided. +19. [`Simple`](./sort/simplesort.go#L13): No description provided. --- ##### Types -1. [`Int`](#L0): - - Methods: - 1. [`More`](./sort/heapsort.go#L114): No description provided. -2. [`MaxHeap`](./sort/heapsort.go#L3): No description provided. +1. [`MaxHeap`](./sort/heapsort.go#L5): No description provided. --- diff --git a/cipher/rot13/rot13_test.go b/cipher/rot13/rot13_test.go index 1e5716357..235039bbb 100644 --- a/cipher/rot13/rot13_test.go +++ b/cipher/rot13/rot13_test.go @@ -64,7 +64,19 @@ func TestRot13Decrypt(t *testing.T) { func assertRot13Output(t *testing.T, input, expected string) { actual := rot13(input) if actual != expected { - t.Fatalf("With input string '%s' was expecting '%s' but actual was '%s'", + t.Fatalf("With input string %q was expecting %q but actual was %q", input, expected, actual) } } + +func FuzzRot13(f *testing.F) { + for _, rot13TestInput := range rot13TestData { + f.Add(rot13TestInput.input) + } + f.Fuzz(func(t *testing.T, input string) { + if result := rot13(rot13(input)); result != input { + t.Fatalf("With input string %q was expecting %q but actual was %q", + input, input, result) + } + }) +} From 5a42d85e310f81051c1995c4be212a365a2dc02e Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 26 Oct 2022 14:23:24 +0200 Subject: [PATCH 382/488] fix: handle multibyte chars propertly in `LongestCommonSubsequence` (#578) --- dynamic/longestcommonsubsequence.go | 13 +++++++------ dynamic/longestcommonsubsequence_test.go | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dynamic/longestcommonsubsequence.go b/dynamic/longestcommonsubsequence.go index 8ca739811..739aeb8c1 100644 --- a/dynamic/longestcommonsubsequence.go +++ b/dynamic/longestcommonsubsequence.go @@ -4,14 +4,15 @@ package dynamic -import ( - "unicode/utf8" -) +func strToRuneSlice(s string) (r []rune, size int) { + r = []rune(s) + return r, len(r) +} // LongestCommonSubsequence function func LongestCommonSubsequence(a string, b string) int { - var aLen = utf8.RuneCountInString(a) - var bLen = utf8.RuneCountInString(b) + aRunes, aLen := strToRuneSlice(a) + bRunes, bLen := strToRuneSlice(b) // here we are making a 2d slice of size (aLen+1)*(bLen+1) lcs := make([][]int, aLen+1) @@ -24,7 +25,7 @@ func LongestCommonSubsequence(a string, b string) int { for j := 0; j <= bLen; j++ { if i == 0 || j == 0 { lcs[i][j] = 0 - } else if a[i-1] == b[j-1] { + } else if aRunes[i-1] == bRunes[j-1] { lcs[i][j] = lcs[i-1][j-1] + 1 } else { lcs[i][j] = Max(lcs[i-1][j], lcs[i][j-1]) diff --git a/dynamic/longestcommonsubsequence_test.go b/dynamic/longestcommonsubsequence_test.go index 1c102c3be..5112f1270 100644 --- a/dynamic/longestcommonsubsequence_test.go +++ b/dynamic/longestcommonsubsequence_test.go @@ -28,6 +28,8 @@ func getLCSTestCases() []testCaseLCS { {"", "abc", 0}, {"", "", 0}, {"££", "££", 2}, + {"x笑x笑", "aaa笑a笑", 2}, + {"xYxY", "aaaYaY", 2}, } } From 298ce1b402eaa2184d147a58d145644893b8f273 Mon Sep 17 00:00:00 2001 From: Chetan Patil <31822501+Chetan07j@users.noreply.github.com> Date: Wed, 26 Oct 2022 21:31:15 +0200 Subject: [PATCH 383/488] algorithm: distance between two points (#568) * feat: cartesian plane algorithm two point distance added * test: function tests and bechmark test added * Fix: typo mistake Co-authored-by: Rak Laptudirm * fix: review comments incorporated * fix: review suggestions * fix: linter issues * fix: updated comment as per code changes * test: added test for error, updated benchmark test * fix: test package name and error handling Co-authored-by: Rak Laptudirm --- math/geometry/distance.go | 36 +++++++++++++++ math/geometry/distance_test.go | 80 ++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 math/geometry/distance.go create mode 100644 math/geometry/distance_test.go diff --git a/math/geometry/distance.go b/math/geometry/distance.go new file mode 100644 index 000000000..5b1c3c82e --- /dev/null +++ b/math/geometry/distance.go @@ -0,0 +1,36 @@ +// distance.go +// Find Euclidean distance between two points +// author(s) [Chetan Patil](https://github.com/Chetan07j) + +// Package geometry contains geometric algorithms +package geometry + +import ( + "errors" + "math" +) + +// EuclideanPoint defines a point with x and y coordinates. +type EuclideanPoint []float64 + +var ErrDimMismatch = errors.New("mismatched dimensions") + +// EuclideanDistance returns the Euclidean distance between points in +// any `n` dimensional Euclidean space. +func EuclideanDistance(p1 EuclideanPoint, p2 EuclideanPoint) (float64, error) { + n := len(p1) + + if len(p2) != n { + return -1, ErrDimMismatch + } + + var total float64 = 0 + + for i, x_i := range p1 { + // using Abs since the value could be negative but we require the magnitude + diff := math.Abs(x_i - p2[i]) + total += diff * diff + } + + return math.Sqrt(total), nil +} diff --git a/math/geometry/distance_test.go b/math/geometry/distance_test.go new file mode 100644 index 000000000..bea9ebba5 --- /dev/null +++ b/math/geometry/distance_test.go @@ -0,0 +1,80 @@ +package geometry_test + +import ( + "errors" + "testing" + + geometry "github.com/TheAlgorithms/Go/math/geometry" +) + +type args struct { + p1 geometry.EuclideanPoint + p2 geometry.EuclideanPoint +} + +func TestFindDistanceBetweenTwoPoints(t *testing.T) { + tests := []struct { + name string + args args + want float64 + wantErr bool + }{ + { + "(0,0) and (2,-2)", + args{ + geometry.EuclideanPoint{0, 0}, + geometry.EuclideanPoint{2, -2}, + }, + 2.8284271247461903, + false, + }, + { + "(-20,23) and (-15,68)", + args{ + geometry.EuclideanPoint{-20, 23}, + geometry.EuclideanPoint{-15, 68}, + }, + 45.27692569068709, + false, + }, + { + "(2,2) and (14,11)", + args{ + geometry.EuclideanPoint{2, 2}, + geometry.EuclideanPoint{14, 11}, + }, + 15, + false, + }, + { + "Return error for mismatched dimensions(2,2) and ()", + args{ + geometry.EuclideanPoint{2, 2}, + geometry.EuclideanPoint{}, + }, + -1, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := geometry.EuclideanDistance(tt.args.p1, tt.args.p2) + if (err != nil) != tt.wantErr && errors.Is(err, geometry.ErrDimMismatch) { + t.Errorf("EuclideanDistance() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("EuclideanDistance() = %v, want %v", got, tt.want) + } + }) + } +} + +func BenchmarkFindDistanceBetweenTwoPoints(b *testing.B) { + p1 := geometry.EuclideanPoint{0, 0} + p2 := geometry.EuclideanPoint{2, -2} + + for i := 0; i < b.N; i++ { + _, _ = geometry.EuclideanDistance(p1, p2) + } +} From 089c427640b047fb63d520a606cb233365f9deed Mon Sep 17 00:00:00 2001 From: Royce Date: Sun, 30 Oct 2022 12:31:30 -0400 Subject: [PATCH 384/488] docs: Documentation changes (#598) Bolded "removing bugs" on line 28. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2a2565430..0eb6982c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ Being a contributor at The Algorithms, we request you to follow the points menti - New implementations are welcome! -- You can add new algorithms or data structures that are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs, or in any other reasonable sense) +- You can add new algorithms or data structures that are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, **removing bugs**, or in any other reasonable sense) #### Issues From 1d2c0545ac9065639125a5e5bcc1f8d002986da3 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Mon, 31 Oct 2022 17:43:56 +0100 Subject: [PATCH 385/488] tests(cipher/rsa): add fuzz test to rsa cipher (#591) * Updated Documentation in README.md * feat(cipher/rsa): add fuzz test to rsa Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Taj --- cipher/rsa/rsa_test.go | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/cipher/rsa/rsa_test.go b/cipher/rsa/rsa_test.go index fde10be33..43ce90245 100644 --- a/cipher/rsa/rsa_test.go +++ b/cipher/rsa/rsa_test.go @@ -35,30 +35,28 @@ var rsaTestData = []struct { }, } -func TestEncryptDecrypt(t *testing.T) { +func testPrecondition(t *testing.T) (int64, int64, int64) { // Both prime numbers + t.Helper() p := int64(61) q := int64(53) - n := p * q - delta := lcm.Lcm(p-1, q-1) - e := int64(17) // Coprime with delta - if gcd.Recursive(e, delta) != 1 { - t.Fatal("Algorithm failed in preamble stage:\n\tPrime numbers are chosen statically and it shouldn't fail at this stage") + t.Fatal("something went wrong: prime numbers are chosen statically and it shouldn't fail at this stage") } - d, err := modular.Inverse(e, delta) - if err != nil { - t.Fatalf("Algorithm failed in preamble stage:\n\tProblem with a modular directory dependency: %v", err) + t.Fatalf("something went wrong: problem with %q: %v", "modular.Inverse", err) } + return e, d, n +} +func TestEncryptDecrypt(t *testing.T) { for _, test := range rsaTestData { t.Run(test.description, func(t *testing.T) { - + e, d, n := testPrecondition(t) message := []rune(test.input) encrypted, err := Encrypt(message, e, n) if err != nil { @@ -77,3 +75,23 @@ func TestEncryptDecrypt(t *testing.T) { }) } } + +func FuzzRsa(f *testing.F) { + for _, rsaTestInput := range rsaTestData { + f.Add(rsaTestInput.input) + } + f.Fuzz(func(t *testing.T, input string) { + e, d, n := testPrecondition(t) + encrypted, err := Encrypt([]rune(input), e, n) + if err != nil { + t.Fatalf("failed to encrypt string: %v", err) + } + decrypted, err := Decrypt(encrypted, d, n) + if err != nil { + t.Fatalf("failed to decrypt string: %v", err) + } + if decrypted != input { + t.Fatalf("expected: %q, got: %q", input, decrypted) + } + }) +} From 7eb041010aed929cbe9140d018e99b2baf5d040b Mon Sep 17 00:00:00 2001 From: Akshay Dubey <38462415+itsAkshayDubey@users.noreply.github.com> Date: Mon, 31 Oct 2022 22:18:11 +0530 Subject: [PATCH 386/488] algorithm: Aliquot Sum (#594) * feat: Add Aliquot Sum implementation * test: Add test for Aliquot Sum algorithm * fix: Add separate case for n=1 * refactor: Refactor condition in for loop Co-authored-by: Rak Laptudirm --- math/aliquot_test.go | 39 +++++++++++++++++++++++++++++++++++++++ math/aliquotsum.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 math/aliquot_test.go create mode 100644 math/aliquotsum.go diff --git a/math/aliquot_test.go b/math/aliquot_test.go new file mode 100644 index 000000000..0c6abd956 --- /dev/null +++ b/math/aliquot_test.go @@ -0,0 +1,39 @@ +// aliquotsum_test.go +// description: Returns s(n) +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see aliquotsum.go + +package math_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math" +) + +func TestAliquotSum(t *testing.T) { + var tests = []struct { + name string + n int + expectedValue int + expectedError error + }{ + {"n = 10", 10, 8, nil}, + {"n = 11", 11, 1, nil}, + {"n = -1", -1, 0, math.ErrPosArgsOnly}, + {"n = 0", 0, 0, math.ErrNonZeroArgsOnly}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := math.AliquotSum(test.n) + if result != test.expectedValue || test.expectedError != err { + t.Errorf("expected error: %s, got: %s; expected value: %v, got: %v", test.expectedError, err, test.expectedValue, result) + } + }) + } +} +func BenchmarkAliquotSum(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = math.AliquotSum(65536) + } +} diff --git a/math/aliquotsum.go b/math/aliquotsum.go new file mode 100644 index 000000000..707b818a2 --- /dev/null +++ b/math/aliquotsum.go @@ -0,0 +1,31 @@ +// aliquotsum.go +// description: Returns s(n) +// details: +// the aliquot sum s(n) of a positive integer n +// is the sum of all proper divisors of n, +// that is, all divisors of n other than n itself +// wikipedia: https://en.wikipedia.org/wiki/Aliquot_sum +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see aliquotsum_test.go + +package math + +// This function returns s(n) for given number +func AliquotSum(n int) (int, error) { + switch { + case n < 0: + return 0, ErrPosArgsOnly + case n == 0: + return 0, ErrNonZeroArgsOnly + case n == 1: + return 0, nil + default: + var sum int + for i := 1; i <= n/2; i++ { + if n%i == 0 { + sum += i + } + } + return sum, nil + } +} From aa85e4e535c1595b3f860baac4790f19fc07fa40 Mon Sep 17 00:00:00 2001 From: KedarisettiSreeVamsi <34485436+KedarisettiSreeVamsi@users.noreply.github.com> Date: Wed, 9 Nov 2022 20:49:58 +0530 Subject: [PATCH 387/488] update: delete middle func for linked list (#560) * Added code for delete in middle for linkedlist * update to previous commit of linked list * Changes as requested to linkedlist * removed delete in middle code Co-authored-by: Rak Laptudirm --- structure/linkedlist/doubly.go | 33 ++++++++++++++++++++++ structure/linkedlist/singlylinkedlist.go | 36 +++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/structure/linkedlist/doubly.go b/structure/linkedlist/doubly.go index a14513751..6864dacf0 100644 --- a/structure/linkedlist/doubly.go +++ b/structure/linkedlist/doubly.go @@ -101,6 +101,39 @@ func (ll *Doubly[T]) DelAtEnd() (T, bool) { return val, true } +// DelByPos deletes node at middle based on position in list +// and returns value. If empty or position of node is less than linked list length, returns false +func (ll *Doubly[T]) DelByPos(pos int) (T, bool) { + + switch { + case ll.Head == nil: + var r T + return r, false + case pos-1 == 0: + return ll.DelAtBeg() + case pos-1 == ll.Count(): + return ll.DelAtEnd() + case pos-1 > ll.Count(): + var r T + return r, false + } + var prev *Node[T] + var val T + cur := ll.Head + count := 0 + + for count < pos-1 { + prev = cur + cur = cur.Next + count++ + } + + cur.Next.Prev = prev + val = cur.Val + prev.Next = cur.Next + return val, true +} + // Count Number of nodes in the linkedlist func (ll *Doubly[T]) Count() int { var ctr int = 0 diff --git a/structure/linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go index 18d661799..9f951737f 100644 --- a/structure/linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -22,7 +22,7 @@ func NewSingly[T any]() *Singly[T] { // AddAtBeg adds a new snode with given value at the beginning of the list. func (ll *Singly[T]) AddAtBeg(val T) { - n := NewNode[T](val) + n := NewNode(val) n.Next = ll.Head ll.Head = n ll.length++ @@ -84,6 +84,40 @@ func (ll *Singly[T]) DelAtEnd() (T, bool) { } +// DelByPos deletes the node at the middle based on position in the list +// and returns its value. Returns false if the list is empty or length is not more than given position +func (ll *Singly[T]) DelByPos(pos int) (T, bool) { + switch { + case ll.Head == nil: + var r T + return r, false + case pos-1 > ll.length: + var r T + return r, false + case pos-1 == 0: + return ll.DelAtBeg() + case pos-1 == ll.Count(): + return ll.DelAtEnd() + } + + var prev *Node[T] + var val T + cur := ll.Head + count := 0 + + for count < pos-1 { + prev = cur + cur = cur.Next + count++ + } + + val = cur.Val + prev.Next = cur.Next + ll.length-- + + return val, true +} + // Count returns the current size of the list. func (ll *Singly[T]) Count() int { return ll.length From 7523f410d9dca40b55a0da2e756ba37e8cb11b38 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Fri, 11 Nov 2022 05:12:49 +0100 Subject: [PATCH 388/488] feat(cipher/polybius): add fuzz test to polybius cipher (#600) --- README.md | 15 ++++++++++- cipher/polybius/polybius.go | 21 ++++++++++++---- cipher/polybius/polybius_test.go | 43 ++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2f5ea82cc..06be382be 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 7. [`EditDistanceRecursive`](./dynamic/editdistance.go#L10): EditDistanceRecursive is a naive implementation with exponential time complexity. 8. [`IsSubsetSum`](./dynamic/subsetsum.go#L14): No description provided. 9. [`Knapsack`](./dynamic/knapsack.go#L17): Knapsack solves knapsack problem return maxProfit -10. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L12): LongestCommonSubsequence function +10. [`LongestCommonSubsequence`](./dynamic/longestcommonsubsequence.go#L13): LongestCommonSubsequence function 11. [`LongestIncreasingSubsequence`](./dynamic/longestincreasingsubsequence.go#L9): LongestIncreasingSubsequence returns the longest increasing subsequence where all elements of the subsequence are sorted in increasing order 12. [`LongestIncreasingSubsequenceGreedy`](./dynamic/longestincreasingsubsequencegreedy.go#L9): LongestIncreasingSubsequenceGreedy is a function to find the longest increasing subsequence in a given array using a greedy approach. The dynamic programming approach is implemented alongside this one. Worst Case Time Complexity: O(nlogn) Auxiliary Space: O(n), where n is the length of the array(slice). Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ 13. [`LpsDp`](./dynamic/longestpalindromicsubsequence.go#L25): LpsDp function @@ -778,6 +778,19 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 3. [`Queue`](./structure/queue/queuelinkedlist.go#L19): No description provided. +--- +
+ rot13 + +--- + +##### Package rot13 is a simple letter substitution cipher that replaces a letter with the 13th letter after it in the alphabet. ref: https://en.wikipedia.org/wiki/ROT13 + +--- +##### Functions: + +1. [`FuzzRot13`](./cipher/rot13/rot13_test.go#L72): No description provided. + ---
rsa diff --git a/cipher/polybius/polybius.go b/cipher/polybius/polybius.go index 7c2760334..7b57ab344 100644 --- a/cipher/polybius/polybius.go +++ b/cipher/polybius/polybius.go @@ -19,11 +19,22 @@ type Polybius struct { // If the size of "chars" is longer than "size", // "chars" are truncated to "size". func NewPolybius(key string, size int, chars string) (*Polybius, error) { + if size < 0 { + return nil, fmt.Errorf("provided size %d cannot be negative", size) + } key = strings.ToUpper(key) + if size > len(chars) { + return nil, fmt.Errorf("provided size %d is too small to use to slice string %q of len %d", size, chars, len(chars)) + } + for _, r := range chars { + if (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') { + return nil, fmt.Errorf("provided string %q should only contain latin characters", chars) + } + } chars = strings.ToUpper(chars)[:size] - for idx, ch := range chars { - if strings.Contains(chars[idx+1:], string(ch)) { - return nil, fmt.Errorf("\"chars\" contains same character: %c", ch) + for i, r := range chars { + if strings.ContainsRune(chars[i+1:], r) { + return nil, fmt.Errorf("%q contains same character %q", chars[i+1:], r) } } @@ -63,7 +74,7 @@ func (p *Polybius) Decrypt(text string) (string, error) { func (p *Polybius) encipher(char rune) (string, error) { index := strings.IndexRune(p.key, char) if index < 0 { - return "", fmt.Errorf("%c does not exist in keys", char) + return "", fmt.Errorf("%q does not exist in keys", char) } row := index / p.size col := index % p.size @@ -83,5 +94,5 @@ func (p *Polybius) decipher(chars []rune) (string, error) { if col < 0 { return "", fmt.Errorf("%c does not exist in characters", chars[1]) } - return string([]rune(p.key)[row*p.size+col]), nil + return string(p.key[row*p.size+col]), nil } diff --git a/cipher/polybius/polybius_test.go b/cipher/polybius/polybius_test.go index 89b4769fc..03fb4ca00 100644 --- a/cipher/polybius/polybius_test.go +++ b/cipher/polybius/polybius_test.go @@ -3,6 +3,7 @@ package polybius import ( "fmt" "log" + "strings" "testing" ) @@ -54,7 +55,7 @@ func TestNewPolybius(t *testing.T) { name: "invalid key", size: 5, characters: "HogeFuga", key: "abcdefghi", wantErr: "len(key): 9 must be as long as size squared: 25", }, { - name: "invalid characters", size: 5, characters: "HogeH", key: "abcdefghijklmnopqrstuvwxy", wantErr: "\"chars\" contains same character: H", + name: "invalid characters", size: 5, characters: "HogeH", key: "abcdefghijklmnopqrstuvwxy", wantErr: "\"OGEH\" contains same character 'H'", }, } @@ -79,7 +80,7 @@ func TestPolybiusEncrypt(t *testing.T) { name: "correct encryption", text: "HogeFugaPiyoSpam", want: "OGGFOOHFOHFHOOHHEHOEFFGFEEEHHHGG", }, { - name: "invalid encryption", text: "hogz", want: "failed encipher: Z does not exist in keys", + name: "invalid encryption", text: "hogz", want: "failed encipher: 'Z' does not exist in keys", }, } // initialize @@ -149,3 +150,41 @@ func TestPolybiusDecrypt(t *testing.T) { }) } } + +func FuzzPolybius(f *testing.F) { + const ( + size = 5 + characters = "HogeF" + key = "abcdefghijklmnopqrstuvwxy" + ) + f.Add(size, characters, key) + f.Fuzz(func(t *testing.T, size int, characters, key string) { + p, err := NewPolybius(key, size, characters) + switch { + case err == nil: + case strings.Contains(err.Error(), "cannot be negative"), + strings.Contains(err.Error(), "is too small"), + strings.Contains(err.Error(), "should only contain latin characters"), + strings.Contains(err.Error(), "contains same character"), + strings.Contains(err.Error(), "must be as long as size squared"): + return + default: + t.Fatalf("unexpected error when creating a new polybius variable: %v", err) + } + encrypted, err := p.Encrypt(characters) + switch { + case err == nil: + case strings.Contains(err.Error(), "does not exist in keys"): + return + default: + t.Fatalf("unexpected error during encryption: %v", err) + } + decrypted, err := p.Decrypt(encrypted) + if err != nil { + t.Fatalf("unexpected error during decryption: %v", err) + } + if decrypted != strings.ToUpper(characters) { + t.Errorf("Expecting output to match with %q but was %q", characters, decrypted) + } + }) +} From f2296d57fb07dc482f6ea4b67eb37da45d36973e Mon Sep 17 00:00:00 2001 From: Akshay Dubey <38462415+itsAkshayDubey@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:23:08 +0530 Subject: [PATCH 389/488] algorithm: Pronic number (#595) --- math/pronicnumber.go | 21 ++ math/pronicnumber_test.go | 438 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 459 insertions(+) create mode 100644 math/pronicnumber.go create mode 100644 math/pronicnumber_test.go diff --git a/math/pronicnumber.go b/math/pronicnumber.go new file mode 100644 index 000000000..90850d28e --- /dev/null +++ b/math/pronicnumber.go @@ -0,0 +1,21 @@ +// pronicnumber.go +// description: Returns true if the number is pronic and false otherwise +// details: +// Pronic number: For any integer n, if there exists integer m +// such that n = m * (m + 1) then n is called a pronic number. +// wikipedia: https://en.wikipedia.org/wiki/Pronic_number +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see pronicnumber_test.go + +package math + +import stdMath "math" + +// PronicNumber returns true if argument passed to the function is pronic and false otherwise. +func PronicNumber(n int) bool { + if n < 0 || n%2 == 1 { + return false + } + x := int(stdMath.Sqrt(float64(n))) + return n == x*(x+1) +} diff --git a/math/pronicnumber_test.go b/math/pronicnumber_test.go new file mode 100644 index 000000000..34880d68e --- /dev/null +++ b/math/pronicnumber_test.go @@ -0,0 +1,438 @@ +// pronicnumber_test.go +// author: Akshay Dubey (https://github.com/itsAkshayDubey) +// see pronicnumber.go + +package math_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math" +) + +func TestPronicNumber(t *testing.T) { + var tests = []struct { + name string + n int + expectedValue bool + }{ + {"-12 is not pronic", -12, false}, + {"0 is pronic", 0, true}, + {"1 is not pronic", 1, false}, + {"2 is pronic", 2, true}, + {"3 is not pronic", 3, false}, + {"4 is not pronic", 4, false}, + {"5 is not pronic", 5, false}, + {"6 is pronic", 6, true}, + {"7 is not pronic", 7, false}, + {"8 is not pronic", 8, false}, + {"9 is not pronic", 9, false}, + {"10 is not pronic", 10, false}, + {"11 is not pronic", 11, false}, + {"12 is pronic", 12, true}, + {"13 is not pronic", 13, false}, + {"14 is not pronic", 14, false}, + {"15 is not pronic", 15, false}, + {"16 is not pronic", 16, false}, + {"17 is not pronic", 17, false}, + {"18 is not pronic", 18, false}, + {"19 is not pronic", 19, false}, + {"20 is pronic", 20, true}, + {"21 is not pronic", 21, false}, + {"22 is not pronic", 22, false}, + {"23 is not pronic", 23, false}, + {"24 is not pronic", 24, false}, + {"25 is not pronic", 25, false}, + {"26 is not pronic", 26, false}, + {"27 is not pronic", 27, false}, + {"28 is not pronic", 28, false}, + {"29 is not pronic", 29, false}, + {"30 is pronic", 30, true}, + {"31 is not pronic", 31, false}, + {"32 is not pronic", 32, false}, + {"33 is not pronic", 33, false}, + {"34 is not pronic", 34, false}, + {"35 is not pronic", 35, false}, + {"36 is not pronic", 36, false}, + {"37 is not pronic", 37, false}, + {"38 is not pronic", 38, false}, + {"39 is not pronic", 39, false}, + {"40 is not pronic", 40, false}, + {"41 is not pronic", 41, false}, + {"42 is pronic", 42, true}, + {"43 is not pronic", 43, false}, + {"44 is not pronic", 44, false}, + {"45 is not pronic", 45, false}, + {"46 is not pronic", 46, false}, + {"47 is not pronic", 47, false}, + {"48 is not pronic", 48, false}, + {"49 is not pronic", 49, false}, + {"50 is not pronic", 50, false}, + {"51 is not pronic", 51, false}, + {"52 is not pronic", 52, false}, + {"53 is not pronic", 53, false}, + {"54 is not pronic", 54, false}, + {"55 is not pronic", 55, false}, + {"56 is pronic", 56, true}, + {"57 is not pronic", 57, false}, + {"58 is not pronic", 58, false}, + {"59 is not pronic", 59, false}, + {"60 is not pronic", 60, false}, + {"61 is not pronic", 61, false}, + {"62 is not pronic", 62, false}, + {"63 is not pronic", 63, false}, + {"64 is not pronic", 64, false}, + {"65 is not pronic", 65, false}, + {"66 is not pronic", 66, false}, + {"67 is not pronic", 67, false}, + {"68 is not pronic", 68, false}, + {"69 is not pronic", 69, false}, + {"70 is not pronic", 70, false}, + {"71 is not pronic", 71, false}, + {"72 is pronic", 72, true}, + {"73 is not pronic", 73, false}, + {"74 is not pronic", 74, false}, + {"75 is not pronic", 75, false}, + {"76 is not pronic", 76, false}, + {"77 is not pronic", 77, false}, + {"78 is not pronic", 78, false}, + {"79 is not pronic", 79, false}, + {"80 is not pronic", 80, false}, + {"81 is not pronic", 81, false}, + {"82 is not pronic", 82, false}, + {"83 is not pronic", 83, false}, + {"84 is not pronic", 84, false}, + {"85 is not pronic", 85, false}, + {"86 is not pronic", 86, false}, + {"87 is not pronic", 87, false}, + {"88 is not pronic", 88, false}, + {"89 is not pronic", 89, false}, + {"90 is pronic", 90, true}, + {"91 is not pronic", 91, false}, + {"92 is not pronic", 92, false}, + {"93 is not pronic", 93, false}, + {"94 is not pronic", 94, false}, + {"95 is not pronic", 95, false}, + {"96 is not pronic", 96, false}, + {"97 is not pronic", 97, false}, + {"98 is not pronic", 98, false}, + {"99 is not pronic", 99, false}, + {"100 is not pronic", 100, false}, + {"101 is not pronic", 101, false}, + {"102 is not pronic", 102, false}, + {"103 is not pronic", 103, false}, + {"104 is not pronic", 104, false}, + {"105 is not pronic", 105, false}, + {"106 is not pronic", 106, false}, + {"107 is not pronic", 107, false}, + {"108 is not pronic", 108, false}, + {"109 is not pronic", 109, false}, + {"110 is pronic", 110, true}, + {"111 is not pronic", 111, false}, + {"112 is not pronic", 112, false}, + {"113 is not pronic", 113, false}, + {"114 is not pronic", 114, false}, + {"115 is not pronic", 115, false}, + {"116 is not pronic", 116, false}, + {"117 is not pronic", 117, false}, + {"118 is not pronic", 118, false}, + {"119 is not pronic", 119, false}, + {"120 is not pronic", 120, false}, + {"121 is not pronic", 121, false}, + {"122 is not pronic", 122, false}, + {"123 is not pronic", 123, false}, + {"124 is not pronic", 124, false}, + {"125 is not pronic", 125, false}, + {"126 is not pronic", 126, false}, + {"127 is not pronic", 127, false}, + {"128 is not pronic", 128, false}, + {"129 is not pronic", 129, false}, + {"130 is not pronic", 130, false}, + {"131 is not pronic", 131, false}, + {"132 is pronic", 132, true}, + {"133 is not pronic", 133, false}, + {"134 is not pronic", 134, false}, + {"135 is not pronic", 135, false}, + {"136 is not pronic", 136, false}, + {"137 is not pronic", 137, false}, + {"138 is not pronic", 138, false}, + {"139 is not pronic", 139, false}, + {"140 is not pronic", 140, false}, + {"141 is not pronic", 141, false}, + {"142 is not pronic", 142, false}, + {"143 is not pronic", 143, false}, + {"144 is not pronic", 144, false}, + {"145 is not pronic", 145, false}, + {"146 is not pronic", 146, false}, + {"147 is not pronic", 147, false}, + {"148 is not pronic", 148, false}, + {"149 is not pronic", 149, false}, + {"150 is not pronic", 150, false}, + {"151 is not pronic", 151, false}, + {"152 is not pronic", 152, false}, + {"153 is not pronic", 153, false}, + {"154 is not pronic", 154, false}, + {"155 is not pronic", 155, false}, + {"156 is pronic", 156, true}, + {"157 is not pronic", 157, false}, + {"158 is not pronic", 158, false}, + {"159 is not pronic", 159, false}, + {"160 is not pronic", 160, false}, + {"161 is not pronic", 161, false}, + {"162 is not pronic", 162, false}, + {"163 is not pronic", 163, false}, + {"164 is not pronic", 164, false}, + {"165 is not pronic", 165, false}, + {"166 is not pronic", 166, false}, + {"167 is not pronic", 167, false}, + {"168 is not pronic", 168, false}, + {"169 is not pronic", 169, false}, + {"170 is not pronic", 170, false}, + {"171 is not pronic", 171, false}, + {"172 is not pronic", 172, false}, + {"173 is not pronic", 173, false}, + {"174 is not pronic", 174, false}, + {"175 is not pronic", 175, false}, + {"176 is not pronic", 176, false}, + {"177 is not pronic", 177, false}, + {"178 is not pronic", 178, false}, + {"179 is not pronic", 179, false}, + {"180 is not pronic", 180, false}, + {"181 is not pronic", 181, false}, + {"182 is pronic", 182, true}, + {"183 is not pronic", 183, false}, + {"184 is not pronic", 184, false}, + {"185 is not pronic", 185, false}, + {"186 is not pronic", 186, false}, + {"187 is not pronic", 187, false}, + {"188 is not pronic", 188, false}, + {"189 is not pronic", 189, false}, + {"190 is not pronic", 190, false}, + {"191 is not pronic", 191, false}, + {"192 is not pronic", 192, false}, + {"193 is not pronic", 193, false}, + {"194 is not pronic", 194, false}, + {"195 is not pronic", 195, false}, + {"196 is not pronic", 196, false}, + {"197 is not pronic", 197, false}, + {"198 is not pronic", 198, false}, + {"199 is not pronic", 199, false}, + {"200 is not pronic", 200, false}, + {"201 is not pronic", 201, false}, + {"202 is not pronic", 202, false}, + {"203 is not pronic", 203, false}, + {"204 is not pronic", 204, false}, + {"205 is not pronic", 205, false}, + {"206 is not pronic", 206, false}, + {"207 is not pronic", 207, false}, + {"208 is not pronic", 208, false}, + {"209 is not pronic", 209, false}, + {"210 is pronic", 210, true}, + {"211 is not pronic", 211, false}, + {"212 is not pronic", 212, false}, + {"213 is not pronic", 213, false}, + {"214 is not pronic", 214, false}, + {"215 is not pronic", 215, false}, + {"216 is not pronic", 216, false}, + {"217 is not pronic", 217, false}, + {"218 is not pronic", 218, false}, + {"219 is not pronic", 219, false}, + {"220 is not pronic", 220, false}, + {"221 is not pronic", 221, false}, + {"222 is not pronic", 222, false}, + {"223 is not pronic", 223, false}, + {"224 is not pronic", 224, false}, + {"225 is not pronic", 225, false}, + {"226 is not pronic", 226, false}, + {"227 is not pronic", 227, false}, + {"228 is not pronic", 228, false}, + {"229 is not pronic", 229, false}, + {"230 is not pronic", 230, false}, + {"231 is not pronic", 231, false}, + {"232 is not pronic", 232, false}, + {"233 is not pronic", 233, false}, + {"234 is not pronic", 234, false}, + {"235 is not pronic", 235, false}, + {"236 is not pronic", 236, false}, + {"237 is not pronic", 237, false}, + {"238 is not pronic", 238, false}, + {"239 is not pronic", 239, false}, + {"240 is pronic", 240, true}, + {"241 is not pronic", 241, false}, + {"242 is not pronic", 242, false}, + {"243 is not pronic", 243, false}, + {"244 is not pronic", 244, false}, + {"245 is not pronic", 245, false}, + {"246 is not pronic", 246, false}, + {"247 is not pronic", 247, false}, + {"248 is not pronic", 248, false}, + {"249 is not pronic", 249, false}, + {"250 is not pronic", 250, false}, + {"251 is not pronic", 251, false}, + {"252 is not pronic", 252, false}, + {"253 is not pronic", 253, false}, + {"254 is not pronic", 254, false}, + {"255 is not pronic", 255, false}, + {"256 is not pronic", 256, false}, + {"257 is not pronic", 257, false}, + {"258 is not pronic", 258, false}, + {"259 is not pronic", 259, false}, + {"260 is not pronic", 260, false}, + {"261 is not pronic", 261, false}, + {"262 is not pronic", 262, false}, + {"263 is not pronic", 263, false}, + {"264 is not pronic", 264, false}, + {"265 is not pronic", 265, false}, + {"266 is not pronic", 266, false}, + {"267 is not pronic", 267, false}, + {"268 is not pronic", 268, false}, + {"269 is not pronic", 269, false}, + {"270 is not pronic", 270, false}, + {"271 is not pronic", 271, false}, + {"272 is pronic", 272, true}, + {"273 is not pronic", 273, false}, + {"274 is not pronic", 274, false}, + {"275 is not pronic", 275, false}, + {"276 is not pronic", 276, false}, + {"277 is not pronic", 277, false}, + {"278 is not pronic", 278, false}, + {"279 is not pronic", 279, false}, + {"280 is not pronic", 280, false}, + {"281 is not pronic", 281, false}, + {"282 is not pronic", 282, false}, + {"283 is not pronic", 283, false}, + {"284 is not pronic", 284, false}, + {"285 is not pronic", 285, false}, + {"286 is not pronic", 286, false}, + {"287 is not pronic", 287, false}, + {"288 is not pronic", 288, false}, + {"289 is not pronic", 289, false}, + {"290 is not pronic", 290, false}, + {"291 is not pronic", 291, false}, + {"292 is not pronic", 292, false}, + {"293 is not pronic", 293, false}, + {"294 is not pronic", 294, false}, + {"295 is not pronic", 295, false}, + {"296 is not pronic", 296, false}, + {"297 is not pronic", 297, false}, + {"298 is not pronic", 298, false}, + {"299 is not pronic", 299, false}, + {"300 is not pronic", 300, false}, + {"301 is not pronic", 301, false}, + {"302 is not pronic", 302, false}, + {"303 is not pronic", 303, false}, + {"304 is not pronic", 304, false}, + {"305 is not pronic", 305, false}, + {"306 is pronic", 306, true}, + {"307 is not pronic", 307, false}, + {"308 is not pronic", 308, false}, + {"309 is not pronic", 309, false}, + {"310 is not pronic", 310, false}, + {"311 is not pronic", 311, false}, + {"312 is not pronic", 312, false}, + {"313 is not pronic", 313, false}, + {"314 is not pronic", 314, false}, + {"315 is not pronic", 315, false}, + {"316 is not pronic", 316, false}, + {"317 is not pronic", 317, false}, + {"318 is not pronic", 318, false}, + {"319 is not pronic", 319, false}, + {"320 is not pronic", 320, false}, + {"321 is not pronic", 321, false}, + {"322 is not pronic", 322, false}, + {"323 is not pronic", 323, false}, + {"324 is not pronic", 324, false}, + {"325 is not pronic", 325, false}, + {"326 is not pronic", 326, false}, + {"327 is not pronic", 327, false}, + {"328 is not pronic", 328, false}, + {"329 is not pronic", 329, false}, + {"330 is not pronic", 330, false}, + {"331 is not pronic", 331, false}, + {"332 is not pronic", 332, false}, + {"333 is not pronic", 333, false}, + {"334 is not pronic", 334, false}, + {"335 is not pronic", 335, false}, + {"336 is not pronic", 336, false}, + {"337 is not pronic", 337, false}, + {"338 is not pronic", 338, false}, + {"339 is not pronic", 339, false}, + {"340 is not pronic", 340, false}, + {"341 is not pronic", 341, false}, + {"342 is pronic", 342, true}, + {"343 is not pronic", 343, false}, + {"344 is not pronic", 344, false}, + {"345 is not pronic", 345, false}, + {"346 is not pronic", 346, false}, + {"347 is not pronic", 347, false}, + {"348 is not pronic", 348, false}, + {"349 is not pronic", 349, false}, + {"350 is not pronic", 350, false}, + {"351 is not pronic", 351, false}, + {"352 is not pronic", 352, false}, + {"353 is not pronic", 353, false}, + {"354 is not pronic", 354, false}, + {"355 is not pronic", 355, false}, + {"356 is not pronic", 356, false}, + {"357 is not pronic", 357, false}, + {"358 is not pronic", 358, false}, + {"359 is not pronic", 359, false}, + {"360 is not pronic", 360, false}, + {"361 is not pronic", 361, false}, + {"362 is not pronic", 362, false}, + {"363 is not pronic", 363, false}, + {"364 is not pronic", 364, false}, + {"365 is not pronic", 365, false}, + {"366 is not pronic", 366, false}, + {"367 is not pronic", 367, false}, + {"368 is not pronic", 368, false}, + {"369 is not pronic", 369, false}, + {"370 is not pronic", 370, false}, + {"371 is not pronic", 371, false}, + {"372 is not pronic", 372, false}, + {"373 is not pronic", 373, false}, + {"374 is not pronic", 374, false}, + {"375 is not pronic", 375, false}, + {"376 is not pronic", 376, false}, + {"377 is not pronic", 377, false}, + {"378 is not pronic", 378, false}, + {"379 is not pronic", 379, false}, + {"380 is pronic", 380, true}, + {"381 is not pronic", 381, false}, + {"382 is not pronic", 382, false}, + {"383 is not pronic", 383, false}, + {"384 is not pronic", 384, false}, + {"385 is not pronic", 385, false}, + {"386 is not pronic", 386, false}, + {"387 is not pronic", 387, false}, + {"388 is not pronic", 388, false}, + {"389 is not pronic", 389, false}, + {"390 is not pronic", 390, false}, + {"391 is not pronic", 391, false}, + {"392 is not pronic", 392, false}, + {"393 is not pronic", 393, false}, + {"394 is not pronic", 394, false}, + {"395 is not pronic", 395, false}, + {"396 is not pronic", 396, false}, + {"397 is not pronic", 397, false}, + {"398 is not pronic", 398, false}, + {"399 is not pronic", 399, false}, + {"400 is not pronic", 400, false}, + {"2147441940 is pronic", 2147441940, true}, + {"9223372033963249500 is pronic", 9223372033963249500, true}, + {"9223372033963249664 is not pronic", 9223372033963249664, false}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := math.PronicNumber(test.n) + if result != test.expectedValue { + t.Errorf("expected value: %v, got: %v", test.expectedValue, result) + } + }) + } +} +func BenchmarkPronicNumber(b *testing.B) { + for i := 0; i < b.N; i++ { + math.PronicNumber(65536) + } +} From 79ff8f173b423af91b639d36c8efbc5d8456c2dd Mon Sep 17 00:00:00 2001 From: M3talM0nk3y Date: Sun, 13 Nov 2022 12:46:30 -0500 Subject: [PATCH 390/488] algorithm: check if string is isogram (#599) --- strings/isisogram.go | 71 +++++++++++++++++++++ strings/isisogram_test.go | 131 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 strings/isisogram.go create mode 100644 strings/isisogram_test.go diff --git a/strings/isisogram.go b/strings/isisogram.go new file mode 100644 index 000000000..1a3c1a55a --- /dev/null +++ b/strings/isisogram.go @@ -0,0 +1,71 @@ +// Checks if a given string is an isogram. +// A first-order isogram is a word in which no letter of the alphabet occurs more than once. +// A second-order isogram is a word in which each letter appears twice. +// A third-order isogram is a word in which each letter appears three times. +// wiki: https://en.wikipedia.org/wiki/Heterogram_(literature)#Isograms +// Author: M3talM0nk3y + +package strings + +import ( + "errors" + "regexp" + "strings" +) + +type IsogramOrder int + +const ( + First IsogramOrder = iota + 1 + Second + Third +) + +func hasDigit(text string) bool { + re := regexp.MustCompile(`\d`) + return re.MatchString(text) +} + +func hasSymbol(text string) bool { + re := regexp.MustCompile(`[-!@#$%^&*()+]`) + return re.MatchString(text) +} + +func IsIsogram(text string, order IsogramOrder) (bool, error) { + if order < First || order > Third { + return false, errors.New("Invalid isogram order provided") + } + + text = strings.ToLower(text) + text = strings.Join(strings.Fields(text), "") + + if hasDigit(text) || hasSymbol(text) { + return false, errors.New("Cannot contain numbers or symbols") + } + + letters := make(map[string]int) + for _, c := range text { + l := string(c) + if _, ok := letters[l]; ok { + letters[l] += 1 + + if letters[l] > 3 { + return false, nil + } + + continue + } + letters[l] = 1 + } + + mapVals := make(map[int]bool) + for _, v := range letters { + mapVals[v] = true + } + + if _, ok := mapVals[int(order)]; ok && len(mapVals) == 1 { + return true, nil + } + + return false, nil +} diff --git a/strings/isisogram_test.go b/strings/isisogram_test.go new file mode 100644 index 000000000..0b54333e6 --- /dev/null +++ b/strings/isisogram_test.go @@ -0,0 +1,131 @@ +package strings_test + +import ( + "errors" + "testing" + + "github.com/TheAlgorithms/Go/strings" +) + +var testCases = []struct { + name string + input string + order strings.IsogramOrder + expectedVal bool + expectedErr error +}{ + { + "Alphanumeric string 1", + "copy1", + 1, + false, + errors.New("Cannot contain numbers or symbols"), + }, + { + "Alphanumeric string 2", + "copy1sentence", + 1, + false, + errors.New("Cannot contain numbers or symbols"), + }, + { + "Alphanumeric string 3", + "copy1 sentence with space", + 1, + false, + errors.New("Cannot contain numbers or symbols"), + }, + { + "Alphabetic string 1", + "allowance", + 1, + false, + nil, + }, + { + "Alphabetic string 2", + "My Doodle", + 1, + false, + nil, + }, + { + "Alphabetic string with symbol", + "Isogram!", + 1, + false, + errors.New("Cannot contain numbers or symbols"), + }, + { + "Isogram string 1", + "Uncopyrightable", + 1, + true, + nil, + }, + { + "Second order isogram 1", + "Caucasus", + 2, + true, + nil, + }, + { + "Second order isogram 2", + "Couscous", + 2, + true, + nil, + }, + { + "Third order isogram 1", + "Deeded", + 3, + true, + nil, + }, + { + "Third order isogram 2", + "Sestettes", + 3, + true, + nil, + }, + { + "Not an isogram", + "Pneumonoultramicroscopicsilicovolcanoconiosis", + 1, + false, + nil, + }, + { + "Not an isogram", + "Randomstring", + 4, + false, + errors.New("Invalid isogram order provided"), + }, + { + "Third order isogram checked as first order", + "Deeded", + 1, + false, + nil, + }, +} + +func TestIsIsogram(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + actualVal, actualErr := strings.IsIsogram(test.input, test.order) + + if actualErr != nil && test.expectedErr.Error() != actualErr.Error() { + t.Errorf("Expected to be '%v' for string %s but was '%v'.", test.expectedErr, test.input, actualErr) + } + + if test.expectedVal != actualVal { + t.Errorf("Expected to be '%v' for string %s but was '%v'.", test.expectedVal, test.input, actualVal) + } + }) + } +} From 54f082bf028e5d6dc09f63167ed837e5d4501759 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Mon, 21 Nov 2022 12:20:16 +0100 Subject: [PATCH 391/488] feat(cipher/transposition): add fuzz test to transposition cipher #600 (#601) --- cipher/transposition/transposition.go | 43 ++++++----- cipher/transposition/transposition_test.go | 84 +++++++++++++++------- 2 files changed, 78 insertions(+), 49 deletions(-) diff --git a/cipher/transposition/transposition.go b/cipher/transposition/transposition.go index e27020b43..6365ffa4a 100644 --- a/cipher/transposition/transposition.go +++ b/cipher/transposition/transposition.go @@ -8,19 +8,16 @@ package transposition import ( + "errors" + "fmt" "sort" "strings" ) -type NoTextToEncryptError struct{} -type KeyMissingError struct{} +var ErrNoTextToEncrypt = errors.New("no text to encrypt") +var ErrKeyMissing = errors.New("missing Key") -func (n *NoTextToEncryptError) Error() string { - return "No text to encrypt" -} -func (n *KeyMissingError) Error() string { - return "Missing Key" -} +const placeholder = ' ' func getKey(keyWord string) []int { keyWord = strings.ToLower(keyWord) @@ -51,56 +48,58 @@ func getIndex(wordSet []rune, subString rune) int { return 0 } -func Encrypt(text []rune, keyWord string) (string, error) { +func Encrypt(text []rune, keyWord string) ([]rune, error) { key := getKey(keyWord) - space := ' ' keyLength := len(key) textLength := len(text) if keyLength <= 0 { - return "", &KeyMissingError{} + return nil, ErrKeyMissing } if textLength <= 0 { - return "", &NoTextToEncryptError{} + return nil, ErrNoTextToEncrypt + } + if text[len(text)-1] == placeholder { + return nil, fmt.Errorf("%w: cannot encrypt a text, %q, ending with the placeholder char %q", ErrNoTextToEncrypt, text, placeholder) } n := textLength % keyLength for i := 0; i < keyLength-n; i++ { - text = append(text, space) + text = append(text, placeholder) } textLength = len(text) - result := "" + var result []rune for i := 0; i < textLength; i += keyLength { transposition := make([]rune, keyLength) for j := 0; j < keyLength; j++ { transposition[key[j]-1] = text[i+j] } - result += string(transposition) + result = append(result, transposition...) } return result, nil } -func Decrypt(text []rune, keyWord string) (string, error) { +func Decrypt(text []rune, keyWord string) ([]rune, error) { key := getKey(keyWord) textLength := len(text) if textLength <= 0 { - return "", &NoTextToEncryptError{} + return nil, ErrNoTextToEncrypt } keyLength := len(key) if keyLength <= 0 { - return "", &KeyMissingError{} + return nil, ErrKeyMissing } - space := ' ' n := textLength % keyLength for i := 0; i < keyLength-n; i++ { - text = append(text, space) + text = append(text, placeholder) } - result := "" + var result []rune for i := 0; i < textLength; i += keyLength { transposition := make([]rune, keyLength) for j := 0; j < keyLength; j++ { transposition[j] = text[i+key[j]-1] } - result += string(transposition) + result = append(result, transposition...) } + result = []rune(strings.TrimRight(string(result), string(placeholder))) return result, nil } diff --git a/cipher/transposition/transposition_test.go b/cipher/transposition/transposition_test.go index f2f155a15..250f43832 100644 --- a/cipher/transposition/transposition_test.go +++ b/cipher/transposition/transposition_test.go @@ -8,20 +8,18 @@ package transposition import ( "errors" "math/rand" - "strings" + "reflect" "testing" ) -const enAlphabet = "abcdefghijklmnopqrstuvwxyz " +const enAlphabet = "abcdefghijklmnopqrstuvwxyz" -func getTexts() []string { - return []string{ - "Ilya Sokolov", - "A slice literal is declared just like an array literal, except you leave out the element count", - "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.", - "Go’s treatment of errors as values has served us well over the last decade. Although the standard library’s support for errors has been minimal—just the errors.New and fmt.Errorf functions, which produce errors that contain only a message—the built-in error interface allows Go programmers to add whatever information they desire. All it requires is a type that implements an Error method:", - "А тут для примера русский текст", - } +var texts = []string{ + "Ilya Sokolov", + "A slice literal is declared just like an array literal, except you leave out the element count", + "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.", + "Go’s treatment of errors as values has served us well over the last decade. Although the standard library’s support for errors has been minimal—just the errors.New and fmt.Errorf functions, which produce errors that contain only a message—the built-in error interface allows Go programmers to add whatever information they desire. All it requires is a type that implements an Error method:", + "А тут для примера русский текст", } func getRandomString() string { @@ -36,12 +34,12 @@ func getRandomString() string { func TestEncrypt(t *testing.T) { fn := func(text string, keyWord string) (bool, error) { encrypt, err := Encrypt([]rune(text), keyWord) - if err != nil && !errors.Is(err, &NoTextToEncryptError{}) && !errors.Is(err, &KeyMissingError{}) { + if err != nil && !errors.Is(err, ErrNoTextToEncrypt) && !errors.Is(err, ErrKeyMissing) { t.Error("Unexpected error ", err) } - return text == encrypt, err + return text == string(encrypt), err } - for _, s := range getTexts() { + for _, s := range texts { if check, err := fn(s, getRandomString()); check || err != nil { t.Error("String ", s, " not encrypted") } @@ -52,12 +50,12 @@ func TestEncrypt(t *testing.T) { } func TestDecrypt(t *testing.T) { - for _, s := range getTexts() { + for _, s := range texts { keyWord := getRandomString() encrypt, errEncrypt := Encrypt([]rune(s), keyWord) if errEncrypt != nil && - !errors.Is(errEncrypt, &NoTextToEncryptError{}) && - !errors.Is(errEncrypt, &KeyMissingError{}) { + !errors.Is(errEncrypt, ErrNoTextToEncrypt) && + !errors.Is(errEncrypt, ErrKeyMissing) { t.Error("Unexpected error ", errEncrypt) } if errEncrypt != nil { @@ -65,39 +63,71 @@ func TestDecrypt(t *testing.T) { } decrypt, errDecrypt := Decrypt([]rune(encrypt), keyWord) if errDecrypt != nil && - !errors.Is(errDecrypt, &NoTextToEncryptError{}) && - !errors.Is(errDecrypt, &KeyMissingError{}) { + !errors.Is(errDecrypt, ErrNoTextToEncrypt) && + !errors.Is(errDecrypt, ErrKeyMissing) { t.Error("Unexpected error ", errDecrypt) } if errDecrypt != nil { t.Error(errDecrypt) } - if encrypt == decrypt { + if reflect.DeepEqual(encrypt, decrypt) { t.Error("String ", s, " not encrypted") } - if encrypt == s { + if reflect.DeepEqual(encrypt, s) { t.Error("String ", s, " not encrypted") } } } func TestEncryptDecrypt(t *testing.T) { - text := "Test text for checking the algorithm" + text := []rune("Test text for checking the algorithm") key1 := "testKey" key2 := "Test Key2" - encrypt, errEncrypt := Encrypt([]rune(text), key1) + encrypt, errEncrypt := Encrypt(text, key1) if errEncrypt != nil { t.Error(errEncrypt) } - decrypt, errDecrypt := Decrypt([]rune(encrypt), key1) + decrypt, errDecrypt := Decrypt(encrypt, key1) if errDecrypt != nil { t.Error(errDecrypt) } - if strings.Contains(decrypt, text) == false { - t.Error("The string was not decrypted correctly") + if !reflect.DeepEqual(decrypt, text) { + t.Errorf("The string was not decrypted correctly %q %q", decrypt, text) } decrypt, _ = Decrypt([]rune(encrypt), key2) - if strings.Contains(decrypt, text) == true { - t.Error("The string was decrypted with a different key") + if reflect.DeepEqual(decrypt, text) { + t.Errorf("The string was decrypted with a different key: %q %q", decrypt, text) + } +} + +func FuzzTransposition(f *testing.F) { + for _, transpositionTestInput := range texts { + f.Add(transpositionTestInput) } + f.Fuzz(func(t *testing.T, input string) { + keyword := getRandomString() + message := []rune(input) + encrypted, err := Encrypt(message, keyword) + switch { + case err == nil: + case errors.Is(err, ErrKeyMissing), + errors.Is(err, ErrNoTextToEncrypt): + return + default: + t.Fatalf("unexpected error when encrypting string %q: %v", input, err) + } + decrypted, err := Decrypt([]rune(encrypted), keyword) + switch { + case err == nil: + case errors.Is(err, ErrKeyMissing), + errors.Is(err, ErrNoTextToEncrypt): + return + default: + t.Fatalf("unexpected error when decrypting string %q: %v", encrypted, err) + } + + if !reflect.DeepEqual(message, decrypted) { + t.Fatalf("expected: %+v, got: %+v", message, []rune(decrypted)) + } + }) } From d21128ee8cc06147246d3cf872ab45023962369e Mon Sep 17 00:00:00 2001 From: tabosuke <45633620+tabo-syu@users.noreply.github.com> Date: Tue, 22 Nov 2022 02:12:53 +0900 Subject: [PATCH 392/488] fix: Fix file name of constraints package (#608) --- constraints/{contraints.go => constraints.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename constraints/{contraints.go => constraints.go} (100%) diff --git a/constraints/contraints.go b/constraints/constraints.go similarity index 100% rename from constraints/contraints.go rename to constraints/constraints.go From c027418e6c6529b86232dc3999a43b918cf5c874 Mon Sep 17 00:00:00 2001 From: hypntc <88018994+hypntc@users.noreply.github.com> Date: Sat, 26 Nov 2022 19:41:57 +0100 Subject: [PATCH 393/488] algorithm: bucketsort and pancakesort (#606) --- README.md | 38 +++++++++++++++++++------------------ sort/bucketsort.go | 46 +++++++++++++++++++++++++++++++++++++++++++++ sort/pancakesort.go | 44 +++++++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 16 ++++++++++++++++ 4 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 sort/bucketsort.go create mode 100644 sort/pancakesort.go diff --git a/README.md b/README.md index 06be382be..931f1af5c 100644 --- a/README.md +++ b/README.md @@ -867,24 +867,26 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Bubble`](./sort/bubblesort.go#L9): Bubble is a simple generic definition of Bubble sort algorithm. -2. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. -3. [`Count`](./sort/countingsort.go#L11): No description provided. -4. [`Exchange`](./sort/exchangesort.go#L8): No description provided. -5. [`HeapSort`](./sort/heapsort.go#L116): No description provided. -6. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort -7. [`Insertion`](./sort/insertionsort.go#L5): No description provided. -8. [`Merge`](./sort/mergesort.go#L41): Merge Perform merge sort on a slice -9. [`MergeIter`](./sort/mergesort.go#L55): No description provided. -10. [`ParallelMerge`](./sort/mergesort.go#L66): ParallelMerge Perform merge sort on a slice using goroutines -11. [`Partition`](./sort/quicksort.go#L12): No description provided. -12. [`Patience`](./sort/patiencesort.go#L13): No description provided. -13. [`Pigeonhole`](./sort/pigeonholesort.go#L15): Pigeonhole sorts a slice using pigeonhole sorting algorithm. NOTE: To maintain time complexity O(n + N), this is the reason for having only Integer constraint instead of Ordered. -14. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array -15. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array -16. [`RadixSort`](./sort/radixsort.go#L43): No description provided. -17. [`Selection`](./sort/selectionsort.go#L5): No description provided. -18. [`Shell`](./sort/shellsort.go#L5): No description provided. -19. [`Simple`](./sort/simplesort.go#L13): No description provided. +2. [`Bucket Sort`](./sort/bucketsort.go#L5): Bucket Sort works with the idea of distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm, or by recursively applying the bucket sorting algorithm. +3. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. +4. [`Count`](./sort/countingsort.go#L11): No description provided. +5. [`Exchange`](./sort/exchangesort.go#L8): No description provided. +6. [`HeapSort`](./sort/heapsort.go#L116): No description provided. +7. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort +8. [`Insertion`](./sort/insertionsort.go#L5): No description provided. +9. [`Merge`](./sort/mergesort.go#L41): Merge Perform merge sort on a slice +10. [`MergeIter`](./sort/mergesort.go#L55): No description provided. +11. [`Pancake Sort`](./sort/pancakesort.go#L7): Pancake Sort is a sorting algorithm that is similar to selection sort that reverses elements of an array. The Pancake Sort uses the flip operation to sort the array. +12. [`ParallelMerge`](./sort/mergesort.go#L66): ParallelMerge Perform merge sort on a slice using goroutines +13. [`Partition`](./sort/quicksort.go#L12): No description provided. +14. [`Patience`](./sort/patiencesort.go#L13): No description provided. +15. [`Pigeonhole`](./sort/pigeonholesort.go#L15): Pigeonhole sorts a slice using pigeonhole sorting algorithm. NOTE: To maintain time complexity O(n + N), this is the reason for having only Integer constraint instead of Ordered. +16. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array +17. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array +18. [`RadixSort`](./sort/radixsort.go#L43): No description provided. +19. [`Selection`](./sort/selectionsort.go#L5): No description provided. +20. [`Shell`](./sort/shellsort.go#L5): No description provided. +21. [`Simple`](./sort/simplesort.go#L13): No description provided. --- ##### Types diff --git a/sort/bucketsort.go b/sort/bucketsort.go new file mode 100644 index 000000000..3f05a41a4 --- /dev/null +++ b/sort/bucketsort.go @@ -0,0 +1,46 @@ +package sort + +import "github.com/TheAlgorithms/Go/constraints" + +// Bucket sorts a slice. It is mainly useful +// when input is uniformly distributed over a range. +func Bucket[T constraints.Number](arr []T) []T { + // early return if the array too small + if len(arr) <= 1 { + return arr + } + + // find the maximum and minimum elements in arr + max := arr[0] + min := arr[0] + for _, v := range arr { + if v > max { + max = v + } + if v < min { + min = v + } + } + + // create an empty bucket for each element in arr + bucket := make([][]T, len(arr)) + + // put each element in the appropriate bucket + for _, v := range arr { + bucketIndex := int((v - min) / (max - min) * T(len(arr)-1)) + bucket[bucketIndex] = append(bucket[bucketIndex], v) + } + + // use insertion sort to sort each bucket + for i := range bucket { + bucket[i] = Insertion(bucket[i]) + } + + // concatenate the sorted buckets + sorted := make([]T, 0, len(arr)) + for _, v := range bucket { + sorted = append(sorted, v...) + } + + return sorted +} diff --git a/sort/pancakesort.go b/sort/pancakesort.go new file mode 100644 index 000000000..a809ba1c4 --- /dev/null +++ b/sort/pancakesort.go @@ -0,0 +1,44 @@ +package sort + +import "github.com/TheAlgorithms/Go/constraints" + +// Pancake sorts a slice using flip operations, +// where flip refers to the idea of reversing the +// slice from index `0` to `i`. +func Pancake[T constraints.Ordered](arr []T) []T { + // early return if the array too small + if len(arr) <= 1 { + return arr + } + + // start from the end of the array + for i := len(arr) - 1; i > 0; i-- { + // find the index of the maximum element in arr + max := 0 + for j := 1; j <= i; j++ { + if arr[j] > arr[max] { + max = j + } + } + + // if the maximum element is not at the end of the array + if max != i { + // flip the maximum element to the beginning of the array + arr = flip(arr, max) + + // flip the maximum element to the end of the array by flipping the whole array + arr = flip(arr, i) + } + } + + return arr +} + +// flip reverses the input slice from `0` to `i`. +func flip[T constraints.Ordered](arr []T, i int) []T { + for j := 0; j < i; j++ { + arr[j], arr[i] = arr[i], arr[j] + i-- + } + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index ecee3d33c..9f34a23cb 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -81,6 +81,10 @@ func TestBubble(t *testing.T) { testFramework(t, sort.Bubble[int]) } +func TestBucketSort(t *testing.T) { + testFramework(t, sort.Bucket[int]) +} + func TestExchange(t *testing.T) { testFramework(t, sort.Exchange[int]) } @@ -153,6 +157,10 @@ func TestComb(t *testing.T) { testFramework(t, sort.Comb[int]) } +func TestPancakeSort(t *testing.T) { + testFramework(t, sort.Pancake[int]) +} + func TestPigeonhole(t *testing.T) { testFramework(t, sort.Pigeonhole[int]) } @@ -206,6 +214,10 @@ func BenchmarkBubble(b *testing.B) { benchmarkFramework(b, sort.Bubble[int]) } +func BenchmarkBucketSort(b *testing.B) { + benchmarkFramework(b, sort.Bucket[int]) +} + func BenchmarkExchange(b *testing.B) { benchmarkFramework(b, sort.Exchange[int]) } @@ -263,6 +275,10 @@ func BenchmarkComb(b *testing.B) { benchmarkFramework(b, sort.Comb[int]) } +func BenchmarkPancakeSort(b *testing.B) { + benchmarkFramework(b, sort.Pancake[int]) +} + func BenchmarkPigeonhole(b *testing.B) { benchmarkFramework(b, sort.Pigeonhole[int]) } From 41fa294871a58f0da65500a01c413e287fdbf0b4 Mon Sep 17 00:00:00 2001 From: Reo Uehara <47747828+uh-zz@users.noreply.github.com> Date: Sun, 4 Dec 2022 23:29:58 +0900 Subject: [PATCH 394/488] Add: kmp(Knuth-Morris-Pratt) algorithm (#586) --- README.md | 8 +-- strings/kmp/kmp.go | 132 ++++++++++------------------------------ strings/kmp/kmp_test.go | 87 ++++++++++++++------------ 3 files changed, 81 insertions(+), 146 deletions(-) diff --git a/README.md b/README.md index 931f1af5c..f672ba088 100644 --- a/README.md +++ b/README.md @@ -435,13 +435,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`Kmp`](./strings/kmp/kmp.go#L70): Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. Prints whether the word/pattern was found and on what position in the text or not. m - current match in text, i - current character in w, c - amount of comparisons. - ---- -##### Types - -1. [`Result`](./strings/kmp/kmp.go#L15): No description provided. - +1. [`Kmp`](./strings/kmp/kmp.go#L4): Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. ---
diff --git a/strings/kmp/kmp.go b/strings/kmp/kmp.go index a0f138724..cef57d7d1 100644 --- a/strings/kmp/kmp.go +++ b/strings/kmp/kmp.go @@ -1,117 +1,49 @@ package kmp -import ( - "fmt" -) - -// User defined. -// Set to true to read input from two command line arguments -// Set to false to read input from two files "pattern.txt" and "text.txt" - -// const isTakingInputFromCommandLine bool = true - -const notFoundPosition int = -1 - -type Result struct { - resultPosition int - numberOfComparison int -} - -// Implementation of Knuth-Morris-Pratt algorithm (Prefix based approach). -// Requires either a two command line arguments separated by a single space, -// or two files in the same folder: "pattern.txt" containing the string to -// be searched for, "text.txt" containing the text to be searched in. -// func main() { -// var text string -// var word string - -// if isTakingInputFromCommandLine { // case of command line input -// args := os.Args -// if len(args) <= 2 { -// log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") -// } -// word = args[1] -// text = args[2] -// for i := 3; i < len(args); i++ { -// text = text + " " + args[i] -// } -// } else { // case of file input -// patFile, err := ioutil.ReadFile("../pattern.txt") -// if err != nil { -// log.Fatal(err) -// } -// textFile, err := ioutil.ReadFile("../text.txt") -// if err != nil { -// log.Fatal(err) -// } -// text = string(textFile) -// word = string(patFile) -// } +// Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. +func Kmp(word, text string, patternTable []int) []int { + if len(word) > len(text) { + return nil + } -// if len(word) > len(text) { -// log.Fatal("Pattern is longer than text!") -// } -// fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n") -// fmt.Printf("Search word (%d chars long): %q.\n", len(word), word) -// fmt.Printf("Text (%d chars long): %q.\n\n", len(text), text) + var ( + i, j int + matches []int + ) + for i+j < len(text) { -// r := kmp(text, word) -// if r.resultPosition == notFoundPosition { -// fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", r.numberOfComparison) -// } else { -// fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word, -// r.resultPosition, text, r.numberOfComparison) -// } -// } + if word[j] == text[i+j] { + j++ + if j == len(word) { + matches = append(matches, i) -// Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. -// Prints whether the word/pattern was found and on what position in the text or not. -// m - current match in text, i - current character in w, c - amount of comparisons. -func Kmp(text string, word string) Result { - m, i, c := 0, 0, 0 - t := kmpTable(word) - for m+i < len(text) { - fmt.Printf("\n comparing characters %c %c at positions %d %d", text[m+i], word[i], m+i, i) - c++ - if word[i] == text[m+i] { - fmt.Printf(" - match") - if i == len(word)-1 { - return Result{ - m, c, - } + i = i + j + j = 0 } - i++ } else { - m = m + i - t[i] - if t[i] > -1 { - i = t[i] + i = i + j - patternTable[j] + if patternTable[j] > -1 { + j = patternTable[j] } else { - i = 0 + j = 0 } } } - return Result{notFoundPosition, - c, - } + return matches } -// Table building algorithm. -// Takes word to be analyzed and table to be filled. -func kmpTable(word string) (t []int) { - t = make([]int, len(word)) - pos, cnd := 2, 0 - t[0], t[1] = -1, 0 - for pos < len(word) { - if word[pos-1] == word[cnd] { - cnd++ - t[pos] = cnd - pos++ - } else if cnd > 0 { - cnd = t[cnd] - } else { - t[pos] = 0 - pos++ +// table building for kmp algorithm. +func table(w string) []int { + var ( + t []int = []int{-1} + k int + ) + for j := 1; j < len(w); j++ { + k = j - 1 + for w[0:k] != w[j-k:j] && k > 0 { + k-- } + t = append(t, k) } return t } diff --git a/strings/kmp/kmp_test.go b/strings/kmp/kmp_test.go index f25c68a07..4d012986a 100644 --- a/strings/kmp/kmp_test.go +++ b/strings/kmp/kmp_test.go @@ -5,48 +5,57 @@ import ( "testing" ) -var testCases = []struct { - name string - word string - text string - expected Result -}{ - { - "String comparison on single pattern match", - "announce", - "CPM_annual_conference_announce", - Result{ - 22, - 32, - }, - }, - { - "String comparison on multiple pattern match", - "AABA", - "AABAACAADAABAABA", - Result{ - 0, - 4, - }, - }, - { - "String comparison with not found pattern", - "AABC", - "AABAACAADAABAABA", - Result{ - -1, - 23, +func TestKmp(t *testing.T) { + type args struct { + word string + text string + patternTable []int + } + tests := []struct { + name string + args args + want []int + }{ + { + name: "test1", + args: args{ + word: "ab", + text: "ababacaab", + patternTable: table("ababacaab"), + }, + want: []int{0, 2, 7}, }, - }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Kmp(tt.args.word, tt.args.text, tt.args.patternTable); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Kmp() = %v, want %v", got, tt.want) + } + }) + } } -func TestKMP(t *testing.T) { - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - actual := Kmp(tc.text, tc.word) - if !reflect.DeepEqual(actual, tc.expected) { - t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v steps at position %v, but actual matches are: %v steps at position %v", - tc.word, tc.text, tc.expected.numberOfComparison, tc.expected.resultPosition, actual.numberOfComparison, actual.resultPosition) +func TestTable(t *testing.T) { + type args struct { + w string + } + tests := []struct { + name string + args args + want []int + }{ + { + name: "test1", + args: args{ + w: "ababacaab", + }, + want: []int{-1, 0, 0, 1, 2, 3, 0, 1, 1}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := table(tt.args.w); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Table() = %v, want %v", got, tt.want) } }) } From 1be70bd84835778d9538bd20c0db296e00ea91c3 Mon Sep 17 00:00:00 2001 From: Rangding Zhang Date: Thu, 8 Dec 2022 20:13:34 +0800 Subject: [PATCH 395/488] rename LRU field capacity->size, maxCapacity->capacity (#612) --- cache/lru.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cache/lru.go b/cache/lru.go index d937118f9..c6b8c734e 100644 --- a/cache/lru.go +++ b/cache/lru.go @@ -10,19 +10,19 @@ type item struct { } type LRU struct { - dl *linkedlist.Doubly[any] - capacity int - maxCapacity int - storage map[string]*linkedlist.Node[any] + dl *linkedlist.Doubly[any] + size int + capacity int + storage map[string]*linkedlist.Node[any] } // NewLRU represent initiate lru cache with capacity func NewLRU(capacity int) LRU { return LRU{ - dl: linkedlist.NewDoubly[any](), - storage: make(map[string]*linkedlist.Node[any], capacity), - capacity: 0, - maxCapacity: capacity, + dl: linkedlist.NewDoubly[any](), + storage: make(map[string]*linkedlist.Node[any], capacity), + size: 0, + capacity: capacity, } } @@ -49,17 +49,17 @@ func (c *LRU) Put(key string, value any) { return } - if c.capacity >= c.maxCapacity { + if c.size >= c.capacity { e := c.dl.Front() dk := e.Val.(item).key c.dl.Remove(e) delete(c.storage, dk) - c.capacity-- + c.size-- } n := item{key: key, value: value} c.dl.AddAtEnd(n) ne := c.dl.Back() c.storage[key] = ne - c.capacity++ + c.size++ } From 83cff67238da18d5a94c917ae713f5697b98a383 Mon Sep 17 00:00:00 2001 From: Tan <118096187+qizhaoTan@users.noreply.github.com> Date: Thu, 8 Dec 2022 21:30:23 +0800 Subject: [PATCH 396/488] feat: add heap implementation using generic. (#607) --- structure/heap/heap.go | 98 +++++++++++++++++++++++ structure/heap/heap_test.go | 150 ++++++++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 structure/heap/heap.go create mode 100644 structure/heap/heap_test.go diff --git a/structure/heap/heap.go b/structure/heap/heap.go new file mode 100644 index 000000000..693f1ab88 --- /dev/null +++ b/structure/heap/heap.go @@ -0,0 +1,98 @@ +package heap + +import ( + "errors" + "github.com/TheAlgorithms/Go/constraints" +) + +// Heap heap implementation using generic. +type Heap[T any] struct { + heaps []T + lessFunc func(a, b T) bool +} + +// New gives a new heap object. +func New[T constraints.Ordered]() *Heap[T] { + less := func(a, b T) bool { + return a < b + } + h, _ := NewAny[T](less) + return h +} + +// NewAny gives a new heap object. element can be anything, but must provide less function. +func NewAny[T any](less func(a, b T) bool) (*Heap[T], error) { + if less == nil { + return nil, errors.New("less func is necessary") + } + return &Heap[T]{ + lessFunc: less, + }, nil +} + +// Push pushes the element t onto the heap. +// The complexity is O(log n) where n = h.Len(). +func (h *Heap[T]) Push(t T) { + h.heaps = append(h.heaps, t) + h.up(len(h.heaps) - 1) +} + +// Top returns the minimum element (according to Less) from the heap. +// Top panics if the heap is empty. +func (h *Heap[T]) Top() T { + return h.heaps[0] +} + +// Pop removes the minimum element (according to Less) from the heap. +// The complexity is O(log n) where n = h.Len(). +func (h *Heap[T]) Pop() { + if len(h.heaps) <= 1 { + h.heaps = nil + return + } + h.swap(0, len(h.heaps)-1) + h.heaps = h.heaps[:len(h.heaps)-1] + h.down(0) +} + +// Empty returns the heap is empty or not. +func (h *Heap[T]) Empty() bool { + return len(h.heaps) == 0 +} + +// Size returns the size of the heap +func (h *Heap[T]) Size() int { + return len(h.heaps) +} + +func (h *Heap[T]) swap(i, j int) { + h.heaps[i], h.heaps[j] = h.heaps[j], h.heaps[i] +} + +func (h *Heap[T]) up(child int) { + if child <= 0 { + return + } + parent := (child - 1) >> 1 + if !h.lessFunc(h.heaps[child], h.heaps[parent]) { + return + } + h.swap(child, parent) + h.up(parent) +} + +func (h *Heap[T]) down(parent int) { + lessIdx := parent + lChild, rChild := (parent<<1)+1, (parent<<1)+2 + if lChild < len(h.heaps) && h.lessFunc(h.heaps[lChild], h.heaps[lessIdx]) { + lessIdx = lChild + } + if rChild < len(h.heaps) && h.lessFunc(h.heaps[rChild], h.heaps[lessIdx]) { + lessIdx = rChild + } + if lessIdx == parent { + return + } + h.swap(lessIdx, parent) + h.down(lessIdx) +} diff --git a/structure/heap/heap_test.go b/structure/heap/heap_test.go new file mode 100644 index 000000000..00ba54d7e --- /dev/null +++ b/structure/heap/heap_test.go @@ -0,0 +1,150 @@ +package heap_test + +import ( + "github.com/TheAlgorithms/Go/structure/heap" + "reflect" + "testing" +) + +type testInt int + +func (u testInt) Less(o testInt) bool { + return u < o +} + +type testStudent struct { + Name string + Score int64 +} + +func (u testStudent) Less(o testStudent) bool { + if u.Score == o.Score { + return u.Name < o.Name + } + return u.Score > o.Score +} + +func TestHeap_Empty(t *testing.T) { + tests := []struct { + name string + want bool + }{ + {name: "empty", want: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := heap.New[testInt]() + if got := h.Empty(); got != tt.want { + t.Errorf("Empty() = %v, want %v", got, tt.want) + } + }) + } +} + +type testOpType int + +const ( + testPush = 1 + testPop = 2 + testTop = 3 + testEmpty = 4 +) + +type testOp[T any] struct { + typ testOpType + x T + isEmpty bool +} + +type testStruct[T any] struct { + name string + ops []testOp[T] +} + +func TestHeapExample1(t *testing.T) { + tests1 := []testStruct[testInt]{ + { + name: "example 1", + ops: []testOp[testInt]{ + {typ: testEmpty, isEmpty: true}, + {typ: testPush, x: 10}, + {typ: testEmpty, isEmpty: false}, + {typ: testTop, x: 10}, + {typ: testPop}, + {typ: testEmpty, isEmpty: true}, + {typ: testPush, x: 9}, + {typ: testPush, x: 8}, + {typ: testPop}, + {typ: testPush, x: 3}, + {typ: testTop, x: 3}, + {typ: testPush, x: 2}, + {typ: testTop, x: 2}, + {typ: testPush, x: 4}, + {typ: testPush, x: 6}, + {typ: testPush, x: 5}, + {typ: testTop, x: 2}, + {typ: testPop}, + {typ: testTop, x: 3}, + {typ: testPop}, + {typ: testPop}, + {typ: testTop, x: 5}, + {typ: testEmpty, isEmpty: false}, + }, + }, + } + testFunc(t, tests1, testInt.Less) +} + +func TestHeapExample2(t *testing.T) { + tests1 := []testStruct[testStudent]{ + { + name: "example 2", + ops: []testOp[testStudent]{ + {typ: testPush, x: testStudent{Name: "Alan", Score: 87}}, + {typ: testPush, x: testStudent{Name: "Bob", Score: 98}}, + {typ: testTop, x: testStudent{Name: "Bob", Score: 98}}, + {typ: testPop}, + {typ: testPush, x: testStudent{Name: "Carl", Score: 70}}, + {typ: testTop, x: testStudent{Name: "Alan", Score: 87}}, + }, + }, + } + testFunc(t, tests1, testStudent.Less) +} + +func testFunc[T any](t *testing.T, tests []testStruct[T], less func(a, b T) bool) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h, err := heap.NewAny[T](less) + if err != nil { + t.Errorf("New Heap err %v", err) + } + for i, op := range tt.ops { + switch op.typ { + case testPush: + oldSize := h.Size() + h.Push(op.x) + newSize := h.Size() + if oldSize+1 != newSize { + t.Errorf("op %d testPush %v failed", i, op.x) + } + case testPop: + oldSize := h.Size() + h.Pop() + newSize := h.Size() + if oldSize-1 != newSize { + t.Errorf("op %d testPop %v failed", i, op.x) + } + case testTop: + if got := h.Top(); !reflect.DeepEqual(got, op.x) { + t.Errorf("op %d testTop %v, want %v", i, got, op.x) + } + case testEmpty: + if got := h.Empty(); got != op.isEmpty { + t.Errorf("op %d Empty() = %v, want %v", i, got, op.isEmpty) + } + } + } + }) + } +} From e5658c3df734e87874ec5e7a508b4b1fc3a2d770 Mon Sep 17 00:00:00 2001 From: Paulden Date: Sun, 15 Jan 2023 22:34:30 +0800 Subject: [PATCH 397/488] fix: Tree package bug (#589) * add Parent to binary search tree * refactor NIL in all trees * add Successor and Predecessor to * fix: tree package bug * remove dummy variable leaf * Refactoring: remove method; make NIL a sentinel value for 3 trees, and eliminate nil in those implementations. * change the method isRBTree to isRB * fix:remove base struct, separate Node to three different nodes that complete Node Interface; still save NIL, but make it unexported * Add more comments; Move Tree interface to tree_test package for future development. * code tidy * fix typo in comments --- structure/tree/avl.go | 309 ++++++++++++++++----- structure/tree/avl_test.go | 164 ++++++++---- structure/tree/bstree.go | 228 +++++++++++++--- structure/tree/bstree_test.go | 71 ++++- structure/tree/example_test.go | 167 ++++++++++++ structure/tree/rbtree.go | 477 +++++++++++++++++++-------------- structure/tree/rbtree_test.go | 91 ++----- structure/tree/tree.go | 262 ++++++------------ structure/tree/tree_test.go | 227 ++++++++-------- 9 files changed, 1252 insertions(+), 744 deletions(-) create mode 100644 structure/tree/example_test.go diff --git a/structure/tree/avl.go b/structure/tree/avl.go index 7cb62d885..4b0aee7c4 100644 --- a/structure/tree/avl.go +++ b/structure/tree/avl.go @@ -1,3 +1,9 @@ +// AVL tree is a self-balancing binary search tree. +// +// For more details check out those link below here: +// Wikipedia article: https://en.wikipedia.org/wiki/AVL_tree +// see avl.go + package tree import ( @@ -5,20 +11,58 @@ import ( "github.com/TheAlgorithms/Go/math/max" ) +// Verify Interface Compliance +var _ Node[int] = &AVLNode[int]{} + +// AVLNode represents a single node in the AVL. +type AVLNode[T constraints.Ordered] struct { + key T + parent *AVLNode[T] + left *AVLNode[T] + right *AVLNode[T] + height int +} + +func (n *AVLNode[T]) Key() T { + return n.key +} + +func (n *AVLNode[T]) Parent() Node[T] { + return n.parent +} + +func (n *AVLNode[T]) Left() Node[T] { + return n.left +} + +func (n *AVLNode[T]) Right() Node[T] { + return n.right +} + +func (n *AVLNode[T]) Height() int { + return n.height +} + +// AVL represents a AVL tree. +// By default, _NIL = nil. type AVL[T constraints.Ordered] struct { - *binaryTree[T] + Root *AVLNode[T] + _NIL *AVLNode[T] // a sentinel value for nil } -// NewAVL create a novel AVL tree +// NewAVL creates a novel AVL tree func NewAVL[T constraints.Ordered]() *AVL[T] { return &AVL[T]{ - binaryTree: &binaryTree[T]{ - Root: nil, - NIL: nil, - }, + Root: nil, + _NIL: nil, } } +// Empty determines the AVL tree is empty +func (avl *AVL[T]) Empty() bool { + return avl.Root == avl._NIL +} + // Push a chain of Node's into the AVL Tree func (avl *AVL[T]) Push(keys ...T) { for _, k := range keys { @@ -36,42 +80,140 @@ func (avl *AVL[T]) Delete(key T) bool { return true } -func (avl *AVL[T]) pushHelper(root *Node[T], key T) *Node[T] { - if root == nil { - return &Node[T]{ - Key: key, - Height: 1, +// Get a Node from the AVL Tree +func (avl *AVL[T]) Get(key T) (Node[T], bool) { + return searchTreeHelper[T](avl.Root, avl._NIL, key) +} + +// Has Determines the tree has the node of Key +func (avl *AVL[T]) Has(key T) bool { + _, ok := searchTreeHelper[T](avl.Root, avl._NIL, key) + return ok +} + +// PreOrder Traverses the tree in the following order Root --> Left --> Right +func (avl *AVL[T]) PreOrder() []T { + traversal := make([]T, 0) + preOrderRecursive[T](avl.Root, avl._NIL, &traversal) + return traversal +} + +// InOrder Traverses the tree in the following order Left --> Root --> Right +func (avl *AVL[T]) InOrder() []T { + return inOrderHelper[T](avl.Root, avl._NIL) +} + +// PostOrder traverses the tree in the following order Left --> Right --> Root +func (avl *AVL[T]) PostOrder() []T { + traversal := make([]T, 0) + postOrderRecursive[T](avl.Root, avl._NIL, &traversal) + return traversal +} + +// LevelOrder returns the level order traversal of the tree +func (avl *AVL[T]) LevelOrder() []T { + traversal := make([]T, 0) + levelOrderHelper[T](avl.Root, avl._NIL, &traversal) + return traversal +} + +// AccessNodesByLayer accesses nodes layer by layer (2-D array), instead of printing the results as 1-D array. +func (avl *AVL[T]) AccessNodesByLayer() [][]T { + return accessNodeByLayerHelper[T](avl.Root, avl._NIL) +} + +// Depth returns the calculated depth of the AVL tree +func (avl *AVL[T]) Depth() int { + return calculateDepth[T](avl.Root, avl._NIL, 0) +} + +// Max returns the Max value of the tree +func (avl *AVL[T]) Max() (T, bool) { + ret := maximum[T](avl.Root, avl._NIL) + if ret == avl._NIL { + var dft T + return dft, false + } + return ret.Key(), true +} + +// Min returns the Min value of the tree +func (avl *AVL[T]) Min() (T, bool) { + ret := minimum[T](avl.Root, avl._NIL) + if ret == avl._NIL { + var dft T + return dft, false + } + return ret.Key(), true +} + +// Predecessor returns the Predecessor of the node of Key +// if there is no predecessor, return default value of type T and false +// otherwise return the Key of predecessor and true +func (avl *AVL[T]) Predecessor(key T) (T, bool) { + node, ok := searchTreeHelper[T](avl.Root, avl._NIL, key) + if !ok { + var dft T + return dft, ok + } + return predecessorHelper[T](node, avl._NIL) +} + +// Successor returns the Successor of the node of Key +// if there is no successor, return default value of type T and false +// otherwise return the Key of successor and true +func (avl *AVL[T]) Successor(key T) (T, bool) { + node, ok := searchTreeHelper[T](avl.Root, avl._NIL, key) + if !ok { + var dft T + return dft, ok + } + return successorHelper[T](node, avl._NIL) +} + +func (avl *AVL[T]) pushHelper(root *AVLNode[T], key T) *AVLNode[T] { + if root == avl._NIL { + return &AVLNode[T]{ + key: key, + left: avl._NIL, + right: avl._NIL, + parent: avl._NIL, + height: 1, } } switch { - case key < root.Key: - root.Left = avl.pushHelper(root.Left, key) - case key > root.Key: - root.Right = avl.pushHelper(root.Right, key) + case key < root.key: + tmp := avl.pushHelper(root.left, key) + tmp.parent = root + root.left = tmp + case key > root.key: + tmp := avl.pushHelper(root.right, key) + tmp.parent = root + root.right = tmp default: return root } // balance the tree - root.Height = avl.height(root) + root.height = avl.height(root) bFactor := avl.balanceFactor(root) if bFactor > 1 { switch { - case key < root.Left.Key: + case key < root.left.key: return avl.rightRotate(root) - case key > root.Left.Key: - root.Left = avl.leftRotate(root.Left) + case key > root.left.key: + root.left = avl.leftRotate(root.left) return avl.rightRotate(root) } } if bFactor < -1 { switch { - case key > root.Right.Key: + case key > root.right.key: return avl.leftRotate(root) - case key < root.Right.Key: - root.Right = avl.rightRotate(root.Right) + case key < root.right.key: + root.right = avl.rightRotate(root.right) return avl.leftRotate(root) } } @@ -79,57 +221,70 @@ func (avl *AVL[T]) pushHelper(root *Node[T], key T) *Node[T] { return root } -func (avl *AVL[T]) deleteHelper(root *Node[T], key T) *Node[T] { - if root == nil { +func (avl *AVL[T]) deleteHelper(root *AVLNode[T], key T) *AVLNode[T] { + if root == avl._NIL { return root } switch { - case key < root.Key: - root.Left = avl.deleteHelper(root.Left, key) - case key > root.Key: - root.Right = avl.deleteHelper(root.Right, key) + case key < root.key: + tmp := avl.deleteHelper(root.left, key) + root.left = tmp + if tmp != avl._NIL { + tmp.parent = root + } + case key > root.key: + tmp := avl.deleteHelper(root.right, key) + root.right = tmp + if tmp != avl._NIL { + tmp.parent = root + } default: - if root.Left == nil || root.Right == nil { - tmp := root.Left - if root.Left != nil { - tmp = root.Right + if root.left == avl._NIL || root.right == avl._NIL { + tmp := root.left + if root.right != avl._NIL { + tmp = root.right } - if tmp == nil { - root = nil + if tmp == avl._NIL { + root = avl._NIL } else { - *root = *tmp + tmp.parent = root.parent + root = tmp } } else { - tmp := avl.minimum(root.Right) - root.Key = tmp.Key - root.Right = avl.deleteHelper(root.Right, tmp.Key) + tmp := minimum[T](root.right, avl._NIL).(*AVLNode[T]) + root.key = tmp.key + del := avl.deleteHelper(root.right, tmp.key) + root.right = del + if del != avl._NIL { + del.parent = root + } } } - if root == nil { + if root == avl._NIL { return root } // balance the tree - root.Height = avl.height(root) + root.height = avl.height(root) bFactor := avl.balanceFactor(root) switch { case bFactor > 1: switch { - case avl.balanceFactor(root.Left) >= 0: + case avl.balanceFactor(root.left) >= 0: return avl.rightRotate(root) default: - root.Left = avl.leftRotate(root.Left) + root.left = avl.leftRotate(root.left) return avl.rightRotate(root) } case bFactor < -1: switch { - case avl.balanceFactor(root.Right) <= 0: + case avl.balanceFactor(root.right) <= 0: return avl.leftRotate(root) default: - root.Right = avl.rightRotate(root.Right) + root.right = avl.rightRotate(root.right) return avl.leftRotate(root) } } @@ -137,52 +292,66 @@ func (avl *AVL[T]) deleteHelper(root *Node[T], key T) *Node[T] { return root } -func (avl *AVL[T]) height(root *Node[T]) int { - if root == nil { - return 0 +func (avl *AVL[T]) height(root *AVLNode[T]) int { + if root == avl._NIL { + return 1 } var leftHeight, rightHeight int - if root.Left != nil { - leftHeight = root.Left.Height + if root.left != avl._NIL { + leftHeight = root.left.height } - if root.Right != nil { - rightHeight = root.Right.Height + if root.right != avl._NIL { + rightHeight = root.right.height } return 1 + max.Int(leftHeight, rightHeight) } // balanceFactor : negative balance factor means subtree Root is heavy toward Left // and positive balance factor means subtree Root is heavy toward Right side -func (avl *AVL[T]) balanceFactor(root *Node[T]) int { +func (avl *AVL[T]) balanceFactor(root *AVLNode[T]) int { var leftHeight, rightHeight int - if root.Left != nil { - leftHeight = root.Left.Height + if root.left != avl._NIL { + leftHeight = root.left.height } - if root.Right != nil { - rightHeight = root.Right.Height + if root.right != avl._NIL { + rightHeight = root.right.height } return leftHeight - rightHeight } -func (avl *AVL[T]) leftRotate(root *Node[T]) *Node[T] { - y := root.Right - yl := y.Left - y.Left = root - root.Right = yl +func (avl *AVL[T]) leftRotate(x *AVLNode[T]) *AVLNode[T] { + y := x.right + yl := y.left + y.left = x + x.right = yl - root.Height = avl.height(root) - y.Height = avl.height(y) + if yl != avl._NIL { + yl.parent = x + } + + y.parent = x.parent + x.parent = y + + x.height = avl.height(x) + y.height = avl.height(y) return y } -func (avl *AVL[T]) rightRotate(root *Node[T]) *Node[T] { - y := root.Left - yr := y.Right - y.Right = root - root.Left = yr +func (avl *AVL[T]) rightRotate(x *AVLNode[T]) *AVLNode[T] { + y := x.left + yr := y.right + y.right = x + x.left = yr + + if yr != avl._NIL { + yr.parent = x + } + + y.parent = x.parent + x.parent = y - root.Height = avl.height(root) - y.Height = avl.height(y) + x.height = avl.height(x) + y.height = avl.height(y) return y } diff --git a/structure/tree/avl_test.go b/structure/tree/avl_test.go index cbbc3581e..14a7ab570 100644 --- a/structure/tree/avl_test.go +++ b/structure/tree/avl_test.go @@ -1,9 +1,11 @@ package tree_test import ( - "testing" - bt "github.com/TheAlgorithms/Go/structure/tree" + "math/rand" + "sort" + "testing" + "time" ) func TestAVLPush(t *testing.T) { @@ -12,51 +14,51 @@ func TestAVLPush(t *testing.T) { tree.Push(5, 4, 3) root := tree.Root - if root.Key != 4 { - t.Errorf("Root should have value = 4, not %v", root.Key) + if root.Key() != 4 { + t.Errorf("Root should have value = 4, not %v", root.Key()) } - if root.Height != 2 { - t.Errorf("Height of Root should be = 2, not %d", root.Height) + if root.Height() != 2 { + t.Errorf("Height of Root should be = 2, not %d", root.Height()) } - if root.Left.Key != 3 { + if root.Left().Key() != 3 { t.Errorf("Left child should have value = 3") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 5 { + if root.Right().Key() != 5 { t.Errorf("Right child should have value = 5") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } - }) + t.Run("LRRotation-Test", func(t *testing.T) { tree := bt.NewAVL[int]() tree.Push(5, 3, 4) root := tree.Root - if root.Key != 4 { - t.Errorf("Root should have value = 4") + if root.Key() != 4 { + t.Errorf("Root should have value = 4, not %v", root.Key()) } - if root.Height != 2 { - t.Errorf("Height of Root should be = 2") + if root.Height() != 2 { + t.Errorf("Height of Root should be = 2, not %d", root.Height()) } - if root.Left.Key != 3 { + if root.Left().Key() != 3 { t.Errorf("Left child should have value = 3") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 5 { + if root.Right().Key() != 5 { t.Errorf("Right child should have value = 5") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } }) @@ -68,52 +70,52 @@ func TestAVLPush(t *testing.T) { tree.Push(5) root := tree.Root - if root.Key != 4 { - t.Errorf("Root should have value = 4") + if root.Key() != 4 { + t.Errorf("Root should have value = 4, not %v", root.Key()) } - if root.Height != 2 { - t.Errorf("Height of Root should be = 2") + if root.Height() != 2 { + t.Errorf("Height of Root should be = 2, not %d", root.Height()) } - if root.Left.Key != 3 { + if root.Left().Key() != 3 { t.Errorf("Left child should have value = 3") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 5 { + if root.Right().Key() != 5 { t.Errorf("Right child should have value = 5") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } }) - t.Run("RLRotaion-Test", func(t *testing.T) { + t.Run("RLRotation-Test", func(t *testing.T) { tree := bt.NewAVL[int]() tree.Push(3) tree.Push(5) tree.Push(4) root := tree.Root - if root.Key != 4 { + if root.Key() != 4 { t.Errorf("Root should have value = 4") } - if root.Height != 2 { + if root.Height() != 2 { t.Errorf("Height of Root should be = 2") } - if root.Left.Key != 3 { + if root.Left().Key() != 3 { t.Errorf("Left child should have value = 3") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 5 { + if root.Right().Key() != 5 { t.Errorf("Right child should have value = 5") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } }) @@ -122,6 +124,9 @@ func TestAVLPush(t *testing.T) { func TestAVLDelete(t *testing.T) { t.Run("LLRotation-Test", func(t *testing.T) { tree := bt.NewAVL[int]() + if tree.Delete(5) { + t.Errorf("There is no node, whose value is 5") + } tree.Push(5) tree.Push(4) @@ -137,24 +142,24 @@ func TestAVLDelete(t *testing.T) { } root := tree.Root - if root.Key != 3 { + if root.Key() != 3 { t.Errorf("Root should have value = 3") } - if root.Height != 2 { + if root.Height() != 2 { t.Errorf("Height of Root should be = 2") } - if root.Left.Key != 2 { + if root.Left().Key() != 2 { t.Errorf("Left child should have value = 2") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 4 { + if root.Right().Key() != 4 { t.Errorf("Right child should have value = 5") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } }) @@ -164,6 +169,7 @@ func TestAVLDelete(t *testing.T) { tree.Push(10) tree.Push(8) + tree.Push(8) tree.Push(6) tree.Push(7) @@ -176,24 +182,24 @@ func TestAVLDelete(t *testing.T) { } root := tree.Root - if root.Key != 7 { + if root.Key() != 7 { t.Errorf("Root should have value = 7") } - if root.Height != 2 { + if root.Height() != 2 { t.Errorf("Height of Root should be = 2") } - if root.Left.Key != 6 { + if root.Left().Key() != 6 { t.Errorf("Left child should have value = 6") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 8 { + if root.Right().Key() != 8 { t.Errorf("Right child should have value = 8") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } @@ -204,6 +210,7 @@ func TestAVLDelete(t *testing.T) { tree.Push(2) tree.Push(3) + tree.Push(3) tree.Push(4) tree.Push(5) @@ -216,60 +223,99 @@ func TestAVLDelete(t *testing.T) { } root := tree.Root - if root.Key != 4 { + if root.Key() != 4 { t.Errorf("Root should have value = 4") } - if root.Height != 2 { + if root.Height() != 2 { t.Errorf("Height of Root should be = 2") } - if root.Left.Key != 3 { + if root.Left().Key() != 3 { t.Errorf("Left child should have value = 3") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 5 { + if root.Right().Key() != 5 { t.Errorf("Right child should have value = 5") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } }) - t.Run("RLRotaion-Test", func(t *testing.T) { + t.Run("RLRotation-Test", func(t *testing.T) { tree := bt.NewAVL[int]() tree.Push(7) tree.Push(6) + tree.Push(6) tree.Push(9) tree.Push(8) tree.Delete(6) root := tree.Root - if root.Key != 8 { + if root.Key() != 8 { t.Errorf("Root should have value = 8") } - if root.Height != 2 { + if root.Height() != 2 { t.Errorf("Height of Root should be = 2") } - if root.Left.Key != 7 { + if root.Left().Key() != 7 { t.Errorf("Left child should have value = 7") } - if root.Left.Height != 1 { + if root.Left().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Left child should be 1") } - if root.Right.Key != 9 { + if root.Right().Key() != 9 { t.Errorf("Right child should have value = 9") } - if root.Right.Height != 1 { + if root.Right().(*bt.AVLNode[int]).Height() != 1 { t.Errorf("Height of Right should be 1") } }) + + t.Run("Random Test", func(t *testing.T) { + nums := []int{100, 500, 1000, 10_000} + for _, n := range nums { + rand.Seed(time.Now().Unix()) + tree := bt.NewAVL[int]() + nums := rand.Perm(n) + tree.Push(nums...) + + rets := tree.InOrder() + if !sort.IntsAreSorted(rets) { + t.Error("Error with Push") + } + + if res, ok := tree.Min(); !ok || res != rets[0] { + t.Errorf("Error with Min, get %d, want: %d", res, rets[0]) + } + + if res, ok := tree.Max(); !ok || res != rets[n-1] { + t.Errorf("Error with Max, get %d, want: %d", res, rets[n-1]) + } + + for i := 0; i < n-1; i++ { + if ret, ok := tree.Successor(rets[0]); ret != rets[1] || !ok { + t.Error("Error with Successor") + } + if ret, ok := tree.Predecessor(rets[1]); ret != rets[0] || !ok { + t.Error("Error with Predecessor") + } + + ok := tree.Delete(nums[i]) + rets = tree.InOrder() + if !ok || !sort.IntsAreSorted(rets) { + t.Errorf("Error With Delete") + } + } + } + }) } diff --git a/structure/tree/bstree.go b/structure/tree/bstree.go index 72c0e4da2..b4f6a0a7c 100644 --- a/structure/tree/bstree.go +++ b/structure/tree/bstree.go @@ -6,73 +6,223 @@ package tree -import ( - "github.com/TheAlgorithms/Go/constraints" -) +import "github.com/TheAlgorithms/Go/constraints" +// Verify Interface Compliance +var _ Node[int] = &BSNode[int]{} + +// BSNode represents a single node in the BinarySearch. +type BSNode[T constraints.Ordered] struct { + key T + parent *BSNode[T] + left *BSNode[T] + right *BSNode[T] +} + +func (n *BSNode[T]) Key() T { + return n.key +} + +func (n *BSNode[T]) Parent() Node[T] { + return n.parent +} + +func (n *BSNode[T]) Left() Node[T] { + return n.left +} + +func (n *BSNode[T]) Right() Node[T] { + return n.right +} + +// BinarySearch represents a Binary-Search tree. +// By default, _NIL = nil. type BinarySearch[T constraints.Ordered] struct { - *binaryTree[T] + Root *BSNode[T] + _NIL *BSNode[T] // a sentinel value for nil } -// NewBinarySearch create a novel Binary-Search tree +// NewBinarySearch creates a novel Binary-Search tree func NewBinarySearch[T constraints.Ordered]() *BinarySearch[T] { return &BinarySearch[T]{ - binaryTree: &binaryTree[T]{ - Root: nil, - NIL: nil, - }, + Root: nil, + _NIL: nil, } } +// Empty determines the Binary-Search tree is empty +func (t *BinarySearch[T]) Empty() bool { + return t.Root == t._NIL +} + // Push a chain of Node's into the BinarySearch func (t *BinarySearch[T]) Push(keys ...T) { for _, key := range keys { - t.Root = t.pushHelper(t.Root, key) + t.pushHelper(t.Root, key) } } // Delete removes the node of val func (t *BinarySearch[T]) Delete(val T) bool { - if !t.Has(val) { + node, ok := t.Get(val) + if !ok { return false } - t.deleteHelper(t.Root, val) + t.deleteHelper(node.(*BSNode[T])) return true } -func (t *BinarySearch[T]) pushHelper(root *Node[T], val T) *Node[T] { - if root == nil { - return &Node[T]{Key: val, Left: nil, Right: nil} +// Get a Node from the Binary-Search Tree +func (t *BinarySearch[T]) Get(key T) (Node[T], bool) { + return searchTreeHelper[T](t.Root, t._NIL, key) +} + +// Has Determines the tree has the node of Key +func (t *BinarySearch[T]) Has(key T) bool { + _, ok := searchTreeHelper[T](t.Root, t._NIL, key) + return ok +} + +// PreOrder Traverses the tree in the following order Root --> Left --> Right +func (t *BinarySearch[T]) PreOrder() []T { + traversal := make([]T, 0) + preOrderRecursive[T](t.Root, t._NIL, &traversal) + return traversal +} + +// InOrder Traverses the tree in the following order Left --> Root --> Right +func (t *BinarySearch[T]) InOrder() []T { + return inOrderHelper[T](t.Root, t._NIL) +} + +// PostOrder traverses the tree in the following order Left --> Right --> Root +func (t *BinarySearch[T]) PostOrder() []T { + traversal := make([]T, 0) + postOrderRecursive[T](t.Root, t._NIL, &traversal) + return traversal +} + +// LevelOrder returns the level order traversal of the tree +func (t *BinarySearch[T]) LevelOrder() []T { + traversal := make([]T, 0) + levelOrderHelper[T](t.Root, t._NIL, &traversal) + return traversal +} + +// AccessNodesByLayer accesses nodes layer by layer (2-D array), instead of printing the results as 1-D array. +func (t *BinarySearch[T]) AccessNodesByLayer() [][]T { + return accessNodeByLayerHelper[T](t.Root, t._NIL) +} + +// Depth returns the calculated depth of a binary search tree +func (t *BinarySearch[T]) Depth() int { + return calculateDepth[T](t.Root, t._NIL, 0) +} + +// Max returns the Max value of the tree +func (t *BinarySearch[T]) Max() (T, bool) { + ret := maximum[T](t.Root, t._NIL) + if ret == t._NIL { + var dft T + return dft, false } - if val < root.Key { - root.Left = t.pushHelper(root.Left, val) - } else { - root.Right = t.pushHelper(root.Right, val) + return ret.Key(), true +} + +// Min returns the Min value of the tree +func (t *BinarySearch[T]) Min() (T, bool) { + ret := minimum[T](t.Root, t._NIL) + if ret == t._NIL { + var dft T + return dft, false } - return root + return ret.Key(), true } -func (t *BinarySearch[T]) deleteHelper(root *Node[T], val T) *Node[T] { - if root == nil { - return nil +// Predecessor returns the Predecessor of the node of Key +// if there is no predecessor, return default value of type T and false +// otherwise return the Key of predecessor and true +func (t *BinarySearch[T]) Predecessor(key T) (T, bool) { + node, ok := searchTreeHelper[T](t.Root, t._NIL, key) + if !ok { + var dft T + return dft, ok } - if val < root.Key { - root.Left = t.deleteHelper(root.Left, val) - } else if val > root.Key { - root.Right = t.deleteHelper(root.Right, val) + return predecessorHelper[T](node, t._NIL) +} + +// Successor returns the Successor of the node of Key +// if there is no successor, return default value of type T and false +// otherwise return the Key of successor and true +func (t *BinarySearch[T]) Successor(key T) (T, bool) { + node, ok := searchTreeHelper[T](t.Root, t._NIL, key) + if !ok { + var dft T + return dft, ok + } + return successorHelper[T](node, t._NIL) +} + +func (t *BinarySearch[T]) pushHelper(x *BSNode[T], val T) { + y := t._NIL + for x != t._NIL { + y = x + switch { + case val < x.Key(): + x = x.left + case val > x.Key(): + x = x.right + default: + return + } + } + + z := &BSNode[T]{ + key: val, + left: t._NIL, + right: t._NIL, + parent: y, + } + if y == t._NIL { + t.Root = z + } else if val < y.key { + y.left = z } else { - // this is the node to delete - // node with one child - if root.Left == nil { - return root.Right - } else if root.Right == nil { - return root.Left - } else { - n := root.Right - d := t.minimum(n) - d.Left = root.Left - return root.Right + y.right = z + } +} + +func (t *BinarySearch[T]) deleteHelper(z *BSNode[T]) { + switch { + case z.left == t._NIL: + t.transplant(z, z.right) + case z.right == t._NIL: + t.transplant(z, z.left) + default: + y := minimum[T](z.right, t._NIL).(*BSNode[T]) + if y.parent != z { + t.transplant(y, y.right) + y.right = z.right + y.right.parent = y } + + t.transplant(z, y) + y.left = z.left + y.left.parent = y + } +} + +func (t *BinarySearch[T]) transplant(u, v *BSNode[T]) { + switch { + case u.parent == t._NIL: + t.Root = v + case u == u.parent.left: + u.parent.left = v + default: + u.parent.right = v + } + + if v != t._NIL { + v.parent = u.parent } - return root } diff --git a/structure/tree/bstree_test.go b/structure/tree/bstree_test.go index 094406487..abbf8bfea 100644 --- a/structure/tree/bstree_test.go +++ b/structure/tree/bstree_test.go @@ -1,7 +1,10 @@ package tree_test import ( + "math/rand" + "sort" "testing" + "time" bt "github.com/TheAlgorithms/Go/structure/tree" ) @@ -13,15 +16,15 @@ func TestPush(t *testing.T) { bst.Push(80) bst.Push(100) - if bst.Root.Key != 90 { + if bst.Root.Key() != 90 { t.Errorf("Root should have value = 90") } - if bst.Root.Left.Key != 80 { + if bst.Root.Left().Key() != 80 { t.Errorf("Left child should have value = 80") } - if bst.Root.Right.Key != 100 { + if bst.Root.Right().Key() != 100 { t.Errorf("Right child should have value = 100") } @@ -36,6 +39,7 @@ func TestDelete(t *testing.T) { bst.Push(90) bst.Push(80) + bst.Push(80) bst.Push(100) if !bst.Delete(100) { @@ -47,15 +51,15 @@ func TestDelete(t *testing.T) { } root := bst.Root - if root.Key != 90 { + if root.Key() != 90 { t.Errorf("Root should have value = 90") } - if root.Left.Key != 80 { + if root.Left().Key() != 80 { t.Errorf("Left child should have value = 80") } - if root.Right != nil { + if root.Right().(*bt.BSNode[int]) != nil { t.Errorf("Right child should have value = nil") } @@ -65,11 +69,11 @@ func TestDelete(t *testing.T) { bst.Delete(80) - if root.Key != 90 { + if root.Key() != 90 { t.Errorf("Root should have value = 90") } - if root.Left != nil { + if root.Left().(*bt.BSNode[int]) != nil { t.Errorf("Left child should have value = nil") } @@ -95,15 +99,15 @@ func TestDelete(t *testing.T) { } root := bst.Root - if root.Key != 90 { + if root.Key() != 90 { t.Errorf("Root should have value = 90") } - if root.Right.Key != 100 { + if root.Right().Key() != 100 { t.Errorf("Right child should have value = 100") } - if root.Left.Key != 70 { + if root.Left().Key() != 70 { t.Errorf("Left child should have value = 70") } @@ -130,15 +134,15 @@ func TestDelete(t *testing.T) { } root := bst.Root - if root.Key != 90 { + if root.Key() != 90 { t.Errorf("Root should have value = 90") } - if root.Left.Key != 85 { + if root.Left().Key() != 85 { t.Errorf("Left child should have value = 85") } - if root.Right.Key != 100 { + if root.Right().Key() != 100 { t.Errorf("Right child should have value = 100") } @@ -146,4 +150,43 @@ func TestDelete(t *testing.T) { t.Errorf("Depth should have value = 3") } }) + + t.Run("Random Test", func(t *testing.T) { + tests := []int{100, 500, 1000, 10_000} + for _, n := range tests { + rand.Seed(time.Now().Unix()) + tree := bt.NewBinarySearch[int]() + nums := rand.Perm(n) + tree.Push(nums...) + + rets := tree.InOrder() + if !sort.IntsAreSorted(rets) { + t.Error("Error with Push") + } + + if res, ok := tree.Min(); !ok || res != rets[0] { + t.Errorf("Error with Min, get %d, want: %d", res, rets[0]) + } + + if res, ok := tree.Max(); !ok || res != rets[n-1] { + t.Errorf("Error with Max, get %d, want: %d", res, rets[n-1]) + } + + for i := 0; i < n-1; i++ { + if ret, ok := tree.Successor(rets[0]); ret != rets[1] || !ok { + t.Error("Error with Successor") + } + + if ret, ok := tree.Predecessor(rets[1]); ret != rets[0] || !ok { + t.Error("Error with Predecessor") + } + + ok := tree.Delete(nums[i]) + rets = tree.InOrder() + if !ok || !sort.IntsAreSorted(rets) { + t.Errorf("Error With Delete") + } + } + } + }) } diff --git a/structure/tree/example_test.go b/structure/tree/example_test.go new file mode 100644 index 000000000..2d3c384c8 --- /dev/null +++ b/structure/tree/example_test.go @@ -0,0 +1,167 @@ +package tree_test + +import ( + "fmt" + "github.com/TheAlgorithms/Go/constraints" + "testing" + + bt "github.com/TheAlgorithms/Go/structure/tree" +) + +type TestTree[T constraints.Ordered] interface { + Push(...T) + Delete(T) bool + Get(T) (bt.Node[T], bool) + Empty() bool + Has(T) bool + Depth() int + Max() (T, bool) + Min() (T, bool) + Predecessor(T) (T, bool) + Successor(T) (T, bool) + PreOrder() []T + InOrder() []T + PostOrder() []T + LevelOrder() []T + AccessNodesByLayer() [][]T +} + +// BinarySearch, AVL and RB have completed the `TestTree` interface. +var ( + _ TestTree[int] = (*bt.BinarySearch[int])(nil) + _ TestTree[int] = (*bt.AVL[int])(nil) + _ TestTree[int] = (*bt.RB[int])(nil) +) + +var tree TestTree[int] + +func TestBinarySearch(t *testing.T) { + tree = bt.NewBinarySearch[int]() + + if tree.Empty() { + t.Log("Binary Search Tree is empty now.") + } + + tree.Push(1, 4, 10) + tree.Push(-8) + nums := []int{87, 18, 10, -34} + tree.Push(nums...) + tree.Push(4) // duplicate key, dismiss it + + if tree.Has(4) { + t.Logf("There is a node of 4") + } + + if n, ok := tree.Get(10); ok { + t.Logf("node of 10: %T", n) + } + + if ret, ok := tree.Min(); ok { + t.Logf("tree.Min() = %v", ret) + } + + if ret, ok := tree.Max(); ok { + t.Logf("tree.Max() = %v", ret) + } + + if ret, ok := tree.Predecessor(1); ok { + t.Logf("tree.Preducessor(1) = %v", ret) + } + + if ret, ok := tree.Successor(18); ok { + t.Logf("tree.Successor(18) = %v", ret) + } + + fmt.Println(tree.InOrder()) + fmt.Println(tree.AccessNodesByLayer()) + + tree.Delete(18) + fmt.Println("Delete 18") + fmt.Println(tree.InOrder()) +} + +func TestAVL(t *testing.T) { + tree = bt.NewAVL[int]() + + if tree.Empty() { + t.Log("AVL Tree is empty now.") + } + + tree.Push(1, 4, 10) + tree.Push(-8) + nums := []int{87, 18, 10, -34} + tree.Push(nums...) + tree.Push(4) // duplicate key, dismiss it + + if tree.Has(4) { + t.Logf("There is a node of 4") + } + + if n, ok := tree.Get(10); ok { + t.Logf("node of 10: %T", n) + } + + if ret, ok := tree.Min(); ok { + t.Logf("tree.Min() = %v", ret) + } + + if ret, ok := tree.Max(); ok { + t.Logf("tree.Max() = %v", ret) + } + + if ret, ok := tree.Predecessor(1); ok { + t.Logf("tree.Preducessor(1) = %v", ret) + } + + if ret, ok := tree.Successor(18); ok { + t.Logf("tree.Successor(18) = %v", ret) + } + + fmt.Println(tree.InOrder()) + fmt.Println(tree.AccessNodesByLayer()) + + tree.Delete(18) + fmt.Println("Delete 18") + fmt.Println(tree.InOrder()) +} + +func TestRB(t *testing.T) { + tree = bt.NewRB[int]() + + if tree.Empty() { + t.Log("RB Tree is empty now.") + } + + tree.Push(1, 4, 10) + tree.Push(-8) + nums := []int{87, 18, 10, -34} + tree.Push(nums...) + tree.Push(4) // duplicate key, dismiss it + + if tree.Has(4) { + t.Logf("There is a node of 4") + } + + if n, ok := tree.Get(10); ok { + t.Logf("node of 10: %T", n) + } + + if ret, ok := tree.Min(); ok { + t.Logf("tree.Min() = %v", ret) + } + + if ret, ok := tree.Max(); ok { + t.Logf("tree.Max() = %v", ret) + } + + if ret, ok := tree.Predecessor(1); ok { + t.Logf("tree.Preducessor(1) = %v", ret) + } + + if ret, ok := tree.Successor(18); ok { + t.Logf("tree.Successor(18) = %v", ret) + } + + fmt.Println(tree.InOrder()) + fmt.Println(tree.AccessNodesByLayer()) +} diff --git a/structure/tree/rbtree.go b/structure/tree/rbtree.go index 252c99930..de6f2ed6d 100644 --- a/structure/tree/rbtree.go +++ b/structure/tree/rbtree.go @@ -1,5 +1,5 @@ // Red-Black Tree is a kind of self-balancing binary search tree. -// Each node stores "Color" ("red" or "black"), used to ensure that the tree remains balanced during insertions and deletions. +// Each node stores "color" ("red" or "black"), used to ensure that the tree remains balanced during insertions and deletions. // // For more details check out those links below here: // Programiz article : https://www.programiz.com/dsa/red-black-tree @@ -9,27 +9,65 @@ package tree -import ( - "fmt" +import "github.com/TheAlgorithms/Go/constraints" - "github.com/TheAlgorithms/Go/constraints" +type Color byte + +const ( + Red Color = iota + Black ) +// Verify Interface Compliance +var _ Node[int] = &RBNode[int]{} + +// RBNode represents a single node in the RB. +type RBNode[T constraints.Ordered] struct { + key T + parent *RBNode[T] + left *RBNode[T] + right *RBNode[T] + color Color +} + +func (n *RBNode[T]) Key() T { + return n.key +} + +func (n *RBNode[T]) Parent() Node[T] { + return n.parent +} + +func (n *RBNode[T]) Left() Node[T] { + return n.left +} + +func (n *RBNode[T]) Right() Node[T] { + return n.right +} + +// RB represents a Red-Black tree. +// By default, _NIL = leaf, a dummy variable. type RB[T constraints.Ordered] struct { - *binaryTree[T] + Root *RBNode[T] + _NIL *RBNode[T] // a sentinel value for nil } -// Create a new Red-Black Tree +// NewRB creates a new Red-Black Tree func NewRB[T constraints.Ordered]() *RB[T] { - leaf := &Node[T]{Color: Black, Left: nil, Right: nil} + leaf := &RBNode[T]{color: Black, left: nil, right: nil} + leaf.parent = leaf return &RB[T]{ - binaryTree: &binaryTree[T]{ - Root: leaf, - NIL: leaf, - }, + Root: leaf, + _NIL: leaf, } } +// Empty determines the Red-Black tree is empty +func (t *RB[T]) Empty() bool { + return t.Root == t._NIL +} + // Push a chain of Node's into the Red-Black Tree func (t *RB[T]) Push(keys ...T) { for _, key := range keys { @@ -43,145 +81,212 @@ func (t *RB[T]) Delete(data T) bool { return t.deleteHelper(t.Root, data) } -// Return the Predecessor of the node of Key +// Get a Node from the Red-Black Tree +func (t *RB[T]) Get(key T) (Node[T], bool) { + return searchTreeHelper[T](t.Root, t._NIL, key) +} + +// Has Determines the tree has the node of Key +func (t *RB[T]) Has(key T) bool { + _, ok := searchTreeHelper[T](t.Root, t._NIL, key) + return ok +} + +// PreOrder Traverses the tree in the following order Root --> Left --> Right +func (t *RB[T]) PreOrder() []T { + traversal := make([]T, 0) + preOrderRecursive[T](t.Root, t._NIL, &traversal) + return traversal +} + +// InOrder Traverses the tree in the following order Left --> Root --> Right +func (t *RB[T]) InOrder() []T { + return inOrderHelper[T](t.Root, t._NIL) +} + +// PostOrder traverses the tree in the following order Left --> Right --> Root +func (t *RB[T]) PostOrder() []T { + traversal := make([]T, 0) + postOrderRecursive[T](t.Root, t._NIL, &traversal) + return traversal +} + +// LevelOrder returns the level order traversal of the tree +func (t *RB[T]) LevelOrder() []T { + traversal := make([]T, 0) + levelOrderHelper[T](t.Root, t._NIL, &traversal) + return traversal +} + +// AccessNodesByLayer accesses nodes layer by layer (2-D array), instead of printing the results as 1-D array. +func (t *RB[T]) AccessNodesByLayer() [][]T { + return accessNodeByLayerHelper[T](t.Root, t._NIL) +} + +// Depth returns the calculated depth of a Red-Black tree +func (t *RB[T]) Depth() int { + return calculateDepth[T](t.Root, t._NIL, 0) +} + +// Max returns the Max value of the tree +func (t *RB[T]) Max() (T, bool) { + ret := maximum[T](t.Root, t._NIL) + if ret == t._NIL { + var dft T + return dft, false + } + return ret.Key(), true +} + +// Min returns the Min value of the tree +func (t *RB[T]) Min() (T, bool) { + ret := minimum[T](t.Root, t._NIL) + if ret == t._NIL { + var dft T + return dft, false + } + return ret.Key(), true +} + +// Predecessor returns the Predecessor of the node of Key // if there is no predecessor, return default value of type T and false // otherwise return the Key of predecessor and true func (t *RB[T]) Predecessor(key T) (T, bool) { - node, ok := t.searchTreeHelper(t.Root, key) + node, ok := searchTreeHelper[T](t.Root, t._NIL, key) if !ok { - return t.NIL.Key, ok + var dft T + return dft, ok } - return t.predecessorHelper(node) + return predecessorHelper[T](node, t._NIL) } -// Return the Successor of the node of Key +// Successor returns the Successor of the node of Key // if there is no successor, return default value of type T and false // otherwise return the Key of successor and true func (t *RB[T]) Successor(key T) (T, bool) { - node, ok := t.searchTreeHelper(t.Root, key) + node, ok := searchTreeHelper[T](t.Root, t._NIL, key) if !ok { - return t.NIL.Key, ok + var dft T + return dft, ok } - - return t.successorHelper(node) + return successorHelper[T](node, t._NIL) } -func (t *RB[T]) pushHelper(x *Node[T], key T) { - node := &Node[T]{ - Key: key, - Left: t.NIL, - Right: t.NIL, - Parent: nil, - Color: Red, - } - - var y *Node[T] - for !t.isNil(x) { +func (t *RB[T]) pushHelper(x *RBNode[T], key T) { + y := t._NIL + for x != t._NIL { y = x - if node.Key < x.Key { - x = x.Left - } else { - x = x.Right + switch { + case key < x.Key(): + x = x.left + case key > x.Key(): + x = x.right + default: + return } - } - node.Parent = y - if y == nil { + node := &RBNode[T]{ + key: key, + left: t._NIL, + right: t._NIL, + parent: y, + color: Red, + } + if y == t._NIL { t.Root = node - } else if node.Key < y.Key { - y.Left = node + } else if node.key < y.key { + y.left = node } else { - y.Right = node + y.right = node } - if node.Parent == nil { - node.Color = Black + if node.parent == t._NIL { + node.color = Black return } - if node.Parent.Parent == nil { + if node.parent.parent == t._NIL { return } t.pushFix(node) } -func (t *RB[T]) leftRotate(x *Node[T]) { - y := x.Right - x.Right = y.Left +func (t *RB[T]) leftRotate(x *RBNode[T]) { + y := x.right + x.right = y.left - if !t.isNil(y.Left) { - y.Left.Parent = x + if y.left != t._NIL { + y.left.parent = x } - y.Parent = x.Parent - if x.Parent == nil { + y.parent = x.parent + if x.parent == t._NIL { t.Root = y - } else if x == x.Parent.Left { - x.Parent.Left = y + } else if x == x.parent.left { + x.parent.left = y } else { - x.Parent.Right = y + x.parent.right = y } - y.Left = x - x.Parent = y + y.left = x + x.parent = y } -func (t *RB[T]) rightRotate(x *Node[T]) { - y := x.Left - x.Left = y.Right - if !t.isNil(y.Right) { - y.Right.Parent = x +func (t *RB[T]) rightRotate(x *RBNode[T]) { + y := x.left + x.left = y.right + if y.right != t._NIL { + y.right.parent = x } - y.Parent = x.Parent - if x.Parent == nil { + y.parent = x.parent + if x.parent == t._NIL { t.Root = y - } else if x == y.Parent.Right { - y.Parent.Right = y + } else if x == y.parent.right { + y.parent.right = y } else { - y.Parent.Left = y + y.parent.left = y } - y.Right = x - x.Parent = y + y.right = x + x.parent = y } -func (t *RB[T]) pushFix(k *Node[T]) { - var u *Node[T] - for k.Parent.Color == Red { - if k.Parent == k.Parent.Parent.Right { - u = k.Parent.Parent.Left - if u != nil && u.Color == Red { - u.Color = Black - k.Parent.Color = Black - k.Parent.Parent.Color = Red - k = k.Parent.Parent +func (t *RB[T]) pushFix(k *RBNode[T]) { + for k.parent.color == Red { + if k.parent == k.parent.parent.right { + u := k.parent.parent.left + if u.color == Red { + u.color = Black + k.parent.color = Black + k.parent.parent.color = Red + k = k.parent.parent } else { - if k == k.Parent.Left { - k = k.Parent + if k == k.parent.left { + k = k.parent t.rightRotate(k) } - k.Parent.Color = Black - k.Parent.Parent.Color = Red - t.leftRotate(k.Parent.Parent) + k.parent.color = Black + k.parent.parent.color = Red + t.leftRotate(k.parent.parent) } } else { - u = k.Parent.Parent.Right - if u != nil && u.Color == Red { - u.Color = Black - k.Parent.Color = Black - k.Parent.Parent.Color = Red - k = k.Parent.Parent + u := k.parent.parent.right + if u.color == Red { + u.color = Black + k.parent.color = Black + k.parent.parent.color = Red + k = k.parent.parent } else { - if k == k.Parent.Right { - k = k.Parent + if k == k.parent.right { + k = k.parent t.leftRotate(k) } - k.Parent.Color = Black - k.Parent.Parent.Color = Red - t.rightRotate(k.Parent.Parent) + k.parent.color = Black + k.parent.parent.color = Red + t.rightRotate(k.parent.parent) } } if k == t.Root { @@ -189,53 +294,52 @@ func (t *RB[T]) pushFix(k *Node[T]) { } } - t.Root.Color = Black + t.Root.color = Black } -func (t *RB[T]) deleteHelper(node *Node[T], key T) bool { - z := t.NIL - for !t.isNil(node) { +func (t *RB[T]) deleteHelper(node *RBNode[T], key T) bool { + z := t._NIL + for node != t._NIL { switch { - case node.Key == key: + case node.key == key: z = node fallthrough - case node.Key <= key: - node = node.Right - case node.Key > key: - node = node.Left + case node.key <= key: + node = node.right + case node.key > key: + node = node.left } } - if t.isNil(z) { - fmt.Println("Key not found in the tree") + if z == t._NIL { return false } - var x *Node[T] + var x *RBNode[T] y := z - yOriginColor := y.Color - if t.isNil(z.Left) { - x = z.Right - t.rbTransplant(z, z.Right) - } else if t.isNil(z.Right) { - x = z.Left - t.rbTransplant(z, z.Left) + yOriginColor := y.color + if z.left == t._NIL { + x = z.right + t.transplant(z, z.right) + } else if z.right == t._NIL { + x = z.left + t.transplant(z, z.left) } else { - y = t.minimum(z.Right) - yOriginColor = y.Color - x = y.Right - if y.Parent == z { - x.Parent = y + y = minimum[T](z.right, t._NIL).(*RBNode[T]) + yOriginColor = y.color + x = y.right + if y.parent == z { + x.parent = y } else { - t.rbTransplant(y, y.Right) - y.Right = z.Right - y.Right.Parent = y + t.transplant(y, y.right) + y.right = z.right + y.right.parent = y } - t.rbTransplant(z, y) - y.Left = z.Left - y.Left.Parent = y - y.Color = z.Color + t.transplant(z, y) + y.left = z.left + y.left.parent = y + y.color = z.color } if yOriginColor == Black { @@ -245,109 +349,76 @@ func (t *RB[T]) deleteHelper(node *Node[T], key T) bool { return true } -func (t *RB[T]) deleteFix(x *Node[T]) { - var s *Node[T] - for x != t.Root && x.Color == Black { - if x == x.Parent.Left { - s = x.Parent.Right - if s.Color == Red { - s.Color = Black - x.Parent.Color = Red - t.leftRotate(x.Parent) - s = x.Parent.Right +func (t *RB[T]) deleteFix(x *RBNode[T]) { + var s *RBNode[T] + for x != t.Root && x.color == Black { + if x == x.parent.left { + s = x.parent.right + if s.color == Red { + s.color = Black + x.parent.color = Red + t.leftRotate(x.parent) + s = x.parent.right } - if s.Left.Color == Black && s.Right.Color == Black { - s.Color = Red - x = x.Parent + if s.left.color == Black && s.right.color == Black { + s.color = Red + x = x.parent } else { - if s.Right.Color == Black { - s.Left.Color = Black - s.Color = Red + if s.right.color == Black { + s.left.color = Black + s.color = Red t.rightRotate(s) - s = x.Parent.Right + s = x.parent.right } - s.Color = x.Parent.Color - x.Parent.Color = Black - s.Right.Color = Black - t.leftRotate(x.Parent) + s.color = x.parent.color + x.parent.color = Black + s.right.color = Black + t.leftRotate(x.parent) x = t.Root } } else { - s = x.Parent.Left - if s.Color == Red { - s.Color = Black - x.Parent.Color = Red - t.rightRotate(x.Parent) - s = x.Parent.Left + s = x.parent.left + if s.color == Red { + s.color = Black + x.parent.color = Red + t.rightRotate(x.parent) + s = x.parent.left } - if s.Right.Color == Black && s.Left.Color == Black { - s.Color = Red - x = x.Parent + if s.right.color == Black && s.left.color == Black { + s.color = Red + x = x.parent } else { - if s.Left.Color == Black { - s.Right.Color = Black - s.Color = Red + if s.left.color == Black { + s.right.color = Black + s.color = Red t.leftRotate(s) - s = x.Parent.Left + s = x.parent.left } - s.Color = x.Parent.Color - x.Parent.Color = Black - s.Left.Color = Black - t.rightRotate(x.Parent) + s.color = x.parent.color + x.parent.color = Black + s.left.color = Black + t.rightRotate(x.parent) x = t.Root } } } - x.Color = Black + x.color = Black } -func (t *RB[T]) rbTransplant(u, v *Node[T]) { +func (t *RB[T]) transplant(u, v *RBNode[T]) { switch { - case u.Parent == nil: + case u.parent == t._NIL: t.Root = v - case u == u.Parent.Left: - u.Parent.Left = v + case u == u.parent.left: + u.parent.left = v default: - u.Parent.Right = v - } - v.Parent = u.Parent -} - -func (t *RB[T]) predecessorHelper(node *Node[T]) (T, bool) { - if !t.isNil(node.Left) { - return t.maximum(node.Left).Key, true - } - - p := node.Parent - for p != nil && !t.isNil(p) && node == p.Left { - node = p - p = p.Parent - } - - if p == nil { - return t.NIL.Key, false - } - return p.Key, true -} - -func (t *RB[T]) successorHelper(node *Node[T]) (T, bool) { - if !t.isNil(node.Right) { - return t.minimum(node.Right).Key, true + u.parent.right = v } - p := node.Parent - for p != nil && !t.isNil(p) && node == p.Right { - node = p - p = p.Parent - } - - if p == nil { - return t.NIL.Key, false - } - return p.Key, true + v.parent = u.parent } diff --git a/structure/tree/rbtree_test.go b/structure/tree/rbtree_test.go index 25a8c37e1..a609aa7d2 100644 --- a/structure/tree/rbtree_test.go +++ b/structure/tree/rbtree_test.go @@ -26,13 +26,13 @@ func TestRBTreePush(t *testing.T) { t.Errorf("Error with Max: %v", r) } - nums := []int{10, 8, 88, 888, 4, 1<<63 - 1, -(1 << 62), 188, -188, 4, 88, 1 << 32} + nums := []int{10, 8, 88, 888, 4, 1<<63 - 1, -(1 << 62), 188, -188, 4, 1 << 32} tree.Push(nums...) ret = tree.InOrder() - if !sort.IntsAreSorted(ret) || len(ret) != len(nums) { + if !sort.IntsAreSorted(ret) { t.Errorf("Error with Push: %v", ret) } @@ -54,27 +54,22 @@ func TestRBTreeDelete(t *testing.T) { ok = tree.Delete(188) - if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-1 { + if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) { t.Errorf("Error with Delete: %v", ret) } ok = tree.Delete(188) - if ret := tree.InOrder(); ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-1 { + if ret := tree.InOrder(); ok || !sort.IntsAreSorted(ret) { t.Errorf("Error with Delete: %v", ret) } ok = tree.Delete(1<<63 - 1) - if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-2 { - t.Errorf("Error with Delete: %v", ret) - } - - ok = tree.Delete(4) - if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-3 { + if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) { t.Errorf("Error with Delete: %v", ret) } ok = tree.Delete(4) - if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) || len(ret) != len(nums)-4 { + if ret := tree.InOrder(); !ok || !sort.IntsAreSorted(ret) { t.Errorf("Error with Delete: %v", ret) } @@ -87,16 +82,12 @@ func TestRBTreeDelete(t *testing.T) { } } -func FuzzRBTree(f *testing.F) { +func TestRBTree(t *testing.T) { testcases := []int{100, 200, 1000, 10000} - for _, tc := range testcases { - f.Add(tc) - } - - f.Fuzz(func(t *testing.T, a int) { + for _, n := range testcases { rand.Seed(time.Now().Unix()) tree := bt.NewRB[int]() - nums := rand.Perm(a) + nums := rand.Perm(n) tree.Push(nums...) rets := tree.InOrder() @@ -108,68 +99,24 @@ func FuzzRBTree(f *testing.F) { t.Errorf("Error with Min, get %d, want: %d", res, rets[0]) } - if res, ok := tree.Max(); !ok || res != rets[a-1] { - t.Errorf("Error with Max, get %d, want: %d", res, rets[a-1]) + if res, ok := tree.Max(); !ok || res != rets[n-1] { + t.Errorf("Error with Max, get %d, want: %d", res, rets[n-1]) } - for i := 0; i < a-1; i++ { + for i := 0; i < n-1; i++ { + if ret, ok := tree.Successor(rets[0]); ret != rets[1] || !ok { + t.Error("Error with Successor") + } + if ret, ok := tree.Predecessor(rets[1]); ret != rets[0] || !ok { + t.Error("Error with Predecessor") + } + ok := tree.Delete(nums[i]) rets = tree.InOrder() if !ok || !sort.IntsAreSorted(rets) { t.Errorf("Error With Delete") } } - }) -} - -func TestRBTreePredecessorAndSuccessor(t *testing.T) { - tree := bt.NewRB[int]() - - nums := []int{10, 8, 88, 888, 4, -1, 100} - tree.Push(nums...) - - if ret, ok := tree.Predecessor(100); !ok && ret == 88 { - t.Errorf("Error with Predecessor") - } - - if _, ok := tree.Predecessor(-1); ok { - t.Errorf("Error with Predecessor") - } - - if _, ok := tree.Predecessor(-12); ok { - t.Errorf("Error with Predecessor") - } - - if ret, ok := tree.Predecessor(4); !ok && ret == -1 { - t.Errorf("Error with Predecessor") - } - - if ret, ok := tree.Successor(4); !ok && ret == 8 { - t.Errorf("Error with Successor") - } - - if ret, ok := tree.Successor(8); !ok && ret == 88 { - t.Errorf("Error with Successor") - } - - if ret, ok := tree.Successor(88); !ok && ret == 100 { - t.Errorf("Error with Successor") - } - - if ret, ok := tree.Successor(100); !ok && ret == 888 { - t.Errorf("Error with Successor") - } - - if ret, ok := tree.Successor(-1); !ok && ret == 4 { - t.Errorf("Error with Successor") - } - - if _, ok := tree.Successor(888); ok { - t.Errorf("Error with Successor") - } - - if _, ok := tree.Successor(188); ok { - t.Errorf("Error with Successor") } } diff --git a/structure/tree/tree.go b/structure/tree/tree.go index b7ec06fc8..53f89ec74 100644 --- a/structure/tree/tree.go +++ b/structure/tree/tree.go @@ -8,106 +8,25 @@ package tree import ( - "fmt" - "github.com/TheAlgorithms/Go/constraints" "github.com/TheAlgorithms/Go/math/max" ) -type Color byte - -const ( - Red Color = iota - Black -) - -// Node of a binary tree -type Node[T constraints.Ordered] struct { - Key T - Parent *Node[T] // for Red-Black Tree - Left *Node[T] - Right *Node[T] - Color Color // for Red-Black Tree - Height int // for AVL Tree -} - -// binaryTree is a base-struct for BinarySearch, AVL, RB, etc. -// Note: to avoid instantiation, we make the base struct un-exported. -type binaryTree[T constraints.Ordered] struct { - Root *Node[T] - NIL *Node[T] // NIL denotes the leaf node of Red-Black Tree -} - -// Get a Node from the binary-search Tree -func (t *binaryTree[T]) Get(key T) (*Node[T], bool) { - return t.searchTreeHelper(t.Root, key) -} - -// Determines the tree has the node of Key -func (t *binaryTree[T]) Has(key T) bool { - _, ok := t.searchTreeHelper(t.Root, key) - return ok -} - -// Traverses the tree in the following order Root --> Left --> Right -func (t *binaryTree[T]) PreOrder() []T { - traversal := make([]T, 0) - t.preOrderRecursive(t.Root, &traversal) - return traversal -} - -// Traverses the tree in the following order Left --> Root --> Right -func (t *binaryTree[T]) InOrder() []T { - return t.inOrderHelper(t.Root) -} - -// Traverses the tree in the following order Left --> Right --> Root -func (t *binaryTree[T]) PostOrder() []T { - traversal := make([]T, 0) - t.postOrderRecursive(t.Root, &traversal) - return traversal -} - -// Depth returns the calculated depth of a binary search tree -func (t *binaryTree[T]) Depth() int { - return t.calculateDepth(t.Root, 0) -} - -// Returns the Max value of the tree -func (t *binaryTree[T]) Max() (T, bool) { - ret := t.maximum(t.Root) - if t.isNil(ret) { - return t.NIL.Key, false - } - - return ret.Key, true -} - -// Return the Min value of the tree -func (t *binaryTree[T]) Min() (T, bool) { - ret := t.minimum(t.Root) - if t.isNil(ret) { - return t.NIL.Key, false - } - - return ret.Key, true +type Node[T constraints.Ordered] interface { + Key() T + Parent() Node[T] + Left() Node[T] + Right() Node[T] } -// LevelOrder returns the level order traversal of the tree -func (t *binaryTree[T]) LevelOrder() []T { - traversal := make([]T, 0) - t.levelOrderHelper(t.Root, &traversal) - return traversal -} +// The following is a collection of helper functions for BinarySearch, AVL and RB. -// AccessNodesByLayer accesses nodes layer by layer (2-D array), instead of printing the results as 1-D array. -func (t *binaryTree[T]) AccessNodesByLayer() [][]T { - root := t.Root - if t.isNil(root) { +func accessNodeByLayerHelper[T constraints.Ordered](root, nilNode Node[T]) [][]T { + if root == nilNode { return [][]T{} } - var q []*Node[T] - var n *Node[T] + var q []Node[T] + var n Node[T] var idx = 0 q = append(q, root) var res [][]T @@ -117,12 +36,12 @@ func (t *binaryTree[T]) AccessNodesByLayer() [][]T { qLen := len(q) for i := 0; i < qLen; i++ { n, q = q[0], q[1:] - res[idx] = append(res[idx], n.Key) - if !t.isNil(n.Left) { - q = append(q, n.Left) + res[idx] = append(res[idx], n.Key()) + if n.Left() != nilNode { + q = append(q, n.Left()) } - if !t.isNil(n.Right) { - q = append(q, n.Right) + if n.Right() != nilNode { + q = append(q, n.Right()) } } idx++ @@ -130,154 +49,141 @@ func (t *binaryTree[T]) AccessNodesByLayer() [][]T { return res } -// Print the tree horizontally -func (t *binaryTree[T]) Print() { - t.printHelper(t.Root, "", false) -} - -// Determines node is a leaf node -func (t *binaryTree[T]) isNil(node *Node[T]) bool { - return node == t.NIL -} - -func (t *binaryTree[T]) searchTreeHelper(node *Node[T], key T) (*Node[T], bool) { - if node == nil || t.isNil(node) { +func searchTreeHelper[T constraints.Ordered](node, nilNode Node[T], key T) (Node[T], bool) { + if node == nilNode { return node, false } - if key == node.Key { + if key == node.Key() { return node, true } - - if key < node.Key { - return t.searchTreeHelper(node.Left, key) + if key < node.Key() { + return searchTreeHelper(node.Left(), nilNode, key) } - return t.searchTreeHelper(node.Right, key) + return searchTreeHelper(node.Right(), nilNode, key) } -// The iterative inorder; -// The recursive way is similar to the preOrderRecursive -func (t *binaryTree[T]) inOrderHelper(node *Node[T]) []T { - var stack []*Node[T] +func inOrderHelper[T constraints.Ordered](node, nilNode Node[T]) []T { + var stack []Node[T] var ret []T - for !t.isNil(node) || len(stack) > 0 { - for !t.isNil(node) { + for node != nilNode || len(stack) > 0 { + for node != nilNode { stack = append(stack, node) - node = node.Left + node = node.Left() } node = stack[len(stack)-1] stack = stack[:len(stack)-1] - ret = append(ret, node.Key) - node = node.Right + ret = append(ret, node.Key()) + node = node.Right() } return ret } -func (t *binaryTree[T]) preOrderRecursive(n *Node[T], traversal *[]T) { - if t.isNil(n) { +func preOrderRecursive[T constraints.Ordered](n, nilNode Node[T], traversal *[]T) { + if n == nilNode { return } - *traversal = append(*traversal, n.Key) - t.preOrderRecursive(n.Left, traversal) - t.preOrderRecursive(n.Right, traversal) + *traversal = append(*traversal, n.Key()) + preOrderRecursive(n.Left(), nilNode, traversal) + preOrderRecursive(n.Right(), nilNode, traversal) + } -func (t *binaryTree[T]) postOrderRecursive(n *Node[T], traversal *[]T) { - if t.isNil(n) { +func postOrderRecursive[T constraints.Ordered](n, nilNode Node[T], traversal *[]T) { + if n == nilNode { return } - t.postOrderRecursive(n.Left, traversal) - t.postOrderRecursive(n.Right, traversal) - *traversal = append(*traversal, n.Key) + postOrderRecursive(n.Left(), nilNode, traversal) + postOrderRecursive(n.Right(), nilNode, traversal) + *traversal = append(*traversal, n.Key()) } -func (t *binaryTree[T]) calculateDepth(n *Node[T], depth int) int { - if t.isNil(n) { +func calculateDepth[T constraints.Ordered](n, nilNode Node[T], depth int) int { + if n == nilNode { return depth } - return max.Int(t.calculateDepth(n.Left, depth+1), t.calculateDepth(n.Right, depth+1)) + return max.Int(calculateDepth(n.Left(), nilNode, depth+1), calculateDepth(n.Right(), nilNode, depth+1)) } -// Returns the minimum value of node of the tree -func (t *binaryTree[T]) minimum(node *Node[T]) *Node[T] { - if t.isNil(node) { +func minimum[T constraints.Ordered](node, nilNode Node[T]) Node[T] { + if node == nilNode { return node } - for !t.isNil(node.Left) { - node = node.Left + for node.Left() != nilNode { + node = node.Left() } return node } -// Returns the maximum value of node of the tree -func (t *binaryTree[T]) maximum(node *Node[T]) *Node[T] { - if t.isNil(node) { +func maximum[T constraints.Ordered](node, nilNode Node[T]) Node[T] { + if node == nilNode { return node } - for !t.isNil(node.Right) { - node = node.Right + for node.Right() != nilNode { + node = node.Right() } return node } -func (t *binaryTree[T]) levelOrderHelper(root *Node[T], traversal *[]T) { - var q []*Node[T] // queue - var tmp *Node[T] +func levelOrderHelper[T constraints.Ordered](root, nilNode Node[T], traversal *[]T) { + var q []Node[T] // queue + var tmp Node[T] q = append(q, root) for len(q) != 0 { tmp, q = q[0], q[1:] - *traversal = append(*traversal, tmp.Key) - if !t.isNil(tmp.Left) { - q = append(q, tmp.Left) + *traversal = append(*traversal, tmp.Key()) + if tmp.Left() != nilNode { + q = append(q, tmp.Left()) } - if !t.isNil(tmp.Right) { - q = append(q, tmp.Right) + if tmp.Right() != nilNode { + q = append(q, tmp.Right()) } } } -// Reference: https://stackoverflow.com/a/51730733/15437172 -func (t *binaryTree[T]) printHelper(root *Node[T], indent string, isLeft bool) { - if t.isNil(root) { - return +func predecessorHelper[T constraints.Ordered](node, nilNode Node[T]) (T, bool) { + if node.Left() != nilNode { + return maximum(node.Left(), nilNode).Key(), true } - fmt.Print(indent) - if isLeft { - fmt.Print("├──") - indent += "│ " - } else { - fmt.Print("└──") - indent += " " + p := node.Parent() + for p != nilNode && node == p.Left() { + node = p + p = p.Parent() } - if t.isRBTree() { - color := "Black" - if root.Color == Red { - color = "Red" - } + if p == nilNode { + var dft T + return dft, false + } + return p.Key(), true +} - fmt.Println(root.Key, "(", color, ")") - } else { - fmt.Println(root.Key) +func successorHelper[T constraints.Ordered](node, nilNode Node[T]) (T, bool) { + if node.Right() != nilNode { + return minimum(node.Right(), nilNode).Key(), true } - t.printHelper(root.Left, indent, true) - t.printHelper(root.Right, indent, false) -} + p := node.Parent() + for p != nilNode && node == p.Right() { + node = p + p = p.Parent() + } -// Determines the tree is RB -func (t *binaryTree[T]) isRBTree() bool { - return t.NIL != nil + if p == nilNode { + var dft T + return dft, false + } + return p.Key(), true } diff --git a/structure/tree/tree_test.go b/structure/tree/tree_test.go index 2426e57e6..3653f7355 100644 --- a/structure/tree/tree_test.go +++ b/structure/tree/tree_test.go @@ -10,47 +10,42 @@ import ( ) func TestTreeGetOrHas(t *testing.T) { + helper := func(tree TestTree[int], nums []int) { + tree.Push(nums...) + for _, num := range nums { + if !tree.Has(num) { + t.Errorf("Error with Has or Push method") + } + } + + min, _ := tree.Min() + max, _ := tree.Max() + + if _, ok := tree.Get(min - 1); ok { + t.Errorf("Error with Get method") + } + + if _, ok := tree.Get(max + 1); ok { + t.Errorf("Error with Get method") + } + } + lens := []int{100, 1_000, 10_000, 100_000} for _, ll := range lens { nums := rand.Perm(ll) t.Run("Test Binary Search Tree", func(t *testing.T) { bsTree := bt.NewBinarySearch[int]() - bsTree.Push(nums...) - for _, num := range nums { - if !bsTree.Has(num) { - t.Errorf("Error with Has or Push method") - } - } - min, _ := bsTree.Min() - max, _ := bsTree.Max() - - if _, ok := bsTree.Get(min - 1); ok { - t.Errorf("Error with Get method") - } - - if _, ok := bsTree.Get(max + 1); ok { - t.Errorf("Error with Get method") - } + helper(bsTree, nums) }) t.Run("Test Red-Black Tree", func(t *testing.T) { rbTree := bt.NewRB[int]() - rbTree.Push(nums...) - for _, num := range nums { - if !rbTree.Has(num) { - t.Errorf("Error with Has or Push method") - } - } + helper(rbTree, nums) }) t.Run("Test AVL Tree", func(t *testing.T) { avlTree := bt.NewAVL[int]() - avlTree.Push(nums...) - for _, num := range nums { - if !avlTree.Has(num) { - t.Errorf("Error with Has or Push method") - } - } + helper(avlTree, nums) }) } } @@ -261,43 +256,38 @@ func TestTreeLevelOrder(t *testing.T) { } func TestTreeMinAndMax(t *testing.T) { + helper := func(tree TestTree[int], nums []int) { + ll := len(nums) + if _, ok := tree.Min(); ok { + t.Errorf("Error with Min method.") + } + if _, ok := tree.Max(); ok { + t.Errorf("Error with Max method.") + } + tree.Push(nums...) + if min, ok := tree.Min(); !ok || min != nums[0] { + t.Errorf("Error with Min method.") + } + if max, ok := tree.Max(); !ok || max != nums[ll-1] { + t.Errorf("Error with Max method.") + } + } + lens := []int{500, 1_000, 10_000} for _, ll := range lens { nums := rand.Perm(ll) sort.Ints(nums) t.Run("Test Binary Search Tree", func(t *testing.T) { - bsTree := bt.NewBinarySearch[int]() - bsTree.Push(nums...) - if min, ok := bsTree.Min(); !ok || min != nums[0] { - t.Errorf("Error with Min method.") - } - if max, ok := bsTree.Max(); !ok || max != nums[ll-1] { - t.Errorf("Error with Max method.") - } + helper(bt.NewBinarySearch[int](), nums) }) t.Run("Test Red-Black Tree", func(t *testing.T) { - rbTree := bt.NewRB[int]() - rbTree.Push(nums...) - if min, ok := rbTree.Min(); !ok || min != nums[0] { - t.Errorf("Error with Min method.") - } - if max, ok := rbTree.Max(); !ok || max != nums[ll-1] { - t.Errorf("Error with Max method.") - } + helper(bt.NewRB[int](), nums) }) t.Run("Test AVL Tree", func(t *testing.T) { - avlTree := bt.NewAVL[int]() - avlTree.Push(nums...) - if min, ok := avlTree.Min(); !ok || min != nums[0] { - t.Errorf("Error with Min method.") - } - - if max, ok := avlTree.Max(); !ok || max != nums[ll-1] { - t.Errorf("Error with Max method.") - } + helper(bt.NewAVL[int](), nums) }) } } @@ -361,62 +351,6 @@ func TestTreeDepth(t *testing.T) { }) } -func TestTreePrint(t *testing.T) { - t.Run("Test for Binary-Search Tree", func(t *testing.T) { - tests := []struct { - input []int - want []int - }{ - {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, - {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, - []int{61, 51, 41, 31, 21, 1, 71, 70, 85, 80, 95, 105, 100, 90}}, - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, - } - for _, tt := range tests { - tree := bt.NewBinarySearch[int]() - t.Log(reflect.TypeOf(tree).String()) - tree.Push(tt.input...) - tree.Print() - } - }) - - t.Run("Test for AVL Tree", func(t *testing.T) { - tests := []struct { - input []int - want []int - }{ - {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, - {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, - []int{1, 31, 21, 61, 51, 41, 71, 85, 80, 95, 105, 100, 90, 70}}, - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 4, 6, 5, 3, 8, 10, 9, 7}}, - } - for _, tt := range tests { - tree := bt.NewAVL[int]() - t.Log(reflect.TypeOf(tree).String()) - tree.Push(tt.input...) - tree.Print() - } - }) - - t.Run("Test for Red-Black Tree", func(t *testing.T) { - tests := []struct { - input []int - want []int - }{ - {[]int{90, 80, 100, 70, 85, 95, 105}, []int{70, 85, 80, 95, 105, 100, 90}}, - {[]int{90, 80, 100, 70, 85, 95, 105, 1, 21, 31, 41, 51, 61, 71}, - []int{1, 31, 21, 51, 71, 70, 61, 41, 85, 95, 105, 100, 90, 80}}, - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 4, 3, 6, 5, 8, 10, 9, 7}}, - } - for _, tt := range tests { - tree := bt.NewRB[int]() - t.Log(reflect.TypeOf(tree).String() == "*tree.RB[int]") - tree.Push(tt.input...) - tree.Print() - } - }) -} - func TestTreeAccessNodesByLayer(t *testing.T) { t.Run("Test for Binary-Search Tree", func(t *testing.T) { tests := []struct { @@ -480,6 +414,81 @@ func TestTreeAccessNodesByLayer(t *testing.T) { }) } +func TestTreePredecessorAndSuccessor(t *testing.T) { + helper := func(tree TestTree[int]) { + nums := []int{10, 8, 88, 888, 4, -1, 100} + tree.Push(nums...) + if ret, ok := tree.Predecessor(100); !ok || ret != 88 { + t.Error("Error with Predecessor") + } + + if _, ok := tree.Predecessor(-1); ok { + t.Error("Error with Predecessor") + } + + tree.Push(-100) + if ret, ok := tree.Predecessor(-1); !ok || ret != -100 { + t.Error("Error with Predecessor") + } + + if _, ok := tree.Predecessor(-12); ok { + t.Error("Error with Predecessor") + } + + if ret, ok := tree.Predecessor(4); !ok || ret != -1 { + t.Error("Error with Predecessor") + } + + if ret, ok := tree.Successor(4); !ok || ret != 8 { + t.Error("Error with Successor") + } + + if ret, ok := tree.Successor(8); !ok || ret != 10 { + t.Error("Error with Successor") + } + + if ret, ok := tree.Successor(88); !ok || ret != 100 { + t.Error("Error with Successor") + } + + if ret, ok := tree.Successor(100); !ok || ret != 888 { + t.Error("Error with Successor") + } + + tree.Delete(888) + if _, ok := tree.Successor(100); ok { + t.Error("Error with Successor") + } + + if ret, ok := tree.Successor(-1); !ok || ret != 4 { + t.Error("Error with Successor") + } + + if _, ok := tree.Successor(888); ok { + t.Error("Error with Successor") + } + + if _, ok := tree.Successor(188); ok { + t.Error("Error with Successor") + } + } + + t.Run("Test for Binary Search Tree", func(t *testing.T) { + tree := bt.NewBinarySearch[int]() + helper(tree) + }) + + t.Run("Test for Red-Black Tree", func(t *testing.T) { + tree := bt.NewRB[int]() + helper(tree) + }) + + t.Run("Test for AVL Tree", func(t *testing.T) { + tree := bt.NewAVL[int]() + helper(tree) + }) +} + // Benchmark the comparisons between BST, AVL and RB Tree const testNum = 10_000 From bc2ae780e22b212766014967b27f6a4078d3bdc3 Mon Sep 17 00:00:00 2001 From: Yury <72691412+cheatsnake@users.noreply.github.com> Date: Thu, 19 Jan 2023 20:35:14 +0300 Subject: [PATCH 398/488] feat: add GUID algorithm (#614) --- strings/guid/guid.go | 48 +++++++++++++++++++++++++++ strings/guid/guid_test.go | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 strings/guid/guid.go create mode 100644 strings/guid/guid_test.go diff --git a/strings/guid/guid.go b/strings/guid/guid.go new file mode 100644 index 000000000..36cc906a7 --- /dev/null +++ b/strings/guid/guid.go @@ -0,0 +1,48 @@ +// guid.go +// description: Generate random globally unique identifiers (GUIDs). +// details: +// A GUID (globally unique identifier) is a 128-bit text string that +// represents an identification (ID). Organizations generate GUIDs when +// a unique reference number is needed to identify information on +// a computer or network. A GUID can be used to ID hardware, software, +// accounts, documents and other items. The term is also often used in +// software created by Microsoft. +// See more information on: https://en.wikipedia.org/wiki/Universally_unique_identifier +// author(s) [cheatsnake](https://github.com/cheatsnake) +// see guid_test.go + +// Package guid provides facilities for generating random globally unique identifiers. +package guid + +import ( + "crypto/rand" + "fmt" + "math/big" + "strings" +) + +const pattern string = "xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx" +const versionIndex int = 14 + +// New returns a randomly generated global unique identifier. +func New() (string, error) { + var guid strings.Builder + + for i, ch := range pattern { + if i == versionIndex { + guid.WriteRune(ch) + continue + } + if ch == '-' { + guid.WriteRune(ch) + continue + } + random, err := rand.Int(rand.Reader, big.NewInt(16)) + if err != nil { + return "", err + } + guid.WriteString(fmt.Sprintf("%x", random.Int64())) + } + + return guid.String(), nil +} diff --git a/strings/guid/guid_test.go b/strings/guid/guid_test.go new file mode 100644 index 000000000..a9e66c95e --- /dev/null +++ b/strings/guid/guid_test.go @@ -0,0 +1,68 @@ +package guid + +import ( + "strings" + "testing" +) + +func TestNew(t *testing.T) { + t.Run("check for allowed characters", func(t *testing.T) { + allowedChars := "0123456789abcdef-" + guid, err := New() + if err != nil { + t.Errorf(`the test failed, an error occurred: %s`, err.Error()) + } + + for _, char := range guid { + if !strings.Contains(allowedChars, string(char)) { + t.Errorf(`allowed only "%s" characters, but got %v`, allowedChars, char) + } + } + }) + + t.Run("check string length", func(t *testing.T) { + guid, err := New() + if err != nil { + t.Errorf(`the test failed, an error occurred: %s`, err.Error()) + } + + if len(guid) != len(pattern) { + t.Errorf(`the length of the string should be "%d", but got %d`, len(pattern), len(guid)) + } + }) + + t.Run("check for version index", func(t *testing.T) { + expected := "4" + versionIndex := strings.Index(pattern, expected) + guid, err := New() + if err != nil { + t.Errorf(`the test failed, an error occurred: %s`, err.Error()) + } + + result := string(guid[versionIndex]) + + if expected != result { + t.Errorf(`at the index %d should be %s, but got %s`, versionIndex, expected, result) + } + }) + + t.Run("check the number of dashes", func(t *testing.T) { + expected := strings.Count(pattern, "-") + guid, err := New() + if err != nil { + t.Errorf(`the test failed, an error occurred: %s`, err.Error()) + } + + result := strings.Count(guid, "-") + + if expected != result { + t.Errorf(`the length of the string should be "%d", but got %d`, len(pattern), len(guid)) + } + }) +} + +func BenchmarkNew(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = New() + } +} From 771209819da96ee02230fbe2013dcc702d446e78 Mon Sep 17 00:00:00 2001 From: Alexander John Lee <77119221+partylikeits1983@users.noreply.github.com> Date: Tue, 31 Jan 2023 19:34:55 +0300 Subject: [PATCH 399/488] fix: misspelled variable (#618) * fix: misspelled variable * fix: refactor math/binary/sqrt.go --- math/binary/sqrt.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/math/binary/sqrt.go b/math/binary/sqrt.go index 4d352ed49..111dd94a9 100644 --- a/math/binary/sqrt.go +++ b/math/binary/sqrt.go @@ -13,12 +13,12 @@ import ( const threeHalves = 1.5 -func Sqrt(number float32) float32 { - var halfHumber, y float32 - halfHumber = number * 0.5 - z := math.Float32bits(number) +func Sqrt(n float32) float32 { + var half, y float32 + half = n * 0.5 + z := math.Float32bits(n) z = 0x5f3759df - (z >> 1) // floating point bit level hacking y = math.Float32frombits(z) - y = y * (threeHalves - (halfHumber * y * y)) // Newton's approximation + y = y * (threeHalves - (half * y * y)) // Newton's approximation return 1 / y } From 68eb0fbf787d963d5f3bee9a072cfe32114eff6f Mon Sep 17 00:00:00 2001 From: Neha G <113783174+nehag0x1@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:35:55 +0530 Subject: [PATCH 400/488] fix: range condition in IsPowerOfTwoLeftShift (#619) Remove redundant condition --- math/binary/checkisnumberpoweroftwo.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/math/binary/checkisnumberpoweroftwo.go b/math/binary/checkisnumberpoweroftwo.go index 63ecc6e3b..29c023e5a 100644 --- a/math/binary/checkisnumberpoweroftwo.go +++ b/math/binary/checkisnumberpoweroftwo.go @@ -26,10 +26,7 @@ func IsPowerOfTwo(x int) bool { // by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, // which in decimal system is 8 or = 2 * 2 * 2 func IsPowerOfTwoLeftShift(number uint) bool { - if number == 0 { - return false - } - for p := uint(1); p > 0; p = p << 1 { + for p := uint(1); p <= number; p = p << 1 { if number == p { return true } From 97d4a1451082a4fa0b7f269a3b1257cd064ce7ef Mon Sep 17 00:00:00 2001 From: Pedro Rocha Date: Sat, 11 Feb 2023 16:40:09 +0000 Subject: [PATCH 401/488] test: Add benchmark for prime sieve (#621) --- math/prime/sieve_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/math/prime/sieve_test.go b/math/prime/sieve_test.go index 82cc63017..36a1c5811 100644 --- a/math/prime/sieve_test.go +++ b/math/prime/sieve_test.go @@ -44,3 +44,9 @@ func TestGeneratePrimes(t *testing.T) { } }) } + +func BenchmarkSieve10(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Generate(10) + } +} From 27c627e06107f8a4fa472bc1daeede6b60951f6f Mon Sep 17 00:00:00 2001 From: Hidenari-Yuda <106872451+hidenari-yuda@users.noreply.github.com> Date: Tue, 14 Feb 2023 19:48:02 +0900 Subject: [PATCH 402/488] fix: rand.Seed() deparcated (#624) * fix rand.Seed fix rand.Seed * fix rand.Seed fix rand.Seed fix unexpected format change fix unexpected format change * fix unexpected format change --------- Co-authored-by: Andrii Siriak --- cipher/caesar/caesar_test.go | 4 ++-- graph/lowestcommonancestor_test.go | 14 +++++++------- sort/sorts_test.go | 4 ++-- strings/genetic/genetic.go | 16 ++++++++-------- structure/tree/avl_test.go | 4 ++-- structure/tree/bstree_test.go | 4 ++-- structure/tree/rbtree_test.go | 4 ++-- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cipher/caesar/caesar_test.go b/cipher/caesar/caesar_test.go index 4d03ea3ec..1e22a8c34 100644 --- a/cipher/caesar/caesar_test.go +++ b/cipher/caesar/caesar_test.go @@ -156,10 +156,10 @@ func Example() { } func FuzzCaesar(f *testing.F) { - rand.Seed(time.Now().Unix()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) f.Add("The Quick Brown Fox Jumps over the Lazy Dog.") f.Fuzz(func(t *testing.T, input string) { - key := rand.Intn(26) + key := rnd.Intn(26) if result := Decrypt(Encrypt(input, key), key); result != input { t.Fatalf("With input: '%s' and key: %d\n\tExpected: '%s'\n\tGot: '%s'", input, key, input, result) } diff --git a/graph/lowestcommonancestor_test.go b/graph/lowestcommonancestor_test.go index c7149e46e..ab55219fb 100644 --- a/graph/lowestcommonancestor_test.go +++ b/graph/lowestcommonancestor_test.go @@ -147,11 +147,11 @@ func TestLCA(t *testing.T) { } func generateTree() *Tree { - rand.Seed(time.Now().UnixNano()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) const MAXVERTEX int = 2000 - var numbersVertex int = rand.Intn(MAXVERTEX) + 1 - var root int = rand.Intn(numbersVertex) + var numbersVertex int = rnd.Intn(MAXVERTEX) + 1 + var root int = rnd.Intn(numbersVertex) var edges []TreeEdge var fullGraph []TreeEdge @@ -163,7 +163,7 @@ func generateTree() *Tree { }) } } - rand.Shuffle(len(fullGraph), func(i, j int) { + rnd.Shuffle(len(fullGraph), func(i, j int) { fullGraph[i], fullGraph[j] = fullGraph[j], fullGraph[i] }) @@ -201,7 +201,7 @@ func generateTree() *Tree { } func generateQuery(tree *Tree) []Query { - rand.Seed(time.Now().UnixNano()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) const MAXQUERY = 50 var queries []Query @@ -217,8 +217,8 @@ func generateQuery(tree *Tree) []Query { } for q := 1; q <= MAXQUERY; q++ { - u := rand.Intn(tree.numbersVertex) - v := rand.Intn(tree.numbersVertex) + u := rnd.Intn(tree.numbersVertex) + v := rnd.Intn(tree.numbersVertex) queries = append(queries, Query{ u: u, v: v, diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 9f34a23cb..7ff8b4363 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -106,11 +106,11 @@ func TestMergeParallel(t *testing.T) { // Test parallel merge sort with a large slice t.Run("ParallelMerge on large slice", func(t *testing.T) { - rand.Seed(time.Now().UnixNano()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) size := 100000 randomLargeSlice := make([]int, size) for i := range randomLargeSlice { - randomLargeSlice[i] = rand.Intn(size) + randomLargeSlice[i] = rnd.Intn(size) } sortedSlice := sort.ParallelMerge[int](randomLargeSlice) for i := 0; i < len(sortedSlice)-1; i++ { diff --git a/strings/genetic/genetic.go b/strings/genetic/genetic.go index 95fc05fa6..384ecf940 100644 --- a/strings/genetic/genetic.go +++ b/strings/genetic/genetic.go @@ -92,7 +92,7 @@ func GeneticString(target string, charmap []rune, conf *Conf) (*Result, error) { debug := conf.Debug // Just a seed to improve randomness required by the algorithm - rand.Seed(time.Now().UnixNano()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) // Verify that the target contains no genes besides the ones inside genes variable. for position, r := range target { @@ -113,7 +113,7 @@ func GeneticString(target string, charmap []rune, conf *Conf) (*Result, error) { for i := 0; i < populationNum; i++ { key := "" for x := 0; x < utf8.RuneCountInString(target); x++ { - choice := rand.Intn(len(charmap)) + choice := rnd.Intn(len(charmap)) key += string(charmap[choice]) } pop[i] = PopulationItem{key, 0} @@ -165,18 +165,18 @@ func GeneticString(target string, charmap []rune, conf *Conf) (*Result, error) { nChild = 10 } for x := 0.0; x < nChild; x++ { - parent2 := pop[rand.Intn(selectionNum)] + parent2 := pop[rnd.Intn(selectionNum)] // Crossover - split := rand.Intn(utf8.RuneCountInString(target)) + split := rnd.Intn(utf8.RuneCountInString(target)) child1 := append([]rune(parent1.Key)[:split], []rune(parent2.Key)[split:]...) child2 := append([]rune(parent2.Key)[:split], []rune(parent1.Key)[split:]...) // Clean fitness value // Mutate - if rand.Float64() < mutationProb { - child1[rand.Intn(len(child1))] = charmap[rand.Intn(len(charmap))] + if rnd.Float64() < mutationProb { + child1[rnd.Intn(len(child1))] = charmap[rnd.Intn(len(charmap))] } - if rand.Float64() < mutationProb { - child2[rand.Intn(len(child2))] = charmap[rand.Intn(len(charmap))] + if rnd.Float64() < mutationProb { + child2[rnd.Intn(len(child2))] = charmap[rnd.Intn(len(charmap))] } // Push into 'popChildren' popChildren = append(popChildren, PopulationItem{string(child1), 0}) diff --git a/structure/tree/avl_test.go b/structure/tree/avl_test.go index 14a7ab570..70913499a 100644 --- a/structure/tree/avl_test.go +++ b/structure/tree/avl_test.go @@ -284,9 +284,9 @@ func TestAVLDelete(t *testing.T) { t.Run("Random Test", func(t *testing.T) { nums := []int{100, 500, 1000, 10_000} for _, n := range nums { - rand.Seed(time.Now().Unix()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) tree := bt.NewAVL[int]() - nums := rand.Perm(n) + nums := rnd.Perm(n) tree.Push(nums...) rets := tree.InOrder() diff --git a/structure/tree/bstree_test.go b/structure/tree/bstree_test.go index abbf8bfea..211daa28a 100644 --- a/structure/tree/bstree_test.go +++ b/structure/tree/bstree_test.go @@ -154,9 +154,9 @@ func TestDelete(t *testing.T) { t.Run("Random Test", func(t *testing.T) { tests := []int{100, 500, 1000, 10_000} for _, n := range tests { - rand.Seed(time.Now().Unix()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) tree := bt.NewBinarySearch[int]() - nums := rand.Perm(n) + nums := rnd.Perm(n) tree.Push(nums...) rets := tree.InOrder() diff --git a/structure/tree/rbtree_test.go b/structure/tree/rbtree_test.go index a609aa7d2..1b6b38265 100644 --- a/structure/tree/rbtree_test.go +++ b/structure/tree/rbtree_test.go @@ -85,9 +85,9 @@ func TestRBTreeDelete(t *testing.T) { func TestRBTree(t *testing.T) { testcases := []int{100, 200, 1000, 10000} for _, n := range testcases { - rand.Seed(time.Now().Unix()) + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) tree := bt.NewRB[int]() - nums := rand.Perm(n) + nums := rnd.Perm(n) tree.Push(nums...) rets := tree.InOrder() From 4f43cc154fccf98cccd49c1b1fdba21cba8e4a5f Mon Sep 17 00:00:00 2001 From: Rahul <122198550+GooMonk@users.noreply.github.com> Date: Mon, 6 Mar 2023 12:15:56 +0530 Subject: [PATCH 403/488] Add Krishnamurthy number (#620) Co-authored-by: rahul291999 --- math/krishnamurthy.go | 32 ++++++++++++++++++++++++ math/krishnamurthy_test.go | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 math/krishnamurthy.go create mode 100644 math/krishnamurthy_test.go diff --git a/math/krishnamurthy.go b/math/krishnamurthy.go new file mode 100644 index 000000000..641dfbf92 --- /dev/null +++ b/math/krishnamurthy.go @@ -0,0 +1,32 @@ +// filename : krishnamurthy.go +// description: A program which contains the function that returns true if a given number is Krishnamurthy number or not. +// details: A number is a Krishnamurthy number if the sum of all the factorials of the digits is equal to the number. +// Ex: 1! = 1, 145 = 1! + 4! + 5! +// author(s): [GooMonk](https://github.com/GooMonk) +// see krishnamurthy_test.go +package math + +import "github.com/TheAlgorithms/Go/constraints" + +// IsKrishnamurthyNumber returns if the provided number n is a Krishnamurthy number or not. +func IsKrishnamurthyNumber[T constraints.Integer](n T) bool { + if n <= 0 { + return false + } + + // Preprocessing: Using a slice to store the digit Factorials + digitFact := make([]T, 10) + digitFact[0] = 1 // 0! = 1 + + for i := 1; i < 10; i++ { + digitFact[i] = digitFact[i-1] * T(i) + } + + // Subtract the digit Facotorial from the number + nTemp := n + for n > 0 { + nTemp -= digitFact[n%10] + n /= 10 + } + return nTemp == 0 +} diff --git a/math/krishnamurthy_test.go b/math/krishnamurthy_test.go new file mode 100644 index 000000000..c4fc81895 --- /dev/null +++ b/math/krishnamurthy_test.go @@ -0,0 +1,51 @@ +package math + +import ( + "fmt" + "testing" +) + +func retCases() []struct { + input int64 + output bool + outputString string +} { + return []struct { + input int64 + output bool + outputString string + }{ + {-3112312321, false, "is not"}, + {0, false, "is not"}, + {1, true, "is"}, + {2, true, "is"}, + {109, false, "is not"}, + {145, true, "is"}, + {943, false, "is not"}, + {6327, false, "is not"}, + {40585, true, "is"}, + {9743821, false, "is not"}, + {3421488712, false, "is not"}, + } +} + +func TestIsKrishnamurthyNumber(t *testing.T) { + for _, test := range retCases() { + t.Run(fmt.Sprintf("%d %s a Krishnamurthy Number", test.input, test.outputString), func(t *testing.T) { + res := IsKrishnamurthyNumber(test.input) + if res != test.output { + t.Errorf("for input %d, expected: %t, found: %t", test.input, test.output, res) + } + }) + } +} + +func BenchmarkIsKrishnamurthyNumber(b *testing.B) { + for _, test := range retCases() { + b.Run(fmt.Sprintf("%d %s a Krishnamurthy Number", test.input, test.outputString), func(b *testing.B) { + for i := 0; i < b.N; i++ { + IsKrishnamurthyNumber(test.input) + } + }) + } +} From abeec331273c92d9e70921bd30d043164e9149bc Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 15 Mar 2023 19:34:02 +0100 Subject: [PATCH 404/488] Upgrade GitHub Actions (#627) --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40ebab4a1..29615bbe0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,13 +15,13 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: '^1.18' - name: Run Golang CI Lint - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v3 with: version: latest args: -E gofmt @@ -31,7 +31,7 @@ jobs: name: Check for spelling errors runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: codespell-project/actions-codespell@master with: ignore_words_list: "actualy,nwe" From 1a0e193780d3ba6a2cb97289e3797db3f339ffa6 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Thu, 16 Mar 2023 01:07:03 +0530 Subject: [PATCH 405/488] Add Style guide (#493) * chore: basic style suggestions * chore: add commenting and naming guidelines * Update STYLE.md * chore: grammer update Co-authored-by: Taj * chore: clarify the use of the workflows Co-authored-by: Taj * chore: grammer update Co-authored-by: Taj * chore: update package naming guidelines Co-authored-by: Taj * chore: finish sentence fragment Co-authored-by: Taj * chore: use the term UpperCamelCase instead of PascalCase Co-authored-by: Taj * chore: fix typo --------- Co-authored-by: Yang Libin Co-authored-by: Taj --- STYLE.md | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 STYLE.md diff --git a/STYLE.md b/STYLE.md new file mode 100644 index 000000000..2027f05e9 --- /dev/null +++ b/STYLE.md @@ -0,0 +1,188 @@ +# The Algorithms Go Repository Style Guide + +This guide contains a set of go idioms and best practices which should be followed while writing +code whenever they are applicable. The instructions in this document should be given precedence +if there is a conflict between this document and [contribution guidelines](./CONTRIBUTING.md). If you find any issue or ambiguity in +this document, the maintainers of this repository should be consulted. + +## Table of Contents + +- [Formatting](#formatting) +- [Commenting](#commenting) + - [Package Comments](#package-comments) + - [Documentation Comments](#documentation-comments) + - [Author Comments](#author-comments) +- [Naming](#naming) + - [Package Naming](#package-naming) + - [Symbol Naming](#symbol-naming) + - [Function Naming](#function-naming) + - [Constructor Naming](#constructor-naming) + - [Getter Naming](#getter-naming) + - [Setter Naming](#setter-naming) + - [Interface Naming](#interface-naming) + +## Formatting + +All go code should be formatted with the official formatting tool `gofmt`. This requirement is +verified by the repository workflows. + +## Commenting + +All exported symbols should be commented with documentation, so that their motivation and use is +clear. All documentation should record any nuances of the symbol so that users are well aware of +them. + +C++ style line comments should be preferred over C-style block comments. + + + + + +
BadGood
+ +```go +/* + Unmarshal converts a JSON string into a go interface + ... +*/ +``` + + + +```go +// Unmarshal converts a JSON string into a go interface +// ... +``` + +
+ +### Package Comments + +Package comments should start with the word "Package" followed by the package name. For packages +spanning multiple files or with a need for a large documentation, use a separate `doc.go` file for package level documentation comment. + + + + + +
BadGood
+ +```go +// sort is a package which implements sorting functions. +``` + + + +```go +// Package sort implements sorting functions. +``` + +
+ +### Documentation Comments + +All doc comments for symbols should start with the symbol name. + + + + + +
BadGood
+ +```go +// Function Quick is an implementation +// of the Quicksort algorithm. +``` + + + +```go +// Quick is an implementation +// of the Quicksort algorithm. +``` + +
+ +### Author Comments + +A comment recording the author of a particular file may also be added. This comment should be +written at the top of the file and it should not be a part of the package documentation. + + + + + +
BadGood
+ +```go +// author: Rak Laptudirm (@raklaptudirm) +package sort +``` +Comment is a part of the package documentation. + + + +```go +// author: Rak Laptudirm (@raklaptudirm) + +package sort +``` +Comment is not a part of the package documentation. + +
+ +## Naming + +### Package Naming + +Package names should be short and to the point. Keep in mind that this identifier will be used to +refer to your package, so make it easy to remember. It should be only composed of lower case +letters. Prefer `json` to `JSON` or `Json`. If your package name has two words, merge them +together. Prefer `jsonencoding` to `jsonEncoding` or `json_encoding`. Although, there is almost always a word to succinctly describe the package with an appropriate name. So if you have a name that describes the package nicely, please use that. + +Add the `_test` suffix to your package name to implement black-box testing for your package in the test files. + +### Symbol Naming + +Go symbols should be named in the `camelCase` or `PascalCase`, depending of whether the symbol +is exported or not. The case when using acronymns in names should be consistent. Use `json` or +`JSON` instead of `Json`. + +For exported symbols, use the package name to your advantage to write concise symbol names. For +example, if you have a package `png`, instead of defining a `png.PNGFile`, define a `png.File`. +It is much clearer and avoids repetition. + +### Function Naming + +#### Constructor Naming + +Constructors should use the naming format `New()` for constructors which return pointers and +`Make()` for constructors which return values in accordance with the Go Programming Language's +`new` and `make` functions. If the package only exports a single constructor, use the name `New()`. +Some valid names are `reader.New()`, `metainfo.NewFile()`. + +#### Getter Naming + +Usage of Getters and Setters are discouraged. Use exported variables instead. + +Getters should use the name of the field that is being fetched. For example, prefer a getter +name like `user.Name()` to `user.GetName()`. + +#### Setter Naming + +Setters should use names in the format `Set`. For example, `user.SetName()`. + +### Interface Naming + +Interfaces should use names in the format of `er` or ``. For example, some +valid interface names are: + +```go +type Node interface { + Node() +} + +type Writer interface { + Write() +} +``` From 0bf1025ea7d7f080dc7df0082c18a6705f3d6254 Mon Sep 17 00:00:00 2001 From: Pedro Rocha Date: Thu, 23 Mar 2023 03:36:20 +0000 Subject: [PATCH 406/488] feat: adds Huffman coding algorithm (#625) * feat: add Huffman coding algorithm * add struct SymbolFreq to explicitly represent a pair of a symbol and its frequency * adds panic call to BuildTree method * docs: add documentation * test: add basic test for huffman coding algorithm * makes list of symbol-frequency pairs explicitly ordered by frequency * test: Make test cases dependent only on input string by computing sorted symbol-frequency list * doc: add dome doc comments and remove logs * fix some typos * add minor refactoring of if-else statement Co-authored-by: Taj * add minor refactoring of if-else statement Co-authored-by: Taj * add minor refactoring of if-else statement * replace panic call by returning an error * add minor refactoring of if-else statement Co-authored-by: Taj * replace BuildDict by GetEncoding * replace 'dict' with 'codes' * move sort interface instantation to test * move huffman coding to compression folder * rename package 'huffmancodin' to 'compression' * Update compression/huffmancoding_test.go Co-authored-by: Taj * rename functions from huffmancoding * use sort.Slice instead of sort.Sort in SymbolCountOrd --------- Co-authored-by: Taj --- compression/huffmancoding.go | 116 ++++++++++++++++++++++++++++++ compression/huffmancoding_test.go | 55 ++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 compression/huffmancoding.go create mode 100644 compression/huffmancoding_test.go diff --git a/compression/huffmancoding.go b/compression/huffmancoding.go new file mode 100644 index 000000000..f6515872e --- /dev/null +++ b/compression/huffmancoding.go @@ -0,0 +1,116 @@ +// huffman.go +// description: Implements Huffman compression, encoding and decoding +// details: +// We implement the linear-time 2-queue method described here https://en.wikipedia.org/wiki/Huffman_coding. +// It assumes that the list of symbol-frequencies is sorted. +// author(s) [pedromsrocha](https://github.com/pedromsrocha) +// see also huffmancoding_test.go + +package compression + +import "fmt" + +// A Node of an Huffman tree, which can either be a leaf or an internal node. +// Each node has a weight. +// A leaf node has an associated symbol, but no children (i.e., left == right == nil). +// A parent node has a left and right child and no symbol (i.e., symbol == -1). +type Node struct { + left *Node + right *Node + symbol rune + weight int +} + +// A SymbolFreq is a pair of a symbol and its associated frequency. +type SymbolFreq struct { + Symbol rune + Freq int +} + +// HuffTree returns the root Node of the Huffman tree by compressing listfreq. +// The compression produces the most optimal code lengths, provided listfreq is ordered, +// i.e.: listfreq[i] <= listfreq[j], whenever i < j. +func HuffTree(listfreq []SymbolFreq) (*Node, error) { + if len(listfreq) < 1 { + return nil, fmt.Errorf("huffman coding: HuffTree : calling method with empty list of symbol-frequency pairs") + } + q1 := make([]Node, len(listfreq)) + q2 := make([]Node, 0, len(listfreq)) + for i, x := range listfreq { // after the loop, q1 is a slice of leaf nodes representing listfreq + q1[i] = Node{left: nil, right: nil, symbol: x.Symbol, weight: x.Freq} + } + //loop invariant: q1, q2 are ordered by increasing weights + for len(q1)+len(q2) > 1 { + var node1, node2 Node + node1, q1, q2 = least(q1, q2) + node2, q1, q2 = least(q1, q2) + node := Node{left: &node1, right: &node2, + symbol: -1, weight: node1.weight + node2.weight} + q2 = append(q2, node) + } + if len(q1) == 1 { // returns the remaining node in q1, q2 + return &q1[0], nil + } + return &q2[0], nil +} + +// least removes the node with lowest weight from q1, q2. +// It returns the node with lowest weight and the slices q1, q2 after the update. +func least(q1 []Node, q2 []Node) (Node, []Node, []Node) { + if len(q1) == 0 { + return q2[0], q1, q2[1:] + } + if len(q2) == 0 { + return q1[0], q1[1:], q2 + } + if q1[0].weight <= q2[0].weight { + return q1[0], q1[1:], q2 + } + return q2[0], q1, q2[1:] +} + +// HuffEncoding recursively traverses the Huffman tree pointed by node to obtain +// the map codes, that associates a rune with a slice of booleans. +// Each code is prefixed by prefix and left and right children are labelled with +// the booleans false and true, respectively. +func HuffEncoding(node *Node, prefix []bool, codes map[rune][]bool) { + if node.symbol != -1 { //base case + codes[node.symbol] = prefix + return + } + // inductive step + prefixLeft := make([]bool, len(prefix)) + copy(prefixLeft, prefix) + prefixLeft = append(prefixLeft, false) + HuffEncoding(node.left, prefixLeft, codes) + prefixRight := make([]bool, len(prefix)) + copy(prefixRight, prefix) + prefixRight = append(prefixRight, true) + HuffEncoding(node.right, prefixRight, codes) +} + +// HuffEncode encodes the string in by applying the mapping defined by codes. +func HuffEncode(codes map[rune][]bool, in string) []bool { + out := make([]bool, 0) + for _, s := range in { + out = append(out, codes[s]...) + } + return out +} + +// HuffDecode recursively decodes the binary code in, by traversing the Huffman compression tree pointed by root. +// current stores the current node of the traversing algorithm. +// out stores the current decoded string. +func HuffDecode(root, current *Node, in []bool, out string) string { + if current.symbol != -1 { + out += string(current.symbol) + return HuffDecode(root, root, in, out) + } + if len(in) == 0 { + return out + } + if in[0] { + return HuffDecode(root, current.right, in[1:], out) + } + return HuffDecode(root, current.left, in[1:], out) +} diff --git a/compression/huffmancoding_test.go b/compression/huffmancoding_test.go new file mode 100644 index 000000000..8c0434d85 --- /dev/null +++ b/compression/huffmancoding_test.go @@ -0,0 +1,55 @@ +// huffmancoding_test.go +// description: Tests the compression, encoding and decoding algorithms of huffmancoding.go. +// author(s) [pedromsrocha](https://github.com/pedromsrocha) +// see huffmancoding.go + +package compression_test + +import ( + "sort" + "testing" + + "github.com/TheAlgorithms/Go/compression" +) + +// SymbolCountOrd computes sorted symbol-frequency list of input message +func SymbolCountOrd(message string) []compression.SymbolFreq { + runeCount := make(map[rune]int) + for _, s := range message { + runeCount[s]++ + } + listfreq := make([]compression.SymbolFreq, len(runeCount)) + i := 0 + for s, n := range runeCount { + listfreq[i] = compression.SymbolFreq{Symbol: s, Freq: n} + i++ + } + sort.Slice(listfreq, func(i, j int) bool { return listfreq[i].Freq < listfreq[j].Freq }) + return listfreq +} + +func TestHuffman(t *testing.T) { + messages := []string{ + "hello world \U0001F600", + "colorless green ideas sleep furiously", + "the quick brown fox jumps over the lazy dog", + `Lorem ipsum dolor sit amet, consectetur adipiscing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut + aliquip ex ea commodo consequat.`, + } + + for _, message := range messages { + t.Run("huffman: "+message, func(t *testing.T) { + tree, _ := compression.HuffTree(SymbolCountOrd(message)) + codes := make(map[rune][]bool) + compression.HuffEncoding(tree, nil, codes) + messageCoded := compression.HuffEncode(codes, message) + messageHuffDecoded := compression.HuffDecode(tree, tree, messageCoded, "") + if messageHuffDecoded != message { + t.Errorf("got: %q\nbut expected: %q", messageHuffDecoded, message) + + } + }) + } +} From 51028c442fce0c208469fe594d807384266926ad Mon Sep 17 00:00:00 2001 From: Jahnab Dutta <76475829+JahnabDutta@users.noreply.github.com> Date: Mon, 27 Mar 2023 02:25:30 +0530 Subject: [PATCH 407/488] Fix typo in CONTRIBUTING.md (#630) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0eb6982c1..bc45ed171 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,7 +38,7 @@ Being a contributor at The Algorithms, we request you to follow the points menti - Please use the directory structure of the repository. - Make sure the file extensions should be `*.go`. -- Use meaning variable names. +- Use meaningful variable names. - Use standard library inside your code and avoid to import packages from other repositories - If an implementation of the algorithm already exists, please refer to the [filename section below](#new-file-name-guidelines). - You can suggest reasonable changes to existing algorithms. From 434ab6f90b6061ee544e555c3f33e20e80b84db0 Mon Sep 17 00:00:00 2001 From: yan-aint-nickname <50468068+yan-aint-nickname@users.noreply.github.com> Date: Wed, 12 Apr 2023 18:08:58 +0300 Subject: [PATCH 408/488] Fix typos in function and variable names (#632) --- README.md | 2 +- STYLE.md | 2 +- dynamic/longestincreasingsubsequencegreedy.go | 14 +++++++------- math/modular/exponentiation_test.go | 2 +- search/binary_test.go | 2 +- search/testcases.go | 2 +- strings/genetic/genetic.go | 2 +- structure/trie/trie_bench_test.go | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index f672ba088..6d85ad640 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`GeneticString`](./strings/genetic/genetic.go#L71): GeneticString generates PopultaionItem based on the imputed target string, and a set of possible runes to build a string with. In order to optimise string generation additional configurations can be provided with Conf instance. Empty instance of Conf (&Conf{}) can be provided, then default values would be set. Link to the same algorithm implemented in python: https://github.com/TheAlgorithms/Python/blob/master/genetic_algorithm/basic_string.py +1. [`GeneticString`](./strings/genetic/genetic.go#L71): GeneticString generates PopulationItem based on the imputed target string, and a set of possible runes to build a string with. In order to optimise string generation additional configurations can be provided with Conf instance. Empty instance of Conf (&Conf{}) can be provided, then default values would be set. Link to the same algorithm implemented in python: https://github.com/TheAlgorithms/Python/blob/master/genetic_algorithm/basic_string.py --- ##### Types diff --git a/STYLE.md b/STYLE.md index 2027f05e9..e72214bc8 100644 --- a/STYLE.md +++ b/STYLE.md @@ -145,7 +145,7 @@ Add the `_test` suffix to your package name to implement black-box testing for y ### Symbol Naming Go symbols should be named in the `camelCase` or `PascalCase`, depending of whether the symbol -is exported or not. The case when using acronymns in names should be consistent. Use `json` or +is exported or not. The case when using acronyms in names should be consistent. Use `json` or `JSON` instead of `Json`. For exported symbols, use the package name to your advantage to write concise symbol names. For diff --git a/dynamic/longestincreasingsubsequencegreedy.go b/dynamic/longestincreasingsubsequencegreedy.go index 438836527..bb039468a 100644 --- a/dynamic/longestincreasingsubsequencegreedy.go +++ b/dynamic/longestincreasingsubsequencegreedy.go @@ -7,20 +7,20 @@ package dynamic // Auxiliary Space: O(n), where n is the length of the array(slice). // Reference: https://www.geeksforgeeks.org/construction-of-longest-monotonically-increasing-subsequence-n-log-n/ func LongestIncreasingSubsequenceGreedy(nums []int) int { - longestIncreasingSubsequnce := make([]int, 0) + longestIncreasingSubsequence := make([]int, 0) for _, num := range nums { - // find the leftmost index in longestIncreasingSubsequnce with value >= num - leftmostIndex := lowerBound(longestIncreasingSubsequnce, num) + // find the leftmost index in longestIncreasingSubsequence with value >= num + leftmostIndex := lowerBound(longestIncreasingSubsequence, num) - if leftmostIndex == len(longestIncreasingSubsequnce) { - longestIncreasingSubsequnce = append(longestIncreasingSubsequnce, num) + if leftmostIndex == len(longestIncreasingSubsequence) { + longestIncreasingSubsequence = append(longestIncreasingSubsequence, num) } else { - longestIncreasingSubsequnce[leftmostIndex] = num + longestIncreasingSubsequence[leftmostIndex] = num } } - return len(longestIncreasingSubsequnce) + return len(longestIncreasingSubsequence) } // Function to find the leftmost index in arr with value >= val, mimicking the inbuild lower_bound function in C++ diff --git a/math/modular/exponentiation_test.go b/math/modular/exponentiation_test.go index b5c8d4eb9..2c25ac22b 100644 --- a/math/modular/exponentiation_test.go +++ b/math/modular/exponentiation_test.go @@ -1,5 +1,5 @@ // exponentiation_test.go -// description: Test for ModularExponentation +// description: Test for ModularExponentiation // author(s) [Taj](https://github.com/tjgurwara99) // see exponentiation.go diff --git a/search/binary_test.go b/search/binary_test.go index ea77bf817..24e2a0c41 100644 --- a/search/binary_test.go +++ b/search/binary_test.go @@ -39,7 +39,7 @@ func TestLowerBound(t *testing.T) { } func TestUpperBound(t *testing.T) { - for _, test := range uppperBoundTests { + for _, test := range upperBoundTests { actualValue, actualError := UpperBound(test.data, test.key) if actualValue != test.expected { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) diff --git a/search/testcases.go b/search/testcases.go index 7e02bc5c8..0ef2f5cb3 100644 --- a/search/testcases.go +++ b/search/testcases.go @@ -43,7 +43,7 @@ var lowerBoundTests = []searchTest{ {[]int{}, 2, -1, ErrNotFound, "Empty"}, } -var uppperBoundTests = []searchTest{ +var upperBoundTests = []searchTest{ //Sanity {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, -25, 0, nil, "Sanity"}, {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 1, nil, "Sanity"}, diff --git a/strings/genetic/genetic.go b/strings/genetic/genetic.go index 384ecf940..b385ad867 100644 --- a/strings/genetic/genetic.go +++ b/strings/genetic/genetic.go @@ -60,7 +60,7 @@ type Result struct { Best PopulationItem } -// GeneticString generates PopultaionItem based on the imputed target +// GeneticString generates PopulationItem based on the imputed target // string, and a set of possible runes to build a string with. In order // to optimise string generation additional configurations can be provided // with Conf instance. Empty instance of Conf (&Conf{}) can be provided, diff --git a/structure/trie/trie_bench_test.go b/structure/trie/trie_bench_test.go index be59496ee..7243a1bd9 100644 --- a/structure/trie/trie_bench_test.go +++ b/structure/trie/trie_bench_test.go @@ -22,7 +22,7 @@ func BenchmarkTrie_Insert(b *testing.B) { } } -func BenchmarkTrie_Find_non_existant(b *testing.B) { +func BenchmarkTrie_Find_non_existent(b *testing.B) { insert := make([]string, 3000) for i := 0; i < len(insert); i++ { @@ -37,7 +37,7 @@ func BenchmarkTrie_Find_non_existant(b *testing.B) { } } -func BenchmarkTrie_Find_existant(b *testing.B) { +func BenchmarkTrie_Find_existent(b *testing.B) { insert := make([]string, 3000) for i := 0; i < len(insert); i++ { insert[i] = fmt.Sprintf("%f", rand.Float64()) From a0bc6d60cedef86ca34e319a592ed208b38a139d Mon Sep 17 00:00:00 2001 From: David Leal Date: Sun, 23 Apr 2023 05:32:49 -0600 Subject: [PATCH 409/488] chore: fix CI badge (#633) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d85ad640..5fd73e573 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # The Algorithms - Go [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/TheAlgorithms/Go)  -![golangci-lint](https://github.com/TheAlgorithms/Go/workflows/golangci-lint/badge.svg) +[![Continuous Integration](https://github.com/TheAlgorithms/Go/actions/workflows/ci.yml/badge.svg)](https://github.com/TheAlgorithms/Go/actions/workflows/ci.yml) ![godocmd](https://github.com/tjgurwara99/Go/workflows/godocmd/badge.svg) ![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  ![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) From 0de898fed2f753dc6b13614733b84731f6961139 Mon Sep 17 00:00:00 2001 From: Aditya Pal Date: Mon, 1 May 2023 12:05:55 +0530 Subject: [PATCH 410/488] feat: add cycle sort algorithm (#634) * feat: add cycle sort algorithm * feat: add cycle sort algorithm * feat: address code review comments * feat: address code review comments * Remove unnecessary newline --------- Co-authored-by: Taj --- sort/cyclesort.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 8 +++++++ 2 files changed, 66 insertions(+) create mode 100644 sort/cyclesort.go diff --git a/sort/cyclesort.go b/sort/cyclesort.go new file mode 100644 index 000000000..611fe27c2 --- /dev/null +++ b/sort/cyclesort.go @@ -0,0 +1,58 @@ +package sort + +import ( + "github.com/TheAlgorithms/Go/constraints" +) + +// Cycle sort is an in-place, unstable sorting algorithm that is particularly useful +// when sorting arrays containing elements with a small range of values. It is theoretically +// optimal in terms of the total number of writes to the original array. +func Cycle[T constraints.Number](arr []T) []T { + counter, cycle, len := 0, 0, len(arr) + // Early return if the array too small + if len <= 1 { + return arr + } + + for cycle = 0; cycle < len-1; cycle++ { + elem := arr[cycle] + // Find total smaller elements to right + pos := cycle + for counter = cycle + 1; counter < len; counter++ { + if arr[counter] < elem { + pos++ + } + } + // In case this element is already in correct position, let's skip processing + if pos == cycle { + continue + } + // In case we have same elements, we want to skip to the end of that list as well, ignoring order + // This makes the algorithm unstable for composite elements + for elem == arr[pos] { + pos++ + } + // Now let us put the item to it's right position + arr[pos], elem = elem, arr[pos] + + //We need to rotate the array till we have reached the start of the cycle again + for pos != cycle { + pos = cycle + // Find smaller elements to right again + for counter = cycle + 1; counter < len; counter++ { + if arr[counter] < elem { + pos++ + } + } + for elem == arr[pos] { + pos++ + } + //We can do this unconditionally, but the check helps prevent redundant writes to the array + if elem != arr[pos] { + arr[pos], elem = elem, arr[pos] + } + } + } + + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 7ff8b4363..aeb90c04e 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -169,6 +169,10 @@ func TestPatience(t *testing.T) { testFramework(t, sort.Patience[int]) } +func TestCycle(t *testing.T) { + testFramework(t, sort.Cycle[int]) +} + //END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { @@ -286,3 +290,7 @@ func BenchmarkPigeonhole(b *testing.B) { func BenchmarkPatience(b *testing.B) { benchmarkFramework(b, sort.Patience[int]) } + +func BenchmarkCycle(b *testing.B) { + benchmarkFramework(b, sort.Cycle[int]) +} From b8648fb231848af1a418cda6d8fa8b7b85e09694 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 24 May 2023 12:11:10 +0200 Subject: [PATCH 411/488] refactor: simplify logic in `AliquotSum` (#636) * test: add missing test case * refactor: simplify logic by removing one branch --- math/aliquot_test.go | 1 + math/aliquotsum.go | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/math/aliquot_test.go b/math/aliquot_test.go index 0c6abd956..efeda425c 100644 --- a/math/aliquot_test.go +++ b/math/aliquot_test.go @@ -20,6 +20,7 @@ func TestAliquotSum(t *testing.T) { }{ {"n = 10", 10, 8, nil}, {"n = 11", 11, 1, nil}, + {"n = 1", 1, 0, nil}, {"n = -1", -1, 0, math.ErrPosArgsOnly}, {"n = 0", 0, 0, math.ErrNonZeroArgsOnly}, } diff --git a/math/aliquotsum.go b/math/aliquotsum.go index 707b818a2..6e3af6cc0 100644 --- a/math/aliquotsum.go +++ b/math/aliquotsum.go @@ -17,8 +17,6 @@ func AliquotSum(n int) (int, error) { return 0, ErrPosArgsOnly case n == 0: return 0, ErrNonZeroArgsOnly - case n == 1: - return 0, nil default: var sum int for i := 1; i <= n/2; i++ { From 4b49179e8ace094c03fde0b652c5fc7eb1d79e4f Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sun, 28 May 2023 19:43:08 +0200 Subject: [PATCH 412/488] style: use consistent naming (#637) * style: use consistent naming * style: use Int instead of Integer --- .../{integertoroman.go => inttoroman.go} | 0 ...egertoroman_test.go => inttoroman_test.go} | 0 .../{romantointeger.go => romantoint.go} | 4 ++-- ...antointeger_test.go => romantoint_test.go} | 22 +++++++++---------- 4 files changed, 13 insertions(+), 13 deletions(-) rename conversion/{integertoroman.go => inttoroman.go} (100%) rename conversion/{integertoroman_test.go => inttoroman_test.go} (100%) rename conversion/{romantointeger.go => romantoint.go} (89%) rename conversion/{romantointeger_test.go => romantoint_test.go} (70%) diff --git a/conversion/integertoroman.go b/conversion/inttoroman.go similarity index 100% rename from conversion/integertoroman.go rename to conversion/inttoroman.go diff --git a/conversion/integertoroman_test.go b/conversion/inttoroman_test.go similarity index 100% rename from conversion/integertoroman_test.go rename to conversion/inttoroman_test.go diff --git a/conversion/romantointeger.go b/conversion/romantoint.go similarity index 89% rename from conversion/romantointeger.go rename to conversion/romantoint.go index e7a8eb594..dda0000f3 100644 --- a/conversion/romantointeger.go +++ b/conversion/romantoint.go @@ -34,10 +34,10 @@ var nums = []numeral{ {1, "I"}, } -// RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers +// RomanToInt converts a roman numeral string to an integer. Roman numerals for numbers // outside the range 1 to 3,999 will return an error. Nil or empty string return 0 // with no error thrown. -func RomanToInteger(input string) (int, error) { +func RomanToInt(input string) (int, error) { if input == "" { return 0, nil } diff --git a/conversion/romantointeger_test.go b/conversion/romantoint_test.go similarity index 70% rename from conversion/romantointeger_test.go rename to conversion/romantoint_test.go index 2916c1981..0fd34b2c3 100644 --- a/conversion/romantointeger_test.go +++ b/conversion/romantoint_test.go @@ -21,33 +21,33 @@ var romanTestCases = map[string]int{ "MMCMXCIX": 2999, "MMM": 3000, "MMMCMLXXIX": 3979, "MMMCMXCIX": 3999, } -func TestRomanToInteger(t *testing.T) { +func TestRomanToInt(t *testing.T) { for input, expected := range romanTestCases { - out, err := RomanToInteger(input) + out, err := RomanToInt(input) if err != nil { - t.Errorf("RomanToInteger(%s) returned an error %s", input, err.Error()) + t.Errorf("RomanToInt(%s) returned an error %s", input, err.Error()) } if out != expected { - t.Errorf("RomanToInteger(%s) = %d; want %d", input, out, expected) + t.Errorf("RomanToInt(%s) = %d; want %d", input, out, expected) } } - _, err := RomanToInteger("IVCMXCIX") + _, err := RomanToInt("IVCMXCIX") if err == nil { - t.Error("RomanToInteger(IVCMXCIX) expected an error") + t.Error("RomanToInt(IVCMXCIX) expected an error") } - val, err := RomanToInteger("") + val, err := RomanToInt("") if val != 0 { - t.Errorf("RomanToInteger(\"\") = %d; want 0", val) + t.Errorf("RomanToInt(\"\") = %d; want 0", val) } if err != nil { - t.Errorf("RomanToInteger(\"\") returned an error %s", err.Error()) + t.Errorf("RomanToInt(\"\") returned an error %s", err.Error()) } } -func BenchmarkRomanToInteger(b *testing.B) { +func BenchmarkRomanToInt(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - _, _ = RomanToInteger("MMMCMXCIX") + _, _ = RomanToInt("MMMCMXCIX") } } From c57461a314476a97474517d989dc70c3a145ceee Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Mon, 29 May 2023 22:51:00 +0300 Subject: [PATCH 413/488] Check if godocmd runs (#638) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5fd73e573..8c7814432 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ The repository is a collection of open-source implementation of a variety of alg Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ## List of Algorithms + # Packages: From a3beedefdfff450ff1461a19c4ee8855de040780 Mon Sep 17 00:00:00 2001 From: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 29 May 2023 19:51:21 +0000 Subject: [PATCH 414/488] Updated Documentation in README.md --- README.md | 229 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 155 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 8c7814432..776a50f4b 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,37 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Combinations`](./strings/combination/combination.go#L7): No description provided. +--- +
+ compression + +--- + +##### Functions: + +1. [`HuffDecode`](./compression/huffmancoding.go#L104): HuffDecode recursively decodes the binary code in, by traversing the Huffman compression tree pointed by root. current stores the current node of the traversing algorithm. out stores the current decoded string. +2. [`HuffEncode`](./compression/huffmancoding.go#L93): HuffEncode encodes the string in by applying the mapping defined by codes. +3. [`HuffEncoding`](./compression/huffmancoding.go#L76): HuffEncoding recursively traverses the Huffman tree pointed by node to obtain the map codes, that associates a rune with a slice of booleans. Each code is prefixed by prefix and left and right children are labelled with the booleans false and true, respectively. +4. [`HuffTree`](./compression/huffmancoding.go#L33): HuffTree returns the root Node of the Huffman tree by compressing listfreq. The compression produces the most optimal code lengths, provided listfreq is ordered, i.e.: listfreq[i] <= listfreq[j], whenever i < j. + +--- +##### Types + +1. [`Node`](./compression/huffmancoding.go#L17): No description provided. + +2. [`SymbolFreq`](./compression/huffmancoding.go#L25): No description provided. + + +--- +
+ compression_test + +--- + +##### Functions: + +1. [`SymbolCountOrd`](./compression/huffmancoding_test.go#L16): SymbolCountOrd computes sorted symbol-frequency list of input message + ---
conversion @@ -196,10 +227,10 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 4. [`DecimalToBinary`](./conversion/decimaltobinary.go#L32): DecimalToBinary() function that will take Decimal number as int, and return it's Binary equivalent as string. 5. [`FuzzBase64Encode`](./conversion/base64_test.go#L113): No description provided. 6. [`HEXToRGB`](./conversion/rgbhex.go#L10): HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) into the individual components: red, green and blue -7. [`IntToRoman`](./conversion/integertoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. +7. [`IntToRoman`](./conversion/inttoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. 8. [`RGBToHEX`](./conversion/rgbhex.go#L41): RGBToHEX does exactly the opposite of HEXToRGB: it combines the three components red, green and blue to an RGB value, which can be converted to e.g. Hex 9. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. -10. [`RomanToInteger`](./conversion/romantointeger.go#L40): RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. +10. [`RomanToInt`](./conversion/romantoint.go#L40): RomanToInt converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. ---
@@ -343,25 +374,28 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### Package geometry contains geometric algorithms +##### Package geometry contains geometric algorithms Package geometry contains geometric algorithms --- ##### Functions: 1. [`Distance`](./math/geometry/straightlines.go#L18): Distance calculates the shortest distance between two points. -2. [`IsParallel`](./math/geometry/straightlines.go#L42): IsParallel checks if two lines are parallel or not. -3. [`IsPerpendicular`](./math/geometry/straightlines.go#L47): IsPerpendicular checks if two lines are perpendicular or not. -4. [`PointDistance`](./math/geometry/straightlines.go#L53): PointDistance calculates the distance of a given Point from a given line. The slice should contain the coefficiet of x, the coefficient of y and the constant in the respective order. -5. [`Section`](./math/geometry/straightlines.go#L24): Section calculates the Point that divides a line in specific ratio. DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. -6. [`Slope`](./math/geometry/straightlines.go#L32): Slope calculates the slope (gradient) of a line. -7. [`YIntercept`](./math/geometry/straightlines.go#L37): YIntercept calculates the Y-Intercept of a line from a specific Point. +2. [`EuclideanDistance`](./math/geometry/distance.go#L20): EuclideanDistance returns the Euclidean distance between points in any `n` dimensional Euclidean space. +3. [`IsParallel`](./math/geometry/straightlines.go#L42): IsParallel checks if two lines are parallel or not. +4. [`IsPerpendicular`](./math/geometry/straightlines.go#L47): IsPerpendicular checks if two lines are perpendicular or not. +5. [`PointDistance`](./math/geometry/straightlines.go#L53): PointDistance calculates the distance of a given Point from a given line. The slice should contain the coefficiet of x, the coefficient of y and the constant in the respective order. +6. [`Section`](./math/geometry/straightlines.go#L24): Section calculates the Point that divides a line in specific ratio. DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. +7. [`Slope`](./math/geometry/straightlines.go#L32): Slope calculates the slope (gradient) of a line. +8. [`YIntercept`](./math/geometry/straightlines.go#L37): YIntercept calculates the Y-Intercept of a line from a specific Point. --- ##### Types -1. [`Line`](./math/geometry/straightlines.go#L13): No description provided. +1. [`EuclideanPoint`](./math/geometry/distance.go#L14): No description provided. -2. [`Point`](./math/geometry/straightlines.go#L9): No description provided. +2. [`Line`](./math/geometry/straightlines.go#L13): No description provided. + +3. [`Point`](./math/geometry/straightlines.go#L9): No description provided. --- @@ -411,6 +445,19 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 9. [`WeightedGraph`](./graph/floydwarshall.go#L9): No description provided. +--- +
+ guid + +--- + +##### Package guid provides facilities for generating random globally unique identifiers. + +--- +##### Functions: + +1. [`New`](./strings/guid/guid.go#L28): New returns a randomly generated global unique identifier. + ---
hashmap @@ -428,6 +475,40 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`HashMap`](./structure/hashmap/hashmap.go#L17): No description provided. +--- +
+ heap + +--- + +##### Functions: + +1. [`New`](./structure/heap/heap.go#L15): New gives a new heap object. +2. [`NewAny`](./structure/heap/heap.go#L24): NewAny gives a new heap object. element can be anything, but must provide less function. + +--- +##### Types + +1. [`Heap`](./structure/heap/heap.go#L9): No description provided. + + +--- +
+ heap_test + +--- + +##### Types + +1. [`testInt`](#L0): + + Methods: + 1. [`Less`](./structure/heap/heap_test.go#L11): No description provided. +2. [`testStudent`](#L0): + + Methods: + 1. [`Less`](./structure/heap/heap_test.go#L20): No description provided. + ---
kmp @@ -436,7 +517,13 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`Kmp`](./strings/kmp/kmp.go#L4): Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. +1. [`Kmp`](./strings/kmp/kmp.go#L4): Kmp Function kmp performing the Knuth-Morris-Pratt algorithm. + +--- +##### Types + +1. [`args`](./strings/kmp/kmp_test.go#L39): No description provided. + ---
@@ -505,29 +592,32 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### Package math is a package that contains mathematical algorithms and its different implementations. +##### filename : krishnamurthy.go description: A program which contains the function that returns true if a given number is Krishnamurthy number or not. details: A number is a Krishnamurthy number if the sum of all the factorials of the digits is equal to the number. Ex: 1! = 1, 145 = 1! + 4! + 5! author(s): [GooMonk](https://github.com/GooMonk) see krishnamurthy_test.go Package math is a package that contains mathematical algorithms and its different implementations. --- ##### Functions: 1. [`Abs`](./math/abs.go#L11): Abs returns absolute value -2. [`Combinations`](./math/binomialcoefficient.go#L20): C is Binomial Coefficient function This function returns C(n, k) for given n and k -3. [`Cos`](./math/cos.go#L10): Cos returns the cosine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) [Based on the idea of Bhaskara approximation of cos(x)](https://math.stackexchange.com/questions/3886552/bhaskara-approximation-of-cosx) -4. [`DefaultPolynomial`](./math/pollard.go#L16): DefaultPolynomial is the commonly used polynomial g(x) = (x^2 + 1) mod n -5. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -6. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -7. [`IsPerfectNumber`](./math/perfectnumber.go#L34): Checks if inNumber is a perfect number -8. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -9. [`Lerp`](./math/lerp.go#L5): Lerp or Linear interpolation This function will return new value in 't' percentage between 'v0' and 'v1' -10. [`LiouvilleLambda`](./math/liouville.go#L24): Lambda is the liouville function This function returns λ(n) for given number -11. [`Mean`](./math/mean.go#L7): No description provided. -12. [`Median`](./math/median.go#L12): No description provided. -13. [`Mode`](./math/mode.go#L19): No description provided. -14. [`Mu`](./math/mobius.go#L21): Mu is the Mobius function This function returns μ(n) for given number -15. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. -16. [`PollardsRhoFactorization`](./math/pollard.go#L29): PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm using the default parameters x = y = 2 -17. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) -18. [`SumOfProperDivisors`](./math/perfectnumber.go#L17): Returns the sum of proper divisors of inNumber. +2. [`AliquotSum`](./math/aliquotsum.go#L14): This function returns s(n) for given number +3. [`Combinations`](./math/binomialcoefficient.go#L20): C is Binomial Coefficient function This function returns C(n, k) for given n and k +4. [`Cos`](./math/cos.go#L10): Cos returns the cosine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) [Based on the idea of Bhaskara approximation of cos(x)](https://math.stackexchange.com/questions/3886552/bhaskara-approximation-of-cosx) +5. [`DefaultPolynomial`](./math/pollard.go#L16): DefaultPolynomial is the commonly used polynomial g(x) = (x^2 + 1) mod n +6. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +7. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. +8. [`IsKrishnamurthyNumber`](./math/krishnamurthy.go#L12): IsKrishnamurthyNumber returns if the provided number n is a Krishnamurthy number or not. +9. [`IsPerfectNumber`](./math/perfectnumber.go#L34): Checks if inNumber is a perfect number +10. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +11. [`Lerp`](./math/lerp.go#L5): Lerp or Linear interpolation This function will return new value in 't' percentage between 'v0' and 'v1' +12. [`LiouvilleLambda`](./math/liouville.go#L24): Lambda is the liouville function This function returns λ(n) for given number +13. [`Mean`](./math/mean.go#L7): No description provided. +14. [`Median`](./math/median.go#L12): No description provided. +15. [`Mode`](./math/mode.go#L19): No description provided. +16. [`Mu`](./math/mobius.go#L21): Mu is the Mobius function This function returns μ(n) for given number +17. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +18. [`PollardsRhoFactorization`](./math/pollard.go#L29): PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm using the default parameters x = y = 2 +19. [`PronicNumber`](./math/pronicnumber.go#L15): PronicNumber returns true if argument passed to the function is pronic and false otherwise. +20. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +21. [`SumOfProperDivisors`](./math/perfectnumber.go#L17): Returns the sum of proper divisors of inNumber. ---
@@ -690,7 +780,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`NewPolybius`](./cipher/polybius/polybius.go#L21): NewPolybius returns a pointer to object of Polybius. If the size of "chars" is longer than "size", "chars" are truncated to "size". +1. [`FuzzPolybius`](./cipher/polybius/polybius_test.go#L154): No description provided. +2. [`NewPolybius`](./cipher/polybius/polybius.go#L21): NewPolybius returns a pointer to object of Polybius. If the size of "chars" is longer than "size", "chars" are truncated to "size". --- ##### Types @@ -799,6 +890,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Decrypt`](./cipher/rsa/rsa.go#L43): Decrypt decrypts encrypted rune slice based on the RSA algorithm 2. [`Encrypt`](./cipher/rsa/rsa.go#L28): Encrypt encrypts based on the RSA algorithm - uses modular exponentitation in math directory +3. [`FuzzRsa`](./cipher/rsa/rsa_test.go#L79): No description provided. ---
@@ -862,26 +954,27 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Bubble`](./sort/bubblesort.go#L9): Bubble is a simple generic definition of Bubble sort algorithm. -2. [`Bucket Sort`](./sort/bucketsort.go#L5): Bucket Sort works with the idea of distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm, or by recursively applying the bucket sorting algorithm. +2. [`Bucket`](./sort/bucketsort.go#L7): Bucket sorts a slice. It is mainly useful when input is uniformly distributed over a range. 3. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. 4. [`Count`](./sort/countingsort.go#L11): No description provided. -5. [`Exchange`](./sort/exchangesort.go#L8): No description provided. -6. [`HeapSort`](./sort/heapsort.go#L116): No description provided. -7. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort -8. [`Insertion`](./sort/insertionsort.go#L5): No description provided. -9. [`Merge`](./sort/mergesort.go#L41): Merge Perform merge sort on a slice -10. [`MergeIter`](./sort/mergesort.go#L55): No description provided. -11. [`Pancake Sort`](./sort/pancakesort.go#L7): Pancake Sort is a sorting algorithm that is similar to selection sort that reverses elements of an array. The Pancake Sort uses the flip operation to sort the array. -12. [`ParallelMerge`](./sort/mergesort.go#L66): ParallelMerge Perform merge sort on a slice using goroutines -13. [`Partition`](./sort/quicksort.go#L12): No description provided. -14. [`Patience`](./sort/patiencesort.go#L13): No description provided. -15. [`Pigeonhole`](./sort/pigeonholesort.go#L15): Pigeonhole sorts a slice using pigeonhole sorting algorithm. NOTE: To maintain time complexity O(n + N), this is the reason for having only Integer constraint instead of Ordered. -16. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array -17. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array -18. [`RadixSort`](./sort/radixsort.go#L43): No description provided. -19. [`Selection`](./sort/selectionsort.go#L5): No description provided. -20. [`Shell`](./sort/shellsort.go#L5): No description provided. -21. [`Simple`](./sort/simplesort.go#L13): No description provided. +5. [`Cycle`](./sort/cyclesort.go#L10): Cycle sort is an in-place, unstable sorting algorithm that is particularly useful when sorting arrays containing elements with a small range of values. It is theoretically optimal in terms of the total number of writes to the original array. +6. [`Exchange`](./sort/exchangesort.go#L8): No description provided. +7. [`HeapSort`](./sort/heapsort.go#L116): No description provided. +8. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort +9. [`Insertion`](./sort/insertionsort.go#L5): No description provided. +10. [`Merge`](./sort/mergesort.go#L41): Merge Perform merge sort on a slice +11. [`MergeIter`](./sort/mergesort.go#L55): No description provided. +12. [`Pancake`](./sort/pancakesort.go#L8): Pancake sorts a slice using flip operations, where flip refers to the idea of reversing the slice from index `0` to `i`. +13. [`ParallelMerge`](./sort/mergesort.go#L66): ParallelMerge Perform merge sort on a slice using goroutines +14. [`Partition`](./sort/quicksort.go#L12): No description provided. +15. [`Patience`](./sort/patiencesort.go#L13): No description provided. +16. [`Pigeonhole`](./sort/pigeonholesort.go#L15): Pigeonhole sorts a slice using pigeonhole sorting algorithm. NOTE: To maintain time complexity O(n + N), this is the reason for having only Integer constraint instead of Ordered. +17. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array +18. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array +19. [`RadixSort`](./sort/radixsort.go#L43): No description provided. +20. [`Selection`](./sort/selectionsort.go#L5): No description provided. +21. [`Shell`](./sort/shellsort.go#L5): No description provided. +22. [`Simple`](./sort/simplesort.go#L13): No description provided. --- ##### Types @@ -916,6 +1009,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`CountChars`](./strings/charoccurrence.go#L12): CountChars counts the number of a times a character has occurred in the provided string argument and returns a map with `rune` as keys and the count as value. +2. [`IsIsogram`](./strings/isisogram.go#L34): No description provided. ---
@@ -925,16 +1019,9 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`Decrypt`](./cipher/transposition/transposition.go#L82): No description provided. -2. [`Encrypt`](./cipher/transposition/transposition.go#L54): No description provided. - ---- -##### Types - -1. [`KeyMissingError`](./cipher/transposition/transposition.go#L16): No description provided. - -2. [`NoTextToEncryptError`](./cipher/transposition/transposition.go#L15): No description provided. - +1. [`Decrypt`](./cipher/transposition/transposition.go#L81): No description provided. +2. [`Encrypt`](./cipher/transposition/transposition.go#L51): No description provided. +3. [`FuzzTransposition`](./cipher/transposition/transposition_test.go#L103): No description provided. ---
@@ -947,31 +1034,25 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`NewAVL`](./structure/tree/avl.go#L13): NewAVL create a novel AVL tree -2. [`NewBinarySearch`](./structure/tree/bstree.go#L18): NewBinarySearch create a novel Binary-Search tree -3. [`NewRB`](./structure/tree/rbtree.go#L23): Create a new Red-Black Tree +1. [`NewAVL`](./structure/tree/avl.go#L54): NewAVL creates a novel AVL tree +2. [`NewBinarySearch`](./structure/tree/bstree.go#L46): NewBinarySearch creates a novel Binary-Search tree +3. [`NewRB`](./structure/tree/rbtree.go#L57): NewRB creates a new Red-Black Tree --- ##### Types -1. [`AVL`](./structure/tree/avl.go#L8): No description provided. +1. [`AVL`](./structure/tree/avl.go#L48): No description provided. -2. [`BinarySearch`](./structure/tree/bstree.go#L13): No description provided. +2. [`AVLNode`](./structure/tree/avl.go#L18): No description provided. -3. [`Node`](./structure/tree/tree.go#L25): No description provided. +3. [`BSNode`](./structure/tree/bstree.go#L15): No description provided. -4. [`RB`](./structure/tree/rbtree.go#L18): No description provided. +4. [`BinarySearch`](./structure/tree/bstree.go#L40): No description provided. +5. [`RB`](./structure/tree/rbtree.go#L51): No description provided. ---- -
- tree_test - ---- - -##### Functions: +6. [`RBNode`](./structure/tree/rbtree.go#L25): No description provided. -1. [`FuzzRBTree`](./structure/tree/rbtree_test.go#L90): No description provided. ---
From 0b4b2de30187e0015395aca0bab25963d60c38ad Mon Sep 17 00:00:00 2001 From: Lorenzo Tinfena Date: Fri, 21 Jul 2023 06:09:17 +0000 Subject: [PATCH 415/488] Added sqrt decomposition (#613) * Create binary_heap.go * Update binary_heap.go * fix * Update binary_heap.go * Create sqrt_decomposition_simple.go * move files * bono * bono * fix style * fix style * . * some changes * . * . --- sqrt/sqrtdecomposition.go | 102 +++++++++++++++++++++++++++++++++ sqrt/sqrtdecomposition_test.go | 80 ++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 sqrt/sqrtdecomposition.go create mode 100644 sqrt/sqrtdecomposition_test.go diff --git a/sqrt/sqrtdecomposition.go b/sqrt/sqrtdecomposition.go new file mode 100644 index 000000000..34e26fc4a --- /dev/null +++ b/sqrt/sqrtdecomposition.go @@ -0,0 +1,102 @@ +// Package sqrt contains algorithms and data structures that contains a √n in their complexity +package sqrt + +import "math" + +// Sqrt (or Square Root) Decomposition is a technique used for query an array and perform updates +// Inside this package is described its most simple data structure, you can find more at: https://cp-algorithms.com/data_structures/sqrt_decomposition.html +// +// Formally, You can use SqrtDecomposition only if: +// +// Given a function $Query:E_1,...,E_n\rightarrow Q$ +// +// if $\exist unionQ:Q,Q\rightarrow Q$ +// +// s.t. +// +// - $\forall n\in \N > 1, 1\le i 0, E_1,..., E_n\in E \\ query(E_1,...,E_{new},..., E_n)=updateQ(query(E_1,...,E_{old},...,E_n), indexof(E_{old}), E_{new})$ +type SqrtDecomposition[E any, Q any] struct { + querySingleElement func(element E) Q + unionQ func(q1 Q, q2 Q) Q + updateQ func(oldQ Q, oldE E, newE E) (newQ Q) + + elements []E + blocks []Q + blockSize uint64 +} + +// Create a new SqrtDecomposition instance with the parameters as specified by SqrtDecomposition comment +// Assumptions: +// - len(elements) > 0 +func NewSqrtDecomposition[E any, Q any]( + elements []E, + querySingleElement func(element E) Q, + unionQ func(q1 Q, q2 Q) Q, + updateQ func(oldQ Q, oldE E, newE E) (newQ Q), +) *SqrtDecomposition[E, Q] { + sqrtDec := &SqrtDecomposition[E, Q]{ + querySingleElement: querySingleElement, + unionQ: unionQ, + updateQ: updateQ, + elements: elements, + } + sqrt := math.Sqrt(float64(len(sqrtDec.elements))) + blockSize := uint64(sqrt) + numBlocks := uint64(math.Ceil(float64(len(elements)) / float64(blockSize))) + sqrtDec.blocks = make([]Q, numBlocks) + for i := uint64(0); i < uint64(len(elements)); i++ { + if i%blockSize == 0 { + sqrtDec.blocks[i/blockSize] = sqrtDec.querySingleElement(elements[i]) + } else { + sqrtDec.blocks[i/blockSize] = sqrtDec.unionQ(sqrtDec.blocks[i/blockSize], sqrtDec.querySingleElement(elements[i])) + } + } + sqrtDec.blockSize = blockSize + return sqrtDec +} + +// Performs a query from index start to index end (non included) +// Assumptions: +// - start < end +// - start and end are valid +func (s *SqrtDecomposition[E, Q]) Query(start uint64, end uint64) Q { + firstIndexNextBlock := ((start / s.blockSize) + 1) * s.blockSize + q := s.querySingleElement(s.elements[start]) + if firstIndexNextBlock > end { // if in same block + start++ + for start < end { + q = s.unionQ(q, s.querySingleElement(s.elements[start])) + start++ + } + } else { + // left side + start++ + for start < firstIndexNextBlock { + q = s.unionQ(q, s.querySingleElement(s.elements[start])) + start++ + } + + //middle part + endBlock := end / s.blockSize + for i := firstIndexNextBlock / s.blockSize; i < endBlock; i++ { + q = s.unionQ(q, s.blocks[i]) + } + + // right part + for i := endBlock * s.blockSize; i < end; i++ { + q = s.unionQ(q, s.querySingleElement(s.elements[i])) + } + } + return q +} + +// Assumptions: +// - index is valid +func (s *SqrtDecomposition[E, Q]) Update(index uint64, newElement E) { + i := index / s.blockSize + s.blocks[i] = s.updateQ(s.blocks[i], s.elements[index], newElement) + s.elements[index] = newElement +} diff --git a/sqrt/sqrtdecomposition_test.go b/sqrt/sqrtdecomposition_test.go new file mode 100644 index 000000000..7a293c802 --- /dev/null +++ b/sqrt/sqrtdecomposition_test.go @@ -0,0 +1,80 @@ +package sqrt_test + +import ( + "github.com/TheAlgorithms/Go/sqrt" + "testing" +) + +// Query interval +type query struct { + firstIndex uint64 + lastIndex uint64 +} + +type update struct { + index uint64 + value int +} + +func TestSqrtDecomposition(t *testing.T) { + var sqrtDecompositionTestData = []struct { + description string + array []int + updates []update + queries []query + expected []int + }{ + { + description: "test 1-sized array", + array: []int{1}, + queries: []query{{0, 1}}, + expected: []int{1}, + }, + { + description: "test array with size 5", + array: []int{1, 2, 3, 4, 5}, + queries: []query{{0, 5}, {0, 2}, {2, 4}}, + expected: []int{15, 3, 7}, + }, + { + description: "test array with size 5 and updates", + array: []int{1, 2, 3, 4, 5}, + updates: []update{{index: 1, value: 3}, + {index: 2, value: 4}}, + queries: []query{{0, 5}, {0, 2}, {2, 4}}, + expected: []int{17, 4, 8}, + }, + { + description: "test array with size 11 and updates", + array: []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + updates: []update{{index: 2, value: 2}, + {index: 3, value: 3}, + {index: 6, value: 6}}, + queries: []query{{3, 5}, {7, 8}, {3, 7}, {0, 10}}, + expected: []int{4, 1, 11, 18}, + }, + } + for _, test := range sqrtDecompositionTestData { + t.Run(test.description, func(t *testing.T) { + s := sqrt.NewSqrtDecomposition(test.array, + func(e int) int { return e }, + func(q1, q2 int) int { return q1 + q2 }, + func(q, a, b int) int { return q - a + b }, + ) + + for i := 0; i < len(test.updates); i++ { + s.Update(test.updates[i].index, test.updates[i].value) + } + + for i := 0; i < len(test.queries); i++ { + result := s.Query(test.queries[i].firstIndex, test.queries[i].lastIndex) + + if result != test.expected[i] { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expected result: %d\nFound: %d\n", test.expected[i], result) + } + } + + }) + } +} From 6429dfdb87ad0b2ae462f42f5307b6c0bcaca5c4 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Tue, 25 Jul 2023 18:06:51 +0200 Subject: [PATCH 416/488] chore: add basic gitpod configuration (#643) * chore: add basic gitpod configuration * Apply suggestions from code review Co-authored-by: Taj --------- Co-authored-by: Taj --- .gitpod.dockerfile | 1 + .gitpod.yml | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 .gitpod.dockerfile create mode 100644 .gitpod.yml diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile new file mode 100644 index 000000000..84fa1774b --- /dev/null +++ b/.gitpod.dockerfile @@ -0,0 +1 @@ +FROM gitpod/workspace-go diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 000000000..f9199716f --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,7 @@ +--- +image: + file: .gitpod.dockerfile + +tasks: + - init: | + echo "Welcome to TheAlgorithms/Go" From f7ca03bce44b23802e8ca5d7edfa3479ea491a5c Mon Sep 17 00:00:00 2001 From: yan-aint-nickname <50468068+yan-aint-nickname@users.noreply.github.com> Date: Fri, 1 Sep 2023 20:14:21 +0300 Subject: [PATCH 417/488] Add fast inverse square root algorithm (#647) * Add fast inverse square root algorithm * PR improvements see comments in https://github.com/TheAlgorithms/Go/pull/647 * Update math/binary/fast_inverse_sqrt.go file docstring Co-authored-by: Taj * Update math/binary/fast_inverse_sqrt.go function documentation Co-authored-by: Taj * Fix function documentation grammar Co-authored-by: Taj --------- Co-authored-by: Taj --- math/binary/fast_inverse_sqrt.go | 29 +++++++++++++++++++++++++++++ math/binary/sqrt.go | 16 +--------------- math/binary/sqrt_test.go | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 math/binary/fast_inverse_sqrt.go diff --git a/math/binary/fast_inverse_sqrt.go b/math/binary/fast_inverse_sqrt.go new file mode 100644 index 000000000..24ee41a82 --- /dev/null +++ b/math/binary/fast_inverse_sqrt.go @@ -0,0 +1,29 @@ +// Calculating the inverse square root +// [See more](https://en.wikipedia.org/wiki/Fast_inverse_square_root) + +package binary + +import ( + "math" +) + +// FastInverseSqrt assumes that argument is always positive, +// and it does not deal with negative numbers. +// The "magic" number 0x5f3759df is hex for 1597463007 in decimals. +// The math.Float32bits is alias to *(*uint32)(unsafe.Pointer(&f)) +// and math.Float32frombits is to *(*float32)(unsafe.Pointer(&b)). +func FastInverseSqrt(number float32) float32 { + var i uint32 + var y, x2 float32 + const threehalfs float32 = 1.5 + + x2 = number * float32(0.5) + y = number + i = math.Float32bits(y) // evil floating point bit level hacking + i = 0x5f3759df - (i >> 1) // magic number and bitshift hacking + y = math.Float32frombits(i) + + y = y * (threehalfs - (x2 * y * y)) // 1st iteration of Newton's method + y = y * (threehalfs - (x2 * y * y)) // 2nd iteration, this can be removed + return y +} diff --git a/math/binary/sqrt.go b/math/binary/sqrt.go index 111dd94a9..520338eb6 100644 --- a/math/binary/sqrt.go +++ b/math/binary/sqrt.go @@ -7,18 +7,4 @@ package binary -import ( - "math" -) - -const threeHalves = 1.5 - -func Sqrt(n float32) float32 { - var half, y float32 - half = n * 0.5 - z := math.Float32bits(n) - z = 0x5f3759df - (z >> 1) // floating point bit level hacking - y = math.Float32frombits(z) - y = y * (threeHalves - (half * y * y)) // Newton's approximation - return 1 / y -} +func Sqrt(n float32) float32 { return 1 / FastInverseSqrt(n) } diff --git a/math/binary/sqrt_test.go b/math/binary/sqrt_test.go index 426794fd2..fe31aefac 100644 --- a/math/binary/sqrt_test.go +++ b/math/binary/sqrt_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -const epsilon = 0.2 +const epsilon = 0.001 func TestSquareRootCalculation(t *testing.T) { tests := []struct { From ae9e760be410c082e3d56fa761305de974de74fe Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Tue, 5 Sep 2023 22:15:39 +0200 Subject: [PATCH 418/488] Update `actions/checkout` to `v4` (#650) --- .github/workflows/ci.yml | 4 ++-- .github/workflows/godocmd.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29615bbe0..9d18a4464 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v3 with: @@ -31,7 +31,7 @@ jobs: name: Check for spelling errors runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: codespell-project/actions-codespell@master with: ignore_words_list: "actualy,nwe" diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index 2ed6aec61..cac77e1a2 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -1,5 +1,5 @@ name: Generate Documentation -on: +on: push: branches: - master @@ -9,7 +9,7 @@ jobs: name: Markdown Generation runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-go@v2 From 1e62d2126267ce62ff22bc6238aba03a6fe207eb Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Thu, 7 Sep 2023 14:44:47 +0200 Subject: [PATCH 419/488] Update `actions/setup-go` to `v4` (#653) --- .github/workflows/ci.yml | 2 +- .github/workflows/godocmd.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d18a4464..e7bc96e6c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: '^1.18' - name: Run Golang CI Lint diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index cac77e1a2..454f1a632 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v4 with: go-version: '^1.18' - name: Install GoDocMD From 58bb31e80f8347c91db049a09d32a4989c06b485 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Wed, 27 Sep 2023 10:09:14 +0300 Subject: [PATCH 420/488] Remove @siriak from CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fd1f63e16..d709eff88 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,4 +7,4 @@ # Order is important. The last matching pattern has the most precedence. -* @siriak @raklaptudirm @tjgurwara99 @yanglbme +* @raklaptudirm @tjgurwara99 @yanglbme From 30392a3da977d3c3ebb94156489f3bd28d72c89d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=A5=D1=80=D0=BE?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2?= Date: Mon, 2 Oct 2023 10:41:04 +0300 Subject: [PATCH 421/488] feat: add set implementation using generic (#656) * feat: add set implementation using generic * some refact * use gofmt --------- Co-authored-by: Rak Laptudirm --- README.md | 2 +- structure/set/set.go | 78 +++++++++++++++++++-------------------- structure/set/set_test.go | 30 +++++++-------- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 776a50f4b..40ec68ed7 100644 --- a/README.md +++ b/README.md @@ -925,7 +925,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### package set implements a Set using a golang map. This implies that only the types that are accepted as valid map keys can be used as set elements. For instance, do not try to Add a slice, or the program will panic. +##### package set implements a Set using generics and a golang map with comparable interface key. This implies that only the types that are accepted as valid map keys can be used as set elements --- ##### Functions: diff --git a/structure/set/set.go b/structure/set/set.go index 811ec717e..b8c7b51e1 100644 --- a/structure/set/set.go +++ b/structure/set/set.go @@ -4,9 +4,9 @@ package set // New gives new set. -func New(items ...any) Set { - st := set{ - elements: make(map[any]bool), +func New[T comparable](items ...T) Set[T] { + st := set[T]{ + elements: make(map[T]bool), } for _, item := range items { st.Add(item) @@ -15,73 +15,73 @@ func New(items ...any) Set { } // Set is an interface of possible methods on 'set'. -type Set interface { +type Set[T comparable] interface { // Add: adds new element to the set - Add(item any) + Add(item T) // Delete: deletes the passed element from the set if present - Delete(item any) + Delete(item T) // Len: gives the length of the set (total no. of elements in set) Len() int - // GetItems: gives the array( []any ) of elements of the set. - GetItems() []any + // GetItems: gives the array( []T ) of elements of the set. + GetItems() []T // In: checks whether item is present in set or not. - In(item any) bool + In(item T) bool // IsSubsetOf: checks whether set is subset of set2 or not. - IsSubsetOf(set2 Set) bool + IsSubsetOf(set2 Set[T]) bool // IsProperSubsetOf: checks whether set is proper subset of set2 or not. // ex: [1,2,3] proper subset of [1,2,3,4] -> true - IsProperSubsetOf(set2 Set) bool + IsProperSubsetOf(set2 Set[T]) bool // IsSupersetOf: checks whether set is superset of set2 or not. - IsSupersetOf(set2 Set) bool + IsSupersetOf(set2 Set[T]) bool // IsProperSupersetOf: checks whether set is proper superset of set2 or not. // ex: [1,2,3,4] proper superset of [1,2,3] -> true - IsProperSupersetOf(set2 Set) bool + IsProperSupersetOf(set2 Set[T]) bool // Union: gives new union set of both sets. // ex: [1,2,3] union [3,4,5] -> [1,2,3,4,5] - Union(set2 Set) Set + Union(set2 Set[T]) Set[T] // Intersection: gives new intersection set of both sets. // ex: [1,2,3] Intersection [3,4,5] -> [3] - Intersection(set2 Set) Set + Intersection(set2 Set[T]) Set[T] // Difference: gives new difference set of both sets. // ex: [1,2,3] Difference [3,4,5] -> [1,2] - Difference(set2 Set) Set + Difference(set2 Set[T]) Set[T] // SymmetricDifference: gives new symmetric difference set of both sets. // ex: [1,2,3] SymmetricDifference [3,4,5] -> [1,2,4,5] - SymmetricDifference(set2 Set) Set + SymmetricDifference(set2 Set[T]) Set[T] } -type set struct { - elements map[any]bool +type set[T comparable] struct { + elements map[T]bool } -func (st *set) Add(value any) { +func (st *set[T]) Add(value T) { st.elements[value] = true } -func (st *set) Delete(value any) { +func (st *set[T]) Delete(value T) { delete(st.elements, value) } -func (st *set) GetItems() []any { - keys := make([]any, 0, len(st.elements)) +func (st *set[T]) GetItems() []T { + keys := make([]T, 0, len(st.elements)) for k := range st.elements { keys = append(keys, k) } return keys } -func (st *set) Len() int { +func (st *set[T]) Len() int { return len(st.elements) } -func (st *set) In(value any) bool { +func (st *set[T]) In(value T) bool { if _, in := st.elements[value]; in { return true } return false } -func (st *set) IsSubsetOf(superSet Set) bool { +func (st *set[T]) IsSubsetOf(superSet Set[T]) bool { if st.Len() > superSet.Len() { return false } @@ -94,26 +94,26 @@ func (st *set) IsSubsetOf(superSet Set) bool { return true } -func (st *set) IsProperSubsetOf(superSet Set) bool { +func (st *set[T]) IsProperSubsetOf(superSet Set[T]) bool { if st.Len() == superSet.Len() { return false } return st.IsSubsetOf(superSet) } -func (st *set) IsSupersetOf(subSet Set) bool { +func (st *set[T]) IsSupersetOf(subSet Set[T]) bool { return subSet.IsSubsetOf(st) } -func (st *set) IsProperSupersetOf(subSet Set) bool { +func (st *set[T]) IsProperSupersetOf(subSet Set[T]) bool { if st.Len() == subSet.Len() { return false } return st.IsSupersetOf(subSet) } -func (st *set) Union(st2 Set) Set { - unionSet := New() +func (st *set[T]) Union(st2 Set[T]) Set[T] { + unionSet := New[T]() for _, item := range st.GetItems() { unionSet.Add(item) } @@ -123,9 +123,9 @@ func (st *set) Union(st2 Set) Set { return unionSet } -func (st *set) Intersection(st2 Set) Set { - intersectionSet := New() - var minSet, maxSet Set +func (st *set[T]) Intersection(st2 Set[T]) Set[T] { + intersectionSet := New[T]() + var minSet, maxSet Set[T] if st.Len() > st2.Len() { minSet = st2 maxSet = st @@ -141,8 +141,8 @@ func (st *set) Intersection(st2 Set) Set { return intersectionSet } -func (st *set) Difference(st2 Set) Set { - differenceSet := New() +func (st *set[T]) Difference(st2 Set[T]) Set[T] { + differenceSet := New[T]() for _, item := range st.GetItems() { if !st2.In(item) { differenceSet.Add(item) @@ -151,9 +151,9 @@ func (st *set) Difference(st2 Set) Set { return differenceSet } -func (st *set) SymmetricDifference(st2 Set) Set { - symmetricDifferenceSet := New() - dropSet := New() +func (st *set[T]) SymmetricDifference(st2 Set[T]) Set[T] { + symmetricDifferenceSet := New[T]() + dropSet := New[T]() for _, item := range st.GetItems() { if st2.In(item) { dropSet.Add(item) diff --git a/structure/set/set_test.go b/structure/set/set_test.go index 4b12a8f55..2000760ac 100644 --- a/structure/set/set_test.go +++ b/structure/set/set_test.go @@ -118,9 +118,9 @@ func TestIsProperSupersetOf(t *testing.T) { func TestUnion(t *testing.T) { td := []struct { name string - s1 Set - s2 Set - expSet Set + s1 Set[int] + s2 Set[int] + expSet Set[int] }{ {"union of different sets", New(1, 2, 3), New(4, 5, 6), New(1, 2, 3, 4, 5, 6)}, {"union of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(1, 2, 3, 4)}, @@ -144,11 +144,11 @@ func TestUnion(t *testing.T) { func TestIntersection(t *testing.T) { td := []struct { name string - s1 Set - s2 Set - expSet Set + s1 Set[int] + s2 Set[int] + expSet Set[int] }{ - {"intersection of different sets", New(0, 1, 2, 3), New(4, 5, 6), New()}, + {"intersection of different sets", New(0, 1, 2, 3), New(4, 5, 6), New[int]()}, {"intersection of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(1, 2)}, {"intersection of same sets", New(1, 2, 3), New(1, 2, 3), New(1, 2, 3)}, } @@ -170,13 +170,13 @@ func TestIntersection(t *testing.T) { func TestDifference(t *testing.T) { td := []struct { name string - s1 Set - s2 Set - expSet Set + s1 Set[int] + s2 Set[int] + expSet Set[int] }{ {"difference of different sets", New(1, 2, 3), New(4, 5, 6), New(1, 2, 3)}, {"difference of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(3)}, - {"difference of same sets", New(1, 2, 3), New(1, 2, 3), New()}, + {"difference of same sets", New(1, 2, 3), New(1, 2, 3), New[int]()}, } for _, tc := range td { t.Run(tc.name, func(t *testing.T) { @@ -196,13 +196,13 @@ func TestDifference(t *testing.T) { func TestSymmetricDifference(t *testing.T) { td := []struct { name string - s1 Set - s2 Set - expSet Set + s1 Set[int] + s2 Set[int] + expSet Set[int] }{ {"symmetric difference of different sets", New(1, 2, 3), New(4, 5, 6), New(1, 2, 3, 4, 5, 6)}, {"symmetric difference of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(3, 4)}, - {"symmetric difference of same sets", New(1, 2, 3), New(1, 2, 3), New()}, + {"symmetric difference of same sets", New(1, 2, 3), New(1, 2, 3), New[int]()}, } for _, tc := range td { t.Run(tc.name, func(t *testing.T) { From 4460ba0d9fcb8e6e0ec4bf2d22d37010b381c97d Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 4 Oct 2023 06:33:10 +0200 Subject: [PATCH 422/488] style: use proper spelling (#665) --- strings/genetic/genetic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/genetic/genetic.go b/strings/genetic/genetic.go index b385ad867..a91029433 100644 --- a/strings/genetic/genetic.go +++ b/strings/genetic/genetic.go @@ -28,7 +28,7 @@ type PopulationItem struct { Value float64 } -// Conf stands for cofigurations set provided to GeneticString function. +// Conf stands for configurations set provided to GeneticString function. type Conf struct { // Maximum size of the population. // Bigger could be faster but more memory expensive. From a52d8bf89119aa5186902bfd1e60e107dbe11e30 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 4 Oct 2023 14:49:03 +0200 Subject: [PATCH 423/488] Reactivate `horspool` (#663) --- strings/horspool/horspool.go | 145 ++++++++++++------------------ strings/horspool/horspool_test.go | 68 ++++++++++++++ 2 files changed, 123 insertions(+), 90 deletions(-) create mode 100644 strings/horspool/horspool_test.go diff --git a/strings/horspool/horspool.go b/strings/horspool/horspool.go index f210f9187..1611c0ce8 100644 --- a/strings/horspool/horspool.go +++ b/strings/horspool/horspool.go @@ -1,95 +1,60 @@ +// Implementation of the +// [Boyer–Moore–Horspool algorithm](https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm) + package horspool -// User defined. -// Set to true to read input from two command line arguments -// Set to false to read input from two files "pattern.txt" and "text.txt" -// const commandLineInput bool = false +import "errors" + +var ErrNotFound = errors.New("pattern was not found in the input string") + +func Horspool(t, p string) (int, error) { + // in order to handle multy-byte character properly + // the input is converted into rune arrays + return horspool([]rune(t), []rune(p)) +} + +func horspool(t, p []rune) (int, error) { + shiftMap := computeShiftMap(t, p) + pos := 0 + for pos <= len(t)-len(p) { + if isMatch(pos, t, p) { + return pos, nil + } + if pos+len(p) >= len(t) { + // because the remaining length of the input string + // is the same as the length of the pattern + // and it does not match the pattern + // it is impossible to find the pattern + break + } + + // because of the check above + // t[pos+len(p)] is defined + pos += shiftMap[t[pos+len(p)]] + } -// Implementation of Boyer-Moore-Horspool algorithm (Suffix based approach). -// Requires either a two command line arguments separated by a single space, -// or two files in the same folder: "pattern.txt" containing the string to -// be searched for, "text.txt" containing the text to be searched in. -// func main() { -// if commandLineInput == true { // case of command line input -// args := os.Args -// if len(args) <= 2 { -// log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!") -// } -// pattern := args[1] -// s := args[2] -// for i := 3; i < len(args); i++ { -// s = s + " " + args[i] -// } -// if len(args[1]) > len(s) { -// log.Fatal("Pattern is longer than text!") -// } -// fmt.Printf("\nRunning: Horspool algorithm.\n\n") -// fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern) -// fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s) -// horspool(s, pattern) -// } else if commandLineInput == false { // case of file line input -// patFile, err := ioutil.ReadFile("pattern.txt") -// if err != nil { -// log.Fatal(err) -// } -// textFile, err := ioutil.ReadFile("text.txt") -// if err != nil { -// log.Fatal(err) -// } -// if len(patFile) > len(textFile) { -// log.Fatal("Pattern is longer than text!") -// } -// fmt.Printf("\nRunning: Horspool algorithm.\n\n") -// fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) -// fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) -// horspool(string(textFile), string(patFile)) -// } -// } + return -1, ErrNotFound +} -// // Function horspool performing the Horspool algorithm. -// // Prints whether the word/pattern was found and on what position in the text or not. -// func horspool(t, p string) { -// m, n, c, pos := len(p), len(t), 0, 0 -// //Perprocessing -// d := preprocess(t, p) -// //Map output -// fmt.Printf("Precomputed shifts per symbol: ") -// for key, value := range d { -// fmt.Printf("%c:%d; ", key, value) -// } -// fmt.Println() -// //Searching -// for pos <= n-m { -// j := m -// if t[pos+j-1] != p[j-1] { -// fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) -// c++ -// } -// for j > 0 && t[pos+j-1] == p[j-1] { -// fmt.Printf("\n comparing characters %c %c at positions %d %d", t[pos+j-1], p[j-1], pos+j-1, j-1) -// c++ -// fmt.Printf(" - match") -// j-- -// } -// if j == 0 { -// fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", p, pos, t, c) -// return -// } -// pos = pos + d[t[pos+m]] -// } -// fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", c) -// return -// } +// Checks if the array p matches the subarray of t starting at pos. +// Note that backward iteration. +// There are [other](https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm#Tuning_the_comparison_loop) +// approaches possible. +func isMatch(pos int, t, p []rune) bool { + j := len(p) + for j > 0 && t[pos+j-1] == p[j-1] { + j-- + } + return j == 0 +} -// // Function that pre-computes map with Key: uint8 (char) Value: int. -// // Values determine safe shifting of search window. -// func preprocess(t, p string) (d map[uint8]int) { -// d = make(map[uint8]int) -// for i := 0; i < len(t); i++ { -// d[t[i]] = len(p) -// } -// for i := 0; i < len(p); i++ { -// d[p[i]] = len(p) - i -// } -// return d -// } +func computeShiftMap(t, p []rune) (res map[rune]int) { + res = make(map[rune]int) + for _, tCode := range t { + res[tCode] = len(p) + } + for i, pCode := range p { + res[pCode] = len(p) - i + } + return res +} diff --git a/strings/horspool/horspool_test.go b/strings/horspool/horspool_test.go new file mode 100644 index 000000000..6c500f3f2 --- /dev/null +++ b/strings/horspool/horspool_test.go @@ -0,0 +1,68 @@ +// horspool_test.go +// description: Tests for horspool +// see horspool.go + +package horspool + +import "testing" +import "fmt" + +func TestLHorspool(t *testing.T) { + testCases := []struct { + input string + pattern string + expected int + }{ + {"aaaaXaaa", "X", 4}, + {"aaaaXXaa", "XX", 4}, + {"Xaaab", "X", 0}, + {"XYaab", "XY", 0}, + {"abcefghXYZ", "XYZ", 7}, + {"abcefgh€YZ⌘", "€YZ", 7}, + {"⌘bcefgh€YZ⌘", "€YZ", 7}, + {"abc", "abc", 0}, + {"", "", 0}, + {"a", "", 0}, + {"a", "a", 0}, + {"aa", "a", 0}, + {"aa", "aa", 0}, + } + for _, tc := range testCases { + t.Run(fmt.Sprint("test with ", tc.input, " ", tc.pattern), func(t *testing.T) { + result, curError := Horspool(tc.input, tc.pattern) + if curError != nil { + t.Fatalf("Got unexpected error") + } + if tc.expected != result { + t.Fatalf("expected %d, got %d", tc.expected, result) + } + }) + } +} + +func TestLHorspoolNotExisintPattern(t *testing.T) { + testCases := []struct { + input string + pattern string + }{ + {"", "X"}, + {"X", "Y"}, + {"X", "XX"}, + {"aaaaaaaXaXaaaa", "XXX"}, + {"aaaaaaaXaX", "XXX"}, + {"XaX", "XXX"}, + {"XaX", "XXX"}, + {"\xe2\x8c\x98", "\x98"}, + } + for _, tc := range testCases { + t.Run(fmt.Sprint("test with ", tc.input, " ", tc.pattern), func(t *testing.T) { + result, curError := Horspool(tc.input, tc.pattern) + if curError != ErrNotFound { + t.Fatalf("Got unexpected error") + } + if result != -1 { + t.Fatalf("expected -1, got %d", result) + } + }) + } +} From c129115f33975e72953a9e2b61091c3ac77dc569 Mon Sep 17 00:00:00 2001 From: Himanshu Patel Date: Thu, 5 Oct 2023 15:47:56 +0530 Subject: [PATCH 424/488] test: Use error.Is(errorType, errorInstance) to check for error equality (#666) Checking error with == operator might fail on wrapped errors --- graph/bellmanford_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/bellmanford_test.go b/graph/bellmanford_test.go index 2f9d57ea6..83364b5df 100644 --- a/graph/bellmanford_test.go +++ b/graph/bellmanford_test.go @@ -125,7 +125,7 @@ func TestBellmanford(t *testing.T) { if resIsReachable != test.isReachable { t.Errorf("Reachable, Expected: %t, Computed: %t", test.isReachable, resIsReachable) } - if resError != test.err { + if !errors.Is(test.err, resError) { if resError == nil || test.err == nil { t.Errorf("Reachable, Expected: %s, Computed: %s", test.err, resError) } else if resError.Error() != test.err.Error() { From 8a5442213216069a72bec48302db60f313c24454 Mon Sep 17 00:00:00 2001 From: Himanshu Patel Date: Thu, 5 Oct 2023 15:50:31 +0530 Subject: [PATCH 425/488] test: Use error.Is(errorType, errorInstance) to check for error equality (#668) Co-authored-by: Rak Laptudirm --- search/binary_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/search/binary_test.go b/search/binary_test.go index 24e2a0c41..99f907797 100644 --- a/search/binary_test.go +++ b/search/binary_test.go @@ -1,6 +1,9 @@ package search -import "testing" +import ( + "errors" + "testing" +) func TestBinary(t *testing.T) { for _, test := range searchTests { @@ -8,7 +11,7 @@ func TestBinary(t *testing.T) { if actualValue != test.expected { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) } - if actualError != test.expectedError { + if !errors.Is(test.expectedError, actualError) { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) } } @@ -20,7 +23,7 @@ func TestBinaryIterative(t *testing.T) { if actualValue != test.expected { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) } - if actualError != test.expectedError { + if !errors.Is(test.expectedError, actualError) { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) } } @@ -32,7 +35,7 @@ func TestLowerBound(t *testing.T) { if actualValue != test.expected { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) } - if actualError != test.expectedError { + if !errors.Is(test.expectedError, actualError) { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) } } @@ -44,7 +47,7 @@ func TestUpperBound(t *testing.T) { if actualValue != test.expected { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) } - if actualError != test.expectedError { + if !errors.Is(test.expectedError, actualError) { t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) } } From 51a9599da04ffd149b57f3dfa790d9c9462d681e Mon Sep 17 00:00:00 2001 From: Himanshu Patel Date: Fri, 6 Oct 2023 22:22:28 +0530 Subject: [PATCH 426/488] refactor: refactor comments and variable declaration compliant with godoc (#667) Co-authored-by: Rak Laptudirm --- graph/topological.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graph/topological.go b/graph/topological.go index feef703f1..9e99470b7 100644 --- a/graph/topological.go +++ b/graph/topological.go @@ -1,7 +1,7 @@ package graph -// Assumes that graph given is valid and possible to -// get a topo ordering. +// Topological assumes that graph given is valid and that its +// possible to get a topological ordering. // constraints are array of []int{a, b}, representing // an edge going from a to b func Topological(N int, constraints [][]int) []int { @@ -22,7 +22,7 @@ func Topological(N int, constraints [][]int) []int { edges[a][b] = true } - answer := []int{} + var answer []int for s := 0; s < N; s++ { // Only start walking from top level nodes if dependencies[s] == 0 { From 92396c1b4b4a9320b13c1b02d417af7f41564c5b Mon Sep 17 00:00:00 2001 From: Himanshu Patel Date: Fri, 6 Oct 2023 22:39:58 +0530 Subject: [PATCH 427/488] refactor: refactor comments and variable declaration compliant with godoc (#669) Co-authored-by: Rak Laptudirm --- search/binary.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/search/binary.go b/search/binary.go index 3b9241af6..604341edb 100644 --- a/search/binary.go +++ b/search/binary.go @@ -37,7 +37,7 @@ func BinaryIterative(array []int, target int) (int, error) { return -1, ErrNotFound } -// Returns index to the first element in the range [0, len(array)-1] that is not less than (i.e. greater or equal to) target. +// LowerBound returns index to the first element in the range [0, len(array)-1] that is not less than (i.e. greater or equal to) target. // return -1 and ErrNotFound if no such element is found. func LowerBound(array []int, target int) (int, error) { startIndex := 0 @@ -59,7 +59,7 @@ func LowerBound(array []int, target int) (int, error) { return startIndex, nil } -// Returns index to the first element in the range [lowIndex, len(array)-1] that is greater than target. +// UpperBound returns index to the first element in the range [lowIndex, len(array)-1] that is greater than target. // return -1 and ErrNotFound if no such element is found. func UpperBound(array []int, target int) (int, error) { startIndex := 0 From 02fde76aa3d34e13378c0ca7d177d15ecc72009c Mon Sep 17 00:00:00 2001 From: migueldalberto <65927539+migueldalberto@users.noreply.github.com> Date: Sat, 7 Oct 2023 04:14:44 -0300 Subject: [PATCH 428/488] feat: Add Cocktail Sort (#660) * add cocktail sort * add test for cocktail sort * change comments * add comments on cocktailsort.go * add start and end vars to cocktailsort.go for optimization * fix: change for loop structure * fix: change constraints from integer to ordered on cocktailsort.go * test: add benchmark for cocktailsort --------- Co-authored-by: Rak Laptudirm --- sort/cocktailsort.go | 54 ++++++++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 11 ++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 sort/cocktailsort.go diff --git a/sort/cocktailsort.go b/sort/cocktailsort.go new file mode 100644 index 000000000..6aee61681 --- /dev/null +++ b/sort/cocktailsort.go @@ -0,0 +1,54 @@ +// Implementation of Cocktail sorting +// reference: https://en.wikipedia.org/wiki/Cocktail_shaker_sort + +package sort + +import "github.com/TheAlgorithms/Go/constraints" + +// Cocktail sort is a variation of bubble sort, operating in two directions (beginning to end, end to beginning) +func Cocktail[T constraints.Ordered](arr []T) []T { + if len(arr) == 0 { // ignore 0 length arrays + return arr + } + + swapped := true // true if swapped two or more elements in the last loop + // if it loops through the array without swapping, the array is sorted + + // start and end indexes, this will be updated excluding already sorted elements + start := 0 + end := len(arr) - 1 + + for swapped { + swapped = false + var new_start int + var new_end int + + for i := start; i < end; i++ { // first loop, from start to end + if arr[i] > arr[i+1] { // if current and next elements are unordered + arr[i], arr[i+1] = arr[i+1], arr[i] // swap two elements + new_end = i + swapped = true + } + } + + end = new_end + + if !swapped { // early exit, skipping the second loop + break + } + + swapped = false + + for i := end; i > start; i-- { // second loop, from end to start + if arr[i] < arr[i-1] { // same process of the first loop, now going 'backwards' + arr[i], arr[i-1] = arr[i-1], arr[i] + new_start = i + swapped = true + } + } + + start = new_start + } + + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index aeb90c04e..8df55373f 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -1,11 +1,12 @@ package sort_test import ( - "github.com/TheAlgorithms/Go/sort" "math/rand" "reflect" "testing" "time" + + "github.com/TheAlgorithms/Go/sort" ) func testFramework(t *testing.T, sortingFunction func([]int) []int) { @@ -85,6 +86,10 @@ func TestBucketSort(t *testing.T) { testFramework(t, sort.Bucket[int]) } +func TestCocktailSort(t *testing.T) { + testFramework(t, sort.Cocktail[int]) +} + func TestExchange(t *testing.T) { testFramework(t, sort.Exchange[int]) } @@ -222,6 +227,10 @@ func BenchmarkBucketSort(b *testing.B) { benchmarkFramework(b, sort.Bucket[int]) } +func BenchmarkCocktailSort(b *testing.B) { + benchmarkFramework(b, sort.Cocktail[int]) +} + func BenchmarkExchange(b *testing.B) { benchmarkFramework(b, sort.Exchange[int]) } From 85451afbfad6632ed26e66770d1988200c9f0941 Mon Sep 17 00:00:00 2001 From: ")`(-@_.+_^*__*^" <55359898+11-aryan@users.noreply.github.com> Date: Tue, 10 Oct 2023 12:52:53 +0530 Subject: [PATCH 429/488] feat: optimized stack array implementation (#658) * optimized stack array implementation and modified the unit tests accordingly * Fixed formatting issues * fix exported all methods and converted tests to blackbox * Added generic parameter and fixed package name --------- Co-authored-by: Rak Laptudirm --- structure/stack/stack_test.go | 99 ++++++++++++---------- structure/stack/stackarray.go | 52 ++++++++---- structure/stack/stacklinkedlist.go | 12 +-- structure/stack/stacklinkedlistwithlist.go | 22 ++--- 4 files changed, 105 insertions(+), 80 deletions(-) diff --git a/structure/stack/stack_test.go b/structure/stack/stack_test.go index e5a77e70b..0de3dc0d6 100644 --- a/structure/stack/stack_test.go +++ b/structure/stack/stack_test.go @@ -7,23 +7,24 @@ // author [Milad](https://github.com/miraddo) // see stackarray.go, stacklinkedlist.go, stacklinkedlistwithlist.go -package stack +package stack_test import ( "container/list" + "github.com/TheAlgorithms/Go/structure/stack" "reflect" "testing" ) // TestStackLinkedList for testing Stack with LinkedList func TestStackLinkedList(t *testing.T) { - var newStack Stack + var newStack stack.Stack - newStack.push(1) - newStack.push(2) + newStack.Push(1) + newStack.Push(2) t.Run("Stack Push", func(t *testing.T) { - result := newStack.show() + result := newStack.Show() expected := []any{2, 1} for x := range result { if result[x] != expected[x] { @@ -33,20 +34,20 @@ func TestStackLinkedList(t *testing.T) { }) t.Run("Stack isEmpty", func(t *testing.T) { - if newStack.isEmpty() { - t.Error("Stack isEmpty is returned true but expected false", newStack.isEmpty()) + if newStack.IsEmpty() { + t.Error("Stack isEmpty is returned true but expected false", newStack.IsEmpty()) } }) t.Run("Stack Length", func(t *testing.T) { - if newStack.len() != 2 { - t.Error("Stack Length should be 2 but got", newStack.len()) + if newStack.Length() != 2 { + t.Error("Stack Length should be 2 but got", newStack.Length()) } }) - newStack.pop() - pop := newStack.pop() + newStack.Pop() + pop := newStack.Pop() t.Run("Stack Pop", func(t *testing.T) { if pop != 1 { @@ -55,65 +56,73 @@ func TestStackLinkedList(t *testing.T) { }) - newStack.push(52) - newStack.push(23) - newStack.push(99) - t.Run("Stack Peak", func(t *testing.T) { - if newStack.peak() != 99 { - t.Error("Stack Peak should return 99 but got ", newStack.peak()) + newStack.Push(52) + newStack.Push(23) + newStack.Push(99) + t.Run("Stack Peek", func(t *testing.T) { + if newStack.Peek() != 99 { + t.Error("Stack Peak should return 99 but got ", newStack.Peek()) } }) } // TestStackArray for testing Stack with Array func TestStackArray(t *testing.T) { + newStack := stack.NewStack[int]() t.Run("Stack With Array", func(t *testing.T) { - stackPush(2) - stackPush(3) + newStack.Push(2) + newStack.Push(3) t.Run("Stack Push", func(t *testing.T) { - if !reflect.DeepEqual([]any{3, 2}, stackArray) { - t.Errorf("Stack Push is not work we expected %v but got %v", []any{3, 2}, stackArray) + var stackElements []any + for i := 0; i < 2; i++ { + poppedElement := newStack.Pop() + stackElements = append(stackElements, poppedElement) + } + + if !reflect.DeepEqual([]any{3, 2}, stackElements) { + t.Errorf("Stack Push is not work we expected %v but got %v", []any{3, 2}, newStack) } + + newStack.Push(2) + newStack.Push(3) }) - pop := stackPop() + pop := newStack.Pop() t.Run("Stack Pop", func(t *testing.T) { - - if stackLength() == 2 && pop != 3 { + if newStack.Length() == 2 && pop != 3 { t.Errorf("Stack Pop is not work we expected %v but got %v", 3, pop) } }) - stackPush(2) - stackPush(83) + newStack.Push(2) + newStack.Push(83) t.Run("Stack Peak", func(t *testing.T) { - - if stackPeak() != 83 { - t.Errorf("Stack Peak is not work we expected %v but got %v", 83, stackPeak()) + if newStack.Peek() != 83 { + t.Errorf("Stack Peek is not work we expected %v but got %v", 83, newStack.Peek()) } }) t.Run("Stack Length", func(t *testing.T) { - if stackLength() != 3 { - t.Errorf("Stack Length is not work we expected %v but got %v", 3, stackLength()) + if newStack.Length() != 3 { + t.Errorf("Stack Length is not work we expected %v but got %v", 3, newStack.Length()) } }) t.Run("Stack Empty", func(t *testing.T) { - if stackEmpty() == true { - t.Errorf("Stack Empty is not work we expected %v but got %v", false, stackEmpty()) + if newStack.IsEmpty() == true { + t.Errorf("Stack Empty is not work we expected %v but got %v", false, newStack.IsEmpty()) } - stackPop() - stackPop() - stackPop() + newStack.Pop() + newStack.Pop() + newStack.Pop() - if stackEmpty() == false { - t.Errorf("Stack Empty is not work we expected %v but got %v", true, stackEmpty()) + if newStack.IsEmpty() == false { + t.Errorf("Stack Empty is not work we expected %v but got %v", true, newStack.IsEmpty()) } }) }) @@ -121,8 +130,8 @@ func TestStackArray(t *testing.T) { // TestStackLinkedListWithList for testing Stack with Container/List Library (STL) func TestStackLinkedListWithList(t *testing.T) { - stackList := &SList{ - stack: list.New(), + stackList := &stack.SList{ + Stack: list.New(), } t.Run("Stack Push", func(t *testing.T) { @@ -147,7 +156,7 @@ func TestStackLinkedListWithList(t *testing.T) { stackList.Push(2) stackList.Push(83) - peak, _ := stackList.Peak() + peak, _ := stackList.Peek() if peak != 83 { t.Errorf("Stack Peak is not work we expected %v but got %v", 83, peak) } @@ -160,8 +169,8 @@ func TestStackLinkedListWithList(t *testing.T) { }) t.Run("Stack Empty", func(t *testing.T) { - if stackList.Empty() == true { - t.Errorf("Stack Empty is not work we expected %v but got %v", false, stackList.Empty()) + if stackList.IsEmpty() == true { + t.Errorf("Stack Empty is not work we expected %v but got %v", false, stackList.IsEmpty()) } d1, err := stackList.Pop() @@ -172,8 +181,8 @@ func TestStackLinkedListWithList(t *testing.T) { t.Errorf("got an unexpected error %v, pop1: %v, pop2: %v, pop3: %v", err, d1, d2, d3) } - if stackList.Empty() == false { - t.Errorf("Stack Empty is not work we expected %v but got %v", true, stackList.Empty()) + if stackList.IsEmpty() == false { + t.Errorf("Stack Empty is not work we expected %v but got %v", true, stackList.IsEmpty()) } }) } diff --git a/structure/stack/stackarray.go b/structure/stack/stackarray.go index 5aba01cf4..2d0fc05c4 100644 --- a/structure/stack/stackarray.go +++ b/structure/stack/stackarray.go @@ -9,31 +9,47 @@ package stack -var stackArray []any +type Array[T any] struct { + elements []T +} + +// NewStack creates and returns a new stack. +func NewStack[T any]() *Array[T] { + return &Array[T]{} +} -// stackPush push to first index of array -func stackPush(n any) { - stackArray = append([]any{n}, stackArray...) +// Push adds an element to the top of the stack. +func (s *Array[T]) Push(value T) { + s.elements = append(s.elements, value) } -// stackLength return length of array -func stackLength() int { - return len(stackArray) +// Size returns the number of elements in the stack. +func (s *Array[T]) Length() int { + return len(s.elements) } -// stackPeak return last input of array -func stackPeak() any { - return stackArray[0] +// Peek returns the top element of the stack without removing it. +func (s *Array[T]) Peek() T { + if s.IsEmpty() { + var zeroValue T + return zeroValue // Stack is empty + } + return s.elements[len(s.elements)-1] } -// stackEmpty check array is empty or not -func stackEmpty() bool { - return len(stackArray) == 0 +// IsEmpty returns true if the stack is empty, false otherwise. +func (s *Array[T]) IsEmpty() bool { + return len(s.elements) == 0 } -// stackPop return last input and remove it in array -func stackPop() any { - pop := stackArray[0] - stackArray = stackArray[1:] - return pop +// Pop removes and returns the top element from the stack. +func (s *Array[T]) Pop() T { + if s.IsEmpty() { + var zeroValue T + return zeroValue // Stack is empty + } + index := len(s.elements) - 1 + popped := s.elements[index] + s.elements = s.elements[:index] + return popped } diff --git a/structure/stack/stacklinkedlist.go b/structure/stack/stacklinkedlist.go index 4c4973884..1328729e6 100644 --- a/structure/stack/stacklinkedlist.go +++ b/structure/stack/stacklinkedlist.go @@ -22,7 +22,7 @@ type Stack struct { } // push add value to last index -func (ll *Stack) push(n any) { +func (ll *Stack) Push(n any) { newStack := &Node{} // new node newStack.Val = n @@ -33,7 +33,7 @@ func (ll *Stack) push(n any) { } // pop remove last item as first output -func (ll *Stack) pop() any { +func (ll *Stack) Pop() any { result := ll.top.Val if ll.top.Next == nil { ll.top = nil @@ -46,22 +46,22 @@ func (ll *Stack) pop() any { } // isEmpty to check our array is empty or not -func (ll *Stack) isEmpty() bool { +func (ll *Stack) IsEmpty() bool { return ll.length == 0 } // len use to return length of our stack -func (ll *Stack) len() int { +func (ll *Stack) Length() int { return ll.length } // peak return last input value -func (ll *Stack) peak() any { +func (ll *Stack) Peek() any { return ll.top.Val } // show all value as an interface array -func (ll *Stack) show() (in []any) { +func (ll *Stack) Show() (in []any) { current := ll.top for current != nil { diff --git a/structure/stack/stacklinkedlistwithlist.go b/structure/stack/stacklinkedlistwithlist.go index ba3ce6580..ae53a499b 100644 --- a/structure/stack/stacklinkedlistwithlist.go +++ b/structure/stack/stacklinkedlistwithlist.go @@ -16,18 +16,18 @@ import ( // SList is our struct that point to stack with container/list.List library type SList struct { - stack *list.List + Stack *list.List } // Push add a value into our stack func (sl *SList) Push(val any) { - sl.stack.PushFront(val) + sl.Stack.PushFront(val) } // Peak is return last value that insert into our stack -func (sl *SList) Peak() (any, error) { - if !sl.Empty() { - element := sl.stack.Front() +func (sl *SList) Peek() (any, error) { + if !sl.IsEmpty() { + element := sl.Stack.Front() return element.Value, nil } return "", fmt.Errorf("stack list is empty") @@ -36,11 +36,11 @@ func (sl *SList) Peak() (any, error) { // Pop is return last value that insert into our stack // also it will remove it in our stack func (sl *SList) Pop() (any, error) { - if !sl.Empty() { + if !sl.IsEmpty() { // get last element that insert into stack - element := sl.stack.Front() + element := sl.Stack.Front() // remove element in stack - sl.stack.Remove(element) + sl.Stack.Remove(element) // return element value return element.Value, nil } @@ -49,12 +49,12 @@ func (sl *SList) Pop() (any, error) { // Length return length of our stack func (sl *SList) Length() int { - return sl.stack.Len() + return sl.Stack.Len() } // Empty check our stack has value or not -func (sl *SList) Empty() bool { +func (sl *SList) IsEmpty() bool { // check our stack is empty or not // if is 0 it means our stack is empty otherwise is not empty - return sl.stack.Len() == 0 + return sl.Stack.Len() == 0 } From de90bd8c5c48f9bef63aa96c1913e074013987ea Mon Sep 17 00:00:00 2001 From: Flamingo <490493499@qq.com> Date: Wed, 11 Oct 2023 14:05:41 +0800 Subject: [PATCH 430/488] fix: Update generics in counting sort (#676) Co-authored-by: Rak Laptudirm --- sort/countingsort.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sort/countingsort.go b/sort/countingsort.go index 6961efff8..d55a13798 100644 --- a/sort/countingsort.go +++ b/sort/countingsort.go @@ -8,16 +8,27 @@ package sort import "github.com/TheAlgorithms/Go/constraints" -func Count[T constraints.Number](data []int) []int { - var aMin, aMax = -1000, 1000 +func Count[T constraints.Integer](data []T) []T { + if len(data) == 0 { + return data + } + var aMin, aMax = data[0], data[0] + for _, x := range data { + if x < aMin { + aMin = x + } + if x > aMax { + aMax = x + } + } count := make([]int, aMax-aMin+1) for _, x := range data { - count[x-aMin]++ // this is the reason for having only Number constraint instead of Ordered. + count[x-aMin]++ // this is the reason for having only Integer constraint instead of Ordered. } z := 0 for i, c := range count { for c > 0 { - data[z] = i + aMin + data[z] = T(i) + aMin z++ c-- } From be1ce26bd1e08037ea8645883e52b47e25ab56cf Mon Sep 17 00:00:00 2001 From: Randheer Ramesh K <33465991+Randheerrrk@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:47:48 +0530 Subject: [PATCH 431/488] feat: add binary insertion sort algorithm (#671) * feat: add binary insertion sort algorithm * Formatted with gofmt --------- Co-authored-by: randheerrrk <> Co-authored-by: Rak Laptudirm --- sort/binaryinsertionsort.go | 35 +++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 9 ++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 sort/binaryinsertionsort.go diff --git a/sort/binaryinsertionsort.go b/sort/binaryinsertionsort.go new file mode 100644 index 000000000..98b6c5a3d --- /dev/null +++ b/sort/binaryinsertionsort.go @@ -0,0 +1,35 @@ +// Binary Insertion Sort +// description: Implementation of binary insertion sort in Go +// details: Binary Insertion Sort is a variation of +// Insertion sort in which proper location to +// insert the selected element is found using the +// Binary search algorithm. +// ref: https://www.geeksforgeeks.org/binary-insertion-sort + +package sort + +import "github.com/TheAlgorithms/Go/constraints" + +func BinaryInsertion[T constraints.Ordered](arr []T) []T { + for currentIndex := 1; currentIndex < len(arr); currentIndex++ { + temporary := arr[currentIndex] + low := 0 + high := currentIndex - 1 + + for low <= high { + mid := low + (high-low)/2 + if arr[mid] > temporary { + high = mid - 1 + } else { + low = mid + 1 + } + } + + for itr := currentIndex; itr > low; itr-- { + arr[itr] = arr[itr-1] + } + + arr[low] = temporary + } + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 8df55373f..733fa0149 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -76,7 +76,10 @@ func testFramework(t *testing.T, sortingFunction func([]int) []int) { } } -//BEGIN TESTS +// BEGIN TESTS +func TestBinaryInsertion(t *testing.T) { + testFramework(t, sort.BinaryInsertion[int]) +} func TestBubble(t *testing.T) { testFramework(t, sort.Bubble[int]) @@ -219,6 +222,10 @@ func benchmarkFramework(b *testing.B, f func(arr []int) []int) { //BEGIN BENCHMARKS +func BenchmarkBinaryInsertion(b *testing.B) { + benchmarkFramework(b, sort.BinaryInsertion[int]) +} + func BenchmarkBubble(b *testing.B) { benchmarkFramework(b, sort.Bubble[int]) } From dc7ff42efe8c6397b2edaae7fff5cdc580ecc7fe Mon Sep 17 00:00:00 2001 From: ")`(-@_.+_^*__*^" <55359898+11-aryan@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:51:28 +0530 Subject: [PATCH 432/488] refactored comments to comply with godocs (#678) * refactored comments to comply with godocs * added full stop in the end --------- Co-authored-by: Rak Laptudirm --- strings/parenthesis/parenthesis.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/strings/parenthesis/parenthesis.go b/strings/parenthesis/parenthesis.go index 2ae49a641..1fb446ff4 100644 --- a/strings/parenthesis/parenthesis.go +++ b/strings/parenthesis/parenthesis.go @@ -1,14 +1,10 @@ package parenthesis // Parenthesis algorithm checks if every opened parenthesis -// is closed correctly - -// when parcounter is less than 0 is because a closing +// is closed correctly. When parcounter is less than 0 when a closing // parenthesis is detected without an opening parenthesis -// that surrounds it - -// parcounter will be 0 if all open parenthesis are closed -// correctly +// that surrounds it and parcounter will be 0 if all open +// parenthesis are closed correctly. func Parenthesis(text string) bool { parcounter := 0 From a351eab602d055be0c2b484011691895ddda14a2 Mon Sep 17 00:00:00 2001 From: Suhail Malik Date: Wed, 11 Oct 2023 17:38:58 +0530 Subject: [PATCH 433/488] =?UTF-8?q?=D0=90dd=20bogo=20sort=20(#655)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + sort/bogosort.go | 38 ++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 10 ++++++++++ 3 files changed, 49 insertions(+) create mode 100644 sort/bogosort.go diff --git a/README.md b/README.md index 40ec68ed7..7304c78aa 100644 --- a/README.md +++ b/README.md @@ -954,6 +954,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: 1. [`Bubble`](./sort/bubblesort.go#L9): Bubble is a simple generic definition of Bubble sort algorithm. +1. [`Bogo`](./sort/bogosort.go#L32): Bogo generates random permutations until it guesses the correct one. 2. [`Bucket`](./sort/bucketsort.go#L7): Bucket sorts a slice. It is mainly useful when input is uniformly distributed over a range. 3. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. 4. [`Count`](./sort/countingsort.go#L11): No description provided. diff --git a/sort/bogosort.go b/sort/bogosort.go new file mode 100644 index 000000000..a37d18ff8 --- /dev/null +++ b/sort/bogosort.go @@ -0,0 +1,38 @@ +// This is a pure Go implementation of the bogosort algorithm, +// also known as permutation sort, stupid sort, slowsort, shotgun sort, or monkey sort. +// Bogosort generates random permutations until it guesses the correct one. + +// More info on: https://en.wikipedia.org/wiki/Bogosort + +package sort + +import ( + "math/rand" + + "github.com/TheAlgorithms/Go/constraints" +) + +func isSorted[T constraints.Number](arr []T) bool { + for i := 0; i < len(arr)-1; i++ { + if arr[i] > arr[i+1] { + return false + } + } + + return true +} + +func shuffle[T constraints.Number](arr []T) { + for i := range arr { + j := rand.Intn(i + 1) + arr[i], arr[j] = arr[j], arr[i] + } +} + +func Bogo[T constraints.Number](arr []T) []T { + for !isSorted(arr) { + shuffle(arr) + } + + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 733fa0149..0fd0a93fe 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -85,6 +85,11 @@ func TestBubble(t *testing.T) { testFramework(t, sort.Bubble[int]) } +func TestBogo(t *testing.T) { + t.Skip("Skipping test for Bogo Sort, as it uses a lot of resource.") + testFramework(t, sort.Bogo[int]) +} + func TestBucketSort(t *testing.T) { testFramework(t, sort.Bucket[int]) } @@ -230,6 +235,11 @@ func BenchmarkBubble(b *testing.B) { benchmarkFramework(b, sort.Bubble[int]) } +func BenchmarkBogo(b *testing.B) { + b.Skip("Skipping benchmark for Bogo Sort, as it uses a lot of resource.") + benchmarkFramework(b, sort.Bogo[int]) +} + func BenchmarkBucketSort(b *testing.B) { benchmarkFramework(b, sort.Bucket[int]) } From 7a4c099718417a43478b1f8031ed04211e012c43 Mon Sep 17 00:00:00 2001 From: Sayan Bose <111633699+bose-sayan@users.noreply.github.com> Date: Fri, 13 Oct 2023 00:21:02 +0530 Subject: [PATCH 434/488] feat: Add deque structure (#659) * Added Doubly Ended Queue data structure and a few tests to check * Added the doubly ended queue data structure along with a few tests and fixed some linting issues * Added the necessary changes: - Made the member of the DoublyEndedQueue struct private - Removed unnecessary indentations from package comment - Implemented black box testing - Used errors.New() to declare a constant error in case a dequeuing operation is called on an empty deque - Exported the methods of DoublyEndedQueue - Edited the names of getters to follow go's naming conventions. * Removed redundant zero valued variables * Transferred the test file to deque_test package * Removed redundant error variable in deque_test file * refactored the comments to satisfy godoc standard * corrected misspelled words * Update structure/deque/deque.go Refactored comments to be more descriptive Co-authored-by: Taj * Update structure/deque/deque_test.go Removed redundant comments Co-authored-by: Taj * removed redundant comments * Update structure/deque/deque.go Co-authored-by: Taj * Renamed a few method names * Update structure/deque/deque.go Co-authored-by: Taj * Renamed a few variables * Removed redundant comment --------- Co-authored-by: Rak Laptudirm Co-authored-by: Taj --- structure/deque/deque.go | 84 +++++++ structure/deque/deque_test.go | 406 ++++++++++++++++++++++++++++++++++ 2 files changed, 490 insertions(+) create mode 100644 structure/deque/deque.go create mode 100644 structure/deque/deque_test.go diff --git a/structure/deque/deque.go b/structure/deque/deque.go new file mode 100644 index 000000000..538703596 --- /dev/null +++ b/structure/deque/deque.go @@ -0,0 +1,84 @@ +// description: Double Ended Queue is a generalized version of Queue data structure that allows insert and delete at both ends. +// References: +// Wikipedia : https://en.wikipedia.org/wiki/Double-ended_queue +// Github: https://www.geeksforgeeks.org/deque-set-1-introduction-applications/ +// author [Sayan](https://github.com/bose-sayan) + +// Package deque implements a Double Ended Queue data structure. +package deque + +import ( + "errors" +) + +// ErrEmptyDequeue is a custom error for handling cases when some dequeuing operation is performed on an empty deque. +var ErrEmptyDequeue = errors.New("DoublyEnded queue is empty, so can't perform this operation") + +type DoublyEndedQueue[T any] struct { + deque []T +} + +// New returns a new DoublyEndedQueue. +func New[T any]() *DoublyEndedQueue[T] { + return &DoublyEndedQueue[T]{deque: make([]T, 0)} +} + +// EnqueueFront adds an item at the front of Deque. +func (dq *DoublyEndedQueue[T]) EnqueueFront(item T) { + dq.deque = append([]T{item}, dq.deque...) +} + +// EnqueueRear adds an item at the rear of Deque. +func (dq *DoublyEndedQueue[T]) EnqueueRear(item T) { + dq.deque = append(dq.deque, item) +} + +// DequeueFront deletes an item from front of Deque and returns it. +func (dq *DoublyEndedQueue[T]) DequeueFront() (T, error) { + if len(dq.deque) == 0 { + var zeroVal T + return zeroVal, ErrEmptyDequeue + } + frontElement := dq.deque[0] + dq.deque = dq.deque[1:] + return frontElement, nil +} + +// DequeueRear deletes an item from rear of Deque and returns it. +func (dq *DoublyEndedQueue[T]) DequeueRear() (T, error) { + if len(dq.deque) == 0 { + var zeroVal T + return zeroVal, ErrEmptyDequeue + } + rearElement := dq.deque[len(dq.deque)-1] + dq.deque = dq.deque[:len(dq.deque)-1] + return rearElement, nil +} + +// Front gets the front item from queue. +func (dq *DoublyEndedQueue[T]) Front() (T, error) { + if (len(dq.deque)) == 0 { + var zeroVal T + return zeroVal, ErrEmptyDequeue + } + return dq.deque[0], nil +} + +// Rear gets the last item from queue. +func (dq *DoublyEndedQueue[T]) Rear() (T, error) { + if (len(dq.deque)) == 0 { + var zeroVal T + return zeroVal, ErrEmptyDequeue + } + return dq.deque[len(dq.deque)-1], nil +} + +// IsEmpty checks whether Deque is empty or not. +func (dq *DoublyEndedQueue[T]) IsEmpty() bool { + return len(dq.deque) == 0 +} + +// Length gets the length of Deque. +func (dq *DoublyEndedQueue[T]) Length() int { + return len(dq.deque) +} diff --git a/structure/deque/deque_test.go b/structure/deque/deque_test.go new file mode 100644 index 000000000..26439e5be --- /dev/null +++ b/structure/deque/deque_test.go @@ -0,0 +1,406 @@ +// +// This file contains unit tests for the deque package. +// The tests cover the following scenarios: +// - Empty deque +// - Deque with one element +// - Deque with multiple elements +// The tests are parameterized with int and string types. +// Each test case is defined with a description and a list of queries to be executed on the deque. +// The expected results and errors are also defined for each query. +// + +package deque_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/structure/deque" +) + +type QueryStructure[T any] struct { + queryType string + parameter T + expectedResult interface{} + expectedError error +} + +type TestCaseData[T any] struct { + description string + queries []QueryStructure[T] +} + +func TestDeque(t *testing.T) { + + // Test cases with ints as params + testCasesInt := []TestCaseData[int]{ + { + description: "Test empty deque", + queries: []QueryStructure[int]{ + { + queryType: "IsEmpty", + expectedResult: true, + expectedError: nil, + }, + { + queryType: "Front", + expectedError: deque.ErrEmptyDequeue, + }, + { + queryType: "Rear", + expectedError: deque.ErrEmptyDequeue, + }, + { + queryType: "DeQueueFront", + expectedError: deque.ErrEmptyDequeue, + }, + { + queryType: "DeQueueRear", + expectedError: deque.ErrEmptyDequeue, + }, + { + queryType: "Length", + expectedResult: 0, + expectedError: nil, + }, + }, + }, + { + description: "Test deque with one element", + queries: []QueryStructure[int]{ + { + queryType: "EnQueueFront", + parameter: 1, + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: false, + expectedError: nil, + }, + { + queryType: "Front", + expectedResult: 1, + expectedError: nil, + }, + { + queryType: "Rear", + expectedResult: 1, + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 1, + expectedError: nil, + }, + { + queryType: "DeQueueFront", + expectedResult: 1, + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: true, + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 0, + expectedError: nil, + }, + }, + }, + { + description: "Test deque with multiple elements", + queries: []QueryStructure[int]{ + { + queryType: "EnQueueFront", + parameter: 1, + expectedError: nil, + }, + { + queryType: "EnQueueFront", + parameter: 2, + expectedError: nil, + }, + { + queryType: "EnQueueRear", + parameter: 3, + expectedError: nil, + }, + { + queryType: "EnQueueRear", + parameter: 4, + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: false, + expectedError: nil, + }, + { + queryType: "Front", + expectedResult: 2, + expectedError: nil, + }, + { + queryType: "Rear", + expectedResult: 4, + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 4, + expectedError: nil, + }, + { + queryType: "DeQueueFront", + expectedResult: 2, + expectedError: nil, + }, + { + queryType: "DeQueueRear", + expectedResult: 4, + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: false, + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 2, + expectedError: nil, + }, + }, + }, + } + + // Test cases with strings as params + testCasesString := []TestCaseData[string]{ + { + description: "Test one element deque", + queries: []QueryStructure[string]{ + { + queryType: "EnQueueFront", + parameter: "a", + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: false, + expectedError: nil, + }, + { + queryType: "Front", + expectedResult: "a", + expectedError: nil, + }, + { + queryType: "Rear", + expectedResult: "a", + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 1, + expectedError: nil, + }, + { + queryType: "DeQueueFront", + expectedResult: "a", + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: true, + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 0, + expectedError: nil, + }, + }, + }, + { + description: "Test multiple elements deque", + queries: []QueryStructure[string]{ + { + queryType: "EnQueueFront", + parameter: "a", + expectedError: nil, + }, + { + queryType: "EnQueueFront", + parameter: "b", + expectedError: nil, + }, + { + queryType: "EnQueueRear", + parameter: "c", + expectedError: nil, + }, + { + queryType: "EnQueueRear", + parameter: "d", + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: false, + expectedError: nil, + }, + { + queryType: "Front", + expectedResult: "b", + expectedError: nil, + }, + { + queryType: "Rear", + expectedResult: "d", + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 4, + expectedError: nil, + }, + { + queryType: "DeQueueFront", + expectedResult: "b", + expectedError: nil, + }, + { + queryType: "DeQueueRear", + expectedResult: "d", + expectedError: nil, + }, + { + queryType: "IsEmpty", + expectedResult: false, + expectedError: nil, + }, + { + queryType: "Length", + expectedResult: 2, + expectedError: nil, + }, + }, + }, + } + + // Run tests with ints + for _, testCase := range testCasesInt { + t.Run(testCase.description, func(t *testing.T) { + dq := deque.New[int]() + for _, query := range testCase.queries { + switch query.queryType { + case "EnQueueFront": + dq.EnqueueFront(query.parameter) + case "EnQueueRear": + dq.EnqueueRear(query.parameter) + case "DeQueueFront": + result, err := dq.DequeueFront() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v", query.expectedResult, result) + } + case "DeQueueRear": + result, err := dq.DequeueRear() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v", query.expectedResult, result) + } + case "Front": + result, err := dq.Front() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v, %v", query.expectedResult, result, testCase.description) + } + case "Rear": + result, err := dq.Rear() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v", query.expectedResult, result) + } + case "IsEmpty": + result := dq.IsEmpty() + if result != query.expectedResult { + t.Errorf("Expected error: %v, got : %v", query.expectedResult, result) + } + case "Length": + result := dq.Length() + if result != query.expectedResult { + t.Errorf("Expected %v got %v", query.expectedResult, result) + } + } + } + }) + } + + // Run tests with strings + for _, testCase := range testCasesString { + t.Run(testCase.description, func(t *testing.T) { + dq := deque.New[string]() + for _, query := range testCase.queries { + switch query.queryType { + case "EnQueueFront": + dq.EnqueueFront(query.parameter) + case "EnQueueRear": + dq.EnqueueRear(query.parameter) + case "DeQueueFront": + result, err := dq.DequeueFront() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v", query.expectedResult, result) + } + case "DeQueueRear": + result, err := dq.DequeueRear() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v", query.expectedResult, result) + } + case "Front": + result, err := dq.Front() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v, %v", query.expectedResult, result, testCase.description) + } + case "Rear": + result, err := dq.Rear() + if err != query.expectedError { + t.Errorf("Expected error: %v, got : %v", query.expectedError, err) + } + if err == nil && result != query.expectedResult { + t.Errorf("Expected %v, got %v", query.expectedResult, result) + } + case "IsEmpty": + result := dq.IsEmpty() + if result != query.expectedResult { + t.Errorf("Expected %v, got %v", query.expectedResult, result) + } + case "Length": + result := dq.Length() + if result != query.expectedResult { + t.Errorf("Expected %v got %v", query.expectedResult, result) + } + } + } + }) + } +} From 5206ad3945b2a8b58bb0a89ba78962401925dca6 Mon Sep 17 00:00:00 2001 From: Pratik Tripathy <117454569+SilverDragonOfR@users.noreply.github.com> Date: Fri, 13 Oct 2023 19:39:46 +0530 Subject: [PATCH 435/488] feat: Add Automorphic number algorithm and test (#681) * feat: add sum of digit algorithm * test: add test for sum of digit algorithm * Updated Documentation in README.md * fix: removed digit sum folder * feat: add automophic algorithm and tests * Updated Documentation in README.md * Updated Documentation in README.md * fix: remove spaces, comments. add type parameters * Updated Documentation in README.md * Updated Documentation in README.md * fix: moved automorphic files to math package * Updated Documentation in README.md * fix: removed spaces and unnecessary comments * Updated Documentation in README.md * Updated Documentation in README.md * fix: empty commit as per request --------- Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Rak Laptudirm --- README.md | 178 ++++++++++++++++++++++++++----------- math/isautomorphic.go | 32 +++++++ math/isautomorphic_test.go | 58 ++++++++++++ 3 files changed, 215 insertions(+), 53 deletions(-) create mode 100644 math/isautomorphic.go create mode 100644 math/isautomorphic_test.go diff --git a/README.md b/README.md index 7304c78aa..683c7154c 100644 --- a/README.md +++ b/README.md @@ -70,15 +70,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Abs`](./math/binary/abs.go#L10): Abs returns absolute value using binary operation Principle of operation: 1) Get the mask by right shift by the base 2) Base is the size of an integer variable in bits, for example, for int32 it will be 32, for int64 it will be 64 3) For negative numbers, above step sets mask as 1 1 1 1 1 1 1 1 and 0 0 0 0 0 0 0 0 for positive numbers. 4) Add the mask to the given number. 5) XOR of mask + n and mask gives the absolute value. 2. [`BitCounter`](./math/binary/bitcounter.go#L11): BitCounter - The function returns the number of set bits for an unsigned integer number -3. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L21): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. -4. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L28): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 -5. [`LogBase2`](./math/binary/logarithm.go#L7): LogBase2 Finding the exponent of n = 2**x using bitwise operations (logarithm in base 2 of n) [See more](https://en.wikipedia.org/wiki/Logarithm) -6. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations -7. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift -8. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. -9. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n -10. [`Sqrt`](./math/binary/sqrt.go#L16): No description provided. -11. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence +3. [`FastInverseSqrt`](./math/binary/fast_inverse_sqrt.go#L15): FastInverseSqrt assumes that argument is always positive, and it does not deal with negative numbers. The "magic" number 0x5f3759df is hex for 1597463007 in decimals. The math.Float32bits is alias to *(*uint32)(unsafe.Pointer(&f)) and math.Float32frombits is to *(*float32)(unsafe.Pointer(&b)). +4. [`IsPowerOfTwo`](./math/binary/checkisnumberpoweroftwo.go#L21): IsPowerOfTwo This function uses the fact that powers of 2 are represented like 10...0 in binary, and numbers one less than the power of 2 are represented like 11...1. Therefore, using the and function: 10...0 & 01...1 00...0 -> 0 This is also true for 0, which is not a power of 2, for which we have to add and extra condition. +5. [`IsPowerOfTwoLeftShift`](./math/binary/checkisnumberpoweroftwo.go#L28): IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, which in decimal system is 8 or = 2 * 2 * 2 +6. [`LogBase2`](./math/binary/logarithm.go#L7): LogBase2 Finding the exponent of n = 2**x using bitwise operations (logarithm in base 2 of n) [See more](https://en.wikipedia.org/wiki/Logarithm) +7. [`MeanUsingAndXor`](./math/binary/arithmeticmean.go#L12): MeanUsingAndXor This function finds arithmetic mean using "AND" and "XOR" operations +8. [`MeanUsingRightShift`](./math/binary/arithmeticmean.go#L17): MeanUsingRightShift This function finds arithmetic mean using right shift +9. [`ReverseBits`](./math/binary/reversebits.go#L14): ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result and finally move on to the next bit in the input number. Repeat this till all its bits are processed. +10. [`SequenceGrayCode`](./math/binary/rbc.go#L11): SequenceGrayCode The function generates an "Gray code" sequence of length n +11. [`Sqrt`](./math/binary/sqrt.go#L10): No description provided. +12. [`XorSearchMissingNumber`](./math/binary/xorsearch.go#L11): XorSearchMissingNumber This function finds a missing number in a sequence ---
@@ -232,6 +233,38 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 9. [`Reverse`](./conversion/decimaltobinary.go#L22): Reverse() function that will take string, and returns the reverse of that string. 10. [`RomanToInt`](./conversion/romantoint.go#L40): RomanToInt converts a roman numeral string to an integer. Roman numerals for numbers outside the range 1 to 3,999 will return an error. Nil or empty string return 0 with no error thrown. +--- +
+ deque + +--- + +##### Package deque implements a Double Ended Queue data structure. + +--- +##### Functions: + +1. [`New`](./structure/deque/deque.go#L22): New returns a new DoublyEndedQueue. + +--- +##### Types + +1. [`DoublyEndedQueue`](./structure/deque/deque.go#L17): No description provided. + + +--- +
+ deque_test + +--- + +##### Types + +1. [`QueryStructure`](./structure/deque/deque_test.go#L20): No description provided. + +2. [`TestCaseData`](./structure/deque/deque_test.go#L27): No description provided. + + ---
diffiehellman @@ -421,7 +454,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 10. [`NewDSU`](./graph/kruskal.go#L34): NewDSU will return an initialised DSU using the value of n which will be treated as the number of elements out of which the DSU is being made 11. [`NewTree`](./graph/lowestcommonancestor.go#L84): No description provided. 12. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. -13. [`Topological`](./graph/topological.go#L7): Assumes that graph given is valid and possible to get a topo ordering. constraints are array of []int{a, b}, representing an edge going from a to b +13. [`Topological`](./graph/topological.go#L7): Topological assumes that graph given is valid and that its possible to get a topological ordering. constraints are array of []int{a, b}, representing an edge going from a to b --- ##### Types @@ -509,6 +542,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. Methods: 1. [`Less`](./structure/heap/heap_test.go#L20): No description provided. +--- +
+ horspool + +--- + +##### Functions: + +1. [`Horspool`](./strings/horspool/horspool.go#L10): No description provided. + ---
kmp @@ -592,7 +635,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### filename : krishnamurthy.go description: A program which contains the function that returns true if a given number is Krishnamurthy number or not. details: A number is a Krishnamurthy number if the sum of all the factorials of the digits is equal to the number. Ex: 1! = 1, 145 = 1! + 4! + 5! author(s): [GooMonk](https://github.com/GooMonk) see krishnamurthy_test.go Package math is a package that contains mathematical algorithms and its different implementations. +##### Package math is a package that contains mathematical algorithms and its different implementations. filename : krishnamurthy.go description: A program which contains the function that returns true if a given number is Krishnamurthy number or not. details: A number is a Krishnamurthy number if the sum of all the factorials of the digits is equal to the number. Ex: 1! = 1, 145 = 1! + 4! + 5! author(s): [GooMonk](https://github.com/GooMonk) see krishnamurthy_test.go --- ##### Functions: @@ -604,20 +647,21 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 5. [`DefaultPolynomial`](./math/pollard.go#L16): DefaultPolynomial is the commonly used polynomial g(x) = (x^2 + 1) mod n 6. [`FindKthMax`](./math/kthnumber.go#L11): FindKthMax returns the kth large element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. 7. [`FindKthMin`](./math/kthnumber.go#L19): FindKthMin returns kth small element given an integer slice with nil `error` if found and returns -1 with `error` `search.ErrNotFound` if not found. NOTE: The `nums` slice gets mutated in the process. -8. [`IsKrishnamurthyNumber`](./math/krishnamurthy.go#L12): IsKrishnamurthyNumber returns if the provided number n is a Krishnamurthy number or not. -9. [`IsPerfectNumber`](./math/perfectnumber.go#L34): Checks if inNumber is a perfect number -10. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. -11. [`Lerp`](./math/lerp.go#L5): Lerp or Linear interpolation This function will return new value in 't' percentage between 'v0' and 'v1' -12. [`LiouvilleLambda`](./math/liouville.go#L24): Lambda is the liouville function This function returns λ(n) for given number -13. [`Mean`](./math/mean.go#L7): No description provided. -14. [`Median`](./math/median.go#L12): No description provided. -15. [`Mode`](./math/mode.go#L19): No description provided. -16. [`Mu`](./math/mobius.go#L21): Mu is the Mobius function This function returns μ(n) for given number -17. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. -18. [`PollardsRhoFactorization`](./math/pollard.go#L29): PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm using the default parameters x = y = 2 -19. [`PronicNumber`](./math/pronicnumber.go#L15): PronicNumber returns true if argument passed to the function is pronic and false otherwise. -20. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) -21. [`SumOfProperDivisors`](./math/perfectnumber.go#L17): Returns the sum of proper divisors of inNumber. +8. [`IsAutomorphic`](./math/isautomorphic.go#L16): No description provided. +9. [`IsKrishnamurthyNumber`](./math/krishnamurthy.go#L12): IsKrishnamurthyNumber returns if the provided number n is a Krishnamurthy number or not. +10. [`IsPerfectNumber`](./math/perfectnumber.go#L34): Checks if inNumber is a perfect number +11. [`IsPowOfTwoUseLog`](./math/checkisnumberpoweroftwo.go#L10): IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. The limiting degree can be from 0 to 63. See alternatives in the binary package. +12. [`Lerp`](./math/lerp.go#L5): Lerp or Linear interpolation This function will return new value in 't' percentage between 'v0' and 'v1' +13. [`LiouvilleLambda`](./math/liouville.go#L24): Lambda is the liouville function This function returns λ(n) for given number +14. [`Mean`](./math/mean.go#L7): No description provided. +15. [`Median`](./math/median.go#L12): No description provided. +16. [`Mode`](./math/mode.go#L19): No description provided. +17. [`Mu`](./math/mobius.go#L21): Mu is the Mobius function This function returns μ(n) for given number +18. [`Phi`](./math/eulertotient.go#L5): Phi is the Euler totient function. This function computes the number of numbers less then n that are coprime with n. +19. [`PollardsRhoFactorization`](./math/pollard.go#L29): PollardsRhoFactorization is an implementation of Pollard's rho factorization algorithm using the default parameters x = y = 2 +20. [`PronicNumber`](./math/pronicnumber.go#L15): PronicNumber returns true if argument passed to the function is pronic and false otherwise. +21. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) +22. [`SumOfProperDivisors`](./math/perfectnumber.go#L17): Returns the sum of proper divisors of inNumber. ---
@@ -718,7 +762,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`Parenthesis`](./strings/parenthesis/parenthesis.go#L12): parcounter will be 0 if all open parenthesis are closed correctly +1. [`Parenthesis`](./strings/parenthesis/parenthesis.go#L8): Parenthesis algorithm checks if every opened parenthesis is closed correctly. When parcounter is less than 0 when a closing parenthesis is detected without an opening parenthesis that surrounds it and parcounter will be 0 if all open parenthesis are closed correctly. ---
@@ -925,7 +969,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- -##### package set implements a Set using generics and a golang map with comparable interface key. This implies that only the types that are accepted as valid map keys can be used as set elements +##### package set implements a Set using a golang map. This implies that only the types that are accepted as valid map keys can be used as set elements. For instance, do not try to Add a slice, or the program will panic. --- ##### Functions: @@ -953,29 +997,31 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. --- ##### Functions: -1. [`Bubble`](./sort/bubblesort.go#L9): Bubble is a simple generic definition of Bubble sort algorithm. -1. [`Bogo`](./sort/bogosort.go#L32): Bogo generates random permutations until it guesses the correct one. -2. [`Bucket`](./sort/bucketsort.go#L7): Bucket sorts a slice. It is mainly useful when input is uniformly distributed over a range. -3. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. -4. [`Count`](./sort/countingsort.go#L11): No description provided. -5. [`Cycle`](./sort/cyclesort.go#L10): Cycle sort is an in-place, unstable sorting algorithm that is particularly useful when sorting arrays containing elements with a small range of values. It is theoretically optimal in terms of the total number of writes to the original array. -6. [`Exchange`](./sort/exchangesort.go#L8): No description provided. -7. [`HeapSort`](./sort/heapsort.go#L116): No description provided. -8. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort -9. [`Insertion`](./sort/insertionsort.go#L5): No description provided. -10. [`Merge`](./sort/mergesort.go#L41): Merge Perform merge sort on a slice -11. [`MergeIter`](./sort/mergesort.go#L55): No description provided. -12. [`Pancake`](./sort/pancakesort.go#L8): Pancake sorts a slice using flip operations, where flip refers to the idea of reversing the slice from index `0` to `i`. -13. [`ParallelMerge`](./sort/mergesort.go#L66): ParallelMerge Perform merge sort on a slice using goroutines -14. [`Partition`](./sort/quicksort.go#L12): No description provided. -15. [`Patience`](./sort/patiencesort.go#L13): No description provided. -16. [`Pigeonhole`](./sort/pigeonholesort.go#L15): Pigeonhole sorts a slice using pigeonhole sorting algorithm. NOTE: To maintain time complexity O(n + N), this is the reason for having only Integer constraint instead of Ordered. -17. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array -18. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array -19. [`RadixSort`](./sort/radixsort.go#L43): No description provided. -20. [`Selection`](./sort/selectionsort.go#L5): No description provided. -21. [`Shell`](./sort/shellsort.go#L5): No description provided. -22. [`Simple`](./sort/simplesort.go#L13): No description provided. +1. [`BinaryInsertion`](./sort/binaryinsertionsort.go#L13): No description provided. +2. [`Bogo`](./sort/bogosort.go#L32): No description provided. +3. [`Bubble`](./sort/bubblesort.go#L9): Bubble is a simple generic definition of Bubble sort algorithm. +4. [`Bucket`](./sort/bucketsort.go#L7): Bucket sorts a slice. It is mainly useful when input is uniformly distributed over a range. +5. [`Cocktail`](./sort/cocktailsort.go#L9): Cocktail sort is a variation of bubble sort, operating in two directions (beginning to end, end to beginning) +6. [`Comb`](./sort/combSort.go#L17): Comb is a simple sorting algorithm which is an improvement of the bubble sorting algorithm. +7. [`Count`](./sort/countingsort.go#L11): No description provided. +8. [`Cycle`](./sort/cyclesort.go#L10): Cycle sort is an in-place, unstable sorting algorithm that is particularly useful when sorting arrays containing elements with a small range of values. It is theoretically optimal in terms of the total number of writes to the original array. +9. [`Exchange`](./sort/exchangesort.go#L8): No description provided. +10. [`HeapSort`](./sort/heapsort.go#L116): No description provided. +11. [`ImprovedSimple`](./sort/simplesort.go#L27): ImprovedSimple is a improve SimpleSort by skipping an unnecessary comparison of the first and last. This improved version is more similar to implementation of insertion sort +12. [`Insertion`](./sort/insertionsort.go#L5): No description provided. +13. [`Merge`](./sort/mergesort.go#L41): Merge Perform merge sort on a slice +14. [`MergeIter`](./sort/mergesort.go#L55): No description provided. +15. [`Pancake`](./sort/pancakesort.go#L8): Pancake sorts a slice using flip operations, where flip refers to the idea of reversing the slice from index `0` to `i`. +16. [`ParallelMerge`](./sort/mergesort.go#L66): ParallelMerge Perform merge sort on a slice using goroutines +17. [`Partition`](./sort/quicksort.go#L12): No description provided. +18. [`Patience`](./sort/patiencesort.go#L13): No description provided. +19. [`Pigeonhole`](./sort/pigeonholesort.go#L15): Pigeonhole sorts a slice using pigeonhole sorting algorithm. NOTE: To maintain time complexity O(n + N), this is the reason for having only Integer constraint instead of Ordered. +20. [`Quicksort`](./sort/quicksort.go#L39): Quicksort Sorts the entire array +21. [`QuicksortRange`](./sort/quicksort.go#L26): QuicksortRange Sorts the specified range within the array +22. [`RadixSort`](./sort/radixsort.go#L43): No description provided. +23. [`Selection`](./sort/selectionsort.go#L5): No description provided. +24. [`Shell`](./sort/shellsort.go#L5): No description provided. +25. [`Simple`](./sort/simplesort.go#L13): No description provided. --- ##### Types @@ -983,19 +1029,45 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`MaxHeap`](./sort/heapsort.go#L5): No description provided. +--- +
+ sqrt + +--- + +##### Package sqrt contains algorithms and data structures that contains a √n in their complexity + +--- +##### Functions: + +1. [`NewSqrtDecomposition`](./sqrt/sqrtdecomposition.go#L34): Create a new SqrtDecomposition instance with the parameters as specified by SqrtDecomposition comment Assumptions: - len(elements) > 0 + +--- +##### Types + +1. [`SqrtDecomposition`](./sqrt/sqrtdecomposition.go#L21): No description provided. + + ---
stack --- +##### Functions: + +1. [`NewStack`](./structure/stack/stackarray.go#L17): NewStack creates and returns a new stack. + +--- ##### Types -1. [`Node`](./structure/stack/stacklinkedlist.go#L13): No description provided. +1. [`Array`](./structure/stack/stackarray.go#L12): No description provided. + +2. [`Node`](./structure/stack/stacklinkedlist.go#L13): No description provided. -2. [`SList`](./structure/stack/stacklinkedlistwithlist.go#L18): No description provided. +3. [`SList`](./structure/stack/stacklinkedlistwithlist.go#L18): No description provided. -3. [`Stack`](./structure/stack/stacklinkedlist.go#L19): No description provided. +4. [`Stack`](./structure/stack/stacklinkedlist.go#L19): No description provided. --- diff --git a/math/isautomorphic.go b/math/isautomorphic.go new file mode 100644 index 000000000..855d224a1 --- /dev/null +++ b/math/isautomorphic.go @@ -0,0 +1,32 @@ +// isautomorphic.go +// description: Checks whether a whole number integer is Automorphic or not. If number < 0 then returns false. +// details: +// In mathematics, a number n is said to be a Automorphic number if the square of n ends in the same digits as n itself. +// ref: (https://en.wikipedia.org/wiki/Automorphic_number) +// time complexity: O(log10(N)) +// space complexity: O(1) +// author: [SilverDragonOfR](https://github.com/SilverDragonOfR) + +package math + +import ( + "github.com/TheAlgorithms/Go/constraints" +) + +func IsAutomorphic[T constraints.Integer](n T) bool { + // handling the negetive number case + if n < 0 { + return false + } + + n_sq := n * n + for n > 0 { + if (n % 10) != (n_sq % 10) { + return false + } + n /= 10 + n_sq /= 10 + } + + return true +} diff --git a/math/isautomorphic_test.go b/math/isautomorphic_test.go new file mode 100644 index 000000000..d8494b921 --- /dev/null +++ b/math/isautomorphic_test.go @@ -0,0 +1,58 @@ +package math + +import ( + "testing" +) + +var testCases = []struct { + name string + input int + expected bool +}{ + { + "negetive number: not Automorphic", + -1, + false, + }, + { + "negetive number: not Automorphic", + -146, + false, + }, + { + "0: is Automorphic", + 0, + true, + }, + { + "1: is Automorphic", + 1, + true, + }, + { + "7: not Automorphic", + 7, + false, + }, + { + "83: not Automorphic", + 83, + false, + }, + { + "376: is Automorphic", + 376, + true, + }, +} + +func TestIsAutomorphic(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + funcResult := IsAutomorphic(test.input) + if test.expected != funcResult { + t.Errorf("Expected answer '%t' for the number '%d' but answer given was %t", test.expected, test.input, funcResult) + } + }) + } +} From b2fc7e502f6fc7910271a11f5079a87aa2e7af07 Mon Sep 17 00:00:00 2001 From: Norman Soetbeer Date: Mon, 16 Oct 2023 18:43:40 +0200 Subject: [PATCH 436/488] feat: add recursive fibonacci (#686) --- README.md | 1 + math/fibonacci/fibonacci.go | 10 ++++++++++ math/fibonacci/fibonacci_test.go | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/README.md b/README.md index 683c7154c..33134ef6f 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Formula`](./math/fibonacci/fibonacci.go#L42): Formula This function calculates the n-th fibonacci number using the [formula](https://en.wikipedia.org/wiki/Fibonacci_number#Relation_to_the_golden_ratio) Attention! Tests for large values fall due to rounding error of floating point numbers, works well, only on small numbers 2. [`Matrix`](./math/fibonacci/fibonacci.go#L15): Matrix This function calculates the n-th fibonacci number using the matrix method. [See](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) +3. [`Recursive`](./math/fibonacci/fibonacci.go#L51): Recursive calculates the n-th fibonacci number recursively by adding the previous two numbers. [See](https://en.wikipedia.org/wiki/Fibonacci_sequence#Definition) ---
diff --git a/math/fibonacci/fibonacci.go b/math/fibonacci/fibonacci.go index 9718acbbc..92e69ae08 100644 --- a/math/fibonacci/fibonacci.go +++ b/math/fibonacci/fibonacci.go @@ -45,3 +45,13 @@ func Formula(n uint) uint { powPhi := math.Pow(phi, float64(n)) return uint(powPhi/sqrt5 + 0.5) } + +// Recursive calculates the n-th fibonacci number recursively by adding the previous two Fibonacci numbers. +// This algorithm is extremely slow for bigger numbers, but provides a simpler implementation. +func Recursive(n uint) uint { + if n <= 1 { + return n + } + + return Recursive(n-1) + Recursive(n-2) +} diff --git a/math/fibonacci/fibonacci_test.go b/math/fibonacci/fibonacci_test.go index 990930251..bfdbed0bc 100644 --- a/math/fibonacci/fibonacci_test.go +++ b/math/fibonacci/fibonacci_test.go @@ -64,6 +64,19 @@ func TestFormula(t *testing.T) { } } +func TestRecursive(t *testing.T) { + tests := getTests() + for _, test := range tests { + if test.n <= 10 { + t.Run(test.name, func(t *testing.T) { + if got := Recursive(test.n); got != test.want { + t.Errorf("Return value = %v, want %v", got, test.want) + } + }) + } + } +} + func BenchmarkNthFibonacci(b *testing.B) { for i := 0; i < b.N; i++ { dynamic.NthFibonacci(90) From 25dea82b15b0f668ce6ba77d2187e712997eb720 Mon Sep 17 00:00:00 2001 From: Taj Date: Mon, 16 Oct 2023 20:30:53 +0100 Subject: [PATCH 437/488] Use citk (#639) --- .github/workflows/citk.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/citk.yml diff --git a/.github/workflows/citk.yml b/.github/workflows/citk.yml new file mode 100644 index 000000000..ce9360c36 --- /dev/null +++ b/.github/workflows/citk.yml @@ -0,0 +1,28 @@ +# https://github.com/golangci/golangci-lint +name: CI tool kit +on: + pull_request: + +jobs: + CITK: + name: Code style and tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: "^1.18" + - name: Checkout branch + run: | + git fetch origin master:master + - name: Install citk tool + run: | + go install github.com/tjgurwara99/citk@latest + - name: Run citk tool + run: | + citk check -l go -b master From e255e17c00928db982dc3f8a4d68cfa7732a4b0d Mon Sep 17 00:00:00 2001 From: SANJIB GIRI <31872288+sanjibgirics@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:54:24 +0530 Subject: [PATCH 438/488] feat: Add isSubsequence string algorithm (#684) --- strings/issubsequence.go | 35 ++++++++++++++++ strings/issubsequence_test.go | 75 +++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 strings/issubsequence.go create mode 100644 strings/issubsequence_test.go diff --git a/strings/issubsequence.go b/strings/issubsequence.go new file mode 100644 index 000000000..8d34177e9 --- /dev/null +++ b/strings/issubsequence.go @@ -0,0 +1,35 @@ +// Checks if a given string is a subsequence of another string. +// A subsequence of a given string is a string that can be derived from the given +// string by deleting some or no characters without changing the order of the +// remaining characters. (i.e., "dpr" is a subsequence of "depqr" while "drp" is not). +// Author: sanjibgirics + +package strings + +// Returns true if s is subsequence of t, otherwise return false. +func IsSubsequence(s string, t string) bool { + if len(s) > len(t) { + return false + } + + if s == t { + return true + } + + if len(s) == 0 { + return true + } + + sIndex := 0 + for tIndex := 0; tIndex < len(t); tIndex++ { + if s[sIndex] == t[tIndex] { + sIndex++ + } + + if sIndex == len(s) { + return true + } + } + + return false +} diff --git a/strings/issubsequence_test.go b/strings/issubsequence_test.go new file mode 100644 index 000000000..1b8c4cba4 --- /dev/null +++ b/strings/issubsequence_test.go @@ -0,0 +1,75 @@ +package strings_test + +import ( + "reflect" + "testing" + + "github.com/TheAlgorithms/Go/strings" +) + +func TestIsSubsequence(t *testing.T) { + var testCases = []struct { + name string + s string + t string + expected bool + }{ + { + "Valid case 1 ", + "ace", + "abcde", + true, + }, + { + "Invalid case 1", + "aec", + "abcde", + false, + }, + { + "Empty strings", + "", + "", + true, + }, + { + "s is more then t", + "aeccccc", + "abcde", + false, + }, + { + "s is empty", + "", + "abcde", + true, + }, + { + "Equal strings", + "aec", + "aec", + true, + }, + { + "Valid case 2", + "pyr", + "wpxqyrz", + true, + }, + { + "Invalid case 2", + "prx", + "wpxqyrz", + false, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + funcResult := strings.IsSubsequence(test.s, test.t) + if !reflect.DeepEqual(test.expected, funcResult) { + t.Errorf("expected: %v, got %v", test.expected, funcResult) + } + }) + } +} From f2de2860f61ba7601ceb2b7fbbcc147b6d34cf7c Mon Sep 17 00:00:00 2001 From: Mugdha Behere <50405769+MugdhaBehere@users.noreply.github.com> Date: Wed, 25 Oct 2023 03:21:35 +0530 Subject: [PATCH 439/488] Feat: Add Union Find Algorithm, Test: Add test for Union Find Algorithm (#687) * feat:Add Union Find(Dynamic Connectivity)Algorithm * test: Add test for Union Find Algorithm * docs: made changes to comment structure * fix: removed an error in the code * fix: removed errors in unionfind_test.go * fix: updata kruskal's algorithm * fix: update kruskal_test.go * fix: updated comments kruskal.go * fix: removed code redundancy * fix: removed main function * fix: changes to code * fix: updated the code * fix: updated code * fix: removed redundant spaces between comments * fix: formatted code with gofmt * fix: updated code * fix: formatted the files again --- graph/kruskal.go | 102 +++++++--------------------- graph/kruskal_test.go | 147 ++++++++++------------------------------ graph/unionfind.go | 59 ++++++++++++++++ graph/unionfind_test.go | 32 +++++++++ 4 files changed, 149 insertions(+), 191 deletions(-) create mode 100644 graph/unionfind.go create mode 100644 graph/unionfind_test.go diff --git a/graph/kruskal.go b/graph/kruskal.go index c6f094020..0543e2829 100644 --- a/graph/kruskal.go +++ b/graph/kruskal.go @@ -1,6 +1,10 @@ // KRUSKAL'S ALGORITHM -// https://cp-algorithms.com/data_structures/disjoint_set_union.html -// https://cp-algorithms.com/graph/mst_kruskal_with_dsu.html +// Reference: Kruskal's Algorithm: https://www.scaler.com/topics/data-structures/kruskal-algorithm/ +// Reference: Union Find Algorithm: https://www.scaler.com/topics/data-structures/disjoint-set/ +// Author: Author: Mugdha Behere[https://github.com/MugdhaBehere] +// Worst Case Time Complexity: O(E log E), where E is the number of edges. +// Worst Case Space Complexity: O(V + E), where V is the number of vertices and E is the number of edges. +// see kruskal.go, kruskal_test.go package graph @@ -10,104 +14,44 @@ import ( type Vertex int -// Edge describes the edge of a weighted graph type Edge struct { Start Vertex End Vertex Weight int } -// DisjointSetUnionElement describes what an element of DSU looks like -type DisjointSetUnionElement struct { - Parent Vertex - Rank int -} - -// DisjointSetUnion is a data structure that treats its elements as separate sets -// and provides fast operations for set creation, merging sets, and finding the parent -// of the given element of a set. -type DisjointSetUnion []DisjointSetUnionElement - -// NewDSU will return an initialised DSU using the value of n -// which will be treated as the number of elements out of which -// the DSU is being made -func NewDSU(n int) *DisjointSetUnion { - - dsu := DisjointSetUnion(make([]DisjointSetUnionElement, n)) - return &dsu -} - -// MakeSet will create a set in the DSU for the given node -func (dsu DisjointSetUnion) MakeSet(node Vertex) { - - dsu[node].Parent = node - dsu[node].Rank = 0 -} - -// FindSetRepresentative will return the parent element of the set the given node -// belongs to. Since every single element in the path from node to parent -// has the same parent, we store the parent value for each element in the -// path. This reduces consequent function calls and helps in going from O(n) -// to O(log n). This is known as path compression technique. -func (dsu DisjointSetUnion) FindSetRepresentative(node Vertex) Vertex { - - if node == dsu[node].Parent { - return node - } - - dsu[node].Parent = dsu.FindSetRepresentative(dsu[node].Parent) - return dsu[node].Parent -} - -// unionSets will merge two given sets. The naive implementation of this -// always combines the secondNode's tree with the firstNode's tree. This can lead -// to creation of trees of length O(n) so we optimize by attaching the node with -// smaller rank to the node with bigger rank. Rank represents the upper bound depth of the tree. -func (dsu DisjointSetUnion) UnionSets(firstNode Vertex, secondNode Vertex) { - - firstNode = dsu.FindSetRepresentative(firstNode) - secondNode = dsu.FindSetRepresentative(secondNode) - - if firstNode != secondNode { - - if dsu[firstNode].Rank < dsu[secondNode].Rank { - firstNode, secondNode = secondNode, firstNode - } - dsu[secondNode].Parent = firstNode - - if dsu[firstNode].Rank == dsu[secondNode].Rank { - dsu[firstNode].Rank++ - } - } -} - -// KruskalMST will return a minimum spanning tree along with its total cost -// to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is -// the number of edges in the graph and n is number of nodes in it. func KruskalMST(n int, edges []Edge) ([]Edge, int) { + // Initialize variables to store the minimum spanning tree and its total cost + var mst []Edge + var cost int - var mst []Edge // The resultant minimum spanning tree - var cost int = 0 - - dsu := NewDSU(n) + // Create a new UnionFind data structure with 'n' nodes + u := NewUnionFind(n) + // Initialize each node in the UnionFind data structure for i := 0; i < n; i++ { - dsu.MakeSet(Vertex(i)) + u.parent[i] = i + u.size[i] = 1 } + // Sort the edges in non-decreasing order based on their weights sort.SliceStable(edges, func(i, j int) bool { return edges[i].Weight < edges[j].Weight }) + // Iterate through the sorted edges for _, edge := range edges { - - if dsu.FindSetRepresentative(edge.Start) != dsu.FindSetRepresentative(edge.End) { - + // Check if adding the current edge forms a cycle or not + if u.Find(int(edge.Start)) != u.Find(int(edge.End)) { + // Add the edge to the minimum spanning tree mst = append(mst, edge) + // Add the weight of the edge to the total cost cost += edge.Weight - dsu.UnionSets(edge.Start, edge.End) + // Merge the sets containing the start and end vertices of the current edge + u = u.Union(int(edge.Start), int(edge.End)) } } + // Return the minimum spanning tree and its total cost return mst, cost } diff --git a/graph/kruskal_test.go b/graph/kruskal_test.go index 86f062d53..09ed6949d 100644 --- a/graph/kruskal_test.go +++ b/graph/kruskal_test.go @@ -5,157 +5,80 @@ import ( "testing" ) -func Test_KruskalMST(t *testing.T) { - +func TestKruskalMST(t *testing.T) { + // Define test cases with inputs, expected outputs, and sample graphs var testCases = []struct { n int graph []Edge cost int }{ + // Test Case 1 { n: 5, graph: []Edge{ - { - Start: 0, - End: 1, - Weight: 4, - }, - { - Start: 0, - End: 2, - Weight: 13, - }, - { - Start: 0, - End: 3, - Weight: 7, - }, - { - Start: 0, - End: 4, - Weight: 7, - }, - { - Start: 1, - End: 2, - Weight: 9, - }, - { - Start: 1, - End: 3, - Weight: 3, - }, - { - Start: 1, - End: 4, - Weight: 7, - }, - { - Start: 2, - End: 3, - Weight: 10, - }, - { - Start: 2, - End: 4, - Weight: 14, - }, - { - Start: 3, - End: 4, - Weight: 4, - }, + {Start: 0, End: 1, Weight: 4}, + {Start: 0, End: 2, Weight: 13}, + {Start: 0, End: 3, Weight: 7}, + {Start: 0, End: 4, Weight: 7}, + {Start: 1, End: 2, Weight: 9}, + {Start: 1, End: 3, Weight: 3}, + {Start: 1, End: 4, Weight: 7}, + {Start: 2, End: 3, Weight: 10}, + {Start: 2, End: 4, Weight: 14}, + {Start: 3, End: 4, Weight: 4}, }, cost: 20, }, + // Test Case 2 { n: 3, graph: []Edge{ - { - Start: 0, - End: 1, - Weight: 12, - }, - { - Start: 0, - End: 2, - Weight: 18, - }, - { - Start: 1, - End: 2, - Weight: 6, - }, + {Start: 0, End: 1, Weight: 12}, + {Start: 0, End: 2, Weight: 18}, + {Start: 1, End: 2, Weight: 6}, }, cost: 18, }, + // Test Case 3 { n: 4, graph: []Edge{ - { - Start: 0, - End: 1, - Weight: 2, - }, - { - Start: 0, - End: 2, - Weight: 1, - }, - { - Start: 0, - End: 3, - Weight: 2, - }, - { - Start: 1, - End: 2, - Weight: 1, - }, - { - Start: 1, - End: 3, - Weight: 2, - }, - { - Start: 2, - End: 3, - Weight: 3, - }, + {Start: 0, End: 1, Weight: 2}, + {Start: 0, End: 2, Weight: 1}, + {Start: 0, End: 3, Weight: 2}, + {Start: 1, End: 2, Weight: 1}, + {Start: 1, End: 3, Weight: 2}, + {Start: 2, End: 3, Weight: 3}, }, cost: 4, }, + // Test Case 4 { n: 2, graph: []Edge{ - { - Start: 0, - End: 1, - Weight: 4000000, - }, + {Start: 0, End: 1, Weight: 4000000}, }, cost: 4000000, }, + // Test Case 5 { n: 1, graph: []Edge{ - { - Start: 0, - End: 0, - Weight: 0, - }, + {Start: 0, End: 0, Weight: 0}, }, cost: 0, }, } - for i := range testCases { - + // Iterate through the test cases and run the tests + for i, testCase := range testCases { t.Run(fmt.Sprintf("Test Case %d", i), func(t *testing.T) { + // Execute KruskalMST for the current test case + _, computed := KruskalMST(testCase.n, testCase.graph) - _, computed := KruskalMST(testCases[i].n, testCases[i].graph) - if computed != testCases[i].cost { - t.Errorf("Test Case %d, Expected: %d, Computed: %d", i, testCases[i].cost, computed) + // Compare the computed result with the expected result + if computed != testCase.cost { + t.Errorf("Test Case %d, Expected: %d, Computed: %d", i, testCase.cost, computed) } }) } diff --git a/graph/unionfind.go b/graph/unionfind.go new file mode 100644 index 000000000..7a922f3cc --- /dev/null +++ b/graph/unionfind.go @@ -0,0 +1,59 @@ +// Union Find Algorithm or Dynamic Connectivity algorithm, often implemented with the help +//of the union find data structure, +// is used to efficiently maintain connected components in a graph that undergoes dynamic changes, +// such as edges being added or removed over time +// Worst Case Time Complexity: The time complexity of find operation is nearly constant or +//O(α(n)), where where α(n) is the inverse Ackermann function +// practically, this is a very slowly growing function making the time complexity for find +//operation nearly constant. +// The time complexity of the union operation is also nearly constant or O(α(n)) +// Worst Case Space Complexity: O(n), where n is the number of nodes or element in the structure +// Reference: https://www.scaler.com/topics/data-structures/disjoint-set/ +// Author: Mugdha Behere[https://github.com/MugdhaBehere] +// see: unionfind.go, unionfind_test.go + +package graph + +// Defining the union-find data structure +type UnionFind struct { + parent []int + size []int +} + +// Initialise a new union find data structure with s nodes +func NewUnionFind(s int) UnionFind { + parent := make([]int, s) + size := make([]int, s) + for k := 0; k < s; k++ { + parent[k] = k + size[k] = 1 + } + return UnionFind{parent, size} +} + +// to find the root of the set to which the given element belongs, the Find function serves the purpose +func (u UnionFind) Find(q int) int { + for q != u.parent[q] { + q = u.parent[q] + } + return q +} + +// to merge two sets to which the given elements belong, the Union function serves the purpose +func (u UnionFind) Union(a, b int) UnionFind { + rootP := u.Find(a) + rootQ := u.Find(b) + + if rootP == rootQ { + return u + } + + if u.size[rootP] < u.size[rootQ] { + u.parent[rootP] = rootQ + u.size[rootQ] += u.size[rootP] + } else { + u.parent[rootQ] = rootP + u.size[rootP] += u.size[rootQ] + } + return u +} diff --git a/graph/unionfind_test.go b/graph/unionfind_test.go new file mode 100644 index 000000000..b95547649 --- /dev/null +++ b/graph/unionfind_test.go @@ -0,0 +1,32 @@ +package graph + +import ( + "testing" +) + +func TestUnionFind(t *testing.T) { + u := NewUnionFind(10) // Creating a Union-Find data structure with 10 elements + + //union operations + u = u.Union(0, 1) + u = u.Union(2, 3) + u = u.Union(4, 5) + u = u.Union(6, 7) + + // Testing the parent of specific elements + t.Run("Test Find", func(t *testing.T) { + if u.Find(0) != u.Find(1) || u.Find(2) != u.Find(3) || u.Find(4) != u.Find(5) || u.Find(6) != u.Find(7) { + t.Error("Union operation not functioning correctly") + } + }) + + u = u.Union(1, 5) // Additional union operation + u = u.Union(3, 7) // Additional union operation + + // Testing the parent of specific elements after more union operations + t.Run("Test Find after Union", func(t *testing.T) { + if u.Find(0) != u.Find(5) || u.Find(2) != u.Find(7) { + t.Error("Union operation not functioning correctly") + } + }) +} From 855c430f1fd2f3418360c28c8aad5efccbfa08ec Mon Sep 17 00:00:00 2001 From: Mohit Raghav Date: Thu, 26 Oct 2023 19:11:02 +0530 Subject: [PATCH 440/488] feat: Implement Matrix , its Methods and Some Functions including Strassen Matrix Multiplication in Go (#662) * feat: Implement Strassen Matrix Multiplication - Added the Strassen matrix multiplication algorithm for efficient matrix multiplication. - Added strassenmatrixmultiply.go to include the new algorithm. - Added example usage and test functions for verification. - Introduced benchmarks for performance evaluation. Closes #661 (if applicable) * This commit introduces the Strassen matrix multiplication algorithm along with the following supporting functions and test cases: 1. `AddMatrices`: Function to add two matrices. 2. `SubtractMatrices`: Function to subtract two matrices. 3. `MultiplyMatrices`: Function to multiply two matrices simply using loops. 4. `PrintMatrix`: Function to print a matrix for debugging purposes. 5. `EqualMatrix`: Function to check if two matrices are equal. 6. `StrassenMatrixMultiply` : Function to multiply two matrices using strassen algorithm * refactor: Rename functions and add implement new functionality Renamed files and functions: - addmatrices.go to add.go - addmatrices_test.go to add_test.go - matrixmultiply.go to multiply.go - matrixmultiply_test.go to multiply_test.go - subtractmatrices.go to subtract.go - subtractmatrices_test.go to subtract_test.go - printmatrix.go to print.go - printmatrix_test.go to print_test.go New files: - breadth.go - breadth_test.go - checkequal.go - checkequal_test.go - isvalid.go - isvalid_test.go - length.go - length_test.go - samedimensions.go - samedimensions_test.go Modified files: - strassenmatrixmultiply.go - strassenmatrixmultiply_test.go This commit includes renaming and restructuring files for clarity, adding new functionality, and removing some obsolete files. * Implement Matrix as a struct type This commit introduces a new type, represented as a struct with methods for creating, manipulating, and performing operations on matrices. The following changes have been made: - Added the `Matrix` struct with fields for elements, rows, and columns. - Implemented the `New` function to create a new matrix with specified dimensions and initial values. - Implemented the `NewFromElements` function to create a matrix from a provided 2D slice of elements. - Added the `Get` and `Set` methods to access and modify matrix elements by row and column indices. - Implemented the `Print` method to print the matrix to the console. - Introduced the `SameDimensions` method to check if two matrices have the same dimensions. - Implemented functions for matrix operations, including `Add`, `Subtract`, `Multiply`, and `CheckEqual`. - Added a helper function `IsValid` to check if a given matrix has consistent row lengths. These changes provide a foundation for working with matrices in Go, allowing for easy creation, manipulation, and comparison of matrices. * Implement StrassenMatrixMultiply and Matrix Methods In this commit, the following key additions have been made to the folder: - Implemented `StrassenMatrixMultiply`, a fast matrix multiplication algorithm, to efficiently multiply two matrices. - Introduced `Copy` method to create a deep copy of a matrix, allowing for independent manipulation without affecting the original matrix. - Implemented `Submatrix` method to extract a submatrix from an existing matrix based on specified row and column indices. - Added `Rows` and `Columns` methods to retrieve rows and columns of matrix. - Included comprehensive test cases to ensure the correctness and robustness of these newly implemented features. These enhancements expand the capabilities of the type, making it more versatile and efficient in performing matrix operations. * Refactor to Use Value Type `Matrix` and Add Benchmarks In this commit, the following significant changes have been made: 1. Refactored the `Matrix` type from a pointer to a value type. Using a pointer for a small structure like `Matrix` was deemed unnecessary and has been updated to enhance code simplicity. 2. Added comprehensive benchmarks to all functions. These benchmarks will help ensure that the code performs efficiently and allows for easy performance profiling. 3. Fixed code integration errors that were identified during the refactoring process. * Fixed Golang CI lint errors for file copy_test.go & submatrix_test.go * refactor: Change type variable T to constraints.Integer, rename SameDimensions to MatchDimensions, and remove unnecessary code This commit updates the type variable T to constraints.Integer, providing a more specific type constraint. It also renames the SameDimensions function to MatchDimensions for clarity. Additionally, unnecessary code lines have been removed for cleaner and more optimized code. * refractor: Implement goroutines in Add, CheckEqual, Copy, New, Multiply, SubMatrix, and Subtract functions * refractor : Handled error in StrassenMatrixMultiply method instead of ignoring it * refractor : Handle errors gracefully by returning an error message instead of causing a panic. * refractor : Updated the 'copy' function to return an empty matrix if an empty matrix is passed as input. * Updated Documentation in README.md * refactor: matrix operations to use context and sync packages Body: - Updated the Add,Subtract, SubMatrix, and Multiply functions in the matrix package to use the context and sync packages for goroutine management and error handling. - Removed the use of the errgroup package in these functions. * refactor: matrix operations to use context and sync packages Body: - Updated the Add,Subtract, SubMatrix, and Multiply functions in the matrix package to use the context and sync packages for goroutine management and error handling. - Removed the use of the errgroup package in these functions. * Updated Documentation in README.md * chore: Add empty commit to trigger actions The GoDoc action has stopped the execution of other actions. This empty commit is a workaround to trigger the other actions to run. --------- Co-authored-by: github-action <${GITHUB_ACTOR}@users.noreply.github.com> --- README.md | 58 +++-- math/matrix/add.go | 64 ++++++ math/matrix/add_test.go | 58 +++++ math/matrix/checkequal.go | 32 +++ math/matrix/checkequal_test.go | 62 +++++ math/matrix/copy.go | 53 +++++ math/matrix/copy_test.go | 115 ++++++++++ math/matrix/isvalid.go | 17 ++ math/matrix/isvalid_test.go | 64 ++++++ math/matrix/matchdimensions.go | 9 + math/matrix/matchdimensions_test.go | 40 ++++ math/matrix/matrix.go | 92 ++++++++ math/matrix/matrix_test.go | 250 +++++++++++++++++++++ math/matrix/multiply.go | 86 +++++++ math/matrix/multiply_test.go | 101 +++++++++ math/matrix/strassenmatrixmultiply.go | 227 +++++++++++++++++++ math/matrix/strassenmatrixmultiply_test.go | 131 +++++++++++ math/matrix/string.go | 15 ++ math/matrix/string_test.go | 96 ++++++++ math/matrix/submatrix.go | 79 +++++++ math/matrix/submatrix_test.go | 88 ++++++++ math/matrix/subtract.go | 64 ++++++ math/matrix/subtract_test.go | 50 +++++ 23 files changed, 1837 insertions(+), 14 deletions(-) create mode 100644 math/matrix/add.go create mode 100644 math/matrix/add_test.go create mode 100644 math/matrix/checkequal.go create mode 100644 math/matrix/checkequal_test.go create mode 100644 math/matrix/copy.go create mode 100644 math/matrix/copy_test.go create mode 100644 math/matrix/isvalid.go create mode 100644 math/matrix/isvalid_test.go create mode 100644 math/matrix/matchdimensions.go create mode 100644 math/matrix/matchdimensions_test.go create mode 100644 math/matrix/matrix.go create mode 100644 math/matrix/matrix_test.go create mode 100644 math/matrix/multiply.go create mode 100644 math/matrix/multiply_test.go create mode 100644 math/matrix/strassenmatrixmultiply.go create mode 100644 math/matrix/strassenmatrixmultiply_test.go create mode 100644 math/matrix/string.go create mode 100644 math/matrix/string_test.go create mode 100644 math/matrix/submatrix.go create mode 100644 math/matrix/submatrix_test.go create mode 100644 math/matrix/subtract.go create mode 100644 math/matrix/subtract_test.go diff --git a/README.md b/README.md index 33134ef6f..4837c61f4 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Formula`](./math/fibonacci/fibonacci.go#L42): Formula This function calculates the n-th fibonacci number using the [formula](https://en.wikipedia.org/wiki/Fibonacci_number#Relation_to_the_golden_ratio) Attention! Tests for large values fall due to rounding error of floating point numbers, works well, only on small numbers 2. [`Matrix`](./math/fibonacci/fibonacci.go#L15): Matrix This function calculates the n-th fibonacci number using the matrix method. [See](https://en.wikipedia.org/wiki/Fibonacci_number#Matrix_form) -3. [`Recursive`](./math/fibonacci/fibonacci.go#L51): Recursive calculates the n-th fibonacci number recursively by adding the previous two numbers. [See](https://en.wikipedia.org/wiki/Fibonacci_sequence#Definition) +3. [`Recursive`](./math/fibonacci/fibonacci.go#L51): Recursive calculates the n-th fibonacci number recursively by adding the previous two Fibonacci numbers. This algorithm is extremely slow for bigger numbers, but provides a simpler implementation. ---
@@ -449,34 +449,32 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 4. [`DepthFirstSearchHelper`](./graph/depthfirstsearch.go#L21): No description provided. 5. [`FloydWarshall`](./graph/floydwarshall.go#L15): FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm 6. [`GetIdx`](./graph/depthfirstsearch.go#L3): No description provided. -7. [`KruskalMST`](./graph/kruskal.go#L87): KruskalMST will return a minimum spanning tree along with its total cost to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is the number of edges in the graph and n is number of nodes in it. +7. [`KruskalMST`](./graph/kruskal.go#L23): No description provided. 8. [`LowestCommonAncestor`](./graph/lowestcommonancestor.go#L111): For each node, we will precompute its ancestor above him, its ancestor two nodes above, its ancestor four nodes above, etc. Let's call `jump[j][u]` is the `2^j`-th ancestor above the node `u` with `u` in range `[0, numbersVertex)`, `j` in range `[0,MAXLOG)`. These information allow us to jump from any node to any ancestor above it in `O(MAXLOG)` time. 9. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) -10. [`NewDSU`](./graph/kruskal.go#L34): NewDSU will return an initialised DSU using the value of n which will be treated as the number of elements out of which the DSU is being made -11. [`NewTree`](./graph/lowestcommonancestor.go#L84): No description provided. +10. [`NewTree`](./graph/lowestcommonancestor.go#L84): No description provided. +11. [`NewUnionFind`](./graph/unionfind.go#L24): Initialise a new union find data structure with s nodes 12. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. 13. [`Topological`](./graph/topological.go#L7): Topological assumes that graph given is valid and that its possible to get a topological ordering. constraints are array of []int{a, b}, representing an edge going from a to b --- ##### Types -1. [`DisjointSetUnion`](./graph/kruskal.go#L29): No description provided. +1. [`Edge`](./graph/kruskal.go#L17): No description provided. -2. [`DisjointSetUnionElement`](./graph/kruskal.go#L21): No description provided. +2. [`Graph`](./graph/graph.go#L9): No description provided. -3. [`Edge`](./graph/kruskal.go#L14): No description provided. +3. [`Item`](./graph/dijkstra.go#L5): No description provided. -4. [`Graph`](./graph/graph.go#L9): No description provided. +4. [`Query`](./graph/lowestcommonancestor_test.go#L9): No description provided. -5. [`Item`](./graph/dijkstra.go#L5): No description provided. +5. [`Tree`](./graph/lowestcommonancestor.go#L25): No description provided. -6. [`Query`](./graph/lowestcommonancestor_test.go#L9): No description provided. +6. [`TreeEdge`](./graph/lowestcommonancestor.go#L12): No description provided. -7. [`Tree`](./graph/lowestcommonancestor.go#L25): No description provided. +7. [`UnionFind`](./graph/unionfind.go#L18): No description provided. -8. [`TreeEdge`](./graph/lowestcommonancestor.go#L12): No description provided. - -9. [`WeightedGraph`](./graph/floydwarshall.go#L9): No description provided. +8. [`WeightedGraph`](./graph/floydwarshall.go#L9): No description provided. --- @@ -664,6 +662,37 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 21. [`Sin`](./math/sin.go#L9): Sin returns the sine of the radian argument x. [See more](https://en.wikipedia.org/wiki/Sine_and_cosine) 22. [`SumOfProperDivisors`](./math/perfectnumber.go#L17): Returns the sum of proper divisors of inNumber. +--- +
+ matrix + +--- + +##### filename: strassenmatrixmultiply.go description: Implements matrix multiplication using the Strassen algorithm. details: This program takes two matrices as input and performs matrix multiplication using the Strassen algorithm, which is an optimized divide-and-conquer approach. It allows for efficient multiplication of large matrices. author(s): Mohit Raghav(https://github.com/mohit07raghav19) See strassenmatrixmultiply_test.go for test cases + +--- +##### Functions: + +1. [`IsValid`](./math/matrix/isvalid.go#L6): IsValid checks if the input matrix has consistent row lengths. +2. [`New`](./math/matrix/matrix.go#L17): NewMatrix creates a new Matrix based on the provided arguments. +3. [`NewFromElements`](./math/matrix/matrix.go#L43): NewFromElements creates a new Matrix from the given elements. + +--- +##### Types + +1. [`Matrix`](./math/matrix/matrix.go#L10): No description provided. + + +--- +
+ matrix_test + +--- + +##### Functions: + +1. [`MakeRandomMatrix`](./math/matrix/strassenmatrixmultiply_test.go#L105): No description provided. + ---
max @@ -1084,6 +1113,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`CountChars`](./strings/charoccurrence.go#L12): CountChars counts the number of a times a character has occurred in the provided string argument and returns a map with `rune` as keys and the count as value. 2. [`IsIsogram`](./strings/isisogram.go#L34): No description provided. +3. [`IsSubsequence`](./strings/issubsequence.go#L10): Returns true if s is subsequence of t, otherwise return false. ---
diff --git a/math/matrix/add.go b/math/matrix/add.go new file mode 100644 index 000000000..34fdf98be --- /dev/null +++ b/math/matrix/add.go @@ -0,0 +1,64 @@ +package matrix + +import ( + "context" + "errors" + "sync" +) + +// Add adds two matrices. +func (m1 Matrix[T]) Add(m2 Matrix[T]) (Matrix[T], error) { + // Check if the matrices have the same dimensions. + if !m1.MatchDimensions(m2) { + return Matrix[T]{}, errors.New("matrices are not compatible for addition") + } + + // Create a new matrix to store the result. + var zeroVal T + result := New(m1.Rows(), m1.Columns(), zeroVal) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // Make sure it's called to release resources even if no errors + + var wg sync.WaitGroup + errCh := make(chan error, 1) + + for i := 0; i < m1.rows; i++ { + i := i // Capture the loop variable for the goroutine + wg.Add(1) + go func() { + defer wg.Done() + for j := 0; j < m1.columns; j++ { + select { + case <-ctx.Done(): + return // Context canceled; return without an error + default: + } + + sum := m1.elements[i][j] + m2.elements[i][j] + err := result.Set(i, j, sum) + if err != nil { + cancel() // Cancel the context on error + select { + case errCh <- err: + default: + } + return + } + } + }() + } + + // Wait for all goroutines to finish + go func() { + wg.Wait() + close(errCh) + }() + + // Check for any errors + if err := <-errCh; err != nil { + return Matrix[T]{}, err + } + + return result, nil +} diff --git a/math/matrix/add_test.go b/math/matrix/add_test.go new file mode 100644 index 000000000..f3543965c --- /dev/null +++ b/math/matrix/add_test.go @@ -0,0 +1,58 @@ +package matrix_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestAdd(t *testing.T) { + // Create two matrices with the same dimensions for addition + m1 := matrix.New(2, 2, 1) + m2 := matrix.New(2, 2, 2) + + // Test case 1: Valid matrix addition + addedMatrix, err := m1.Add(m2) + if err != nil { + t.Errorf("Add(m1, m2) returned an error: %v, expected no error", err) + } + expectedMatrix := matrix.New(2, 2, 3) + res := addedMatrix.CheckEqual(expectedMatrix) + if !res { + t.Errorf("Add(m1, m2) returned incorrect result:\n%v\nExpected:\n%v", addedMatrix, expectedMatrix) + } + + // Create two matrices with different dimensions for addition + m3 := matrix.New(2, 2, 1) + m4 := matrix.New(2, 3, 2) + + // Test case 2: Matrices with different dimensions + _, err2 := m3.Add(m4) + expectedError2 := fmt.Errorf("matrices are not compatible for addition") + if err2 == nil || err2.Error() != expectedError2.Error() { + t.Errorf("Add(m3, m4) returned error: %v, expected error: %v", err2, expectedError2) + } + +} + +func BenchmarkAddSmallMatrix(b *testing.B) { + m1 := matrix.New(10, 10, 0) // Create a 10x10 matrix with all zeros + m2 := matrix.New(10, 10, 1) // Create a 10x10 matrix with all ones + + for i := 0; i < b.N; i++ { + _, _ = m1.Add(m2) + } +} + +func BenchmarkAddLargeMatrix(b *testing.B) { + size := 1000 // Choose an appropriate size for your large matrix + m1 := MakeRandomMatrix[int](size, size) + m2 := MakeRandomMatrix[int](size, size) + + b.ResetTimer() // Reset the timer to exclude setup time + + for i := 0; i < b.N; i++ { + _, _ = m1.Add(m2) + } +} diff --git a/math/matrix/checkequal.go b/math/matrix/checkequal.go new file mode 100644 index 000000000..c6bde8597 --- /dev/null +++ b/math/matrix/checkequal.go @@ -0,0 +1,32 @@ +package matrix + +// CheckEqual checks if the current matrix is equal to another matrix (m2). +// Two matrices are considered equal if they have the same dimensions and +// all their elements are equal. +func (m1 Matrix[T]) CheckEqual(m2 Matrix[T]) bool { + if !m1.MatchDimensions(m2) { + return false + } + + c := make(chan bool) + + for i := range m1.elements { + go func(i int) { + for j := range m1.elements[i] { + if m1.elements[i][j] != m2.elements[i][j] { + c <- false + return + } + } + c <- true + }(i) + } + + for range m1.elements { + if !<-c { + return false + } + } + + return true +} diff --git a/math/matrix/checkequal_test.go b/math/matrix/checkequal_test.go new file mode 100644 index 000000000..be93d82d7 --- /dev/null +++ b/math/matrix/checkequal_test.go @@ -0,0 +1,62 @@ +package matrix_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestCheckEqual(t *testing.T) { + // Create two matrices with the same dimensions and equal values + m1 := matrix.New(2, 2, 0) + m2 := matrix.New(2, 2, 0) + + // Test case 1: Matrices are equal + equal := m1.CheckEqual(m2) + + if !equal { + t.Errorf("CheckEqual(m1, m2) returned false, expected true (matrices are equal)") + } + + // Create two matrices with the same dimensions but different values + m3 := matrix.New(2, 2, 1) + m4 := matrix.New(2, 2, 0) + + // Test case 2: Matrices are not equal + equal2 := m3.CheckEqual(m4) + if equal2 { + t.Errorf("CheckEqual(m3, m4) returned true, expected false (matrices are not equal)") + } + + // Create two matrices with different dimensions + m5 := matrix.New(2, 2, 0) + m6 := matrix.New(2, 3, 0) + + // Test case 3: Matrices have different dimensions + equal3 := m5.CheckEqual(m6) + + if equal3 { + t.Errorf("CheckEqual(m5, m6) returned true, expected false (matrices are not equal)") + } +} + +func BenchmarkCheckEqualSmallMatrix(b *testing.B) { + m1 := matrix.New(10, 10, 0) // Create a 10x10 matrix with all zeros + m2 := matrix.New(10, 10, 0) // Create another 10x10 matrix with all zeros + + for i := 0; i < b.N; i++ { + _ = m1.CheckEqual(m2) + } +} + +func BenchmarkCheckEqualLargeMatrix(b *testing.B) { + size := 1000 // Choose an appropriate size for your large matrix + m1 := MakeRandomMatrix[int](size, size) + m2 := MakeRandomMatrix[int](size, size) + + b.ResetTimer() // Reset the timer to exclude setup time + + for i := 0; i < b.N; i++ { + _ = m1.CheckEqual(m2) + } +} diff --git a/math/matrix/copy.go b/math/matrix/copy.go new file mode 100644 index 000000000..2b9949750 --- /dev/null +++ b/math/matrix/copy.go @@ -0,0 +1,53 @@ +package matrix + +import "sync" + +func (m Matrix[T]) Copy() (Matrix[T], error) { + + rows := m.Rows() + columns := m.Columns() + if rows == 0 || columns == 0 { + return Matrix[T]{}, nil + } + zeroVal, err := m.Get(0, 0) // Get the zero value of the element type + if err != nil { + return Matrix[T]{}, err + } + copyMatrix := New(rows, columns, zeroVal) + var wg sync.WaitGroup + wg.Add(rows) + errChan := make(chan error, 1) + + for i := 0; i < rows; i++ { + go func(i int) { + defer wg.Done() + for j := 0; j < columns; j++ { + val, err := m.Get(i, j) + if err != nil { + select { + case errChan <- err: + default: + } + return + } + err = copyMatrix.Set(i, j, val) + if err != nil { + select { + case errChan <- err: + default: + } + return + } + } + }(i) + } + + wg.Wait() + close(errChan) + + if err, ok := <-errChan; ok { + return Matrix[T]{}, err + } + + return copyMatrix, nil +} diff --git a/math/matrix/copy_test.go b/math/matrix/copy_test.go new file mode 100644 index 000000000..027902843 --- /dev/null +++ b/math/matrix/copy_test.go @@ -0,0 +1,115 @@ +package matrix_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestMatrixCopy(t *testing.T) { + // Create a sample matrix + data := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} + // Ensure that the copy is not the same as the original + matrix, err := matrix.NewFromElements(data) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + copyMatrix, err := matrix.Copy() + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + + // Ensure that the copy is not the same as the original + if &matrix == ©Matrix { + t.Errorf("Copy did not create a new matrix.") + } + + for i := 0; i < matrix.Rows(); i++ { + for j := 0; j < matrix.Columns(); j++ { + val1, err := matrix.Get(i, j) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + val2, err := copyMatrix.Get(i, j) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + if val1 != val2 { + t.Errorf("Copy did not correctly copy element (%d, %d).", i, j) + } + } + } + +} + +func TestMatrixCopyEmpty(t *testing.T) { + // Create an empty matrix + emptyMatrix := matrix.New(0, 0, 0) + + // Make a copy of the empty matrix + copyMatrix, err := emptyMatrix.Copy() + if err != nil { // as empty matrix + t.Fatalf("Failed to copy matrix: %v", err) + } + + // Ensure that the copy is not the same as the original by comparing their addresses + if &emptyMatrix == ©Matrix { + t.Errorf("Copy did not create a new matrix for an empty matrix.") + } + + // Check if the copy is also empty + if copyMatrix.Rows() != 0 || copyMatrix.Columns() != 0 { + t.Errorf("Copy of an empty matrix should also be empty.") + } +} + +func TestMatrixCopyWithDefaultValues(t *testing.T) { + // Create a matrix with default values (zeroes) + rows, columns := 3, 3 + defaultValue := 0 + defaultMatrix := matrix.New(rows, columns, defaultValue) + + // Make a copy of the matrix + copyMatrix, err := defaultMatrix.Copy() + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + + // Ensure that the copy is not the same as the original by comparing their addresses + if &defaultMatrix == ©Matrix { + t.Errorf("Copy did not create a new matrix for default values.") + } + + // Check if the copy has the same values as the original (all zeroes) + for i := 0; i < defaultMatrix.Rows(); i++ { + for j := 0; j < defaultMatrix.Columns(); j++ { + val1, err := defaultMatrix.Get(i, j) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + val2, err := copyMatrix.Get(i, j) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + if val1 != val2 || val1 != defaultValue || val2 != defaultValue { + t.Errorf("Copy did not preserve default values at row %d, column %d. Expected %v, got %v", i, j, defaultValue, val2) + } + } + } +} + +func BenchmarkCopyMatrix(b *testing.B) { + // Create a matrix for benchmarking + rows := 100 + columns := 100 + initialValue := 0 + matrix := matrix.New(rows, columns, initialValue) + + // Reset the benchmark timer + b.ResetTimer() + + // Run the benchmarks + for i := 0; i < b.N; i++ { + _, _ = matrix.Copy() + } +} diff --git a/math/matrix/isvalid.go b/math/matrix/isvalid.go new file mode 100644 index 000000000..afe8f5ed3 --- /dev/null +++ b/math/matrix/isvalid.go @@ -0,0 +1,17 @@ +package matrix + +import "github.com/TheAlgorithms/Go/constraints" + +// IsValid checks if the input matrix has consistent row lengths. +func IsValid[T constraints.Integer](elements [][]T) bool { + if len(elements) == 0 { + return true + } + columns := len(elements[0]) + for _, row := range elements { + if len(row) != columns { + return false + } + } + return true +} diff --git a/math/matrix/isvalid_test.go b/math/matrix/isvalid_test.go new file mode 100644 index 000000000..ea7dae338 --- /dev/null +++ b/math/matrix/isvalid_test.go @@ -0,0 +1,64 @@ +package matrix_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestIsValid(t *testing.T) { + // Test case 1: Valid matrix with consistent row lengths + validMatrix := [][]int{ + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + } + result1 := matrix.IsValid(validMatrix) + if !result1 { + t.Errorf("IsValid(validMatrix) returned false, expected true (valid matrix)") + } + + // Test case 2: Valid matrix with empty rows (no inconsistency) + validMatrixEmptyRows := [][]int{ + {}, + {}, + {}, + } + result2 := matrix.IsValid(validMatrixEmptyRows) + if !result2 { + t.Errorf("IsValid(validMatrixEmptyRows) returned false, expected true (valid matrix with empty rows)") + } + + // Test case 3: Invalid matrix with inconsistent row lengths + invalidMatrix := [][]int{ + {1, 2, 3}, + {4, 5}, + {6, 7, 8}, + } + result3 := matrix.IsValid(invalidMatrix) + if result3 { + t.Errorf("IsValid(invalidMatrix) returned true, expected false (invalid matrix with inconsistent row lengths)") + } + +} + +func BenchmarkIsValid(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + elements := make([][]int, rows) + for i := range elements { + elements[i] = make([]int, columns) + for j := range elements[i] { + elements[i][j] = i*columns + j // Some arbitrary values + } + } + + // Reset the benchmark timer + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + _ = matrix.IsValid(elements) + } +} diff --git a/math/matrix/matchdimensions.go b/math/matrix/matchdimensions.go new file mode 100644 index 000000000..982409191 --- /dev/null +++ b/math/matrix/matchdimensions.go @@ -0,0 +1,9 @@ +package matrix + +// MatchDimensions checks if two matrices have the same dimensions. +func (m Matrix[T]) MatchDimensions(m1 Matrix[T]) bool { + if m.rows == m1.rows && m.columns == m1.columns { + return true + } + return false +} diff --git a/math/matrix/matchdimensions_test.go b/math/matrix/matchdimensions_test.go new file mode 100644 index 000000000..645b4211f --- /dev/null +++ b/math/matrix/matchdimensions_test.go @@ -0,0 +1,40 @@ +package matrix_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestMatrixMatchDimensions(t *testing.T) { + // Create two matrices with the same dimensions + m1 := matrix.New(2, 3, 0) + m2 := matrix.New(2, 3, 0) + + // Test case 1: Same dimensions + if !m1.MatchDimensions(m2) { + t.Errorf("m1.MatchDimensions(m2) returned %t, expected 1 (same dimensions)", m1.MatchDimensions(m2)) + } + + // Create two matrices with different dimensions + m3 := matrix.New(2, 3, 0) + m4 := matrix.New(3, 2, 0) + + // Test case 2: Different dimensions + if m3.MatchDimensions(m4) { + t.Errorf("m3.MatchDimensions(m4) returned : %v, expected: %v", m3.MatchDimensions(m4), false) + } +} + +// BenchmarkMatchDimensions benchmarks the MatchDimensions method. +func BenchmarkMatchDimensions(b *testing.B) { + // Create sample matrices for benchmarking + rows := 100 + columns := 100 + m1 := matrix.New(rows, columns, 0) // Replace with appropriate values + m2 := matrix.New(rows, columns, 0) // Replace with appropriate values + + for i := 0; i < b.N; i++ { + _ = m1.MatchDimensions(m2) + } +} diff --git a/math/matrix/matrix.go b/math/matrix/matrix.go new file mode 100644 index 000000000..5a03e1e0b --- /dev/null +++ b/math/matrix/matrix.go @@ -0,0 +1,92 @@ +package matrix + +import ( + "errors" + "sync" + + "github.com/TheAlgorithms/Go/constraints" +) + +type Matrix[T constraints.Integer] struct { + elements [][]T + rows int + columns int +} + +// NewMatrix creates a new Matrix based on the provided arguments. +func New[T constraints.Integer](rows, columns int, initial T) Matrix[T] { + if rows < 0 || columns < 0 { + return Matrix[T]{} // Invalid dimensions, return an empty matrix + } + + // Initialize the matrix with the specified dimensions and fill it with the initial value. + elements := make([][]T, rows) + var wg sync.WaitGroup + wg.Add(rows) + + for i := range elements { + go func(i int) { + defer wg.Done() + elements[i] = make([]T, columns) + for j := range elements[i] { + elements[i][j] = initial + } + }(i) + } + + wg.Wait() + + return Matrix[T]{elements, rows, columns} +} + +// NewFromElements creates a new Matrix from the given elements. +func NewFromElements[T constraints.Integer](elements [][]T) (Matrix[T], error) { + if !IsValid(elements) { + return Matrix[T]{}, errors.New("rows have different numbers of columns") + } + rows := len(elements) + if rows == 0 { + return Matrix[T]{}, nil // Empty matrix + } + + columns := len(elements[0]) + matrix := Matrix[T]{ + elements: make([][]T, rows), + rows: rows, // Set the rows field + columns: columns, // Set the columns field + } + for i := range matrix.elements { + matrix.elements[i] = make([]T, columns) + copy(matrix.elements[i], elements[i]) + } + + return matrix, nil +} + +func (m Matrix[T]) Get(row, col int) (T, error) { + if row < 0 || row >= m.rows || col < 0 || col >= m.columns { + var zeroVal T + return zeroVal, errors.New("index out of range") + } + return m.elements[row][col], nil +} + +func (m Matrix[T]) Set(row, col int, val T) error { + if row < 0 || row >= m.rows || col < 0 || col >= m.columns { + return errors.New("index out of bounds") + } + + m.elements[row][col] = val + return nil +} + +func (m Matrix[T]) Rows() int { + return len(m.elements) +} + +func (m Matrix[T]) Columns() int { + if len(m.elements) == 0 { + return 0 + } + return len(m.elements[0]) +} diff --git a/math/matrix/matrix_test.go b/math/matrix/matrix_test.go new file mode 100644 index 000000000..1425bf933 --- /dev/null +++ b/math/matrix/matrix_test.go @@ -0,0 +1,250 @@ +package matrix_test + +import ( + "errors" + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestNewMatrix(t *testing.T) { + + nullMatrix := matrix.New(0, 0, 0) + if nullMatrix.Rows() != 0 || nullMatrix.Columns() != 0 { + t.Errorf("matrix.New( 0, 0, 0) returned nil, expected a matrix") + } + // Test creating a matrix of integers + intMatrix := matrix.New(3, 4, 0) + if intMatrix.Rows() != 3 || intMatrix.Columns() != 4 { + t.Errorf("matrix.New( 3, 4, 0) returned nil, expected a matrix") + } + +} + +func TestNewFromElements(t *testing.T) { + // Test case 1: Valid matrix + validElements := [][]int{ + {1, 2, 3}, + {4, 5, 6}, + } + expectedm1 := matrix.New(2, 3, 0) + for i := 0; i < len(validElements); i++ { + for j := 0; j < len(validElements[0]); j++ { + err := expectedm1.Set(i, j, validElements[i][j]) + if err != nil { + t.Errorf("copyMatrix.Set error: " + err.Error()) + } + } + } + + m1, err1 := matrix.NewFromElements(validElements) + if err1 != nil { + t.Errorf("NewFromElements(validElements) returned an error: %v", err1) + } + res := m1.CheckEqual(expectedm1) + if res != true { + t.Errorf("NewFromElements(validElements) returned %v, expected %v", m1, expectedm1) + } + + // Test case 2: Invalid matrix with different column counts + invalidElements := [][]int{ + {1, 2, 3}, + {4, 5}, + } + _, err2 := matrix.NewFromElements(invalidElements) + expectedError2 := errors.New("rows have different numbers of columns") + if err2 == nil || err2.Error() != expectedError2.Error() { + t.Errorf("NewFromElements(invalidElements) returned error: %v, expected error: %v", err2, expectedError2) + } + + // Test case 3: Empty matrix + emptyElements := [][]int{} + m3, err3 := matrix.NewFromElements(emptyElements) + if err3 != nil { + t.Errorf("NewFromElements(emptyElements) returned an error: %v", err3) + } + if m3.Rows() != 0 || m3.Columns() != 0 { + t.Errorf("NewFromElements(emptyElements) returned %v, expected nil", m3) + } +} + +func TestMatrixGet(t *testing.T) { + // Create a sample matrix for testing + matrix := matrix.New(3, 3, 0) + err := matrix.Set(1, 1, 42) // Set a specific value for testing + if err != nil { + t.Errorf("copyMatrix.Set error: " + err.Error()) + } + // Test case 1: Valid Get + val1, err1 := matrix.Get(1, 1) + if err1 != nil { + t.Errorf("matrix.Get(1, 1) returned an error: %v, expected no error", err1) + } + if val1 != 42 { + t.Errorf("matrix.Get(1, 1) returned %v, expected 42", val1) + } + + // Test case 2: Get with invalid indices + _, err2 := matrix.Get(10, 10) + expectedError2 := errors.New("index out of range") + if err2 == nil || err2.Error() != expectedError2.Error() { + t.Errorf("matrix.Get(10, 10) returned error: %v, expected error: %v", err2, expectedError2) + } + // Test case 3: Get with invalid indices + _, err3 := matrix.Get(-1, -3) + expectedError3 := errors.New("index out of range") + if err3 == nil || err3.Error() != expectedError3.Error() { + t.Errorf("matrix.Get(10, 10) returned error: %v, expected error: %v", err3, expectedError3) + } +} + +func TestMatrixSet(t *testing.T) { + // Create a sample matrix for testing + matrix := matrix.New(3, 3, 0) + + // Test case 1: Valid Set + err1 := matrix.Set(1, 1, 42) + if err1 != nil { + t.Errorf("matrix.Set(1, 1, 42) returned an error: %v, expected no error", err1) + } + val1, err := matrix.Get(1, 1) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + if val1 != 42 { + t.Errorf("matrix.Set(1, 1, 42) did not set the value correctly, expected 42, got %v", val1) + } + + // Test case 2: Set with invalid indices + err2 := matrix.Set(10, 10, 100) + expectedError2 := errors.New("index out of bounds") + if err2 == nil || err2.Error() != expectedError2.Error() { + t.Errorf("matrix.Set(10, 10, 100) returned error: %v, expected error: %v", err2, expectedError2) + } + // Test case 3: Get with invalid indices + err3 := matrix.Set(-13, -1, 100) + expectedError3 := errors.New("index out of bounds") + if err3 == nil || err3.Error() != expectedError3.Error() { + t.Errorf("matrix.Get(10, 10) returned error: %v, expected error: %v", err3, expectedError3) + } +} + +func TestMatrixRows(t *testing.T) { + // Create a sample matrix + data := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} + matrix, err := matrix.NewFromElements(data) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + // Check the number of rows + expectedRows := len(data) + rows := matrix.Rows() + if rows != expectedRows { + t.Errorf("Expected %d rows, but got %d", expectedRows, rows) + } +} + +func TestMatrixColumns(t *testing.T) { + // Create a sample matrix + data := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} + matrix, err := matrix.NewFromElements(data) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + // Check the number of columns + expectedColumns := len(data[0]) + columns := matrix.Columns() + if columns != expectedColumns { + t.Errorf("Expected %d columns, but got %d", expectedColumns, columns) + } +} + +func TestMatrixEmptyRowsAndColumns(t *testing.T) { + // Create an empty matrix + emptyMatrix := matrix.New(0, 0, 0) + + // Check the number of rows and columns for an empty matrix + rows := emptyMatrix.Rows() + columns := emptyMatrix.Columns() + + if rows != 0 { + t.Errorf("Expected 0 rows for an empty matrix, but got %d", rows) + } + + if columns != 0 { + t.Errorf("Expected 0 columns for an empty matrix, but got %d", columns) + } +} + +// BenchmarkNew benchmarks the New function. +func BenchmarkNew(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = matrix.New(100, 100, 0) // Change the arguments to match your use case + } +} + +// BenchmarkNewFromElements benchmarks the NewFromElements function. +func BenchmarkNewFromElements(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + elements := make([][]int, rows) + for i := range elements { + elements[i] = make([]int, columns) + for j := range elements[i] { + elements[i][j] = i*columns + j // Some arbitrary values + } + } + + for i := 0; i < b.N; i++ { + _, _ = matrix.NewFromElements(elements) + } +} + +// BenchmarkGet benchmarks the Get method. +func BenchmarkGet(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + matrix := matrix.New(rows, columns, 0) + + for i := 0; i < b.N; i++ { + _, _ = matrix.Get(50, 50) // Change the row and column indices as needed + } +} + +// BenchmarkSet benchmarks the Set method. +func BenchmarkSet(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + matrix := matrix.New(rows, columns, 0) + + for i := 0; i < b.N; i++ { + _ = matrix.Set(50, 50, 42) // Change the row, column, and value as needed + } +} + +// BenchmarkRows benchmarks the Rows method. +func BenchmarkRows(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + matrix := matrix.New(rows, columns, 0) + + for i := 0; i < b.N; i++ { + _ = matrix.Rows() + } +} + +// BenchmarkColumns benchmarks the Columns method. +func BenchmarkColumns(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + matrix := matrix.New(rows, columns, 0) + + for i := 0; i < b.N; i++ { + _ = matrix.Columns() + } +} diff --git a/math/matrix/multiply.go b/math/matrix/multiply.go new file mode 100644 index 000000000..718a1b068 --- /dev/null +++ b/math/matrix/multiply.go @@ -0,0 +1,86 @@ +package matrix + +import ( + "context" + "errors" + "sync" +) + +// Multiply multiplies the current matrix (m1) with another matrix (m2) and returns the result as a new matrix. +func (m1 Matrix[T]) Multiply(m2 Matrix[T]) (Matrix[T], error) { + // Check if the matrices can be multiplied. + if m1.Columns() != m2.Rows() { + return Matrix[T]{}, errors.New("matrices cannot be multiplied: column count of the first matrix must match row count of the second matrix") + } + + // Create a new matrix to store the result. + var zeroVal T + result := New(m1.Rows(), m2.Columns(), zeroVal) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // Make sure it's called to release resources even if no errors + + var wg sync.WaitGroup + errCh := make(chan error, 1) + + for i := 0; i < m1.Rows(); i++ { + for j := 0; j < m2.Columns(); j++ { + i, j := i, j // Capture the loop variable for the goroutine + wg.Add(1) + go func() { + defer wg.Done() + // Compute the dot product of the row from the first matrix and the column from the second matrix. + dotProduct := zeroVal + for k := 0; k < m1.Columns(); k++ { + select { + case <-ctx.Done(): + return // Context canceled; return without an error + default: + } + + val1, err := m1.Get(i, k) + if err != nil { + cancel() + select { + case errCh <- err: + default: + } + return + } + val2, err := m2.Get(k, j) + if err != nil { + cancel() + select { + case errCh <- err: + default: + } + return + } + dotProduct += val1 * val2 + } + err := result.Set(i, j, dotProduct) + if err != nil { + cancel() + select { + case errCh <- err: + default: + } + return + } + }() + } + } + + // Wait for all goroutines to finish + go func() { + wg.Wait() + close(errCh) + }() + + // Check for any errors + if err := <-errCh; err != nil { + return Matrix[T]{}, err + } + + return result, nil +} diff --git a/math/matrix/multiply_test.go b/math/matrix/multiply_test.go new file mode 100644 index 000000000..1a1ca39a7 --- /dev/null +++ b/math/matrix/multiply_test.go @@ -0,0 +1,101 @@ +package matrix_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestMultiplyMatrix(t *testing.T) { + // Test case with compatible NULL matrices + t.Run("NULL Matrices", func(t *testing.T) { + mat1 := matrix.New(0, 0, 0) + mat2 := matrix.New(0, 0, 0) + + expected := matrix.New(0, 0, 0) + result, err := mat1.Multiply(mat2) + if err != nil { + t.Errorf("Expected no error, got %v", err) + } else if !result.CheckEqual(expected) { + t.Errorf("Result matrix does not match the expected result.") + } + + }) + // Test case with compatible matrices + t.Run("Compatible Matrices", func(t *testing.T) { + mat1 := [][]int{{1, 2, 3}, {4, 5, 6}} + mat2 := [][]int{{7, 8}, {9, 10}, {11, 12}} + m1, err := matrix.NewFromElements(mat1) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + m2, err := matrix.NewFromElements(mat2) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + exp := [][]int{{58, 64}, {139, 154}} + expected, err := matrix.NewFromElements(exp) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + result, err := m1.Multiply(m2) + if err != nil { + t.Errorf("Expected no error, got %v", err) + } else if !result.CheckEqual(expected) { + t.Errorf("Result matrix does not match the expected result.") + } + + }) + +} + +func TestMultiplyIncompatibleMatrix(t *testing.T) { + // Test case with incompatible matrices + t.Run("Incompatible Matrices", func(t *testing.T) { + mat1 := [][]int{{1, 2, 3}, {4, 5, 6}} + mat2 := [][]int{{7, 8}, {9, 10}} + m1, err := matrix.NewFromElements(mat1) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + m2, err := matrix.NewFromElements(mat2) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + + _, err = m1.Multiply(m2) + if err == nil { + t.Error("Expected an error, but got none") + } + }) + + t.Run("Incompatible Matrices", func(t *testing.T) { + mat1 := [][]int{{1, 2}} + mat2 := [][]int{{}} + m1, err := matrix.NewFromElements(mat1) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + m2, err := matrix.NewFromElements(mat2) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + _, err = m1.Multiply(m2) + + if err == nil { + t.Error("Expected an error, but got none") + } + }) +} + +func BenchmarkMatrixMultiply(b *testing.B) { + // Create sample matrices for benchmarking + rows := 10 + columns := 10 + m1 := matrix.New(rows, columns, 2) // Replace with appropriate values + m2 := matrix.New(rows, columns, 3) // Replace with appropriate values + + for i := 0; i < b.N; i++ { + _, _ = m1.Multiply(m2) + } +} diff --git a/math/matrix/strassenmatrixmultiply.go b/math/matrix/strassenmatrixmultiply.go new file mode 100644 index 000000000..86fb47809 --- /dev/null +++ b/math/matrix/strassenmatrixmultiply.go @@ -0,0 +1,227 @@ +// filename: strassenmatrixmultiply.go +// description: Implements matrix multiplication using the Strassen algorithm. +// details: +// This program takes two matrices as input and performs matrix multiplication +// using the Strassen algorithm, which is an optimized divide-and-conquer +// approach. It allows for efficient multiplication of large matrices. +// author(s): Mohit Raghav(https://github.com/mohit07raghav19) +// See strassenmatrixmultiply_test.go for test cases +package matrix + +// Perform matrix multiplication using Strassen's algorithm +func (A Matrix[T]) StrassenMatrixMultiply(B Matrix[T]) (Matrix[T], error) { + n := A.rows + // Check if matrices are 2x2 or smaller + if n == 1 { + a1, err := A.Get(0, 0) + if err != nil { + return Matrix[T]{}, err + } + b1, err := B.Get(0, 0) + if err != nil { + return Matrix[T]{}, err + } + result := New(1, 1, a1*b1) + return result, nil + } else { + // Calculate the size of submatrices + mid := n / 2 + + // Create submatrices + A11, err := A.SubMatrix(0, 0, mid, mid) + if err != nil { + return Matrix[T]{}, err + } + A12, err := A.SubMatrix(0, mid, mid, n-mid) + if err != nil { + return Matrix[T]{}, err + } + A21, err := A.SubMatrix(mid, 0, n-mid, mid) + if err != nil { + return Matrix[T]{}, err + } + A22, err := A.SubMatrix(mid, mid, n-mid, n-mid) + if err != nil { + return Matrix[T]{}, err + } + + B11, err := B.SubMatrix(0, 0, mid, mid) + if err != nil { + return Matrix[T]{}, err + } + B12, err := B.SubMatrix(0, mid, mid, n-mid) + if err != nil { + return Matrix[T]{}, err + } + B21, err := B.SubMatrix(mid, 0, n-mid, mid) + if err != nil { + return Matrix[T]{}, err + } + B22, err := B.SubMatrix(mid, mid, n-mid, n-mid) + if err != nil { + return Matrix[T]{}, err + } + + // Calculate result submatrices + A1, err := A11.Add(A22) + if err != nil { + return Matrix[T]{}, err + } + + A2, err := B11.Add(B22) + if err != nil { + return Matrix[T]{}, err + } + + A3, err := A21.Add(A22) + if err != nil { + return Matrix[T]{}, err + } + + A4, err := A11.Add(A12) + if err != nil { + return Matrix[T]{}, err + } + + A5, err := B11.Add(B12) + if err != nil { + return Matrix[T]{}, err + } + + A6, err := B21.Add(B22) + if err != nil { + return Matrix[T]{}, err + } + // + S1, err := B12.Subtract(B22) + if err != nil { + return Matrix[T]{}, err + } + S2, err := B21.Subtract(B11) + if err != nil { + return Matrix[T]{}, err + } + S3, err := A21.Subtract(A11) + if err != nil { + return Matrix[T]{}, err + } + S4, err := A12.Subtract(A22) + if err != nil { + return Matrix[T]{}, err + } + // Recursive steps + M1, err := A1.StrassenMatrixMultiply(A2) + if err != nil { + return Matrix[T]{}, err + } + M2, err := A3.StrassenMatrixMultiply(B11) + if err != nil { + return Matrix[T]{}, err + } + M3, err := A11.StrassenMatrixMultiply(S1) + if err != nil { + return Matrix[T]{}, err + } + M4, err := A22.StrassenMatrixMultiply(S2) + if err != nil { + return Matrix[T]{}, err + } + M5, err := A4.StrassenMatrixMultiply(B22) + if err != nil { + return Matrix[T]{}, err + } + M6, err := S3.StrassenMatrixMultiply(A5) + if err != nil { + return Matrix[T]{}, err + } + M7, err := S4.StrassenMatrixMultiply(A6) + + if err != nil { + return Matrix[T]{}, err + } // + A7, err := M1.Add(M4) + + if err != nil { + return Matrix[T]{}, err + } + A8, err := A7.Add(M7) + + if err != nil { + return Matrix[T]{}, err + } + A9, err := M1.Add(M3) + + if err != nil { + return Matrix[T]{}, err + } + A10, err := A9.Add(M6) + + if err != nil { + return Matrix[T]{}, err + } + // Calculate result submatrices + C11, err := A8.Subtract(M5) + if err != nil { + return Matrix[T]{}, err + } + C12, err := M3.Add(M5) + if err != nil { + return Matrix[T]{}, err + } + C21, err := M2.Add(M4) + if err != nil { + return Matrix[T]{}, err + } + C22, err := A10.Subtract(M2) + if err != nil { + return Matrix[T]{}, err + } + + // Combine subMatrices into the result matrix + var zeroVal T + C := New(n, n, zeroVal) + + for i := 0; i < mid; i++ { + for j := 0; j < mid; j++ { + val, err := C11.Get(i, j) + if err != nil { + return Matrix[T]{}, err + } + + err = C.Set(i, j, val) + if err != nil { + return Matrix[T]{}, err + } + + val, err = C12.Get(i, j) + if err != nil { + return Matrix[T]{}, err + } + + err1 := C.Set(i, j+mid, val) + if err1 != nil { + return Matrix[T]{}, err1 + } + val, err = C21.Get(i, j) + if err != nil { + return Matrix[T]{}, err + } + + err2 := C.Set(i+mid, j, val) + if err2 != nil { + return Matrix[T]{}, err2 + } + val, err = C22.Get(i, j) + if err != nil { + return Matrix[T]{}, err + } + + err3 := C.Set(i+mid, j+mid, val) + if err3 != nil { + return Matrix[T]{}, err3 + } + } + } + return C, nil + } +} diff --git a/math/matrix/strassenmatrixmultiply_test.go b/math/matrix/strassenmatrixmultiply_test.go new file mode 100644 index 000000000..a3e58d87a --- /dev/null +++ b/math/matrix/strassenmatrixmultiply_test.go @@ -0,0 +1,131 @@ +package matrix_test + +import ( + "math/rand" + "testing" + "time" + + "github.com/TheAlgorithms/Go/constraints" + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestStrassenMatrixMultiply(t *testing.T) { + // Create two sample matrices + dataA := [][]int{{1, 2}, {4, 5}} + dataB := [][]int{{9, 8}, {6, 5}} + matrixA, err := matrix.NewFromElements(dataA) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + matrixB, err := matrix.NewFromElements(dataB) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + + // Perform matrix multiplication using Strassen's algorithm + resultMatrix, err := matrixA.StrassenMatrixMultiply(matrixB) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + + // Expected result + expectedData, err := matrixA.Multiply(matrixB) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + + // Check the dimensions of the result matrix + expectedRows := expectedData.Rows() + expectedColumns := expectedData.Columns() + rows := resultMatrix.Rows() + columns := resultMatrix.Columns() + + if rows != expectedRows { + t.Errorf("Expected %d rows in result matrix, but got %d", expectedRows, rows) + } + + if columns != expectedColumns { + t.Errorf("Expected %d columns in result matrix, but got %d", expectedColumns, columns) + } + + // Check the values in the result matrix + for i := 0; i < expectedRows; i++ { + for j := 0; j < expectedColumns; j++ { + val, err := resultMatrix.Get(i, j) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + expVal, err := expectedData.Get(i, j) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + if val != expVal { + t.Errorf("Expected value %d at (%d, %d) in result matrix, but got %d", expVal, i, j, val) + } + } + } +} +func TestMatrixMultiplication(t *testing.T) { + rand.Seed(time.Now().UnixNano()) + + // Generate random matrices for testing + size := 1 << (rand.Intn(8) + 1) // tests for matrix with n as power of 2 + matrixA := MakeRandomMatrix[int](size, size) + matrixB := MakeRandomMatrix[int](size, size) + + // Calculate the expected result using the standard multiplication + expected, err := matrixA.Multiply(matrixB) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + // Calculate the result using the Strassen algorithm + result, err := matrixA.StrassenMatrixMultiply(matrixB) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + + // Check if the result matches the expected result + for i := 0; i < size; i++ { + for j := 0; j < size; j++ { + val, err := result.Get(i, j) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + exp, err := expected.Get(i, j) + if err != nil { + t.Error("copyMatrix.Set error: " + err.Error()) + } + if val != exp { + t.Errorf("Mismatch at position (%d, %d). Expected %d, but got %d.", i, j, exp, val) + } + } + } +} + +func MakeRandomMatrix[T constraints.Integer](rows, columns int) matrix.Matrix[T] { + rand.Seed(time.Now().UnixNano()) + + matrixData := make([][]T, rows) + for i := 0; i < rows; i++ { + matrixData[i] = make([]T, columns) + for j := 0; j < columns; j++ { + matrixData[i][j] = T(rand.Intn(1000)) // Generate random integers between 0 and 1000 + } + } + + randomMatrix, _ := matrix.NewFromElements(matrixData) + return randomMatrix +} + +// BenchmarkStrassenMatrixMultiply benchmarks the StrassenMatrixMultiply function. +func BenchmarkStrassenMatrixMultiply(b *testing.B) { + // Create sample matrices for benchmarking + rows := 64 // it is large enough for multiplication + columns := 64 + m1 := matrix.New(rows, columns, 2) // Replace with appropriate values + m2 := matrix.New(rows, columns, 3) // Replace with appropriate values + + for i := 0; i < b.N; i++ { + _, _ = m1.StrassenMatrixMultiply(m2) + } +} diff --git a/math/matrix/string.go b/math/matrix/string.go new file mode 100644 index 000000000..b59fe8c6c --- /dev/null +++ b/math/matrix/string.go @@ -0,0 +1,15 @@ +package matrix + +import "fmt" + +// String implements the fmt.Stringer interface for Matrix. +func (m Matrix[T]) String() string { + var result string + for i := range m.elements { + for j := range m.elements[i] { + result += fmt.Sprintf("%v ", m.elements[i][j]) + } + result += "\n" + } + return result +} diff --git a/math/matrix/string_test.go b/math/matrix/string_test.go new file mode 100644 index 000000000..59ca24510 --- /dev/null +++ b/math/matrix/string_test.go @@ -0,0 +1,96 @@ +package matrix_test + +import ( + "bytes" + "fmt" + "io" + "os" + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestMatrixString(t *testing.T) { + // Create a sample matrix for testing + m1, err := matrix.NewFromElements([][]int{{1, 2}, {3, 4}}) + if err != nil { + t.Errorf("Error creating matrix: %v", err) + } + + // Redirect stdout to capture Stringed output + old := os.Stdout + r, w, err := os.Pipe() + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + os.Stdout = w + + // Call the String method + fmt.Print(m1) + + // Reset stdout + w.Close() + os.Stdout = old + + // Read the captured output + var buf bytes.Buffer + _, err = io.Copy(&buf, r) + if err != nil { + t.Errorf("Error copying output: %v", err) + } + capturedOutput := buf.String() + + // Define the expected output + expectedOutput := "1 2 \n3 4 \n" + + // Compare the captured output with the expected output + if capturedOutput != expectedOutput { + t.Errorf("Matrix.Print() produced incorrect output:\n%s\nExpected:\n%s", capturedOutput, expectedOutput) + } +} + +func TestNullMatrixString(t *testing.T) { + + m1 := matrix.New(0, 0, 0) + // Redirect stdout to capture Stringed output + old := os.Stdout + r, w, err := os.Pipe() + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + os.Stdout = w + + // Call the String method + fmt.Print(m1) + + // Reset stdout + w.Close() + os.Stdout = old + + // Read the captured output + var buf bytes.Buffer + _, err = io.Copy(&buf, r) + if err != nil { + t.Errorf("Error copying output: %v", err) + } + capturedOutput := buf.String() + + // Define the expected output + expectedOutput := "" + + // Compare the captured output with the expected output + if capturedOutput != expectedOutput { + t.Errorf("Matrix.Print() produced incorrect output:\n%s\nExpected:\n%s", capturedOutput, expectedOutput) + } +} + +func BenchmarkString(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + m := matrix.New(rows, columns, 0) // Replace with appropriate values + + for i := 0; i < b.N; i++ { + _ = m.String() + } +} diff --git a/math/matrix/submatrix.go b/math/matrix/submatrix.go new file mode 100644 index 000000000..4d636e2c0 --- /dev/null +++ b/math/matrix/submatrix.go @@ -0,0 +1,79 @@ +package matrix + +import ( + "context" + "errors" + "sync" +) + +// SubMatrix extracts a submatrix from the current matrix. +func (m Matrix[T]) SubMatrix(rowStart, colStart, numRows, numCols int) (Matrix[T], error) { + if rowStart < 0 || colStart < 0 || numRows < 0 || numCols < 0 { + return Matrix[T]{}, errors.New("negative dimensions are not allowed") + } + + if rowStart+numRows > m.rows || colStart+numCols > m.columns { + return Matrix[T]{}, errors.New("submatrix dimensions exceed matrix bounds") + } + + var zeroVal T + if numRows == 0 || numCols == 0 { + return New(numRows, numCols, zeroVal), nil // Return an empty matrix + } + + subMatrix := New(numRows, numCols, zeroVal) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // Make sure it's called to release resources even if no errors + + var wg sync.WaitGroup + errCh := make(chan error, 1) + + for i := 0; i < numRows; i++ { + i := i // Capture the loop variable for the goroutine + wg.Add(1) + go func() { + defer wg.Done() + for j := 0; j < numCols; j++ { + select { + case <-ctx.Done(): + return // Context canceled; return without an error + default: + } + + val, err := m.Get(rowStart+i, colStart+j) + if err != nil { + cancel() + select { + case errCh <- err: + default: + } + return + } + + err = subMatrix.Set(i, j, val) + if err != nil { + cancel() + select { + case errCh <- err: + default: + } + return + } + } + }() + } + + // Wait for all goroutines to finish + go func() { + wg.Wait() + close(errCh) + }() + + // Check for any errors + if err := <-errCh; err != nil { + return Matrix[T]{}, err + } + + return subMatrix, nil +} diff --git a/math/matrix/submatrix_test.go b/math/matrix/submatrix_test.go new file mode 100644 index 000000000..09452496d --- /dev/null +++ b/math/matrix/submatrix_test.go @@ -0,0 +1,88 @@ +package matrix_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestMatrixSubMatrix(t *testing.T) { + // Create a sample matrix + data := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} + matrix, err := matrix.NewFromElements(data) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + // Extract a submatrix + subMatrix, err := matrix.SubMatrix(1, 1, 2, 2) + if err != nil { + t.Errorf("Error extracting submatrix: %v", err) + } + + // Check the dimensions of the submatrix + expectedRows := 2 + expectedColumns := 2 + rows := subMatrix.Rows() + columns := subMatrix.Columns() + + if rows != expectedRows { + t.Errorf("Expected %d rows in submatrix, but got %d", expectedRows, rows) + } + + if columns != expectedColumns { + t.Errorf("Expected %d columns in submatrix, but got %d", expectedColumns, columns) + } + + // Check the values in the submatrix + expectedData := [][]int{{5, 6}, {8, 9}} + for i := 0; i < expectedRows; i++ { + for j := 0; j < expectedColumns; j++ { + val, err := subMatrix.Get(i, j) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + if val != expectedData[i][j] { + t.Errorf("Expected value %d at (%d, %d) in submatrix, but got %d", expectedData[i][j], i, j, val) + } + } + } +} + +func TestMatrixInvalidSubMatrix(t *testing.T) { + // Create a sample matrix + data := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} + matrix, err := matrix.NewFromElements(data) + if err != nil { + t.Fatalf("Failed to copy matrix: %v", err) + } + // Attempt to extract an invalid submatrix + _, err = matrix.SubMatrix(1, 1, 3, 3) + + // Check if an error is returned + if err == nil { + t.Error("Expected an error for invalid submatrix dimensions, but got nil") + } + + // Check the error message + expectedErrorMessage := "submatrix dimensions exceed matrix bounds" + if err.Error() != expectedErrorMessage { + t.Errorf("Expected error message '%s', but got '%s'", expectedErrorMessage, err.Error()) + } +} + +// BenchmarkSubMatrix benchmarks the SubMatrix function. +func BenchmarkSubMatrix(b *testing.B) { + // Create a sample matrix for benchmarking + rows := 100 + columns := 100 + matrix := matrix.New(rows, columns, 2) // Replace with appropriate values + + rowStart := 10 + colStart := 10 + numRows := 20 + numCols := 20 + + for i := 0; i < b.N; i++ { + _, _ = matrix.SubMatrix(rowStart, colStart, numRows, numCols) + } +} diff --git a/math/matrix/subtract.go b/math/matrix/subtract.go new file mode 100644 index 000000000..761a7ed8c --- /dev/null +++ b/math/matrix/subtract.go @@ -0,0 +1,64 @@ +package matrix + +import ( + "context" + "errors" + "sync" +) + +// Subtract subtracts two matrices. +func (m1 Matrix[T]) Subtract(m2 Matrix[T]) (Matrix[T], error) { + // Check if the matrices have the same dimensions. + if !m1.MatchDimensions(m2) { + return Matrix[T]{}, errors.New("matrices are not compatible for subtraction") + } + + // Create a new matrix to store the result. + var zeroVal T + result := New(m1.Rows(), m1.Columns(), zeroVal) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // Make sure it's called to release resources even if no errors + + var wg sync.WaitGroup + errCh := make(chan error, 1) + + for i := 0; i < m1.rows; i++ { + i := i // Capture the loop variable for the goroutine + wg.Add(1) + go func() { + defer wg.Done() + for j := 0; j < m1.columns; j++ { + select { + case <-ctx.Done(): + return // Context canceled; return without an error + default: + } + + diff := m1.elements[i][j] - m2.elements[i][j] + err := result.Set(i, j, diff) + if err != nil { + cancel() // Cancel the context on error + select { + case errCh <- err: + default: + } + return + } + } + }() + } + + // Wait for all goroutines to finish + go func() { + wg.Wait() + close(errCh) + }() + + // Check for any errors + if err := <-errCh; err != nil { + return Matrix[T]{}, err + } + + return result, nil +} diff --git a/math/matrix/subtract_test.go b/math/matrix/subtract_test.go new file mode 100644 index 000000000..827d5c9e3 --- /dev/null +++ b/math/matrix/subtract_test.go @@ -0,0 +1,50 @@ +package matrix_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +func TestSubtract(t *testing.T) { + // Create two matrices with the same dimensions for Subtraction + m1 := matrix.New(2, 2, 1) + m2 := matrix.New(2, 2, 2) + + // Test case 1: Valid matrix Subtraction + subMatrix, err := m1.Subtract(m2) + if err != nil { + t.Errorf("Add(m1, m2) returned an error: %v, expected no error", err) + } + expectedMatrix := matrix.New(2, 2, -1) + res := subMatrix.CheckEqual(expectedMatrix) + if !res { + t.Errorf("Add(m1, m2) returned incorrect result:\n%v\nExpected:\n%v", subMatrix, expectedMatrix) + } + + // Create two matrices with different dimensions for Subtraction + m3 := matrix.New(2, 2, 1) + m4 := matrix.New(2, 3, 2) + + // Test case 2: Matrices with different dimensions + _, err2 := m3.Subtract(m4) + expectedError2 := fmt.Errorf("matrices are not compatible for subtraction") + if err2 == nil || err2.Error() != expectedError2.Error() { + t.Errorf("m3.Subtract(m4) returned error: %v, expected error: %v", err2, expectedError2) + } + +} + +// BenchmarkSubtract benchmarks the Subtract function. +func BenchmarkSubtract(b *testing.B) { + // Create sample matrices for benchmarking + rows := 100 + columns := 100 + m1 := matrix.New(rows, columns, 2) // Replace with appropriate values + m2 := matrix.New(rows, columns, 3) // Replace with appropriate values + + for i := 0; i < b.N; i++ { + _, _ = m1.Subtract(m2) + } +} From e33cfa9fc9ebb88db11cff9514c2605aeb0b07d0 Mon Sep 17 00:00:00 2001 From: Stanislav Zeman Date: Fri, 27 Oct 2023 19:43:25 +0200 Subject: [PATCH 441/488] feat: add Timsort sorting algorithm (#692) * feat: add timsort sorting algorithm implementation * test: add timsort sorting algorithm to tests * chore: remove left-over print statement * refactor: change insertionSortRun temp variable name * docs: add concise documentation to timsort algorithm * refactor: reuse insertion sort algorithm * refactor: reuse merge sort algorithm helper function * refactor: remove slice copying in merge run --------- Co-authored-by: Taj --- sort/sorts_test.go | 10 ++++++- sort/timsort.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 sort/timsort.go diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 0fd0a93fe..63ca010e0 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -186,7 +186,11 @@ func TestCycle(t *testing.T) { testFramework(t, sort.Cycle[int]) } -//END TESTS +func TestTimsort(t *testing.T) { + testFramework(t, sort.Timsort[int]) +} + +// END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { var sortTests = []struct { @@ -320,3 +324,7 @@ func BenchmarkPatience(b *testing.B) { func BenchmarkCycle(b *testing.B) { benchmarkFramework(b, sort.Cycle[int]) } + +func BenchmarkTimsort(b *testing.B) { + benchmarkFramework(b, sort.Timsort[int]) +} diff --git a/sort/timsort.go b/sort/timsort.go new file mode 100644 index 000000000..95520219a --- /dev/null +++ b/sort/timsort.go @@ -0,0 +1,71 @@ +// Implementation of Timsort algorithm +// Reference: https://en.wikipedia.org/wiki/Timsort + +package sort + +import ( + "github.com/TheAlgorithms/Go/constraints" +) + +const runSizeThreshold = 8 + +// Timsort is a simple generic implementation of Timsort algorithm. +func Timsort[T constraints.Ordered](data []T) []T { + runSize := calculateRunSize(len(data)) + insertionSortRuns(data, runSize) + mergeRuns(data, runSize) + return data +} + +// calculateRunSize returns a run size parameter that is further used +// to slice the data slice. +func calculateRunSize(dataLength int) int { + remainder := 0 + for dataLength >= runSizeThreshold { + if dataLength%2 == 1 { + remainder = 1 + } + + dataLength = dataLength / 2 + } + + return dataLength + remainder +} + +// insertionSortRuns runs insertion sort on all the data runs one by one. +func insertionSortRuns[T constraints.Ordered](data []T, runSize int) { + for lower := 0; lower < len(data); lower += runSize { + upper := lower + runSize + if upper >= len(data) { + upper = len(data) + } + + Insertion(data[lower:upper]) + } +} + +// mergeRuns merge sorts all the data runs into a single sorted data slice. +func mergeRuns[T constraints.Ordered](data []T, runSize int) { + for size := runSize; size < len(data); size *= 2 { + for lowerBound := 0; lowerBound < len(data); lowerBound += size * 2 { + middleBound := lowerBound + size - 1 + upperBound := lowerBound + 2*size - 1 + if len(data)-1 < upperBound { + upperBound = len(data) - 1 + } + + mergeRun(data, lowerBound, middleBound, upperBound) + } + } +} + +// mergeRun uses merge sort to sort adjacent data runs. +func mergeRun[T constraints.Ordered](data []T, lower, mid, upper int) { + left := data[lower : mid+1] + right := data[mid+1 : upper+1] + merged := merge(left, right) + // rewrite original data slice values with sorted values from merged slice + for i, value := range merged { + data[lower+i] = value + } +} From 75c49510b49879c736af3b8d21cc942e1a028162 Mon Sep 17 00:00:00 2001 From: Kiarash Hajian <133909368+kiarash8112@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:18:29 +0330 Subject: [PATCH 442/488] feat: graph cycle detection (#689) * feat: add HasCycle algorithm * feat: add FindAllCycles algorithm * docs: add comments to findAllCycles and HasCycle algorithm * test: add test for hasCycle Algorithm * test: add test for FindAllCycles Algorithm * hide imp detail for pkg out side graph/cycle.go Co-authored-by: Taj * hide imp detail for pkg out side graph/cycle.go Co-authored-by: Taj * feat: change FindAllcycles return type to graph * test: update findAllcycles tests * fix: fix HasCycle docs dictation --------- Co-authored-by: user Co-authored-by: Taj --- graph/cycle.go | 110 ++++++++++++++++++++++++++++++++++++++++++++ graph/cycle_test.go | 53 +++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 graph/cycle.go create mode 100644 graph/cycle_test.go diff --git a/graph/cycle.go b/graph/cycle.go new file mode 100644 index 000000000..cf45d1854 --- /dev/null +++ b/graph/cycle.go @@ -0,0 +1,110 @@ +// cycle.go +// this file handle algorithm that related to cycle in graph +// reference: https://en.wikipedia.org/wiki/Cycle_(graph_theory) +// [kiarash hajian](https://github.com/kiarash8112) + +package graph + +func (g *Graph) HasCycle() bool { + //this implimetation referred as 3-color too + all := map[int]struct{}{} + visiting := map[int]struct{}{} + visited := map[int]struct{}{} + + for v := range g.edges { + all[v] = struct{}{} + } + + for current := range all { + if g.hasCycleHelper(current, all, visiting, visited) { + return true + } + } + + return false + +} + +func (g Graph) hasCycleHelper(v int, all, visiting, visited map[int]struct{}) bool { + delete(all, v) + visiting[v] = struct{}{} + + neighbors := g.edges[v] + for v := range neighbors { + if _, ok := visited[v]; ok { + continue + } else if _, ok := visiting[v]; ok { + return true + } else if g.hasCycleHelper(v, all, visiting, visited) { + return true + } + } + delete(visiting, v) + visited[v] = struct{}{} + return false +} + +// this function can do HasCycle() job but it is slower +func (g *Graph) FindAllCycles() []Graph { + all := map[int]struct{}{} + visiting := map[int]struct{}{} + visited := map[int]struct{}{} + + allCycles := []Graph{} + + for v := range g.edges { + all[v] = struct{}{} + } + + for current := range all { + foundCycle, parents := g.findAllCyclesHelper(current, all, visiting, visited) + + if foundCycle { + foundCycleFromCurrent := false + //this loop remove additional vertex from detected cycle + //using foundCycleFromCurrent bool to make sure after removing vertex we still have cycle + for i := len(parents) - 1; i > 0; i-- { + if parents[i][1] == parents[0][0] { + parents = parents[:i+1] + foundCycleFromCurrent = true + } + } + if foundCycleFromCurrent { + graph := Graph{Directed: true} + for _, edges := range parents { + graph.AddEdge(edges[1], edges[0]) + } + allCycles = append(allCycles, graph) + } + + } + + } + + return allCycles + +} + +func (g Graph) findAllCyclesHelper(current int, all, visiting, visited map[int]struct{}) (bool, [][]int) { + parents := [][]int{} + + delete(all, current) + visiting[current] = struct{}{} + + neighbors := g.edges[current] + for v := range neighbors { + if _, ok := visited[v]; ok { + continue + } else if _, ok := visiting[v]; ok { + parents = append(parents, []int{v, current}) + return true, parents + } else if ok, savedParents := g.findAllCyclesHelper(v, all, visiting, visited); ok { + parents = append(parents, savedParents...) + parents = append(parents, []int{v, current}) + return true, parents + } + } + delete(visiting, current) + visited[current] = struct{}{} + return false, parents +} diff --git a/graph/cycle_test.go b/graph/cycle_test.go new file mode 100644 index 000000000..0ac7dfdbe --- /dev/null +++ b/graph/cycle_test.go @@ -0,0 +1,53 @@ +package graph + +import ( + "testing" +) + +func TestHasCycle(t *testing.T) { + graph := Graph{Directed: true} + edges := [][]int{{0, 1}, {1, 2}, {2, 0}, {4, 0}} + for _, edge := range edges { + graph.AddEdge(edge[0], edge[1]) + } + if !graph.HasCycle() { + t.Error("answer of hasCycle is not correct") + } + + graph = Graph{Directed: true} + edges = [][]int{{0, 1}, {1, 2}, {2, 6}, {4, 0}} + for _, edge := range edges { + graph.AddEdge(edge[0], edge[1]) + } + if graph.HasCycle() { + t.Error("answer of hasCycle is not correct") + } +} + +func TestFindAllCycles(t *testing.T) { + graph := Graph{Directed: true} + edges := [][]int{{0, 4}, {1, 3}, {2, 3}, {3, 4}, {4, 7}, {5, 2}, {6, 3}, {7, 3}} + for _, edge := range edges { + graph.AddEdge(edge[0], edge[1]) + } + + res := graph.FindAllCycles() + + if len(res) != 1 { + t.Error("number of cycles is not correct") + } + + firstCycle := res[0] + if len(firstCycle.edges) != 3 { + t.Error("number of vertex in cycle is not correct") + } + if _, ok := firstCycle.edges[3][4]; !ok { + t.Error("connection in cycle is not correct") + } + if _, ok := firstCycle.edges[4][7]; !ok { + t.Error("connection in cycle is not correct") + } + if _, ok := firstCycle.edges[7][3]; !ok { + t.Error("connection in cycle is not correct") + } +} From 5f887c50157f5b62113705be00c64566790db41d Mon Sep 17 00:00:00 2001 From: ")`(-@_.+_^*__*^" <55359898+11-aryan@users.noreply.github.com> Date: Sat, 11 Nov 2023 22:51:32 +0530 Subject: [PATCH 443/488] Added description for the NewSegmentTree function (#691) * Added description for the NewSegmentTree function * Fixed spelling errors and formatting issues * modified comments to comply with go docs * fixed spelling errors * fixed grammatical errors in comments --------- Co-authored-by: Rak Laptudirm --- structure/segmenttree/segmenttree.go | 39 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/structure/segmenttree/segmenttree.go b/structure/segmenttree/segmenttree.go index b55f69f0e..bf70f4522 100644 --- a/structure/segmenttree/segmenttree.go +++ b/structure/segmenttree/segmenttree.go @@ -1,9 +1,9 @@ -//Segment Tree Data Structure for Range Queries -//Build: O(n*log(n)) -//Query: O(log(n)) -//Update: O(log(n)) -//reference: https://cp-algorithms.com/data_structures/segment_tree.html - +// Segment Tree Data Structure for efficient range queries on an array of integers. +// It can query the sum and update the elements to a new value of any range of the array. +// Build: O(n*log(n)) +// Query: O(log(n)) +// Update: O(log(n)) +// reference: https://cp-algorithms.com/data_structures/segment_tree.html package segmenttree import ( @@ -13,14 +13,14 @@ import ( const emptyLazyNode = 0 -// SegmentTree with original Array and the Segment Tree Array +// SegmentTree represents the data structure of a segment tree with lazy propagation type SegmentTree struct { - Array []int - SegmentTree []int - LazyTree []int + Array []int // The original array + SegmentTree []int // Stores the sum of different ranges + LazyTree []int // Stores the values of lazy propagation } -// Propagate lazy tree node values +// Propagate propagates the lazy updates to the child nodes func (s *SegmentTree) Propagate(node int, leftNode int, rightNode int) { if s.LazyTree[node] != emptyLazyNode { //add lazy node value multiplied by (right-left+1), which represents all interval @@ -42,8 +42,8 @@ func (s *SegmentTree) Propagate(node int, leftNode int, rightNode int) { } } -// Query on interval [firstIndex, leftIndex] -// node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +// Query returns the sum of elements of the array in the interval [firstIndex, leftIndex]. +// node, leftNode and rightNode should always start with 1, 0 and len(Array)-1, respectively. func (s *SegmentTree) Query(node int, leftNode int, rightNode int, firstIndex int, lastIndex int) int { if (firstIndex > lastIndex) || (leftNode > rightNode) { //outside the interval @@ -67,10 +67,9 @@ func (s *SegmentTree) Query(node int, leftNode int, rightNode int, firstIndex in return leftNodeSum + rightNodeSum } -// Update Segment Tree -// node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 -// index is the Array index that you want to update -// value is the value that you want to override +// Update updates the elements of the array in the range [firstIndex, lastIndex] +// with the new value provided and recomputes the sum of different ranges. +// node, leftNode and rightNode should always start with 1, 0 and len(Array)-1, respectively. func (s *SegmentTree) Update(node int, leftNode int, rightNode int, firstIndex int, lastIndex int, value int) { //propagate lazy tree s.Propagate(node, leftNode, rightNode) @@ -96,8 +95,8 @@ func (s *SegmentTree) Update(node int, leftNode int, rightNode int, firstIndex i } } -// Build Segment Tree -// node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +// Build builds the SegmentTree by computing the sum of different ranges. +// node, leftNode and rightNode should always start with 1, 0 and len(Array)-1, respectively. func (s *SegmentTree) Build(node int, left int, right int) { if left == right { //leaf node @@ -113,6 +112,8 @@ func (s *SegmentTree) Build(node int, left int, right int) { } } +// NewSegmentTree returns a new instance of a SegmentTree. It takes an input +// array of integers representing Array, initializes and builds the SegmentTree. func NewSegmentTree(Array []int) *SegmentTree { if len(Array) == 0 { return nil From 48a0d570da13576d5d3ae90b029d8fd1cefae0de Mon Sep 17 00:00:00 2001 From: FanOne Date: Wed, 15 Nov 2023 21:56:22 +0800 Subject: [PATCH 444/488] feat:add lfu cache alogrithm (#695) * feat:add lfu cache alogrithm * feat:add the functions and types of LFU in README.md * fix: unexport initItem func --------- Co-authored-by: Taj --- README.md | 8 ++- cache/lfu.go | 127 ++++++++++++++++++++++++++++++++++++++++++++++ cache/lfu_test.go | 58 +++++++++++++++++++++ cache/lru.go | 3 ++ 4 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 cache/lfu.go create mode 100644 cache/lfu_test.go diff --git a/README.md b/README.md index 4837c61f4..938aaa548 100644 --- a/README.md +++ b/README.md @@ -89,12 +89,16 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ##### Functions: -1. [`NewLRU`](./cache/lru.go#L20): NewLRU represent initiate lru cache with capacity +1. [`NewLRU`](./cache/lru.go#L22): NewLRU represent initiate lru cache with capacity +2. [`NewLFU`](./cache/lfu.go#L33): NewLFU represent initiate lfu cache with capacity +3. [`Get`](./cache/lfu.go#L52): Get the value by key from LFU cache +4. [`Put`](./cache/lfu.go#L66): Put the key and value in LFU cache --- ##### Types -1. [`LRU`](./cache/lru.go#L12): No description provided. +1. [`LRU`](./cache/lru.go#L15): Default the struct of lru cache algorithm. +2. [`LFU`](./cache/lfu.go#L19): Default the struct of lfu cache algorithm. --- diff --git a/cache/lfu.go b/cache/lfu.go new file mode 100644 index 000000000..e22670c68 --- /dev/null +++ b/cache/lfu.go @@ -0,0 +1,127 @@ +// lfu.go +// description: a type of cache algorithm used to manage memory within a computer. +// details: +// The standard characteristics of this method involve the system keeping track of the number of times a block is referenced in memory. +// When the cache is full and requires more room the system will purge the item with the lowest reference frequency. +// ref: (https://en.wikipedia.org/wiki/Least_frequently_used) +// time complexity: O(N) +// space complexity: O(1) +// author: [CocaineCong](https://github.com/CocaineCong) + +package cache + +import ( + "container/list" + "math" +) + +// LFU the Least Frequently Used (LFU) page-replacement algorithm +type LFU struct { + len int // length + cap int // capacity + minFreq int // The element that operates least frequently in LFU + + // key: key of element, value: value of element + itemMap map[string]*list.Element + + // key: frequency of possible occurrences of all elements in the itemMap + // value: elements with the same frequency + freqMap map[int]*list.List +} + +// NewLFU init the LFU cache with capacity +func NewLFU(capacity int) LFU { + return LFU{ + len: 0, + cap: capacity, + minFreq: math.MaxInt, + itemMap: make(map[string]*list.Element), + freqMap: make(map[int]*list.List), + } +} + +// initItem to init item for LFU +func initItem(k string, v any, f int) item { + return item{ + key: k, + value: v, + freq: f, + } +} + +// Get the key in cache by LFU +func (c *LFU) Get(key string) any { + // if existed, will return value + if e, ok := c.itemMap[key]; ok { + // the frequency of e +1 and change freqMap + c.increaseFreq(e) + obj := e.Value.(item) + return obj.value + } + + // if not existed, return nil + return nil +} + +// Put the key in LFU cache +func (c *LFU) Put(key string, value any) { + if e, ok := c.itemMap[key]; ok { + // if key existed, update the value + obj := e.Value.(item) + obj.value = value + c.increaseFreq(e) + } else { + // if key not existed + obj := initItem(key, value, 1) + // if the length of item gets to the top line + // remove the least frequently operated element + if c.len == c.cap { + c.eliminate() + c.len-- + } + // insert in freqMap and itemMap + c.insertMap(obj) + // change minFreq to 1 because insert the newest one + c.minFreq = 1 + // length++ + c.len++ + } +} + +// increaseFreq increase the frequency if element +func (c *LFU) increaseFreq(e *list.Element) { + obj := e.Value.(item) + // remove from low frequency first + oldLost := c.freqMap[obj.freq] + oldLost.Remove(e) + // change the value of minFreq + if c.minFreq == obj.freq && oldLost.Len() == 0 { + // if it is the last node of the minimum frequency that is removed + c.minFreq++ + } + // add to high frequency list + c.insertMap(obj) +} + +// insertMap insert item in map +func (c *LFU) insertMap(obj item) { + // add in freqMap + l, ok := c.freqMap[obj.freq] + if !ok { + l = list.New() + c.freqMap[obj.freq] = l + } + e := l.PushFront(obj) + // update or add the value of itemMap key to e + c.itemMap[obj.key] = e +} + +// eliminate clear the least frequently operated element +func (c *LFU) eliminate() { + l := c.freqMap[c.minFreq] + e := l.Back() + obj := e.Value.(item) + l.Remove(e) + + delete(c.itemMap, obj.key) +} diff --git a/cache/lfu_test.go b/cache/lfu_test.go new file mode 100644 index 000000000..7e891412f --- /dev/null +++ b/cache/lfu_test.go @@ -0,0 +1,58 @@ +package cache_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/cache" +) + +func TestLFU(t *testing.T) { + lfuCache := cache.NewLFU(3) + t.Run("Test 1: Put number and Get is correct", func(t *testing.T) { + key, value := "1", 1 + lfuCache.Put(key, value) + got := lfuCache.Get(key) + + if got != value { + t.Errorf("expected: %v, got: %v", value, got) + } + }) + + t.Run("Test 2: Get data not stored in cache should return nil", func(t *testing.T) { + got := lfuCache.Get("2") + if got != nil { + t.Errorf("expected: nil, got: %v", got) + } + }) + + t.Run("Test 3: Put data over capacity and Get should return nil", func(t *testing.T) { + lfuCache.Put("2", 2) + lfuCache.Put("3", 3) + lfuCache.Put("4", 4) + + got := lfuCache.Get("1") + if got != nil { + t.Errorf("expected: nil, got: %v", got) + } + }) + + t.Run("test 4: Put key over capacity but recent key exists", func(t *testing.T) { + lfuCache.Put("4", 4) + lfuCache.Put("3", 3) + lfuCache.Put("2", 2) + lfuCache.Put("1", 1) + + got := lfuCache.Get("4") + if got != nil { + t.Errorf("expected: nil, got: %v", got) + } + + expected := 3 + got = lfuCache.Get("3") + + if got != expected { + t.Errorf("expected: %v, got: %v", expected, got) + } + + }) +} diff --git a/cache/lru.go b/cache/lru.go index c6b8c734e..8c27cfc1f 100644 --- a/cache/lru.go +++ b/cache/lru.go @@ -7,6 +7,9 @@ import ( type item struct { key string value any + + // the frequency of key + freq int } type LRU struct { From 778502aaeb3a98b5825a5e944f72d00218fe849b Mon Sep 17 00:00:00 2001 From: Nabin Khanal <91933095+nabinkhanal00@users.noreply.github.com> Date: Wed, 15 Nov 2023 19:53:41 +0545 Subject: [PATCH 445/488] fixed typo (#696) Co-authored-by: Nabin Khanal Co-authored-by: Rak Laptudirm --- strings/parenthesis/parenthesis_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/strings/parenthesis/parenthesis_test.go b/strings/parenthesis/parenthesis_test.go index b7f5abd6c..685c761c4 100644 --- a/strings/parenthesis/parenthesis_test.go +++ b/strings/parenthesis/parenthesis_test.go @@ -15,17 +15,17 @@ var parenthesisTestCases = []struct { true, }, { - "three nested pharentesis with three deep level", + "three nested parenthesis with three deep level", "(-1*(5+2^(3-4)*(7.44-12)+6.66/(3.43-(1+2)))*(sqrt(3-4)))", true, }, { - "one opened pharentesis without be closed", + "one opened parenthesis without be closed", "(2*9-17)*((7+3/3)*2*(-1+4)", false, }, { - "one open pharentesis for each close one but not in pairs", + "one open parenthesis for each close one but not in pairs", "(4*(39.22-7.4)/6.77))(", false, }, @@ -35,7 +35,7 @@ var parenthesisTestCases = []struct { true, }, { - "inverted pharentesis", + "inverted parenthesis", ")()()()()(", false, }, From c1688bfe84906b05c0aa2ab2def6ee3b4451042f Mon Sep 17 00:00:00 2001 From: ")`(-@_.+_^*__*^" <55359898+11-aryan@users.noreply.github.com> Date: Sun, 10 Dec 2023 13:32:33 +0530 Subject: [PATCH 446/488] Add Fenwick Tree to Structures (#685) * Add Fenwick Tree to Structures * fixed ineffectual assignment to result * removed redundant variable declaration * fixed comments to comply with godocs --------- Co-authored-by: Taj Co-authored-by: Rak Laptudirm --- structure/fenwicktree/fenwicktree.go | 60 +++++++++++++++++ structure/fenwicktree/fenwicktree_test.go | 81 +++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 structure/fenwicktree/fenwicktree.go create mode 100644 structure/fenwicktree/fenwicktree_test.go diff --git a/structure/fenwicktree/fenwicktree.go b/structure/fenwicktree/fenwicktree.go new file mode 100644 index 000000000..915d7b085 --- /dev/null +++ b/structure/fenwicktree/fenwicktree.go @@ -0,0 +1,60 @@ +// Fenwick Tree Data Structure for efficient range queries on an array of integers. +// Also known as Binary Indexed Tree. It can query the sum of any range of the array and +// can update the array at a specific position by adding a value to it (point update). +// Build: O(N) +// Query: O(log(N)) +// Update: O(log(N)) +// reference: https://brilliant.org/wiki/fenwick-tree/ +package fenwicktree + +// FenwickTree represents the data structure of the Fenwick Tree +type FenwickTree struct { + n int // n: Size of the input array. + array []int // array: the input array on which queries are made. + bit []int // bit: store the sum of ranges. +} + +// NewFenwickTree creates a new Fenwick tree, initializes bit with +// the values of the array. Note that the queries and updates should have +// one based indexing. +func NewFenwickTree(array []int) *FenwickTree { + newArray := []int{0} // Appending a 0 to the beginning as this implementation uses 1 based indexing + fenwickTree := &FenwickTree{ + n: len(array), + array: append(newArray, array...), + bit: append(newArray, array...), + } + for i := 1; i < fenwickTree.n; i++ { + nextPos := i + (i & -i) + if nextPos <= fenwickTree.n { + fenwickTree.bit[nextPos] += fenwickTree.bit[i] + } + } + return fenwickTree +} + +// PrefixSum returns the sum of the prefix ending at position pos. +func (f *FenwickTree) PrefixSum(pos int) int { + if pos > f.n { + return 0 + } + prefixSum := 0 + for i := pos; i > 0; i -= (i & -i) { + prefixSum += f.bit[i] + } + return prefixSum +} + +// RangeSum returns the sum of the elements in the range l to r +// both inclusive. +func (f *FenwickTree) RangeSum(l int, r int) int { + return f.PrefixSum(r) - f.PrefixSum(l-1) +} + +// Add Adds value to the element at position pos of the array +// and recomputes the range sums. +func (f *FenwickTree) Add(pos int, value int) { + for i := pos; i <= f.n; i += (i & -i) { + f.bit[i] += value + } +} diff --git a/structure/fenwicktree/fenwicktree_test.go b/structure/fenwicktree/fenwicktree_test.go new file mode 100644 index 000000000..99c9f12fc --- /dev/null +++ b/structure/fenwicktree/fenwicktree_test.go @@ -0,0 +1,81 @@ +package fenwicktree_test + +import ( + "github.com/TheAlgorithms/Go/structure/fenwicktree" + "testing" +) + +type query struct { + queryType string + firstIndex int // firstIndex and lastIndex are same for point queries + lastIndex int +} + +type update struct { + pos int + value int +} + +func TestFenwickTree(t *testing.T) { + var fenwickTreeTestData = []struct { + description string + array []int + updates []update + queries []query + expected []int + }{ + { + description: "test empty array", + array: []int{}, + queries: []query{{"point", 1, 1}}, + expected: []int{0}, + }, + { + description: "test array with size 5", + array: []int{1, 2, 3, 4, 5}, + queries: []query{{"range", 1, 5}, {"range", 1, 3}, {"range", 3, 5}}, + expected: []int{15, 6, 12}, + }, + { + description: "test array with size 5, single index updates and range queries", + array: []int{1, 2, 3, 4, 5}, + updates: []update{{pos: 2, value: 2}, {pos: 3, value: 3}}, + queries: []query{{"range", 1, 5}, {"range", 1, 3}, {"range", 3, 5}}, + expected: []int{20, 11, 15}, + }, + { + description: "test array with size 5, single index updates and point queries", + array: []int{1, 2, 3, 4, 5}, + updates: []update{{pos: 2, value: 2}, {pos: 3, value: 3}}, + queries: []query{{"point", 3, 3}, {"point", 1, 1}, {"point", 5, 5}}, + expected: []int{11, 1, 20}, + }, + } + + for _, test := range fenwickTreeTestData { + t.Run(test.description, func(t *testing.T) { + fenwickTree := fenwicktree.NewFenwickTree(test.array) + + for i := 0; i < len(test.updates); i++ { + fenwickTree.Add(test.updates[i].pos, test.updates[i].value) + } + + for i := 0; i < len(test.queries); i++ { + + var result int + + if test.queries[i].queryType == "point" { + result = fenwickTree.PrefixSum(test.queries[i].firstIndex) + } else { + result = fenwickTree.RangeSum(test.queries[i].firstIndex, test.queries[i].lastIndex) + } + + if result != test.expected[i] { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expected result: %d\nFound: %d\n", test.expected[i], result) + } + } + }) + } + +} From dc0cb361b8c5f8250355948a3e313e837f7e362d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mert=20G=C3=B6r=20=E2=98=AD?= Date: Sun, 31 Dec 2023 09:16:26 +0300 Subject: [PATCH 447/488] Copyright Holders Update to make it more clear (#700) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index f6bcf04e7..71b9656b7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 The Algorithms +Copyright (c) 2021 The Algorithms and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From db7c875cccfd2189afaea3cfda7313f3b83fe6b1 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 13 Jan 2024 16:25:51 +0100 Subject: [PATCH 448/488] fix: use `GITHUB_ACTOR` in `git config` (#701) --- .github/workflows/godocmd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index 454f1a632..a4ea126ca 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -20,8 +20,8 @@ jobs: go install github.com/tjgurwara99/godocmd@v0.1.3 - name: Configure Github Action run: | - git config --global user.name github-action - git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com' + git config --global user.name "$GITHUB_ACTOR" + git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" - name: Update README.md file run: | godocmd -r -module ./ -w From ea269222a7c1f03d9d2516740f62675526eeaea9 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Tue, 23 Jan 2024 07:00:23 +0100 Subject: [PATCH 449/488] chore: add `upload_coverage_report.yml` (#697) --- .github/workflows/upload_coverage_report.yml | 31 ++++++++++++++++++++ .gitignore | 1 + 2 files changed, 32 insertions(+) create mode 100644 .github/workflows/upload_coverage_report.yml diff --git a/.github/workflows/upload_coverage_report.yml b/.github/workflows/upload_coverage_report.yml new file mode 100644 index 000000000..2308cc871 --- /dev/null +++ b/.github/workflows/upload_coverage_report.yml @@ -0,0 +1,31 @@ +--- +name: upload_coverage_report + +on: + workflow_dispatch: + push: + branches: + - master + pull_request: + +env: + REPORT_NAME: "coverage.out" + +jobs: + upload_coverage_report: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: '^1.18' + - name: Generate code coverage + run: | + go test -coverprofile="${{ env.REPORT_NAME }}" ./... + - name: Upload coverage to codecov + uses: codecov/codecov-action@v3 + with: + files: "${{ env.REPORT_NAME }}" + fail_ci_if_error: true +... diff --git a/.gitignore b/.gitignore index 66f8fb502..1af018398 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/ .vscode/ +coverage.out From 36d29bbdcedcd47ef5af36cf1087880e66f5ec5f Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 27 Jan 2024 17:55:55 +0100 Subject: [PATCH 450/488] docs: add codecov badge (#702) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 938aaa548..1d9b007cc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # The Algorithms - Go [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/TheAlgorithms/Go)  [![Continuous Integration](https://github.com/TheAlgorithms/Go/actions/workflows/ci.yml/badge.svg)](https://github.com/TheAlgorithms/Go/actions/workflows/ci.yml) +[![codecov](https://codecov.io/gh/TheAlgorithms/Go/graph/badge.svg?token=aSWh7N8tNx)](https://codecov.io/gh/TheAlgorithms/Go) ![godocmd](https://github.com/tjgurwara99/Go/workflows/godocmd/badge.svg) ![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  ![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) From 6d839027b6765b7cd14b00ffdd54678bd70dc63e Mon Sep 17 00:00:00 2001 From: Taj Date: Mon, 11 Mar 2024 16:03:12 +0000 Subject: [PATCH 451/488] chore: let tjguwara99 take a break (#708) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d709eff88..0aec70ce1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,4 +7,4 @@ # Order is important. The last matching pattern has the most precedence. -* @raklaptudirm @tjgurwara99 @yanglbme +* @raklaptudirm @yanglbme From 3f2fa293d60daeea59265a124ac97427a87efbc7 Mon Sep 17 00:00:00 2001 From: jafar75 Date: Tue, 12 Mar 2024 13:22:49 +0330 Subject: [PATCH 452/488] fix: remove redundant init step for unionFind (#709) --- graph/kruskal.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/graph/kruskal.go b/graph/kruskal.go index 0543e2829..193e3f236 100644 --- a/graph/kruskal.go +++ b/graph/kruskal.go @@ -28,12 +28,6 @@ func KruskalMST(n int, edges []Edge) ([]Edge, int) { // Create a new UnionFind data structure with 'n' nodes u := NewUnionFind(n) - // Initialize each node in the UnionFind data structure - for i := 0; i < n; i++ { - u.parent[i] = i - u.size[i] = 1 - } - // Sort the edges in non-decreasing order based on their weights sort.SliceStable(edges, func(i, j int) bool { return edges[i].Weight < edges[j].Weight From 237d88f7595ca5e1be20830ea7f01fe43e93d154 Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Wed, 13 Mar 2024 00:10:32 -0700 Subject: [PATCH 453/488] feat: Add btree with insertion, deletion, and search (#703) * feat: Add btree with insertion, deletion, and search * Lazy allocate root and handle cases with null root * Fix formatting --------- Co-authored-by: Rak Laptudirm --- structure/tree/btree.go | 355 +++++++++++++++++++++++++++++++++++ structure/tree/btree_test.go | 133 +++++++++++++ 2 files changed, 488 insertions(+) create mode 100644 structure/tree/btree.go create mode 100644 structure/tree/btree_test.go diff --git a/structure/tree/btree.go b/structure/tree/btree.go new file mode 100644 index 000000000..5b2e55eb7 --- /dev/null +++ b/structure/tree/btree.go @@ -0,0 +1,355 @@ +// B-tree is a self balancing tree that promotes data locality. +// For more details, see https://en.wikipedia.org/wiki/B-tree + +package tree + +import "github.com/TheAlgorithms/Go/constraints" + +type BTreeNode[T constraints.Ordered] struct { + keys []T + children []*BTreeNode[T] + numKeys int + isLeaf bool +} + +type BTree[T constraints.Ordered] struct { + root *BTreeNode[T] + maxKeys int +} + +func minKeys(maxKeys int) int { + return (maxKeys - 1) / 2 +} + +func NewBTreeNode[T constraints.Ordered](maxKeys int, isLeaf bool) *BTreeNode[T] { + if maxKeys <= 0 { + panic("BTree maxKeys cannot be zero") + } + return &BTreeNode[T]{ + keys: make([]T, maxKeys), + children: make([]*BTreeNode[T], maxKeys+1), + isLeaf: isLeaf, + } +} + +func NewBTree[T constraints.Ordered](maxKeys int) *BTree[T] { + if maxKeys <= 2 { + panic("Must be >= 3 keys") + } + return &BTree[T]{ + root: nil, + maxKeys: maxKeys, + } +} + +func (node *BTreeNode[T]) Verify(tree *BTree[T]) { + minKeys := minKeys(tree.maxKeys) + if node != tree.root && node.numKeys < minKeys { + panic("node has too few keys") + } else if node.numKeys > tree.maxKeys { + panic("node has too many keys") + } +} + +func (node *BTreeNode[T]) IsFull(maxKeys int) bool { + return node.numKeys == maxKeys +} + +func (node *BTreeNode[T]) Search(key T) bool { + i := 0 + for ; i < node.numKeys; i++ { + if key == node.keys[i] { + return true + } + if key < node.keys[i] { + break + } + } + if node.isLeaf { + return false + } + return node.children[i].Search(key) +} + +func (tree *BTree[T]) Search(key T) bool { + if tree.root == nil { + return false + } + return tree.root.Search(key) +} + +func (node *BTreeNode[T]) InsertKeyChild(key T, child *BTreeNode[T]) { + i := node.numKeys + node.children[i+1] = node.children[i] + for ; i > 0; i-- { + if key > node.keys[i-1] { + node.keys[i] = key + node.children[i] = child + break + } + node.keys[i] = node.keys[i-1] + node.children[i] = node.children[i-1] + } + if i == 0 { + node.keys[0] = key + node.children[0] = child + } + node.numKeys++ +} + +func (node *BTreeNode[T]) Append(key T, child *BTreeNode[T]) { + node.keys[node.numKeys] = key + node.children[node.numKeys+1] = child + node.numKeys++ +} + +// Add all of other's keys starting from idx and children starting from idx + 1 +func (node *BTreeNode[T]) Concat(other *BTreeNode[T], idx int) { + for i := 0; i < other.numKeys-idx; i++ { + node.keys[node.numKeys+i] = other.keys[i+idx] + node.children[node.numKeys+i+1] = other.children[i+idx+1] + } + node.numKeys += other.numKeys - idx +} + +// Transform: +// +// A B +// | +// +// a b c d +// +// Into: +// +// A c B +// / \ +// +// a b d +func (parent *BTreeNode[T]) Split(idx int, maxKeys int) { + child := parent.children[idx] + midKeyIndex := maxKeys / 2 + rightChild := NewBTreeNode[T](maxKeys, child.isLeaf) + rightChild.Concat(child, midKeyIndex+1) + rightChild.children[0] = child.children[midKeyIndex+1] + + // Reuse child as the left node + child.numKeys = midKeyIndex + + // Insert the child's mid index to the parent + for i := parent.numKeys; i > idx; i-- { + parent.keys[i] = parent.keys[i-1] + parent.children[i+1] = parent.children[i] + } + parent.keys[idx] = child.keys[midKeyIndex] + parent.children[idx] = child + parent.children[idx+1] = rightChild + parent.numKeys += 1 +} + +func (node *BTreeNode[T]) InsertNonFull(tree *BTree[T], key T) { + node.Verify(tree) + if node.IsFull(tree.maxKeys) { + panic("Called InsertNonFull() with a full node") + } + + if node.isLeaf { + // Node is a leaf. Directly insert the key. + node.InsertKeyChild(key, nil) + return + } + + // Find the child node to insert into + i := 0 + for ; i < node.numKeys; i++ { + if key < node.keys[i] { + break + } + } + + if node.children[i].IsFull(tree.maxKeys) { + node.Split(i, tree.maxKeys) + if key > node.keys[i] { + i++ + } + } + node.children[i].InsertNonFull(tree, key) +} + +func (tree *BTree[T]) Insert(key T) { + if tree.root == nil { + tree.root = NewBTreeNode[T](tree.maxKeys, true) + tree.root.keys[0] = key + tree.root.numKeys = 1 + return + } + + if tree.root.IsFull(tree.maxKeys) { + newRoot := NewBTreeNode[T](tree.maxKeys, false) + newRoot.numKeys = 0 + newRoot.children[0] = tree.root + newRoot.Split(0, tree.maxKeys) + tree.root = newRoot + } + tree.root.InsertNonFull(tree, key) +} + +func (node *BTreeNode[T]) DeleteIthKey(i int) { + if i >= node.numKeys { + panic("deleting out of bounds key") + } + for j := i; j < node.numKeys-1; j++ { + node.keys[j] = node.keys[j+1] + node.children[j+1] = node.children[j+2] + } + node.numKeys-- +} + +// Transform: +// +// A B C +// / \ +// a b +// +// Into: +// +// A C +// | +// +// a B c +func (node *BTreeNode[T]) Merge(idx int) { + if node.isLeaf { + panic("cannot merge when leaf node is parent") + } + left := node.children[idx] + right := node.children[idx+1] + left.Append(node.keys[idx], right.children[0]) + left.Concat(right, 0) + node.DeleteIthKey(idx) +} + +func (node *BTreeNode[T]) Min() T { + if node.isLeaf { + return node.keys[0] + } + return node.children[0].Min() +} + +func (node *BTreeNode[T]) Max() T { + if node.isLeaf { + return node.keys[node.numKeys-1] + } + return node.children[node.numKeys].Max() +} + +func (node *BTreeNode[T]) Delete(tree *BTree[T], key T) { + node.Verify(tree) + if node.isLeaf { + // Case 1: Node is a leaf. Directly delete the key. + for i := 0; i < node.numKeys; i++ { + if key == node.keys[i] { + node.DeleteIthKey(i) + return + } + } + return + } + + minKeys := minKeys(tree.maxKeys) + i := 0 + for ; i < node.numKeys; i++ { + if key == node.keys[i] { + // Case 2: key exists in a non-leaf node + left := node.children[i] + right := node.children[i+1] + if left.numKeys > minKeys { + // Replace the key we want to delete with the max key from the left + // subtree. Then delete that key from the left subtree. + // A B C + // / + // a b c + // + // If we want to delete `B`, then replace `B` with `c`, and delete `c` in the subtree. + // A c C + // / + // a b + replacementKey := left.Max() + node.keys[i] = replacementKey + left.Delete(tree, replacementKey) + } else if right.numKeys > minKeys { + // Replace the key we want to delete with the min key from the right + // subtree. Then delete that key in the right subtree. Mirrors the + // transformation above for replacing from the left subtree. + replacementKey := right.Min() + node.keys[i] = replacementKey + right.Delete(tree, replacementKey) + } else { + // Both left and right subtrees have the minimum number of keys. Merge + // the left tree, the deleted key, and the right tree together into the + // left tree. Then recursively delete the key in the left tree. + if left.numKeys != minKeys || right.numKeys != minKeys { + panic("nodes should not have less than the minimum number of keys") + } + node.Merge(i) + left.Delete(tree, key) + } + return + } + + if key < node.keys[i] { + break + } + } + + // Case 3: key may exist in a child node. + child := node.children[i] + if child.numKeys == minKeys { + // Before we recurse into the child node, make sure it has more than + // the minimum number of keys. + if i > 0 && node.children[i-1].numKeys > minKeys { + // Take a key from the left sibling + // Transform: + // A B C + // / \ + // a b c + // + // Into: + // A b C + // / \ + // a B c + left := node.children[i-1] + child.InsertKeyChild(node.keys[i-1], left.children[left.numKeys]) + node.keys[i-1] = left.keys[left.numKeys-1] + left.numKeys-- + } else if i < node.numKeys && node.children[i+1].numKeys > minKeys { + // Take a key from the right sibling. Mirrors the transformation above for taking a key from the left sibling. + right := node.children[i+1] + child.Append(node.keys[i], right.children[0]) + node.keys[i] = right.keys[0] + right.children[0] = right.children[1] + right.DeleteIthKey(0) + } else { + if i == 0 { + // Merge with right sibling + node.Merge(i) + } else { + // Merge with left sibling + node.Merge(i - 1) + child = node.children[i-1] + } + } + } + if child.numKeys == minKeys { + panic("cannot delete key from node with minimum number of keys") + } + child.Delete(tree, key) +} + +func (tree *BTree[T]) Delete(key T) { + if tree.root == nil { + return + } + tree.root.Delete(tree, key) + if tree.root.numKeys == 0 { + tree.root = tree.root.children[0] + } +} diff --git a/structure/tree/btree_test.go b/structure/tree/btree_test.go new file mode 100644 index 000000000..056461b1c --- /dev/null +++ b/structure/tree/btree_test.go @@ -0,0 +1,133 @@ +package tree_test + +import ( + bt "github.com/TheAlgorithms/Go/structure/tree" + "math/rand" + "testing" +) + +func TestBTreeIncreasing(t *testing.T) { + maxKeysCases := []int{4, 16} + sizes := []int{100, 0xBA5, 0xF00} + for _, maxKeys := range maxKeysCases { + for _, size := range sizes { + tree := bt.NewBTree[int](maxKeys) + if tree.Search(0) { + t.Errorf("Tree expected to contain 0") + } + for i := 0; i < size; i++ { + tree.Insert(i) + } + for i := 0; i < size; i++ { + if !tree.Search(i) { + t.Errorf("Tree expected to contain %d", i) + } + } + if tree.Search(size + 1) { + t.Errorf("Tree not expected to contain %d", size+1) + } + + for i := 0; i < size; i += 5 { + tree.Delete(i) + } + for i := 0; i < size; i++ { + hasKey := tree.Search(i) + if i%5 == 0 && hasKey { + t.Errorf("Tree not expected to contain %d", i) + } else if i%5 != 0 && !hasKey { + t.Errorf("Tree expected to contain %d", i) + } + } + } + } +} + +func TestBTreeDecreasing(t *testing.T) { + maxKeysCases := []int{4, 16} + sizes := []int{100, 1000} + for _, maxKeys := range maxKeysCases { + for _, size := range sizes { + tree := bt.NewBTree[int](maxKeys) + if tree.Search(0) { + t.Errorf("Tree expected to contain 0") + } + for i := size - 1; i >= 0; i-- { + tree.Insert(i) + } + for i := 0; i < size; i++ { + if !tree.Search(i) { + t.Errorf("Tree expected to contain %d", i) + } + } + if tree.Search(size + 1) { + t.Errorf("Tree not expected to contain %d", size+1) + } + + for i := 0; i < size; i += 5 { + tree.Delete(i) + } + for i := 0; i < size; i++ { + hasKey := tree.Search(i) + if i%5 == 0 && hasKey { + t.Errorf("Tree not expected to contain %d", i) + } else if i%5 != 0 && !hasKey { + t.Errorf("Tree expected to contain %d", i) + } + } + } + } +} + +func TestBTreeRandom(t *testing.T) { + maxKeysCases := []int{4, 16} + sizes := []int{100, 0xBA5, 0xF00} + for _, maxKeys := range maxKeysCases { + for _, size := range sizes { + rnd := rand.New(rand.NewSource(0)) + tree := bt.NewBTree[int](maxKeys) + nums := rnd.Perm(size) + if tree.Search(0) { + t.Errorf("Tree expected to contain 0") + } + for i := 0; i < size; i++ { + tree.Insert(nums[i]) + } + for i := 0; i < size; i++ { + if !tree.Search(nums[i]) { + t.Errorf("Tree expected to contain %d", nums[i]) + } + } + + for i := 0; i < size; i += 5 { + tree.Delete(nums[i]) + } + for i := 0; i < size; i++ { + hasKey := tree.Search(nums[i]) + if i%5 == 0 && hasKey { + t.Errorf("Tree not expected to contain %d", i) + } else if i%5 != 0 && !hasKey { + t.Errorf("Tree expected to contain %d", i) + } + } + } + } +} + +func TestBTreeDeleteEverything(t *testing.T) { + tree := bt.NewBTree[int](4) + size := 128 + for i := 0; i < size; i++ { + tree.Insert(i) + } + for i := 0; i < size; i++ { + tree.Delete(i) + } + tree.Delete(-1) + tree.Delete(1000) + + for i := 0; i < size; i++ { + if tree.Search(i) { + t.Errorf("Tree not expected to contain %d", i) + } + } +} From 0254892642fa4a9c2e55bec0a152bb721830b455 Mon Sep 17 00:00:00 2001 From: jafar75 Date: Fri, 15 Mar 2024 20:55:06 +0330 Subject: [PATCH 454/488] feat: add prim algorithm to find mst (#710) --- README.md | 13 +++-- graph/prim.go | 58 ++++++++++++++++++ graph/prim_test.go | 143 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 graph/prim.go create mode 100644 graph/prim_test.go diff --git a/README.md b/README.md index 1d9b007cc..a7ef32fb5 100644 --- a/README.md +++ b/README.md @@ -455,12 +455,13 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 5. [`FloydWarshall`](./graph/floydwarshall.go#L15): FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm 6. [`GetIdx`](./graph/depthfirstsearch.go#L3): No description provided. 7. [`KruskalMST`](./graph/kruskal.go#L23): No description provided. -8. [`LowestCommonAncestor`](./graph/lowestcommonancestor.go#L111): For each node, we will precompute its ancestor above him, its ancestor two nodes above, its ancestor four nodes above, etc. Let's call `jump[j][u]` is the `2^j`-th ancestor above the node `u` with `u` in range `[0, numbersVertex)`, `j` in range `[0,MAXLOG)`. These information allow us to jump from any node to any ancestor above it in `O(MAXLOG)` time. -9. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) -10. [`NewTree`](./graph/lowestcommonancestor.go#L84): No description provided. -11. [`NewUnionFind`](./graph/unionfind.go#L24): Initialise a new union find data structure with s nodes -12. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. -13. [`Topological`](./graph/topological.go#L7): Topological assumes that graph given is valid and that its possible to get a topological ordering. constraints are array of []int{a, b}, representing an edge going from a to b +8. [`PrimMST`](./graph/prim.go#30): Computes the minimum spanning tree of a weighted undirected graph +9. [`LowestCommonAncestor`](./graph/lowestcommonancestor.go#L111): For each node, we will precompute its ancestor above him, its ancestor two nodes above, its ancestor four nodes above, etc. Let's call `jump[j][u]` is the `2^j`-th ancestor above the node `u` with `u` in range `[0, numbersVertex)`, `j` in range `[0,MAXLOG)`. These information allow us to jump from any node to any ancestor above it in `O(MAXLOG)` time. +10. [`New`](./graph/graph.go#L16): Constructor functions for graphs (undirected by default) +11. [`NewTree`](./graph/lowestcommonancestor.go#L84): No description provided. +12. [`NewUnionFind`](./graph/unionfind.go#L24): Initialise a new union find data structure with s nodes +13. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. +14. [`Topological`](./graph/topological.go#L7): Topological assumes that graph given is valid and that its possible to get a topological ordering. constraints are array of []int{a, b}, representing an edge going from a to b --- ##### Types diff --git a/graph/prim.go b/graph/prim.go new file mode 100644 index 000000000..d99dcd6e1 --- /dev/null +++ b/graph/prim.go @@ -0,0 +1,58 @@ +// The Prim's algorithm computes the minimum spanning tree for a weighted undirected graph +// Worst Case Time Complexity: O(E log V) using Binary heap, where V is the number of vertices and E is the number of edges +// Space Complexity: O(V + E) +// Implementation is based on the book 'Introduction to Algorithms' (CLRS) + +package graph + +import ( + "container/heap" +) + +type minEdge []Edge + +func (h minEdge) Len() int { return len(h) } +func (h minEdge) Less(i, j int) bool { return h[i].Weight < h[j].Weight } +func (h minEdge) Swap(i, j int) { h[i], h[j] = h[j], h[i] } + +func (h *minEdge) Push(x interface{}) { + *h = append(*h, x.(Edge)) +} + +func (h *minEdge) Pop() interface{} { + old := *h + n := len(old) + x := old[n-1] + *h = old[0 : n-1] + return x +} + +func (g *Graph) PrimMST(start Vertex) ([]Edge, int) { + var mst []Edge + marked := make([]bool, g.vertices) + h := &minEdge{} + // Pushing neighbors of the start node to the binary heap + for neighbor, weight := range g.edges[int(start)] { + heap.Push(h, Edge{start, Vertex(neighbor), weight}) + } + marked[start] = true + cost := 0 + for h.Len() > 0 { + e := heap.Pop(h).(Edge) + end := int(e.End) + // To avoid cycles + if marked[end] { + continue + } + marked[end] = true + cost += e.Weight + mst = append(mst, e) + // Check for neighbors of the newly added edge's End vertex + for neighbor, weight := range g.edges[end] { + if !marked[neighbor] { + heap.Push(h, Edge{e.End, Vertex(neighbor), weight}) + } + } + } + return mst, cost +} diff --git a/graph/prim_test.go b/graph/prim_test.go new file mode 100644 index 000000000..8a3d42c12 --- /dev/null +++ b/graph/prim_test.go @@ -0,0 +1,143 @@ +package graph + +import ( + "fmt" + "reflect" + "testing" +) + +func TestPrimMST(t *testing.T) { + + var testCases = []struct { + edges []Edge + vertices int + start int + cost int + mst []Edge + }{ + { + edges: []Edge{ + {Start: 0, End: 1, Weight: 4}, + {Start: 0, End: 2, Weight: 13}, + {Start: 0, End: 3, Weight: 7}, + {Start: 0, End: 4, Weight: 7}, + {Start: 1, End: 2, Weight: 9}, + {Start: 1, End: 3, Weight: 3}, + {Start: 1, End: 4, Weight: 7}, + {Start: 2, End: 3, Weight: 10}, + {Start: 2, End: 4, Weight: 14}, + {Start: 3, End: 4, Weight: 4}, + }, + vertices: 5, + start: 0, + cost: 20, + mst: []Edge{ + {Start: 0, End: 1, Weight: 4}, + {Start: 1, End: 3, Weight: 3}, + {Start: 3, End: 4, Weight: 4}, + {Start: 1, End: 2, Weight: 9}, + }, + }, + { + edges: []Edge{ + {Start: 0, End: 1, Weight: 4}, + {Start: 0, End: 7, Weight: 8}, + {Start: 1, End: 2, Weight: 8}, + {Start: 1, End: 7, Weight: 11}, + {Start: 2, End: 3, Weight: 7}, + {Start: 2, End: 5, Weight: 4}, + {Start: 2, End: 8, Weight: 2}, + {Start: 3, End: 4, Weight: 9}, + {Start: 3, End: 5, Weight: 14}, + {Start: 4, End: 5, Weight: 10}, + {Start: 5, End: 6, Weight: 2}, + {Start: 6, End: 7, Weight: 1}, + {Start: 6, End: 8, Weight: 6}, + {Start: 7, End: 8, Weight: 7}, + }, + vertices: 9, + start: 3, + cost: 37, + mst: []Edge{ + {Start: 3, End: 2, Weight: 7}, + {Start: 2, End: 8, Weight: 2}, + {Start: 2, End: 5, Weight: 4}, + {Start: 5, End: 6, Weight: 2}, + {Start: 6, End: 7, Weight: 1}, + {Start: 2, End: 1, Weight: 8}, + {Start: 1, End: 0, Weight: 4}, + {Start: 3, End: 4, Weight: 9}, + }, + }, + { + edges: []Edge{ + {Start: 0, End: 1, Weight: 2}, + {Start: 0, End: 3, Weight: 6}, + {Start: 1, End: 2, Weight: 3}, + {Start: 1, End: 3, Weight: 8}, + {Start: 1, End: 4, Weight: 5}, + {Start: 2, End: 4, Weight: 7}, + {Start: 3, End: 4, Weight: 9}, + }, + vertices: 5, + start: 2, + cost: 16, + mst: []Edge{ + {Start: 2, End: 1, Weight: 3}, + {Start: 1, End: 0, Weight: 2}, + {Start: 1, End: 4, Weight: 5}, + {Start: 0, End: 3, Weight: 6}, + }, + }, + { + edges: []Edge{ + {Start: 0, End: 0, Weight: 0}, + }, + vertices: 1, + start: 0, + cost: 0, + mst: nil, + }, + { + edges: []Edge{ + {Start: 0, End: 1, Weight: 1}, + {Start: 0, End: 2, Weight: 6}, + {Start: 0, End: 3, Weight: 5}, + {Start: 1, End: 2, Weight: 2}, + {Start: 1, End: 4, Weight: 4}, + {Start: 2, End: 4, Weight: 9}, + }, + vertices: 5, + start: 4, + cost: 12, + mst: []Edge{ + {Start: 4, End: 1, Weight: 4}, + {Start: 1, End: 0, Weight: 1}, + {Start: 1, End: 2, Weight: 2}, + {Start: 0, End: 3, Weight: 5}, + }, + }, + } + + for i, testCase := range testCases { + t.Run(fmt.Sprintf("Test Case %d", i), func(t *testing.T) { + // Initializing graph, adding edges + graph := New(testCase.vertices) + graph.Directed = false + for _, edge := range testCase.edges { + graph.AddWeightedEdge(int(edge.Start), int(edge.End), edge.Weight) + } + + computedMST, computedCost := graph.PrimMST(Vertex(testCase.start)) + + // Compare the computed result with the expected result + if computedCost != testCase.cost { + t.Errorf("Test Case %d, Expected Cost: %d, Computed: %d", i, testCase.cost, computedCost) + } + + if !reflect.DeepEqual(testCase.mst, computedMST) { + t.Errorf("Test Case %d, Expected MST: %v, Computed: %v", i, testCase.mst, computedMST) + } + }) + } +} From 50ddbddec7a80bd11186cc6af6b4ca82fdc26075 Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Mon, 18 Mar 2024 04:52:44 +0100 Subject: [PATCH 455/488] style: handle edge cases uniformly in all implementations of factorial (#705) * style: handle edge cases uniformly in all implementations of factorial * style: add suggestions from the review Co-authored-by: Taj * style: use `Err` suffix for error name * style: define `testCases` and `implementations` as variables * style: return 0 when negative input --------- Co-authored-by: Taj Co-authored-by: Rak Laptudirm --- math/catalan/catalannumber.go | 10 ++- math/factorial/factorial.go | 36 ++++++---- math/factorial/factorial_test.go | 110 ++++++++++++++----------------- 3 files changed, 82 insertions(+), 74 deletions(-) diff --git a/math/catalan/catalannumber.go b/math/catalan/catalannumber.go index 31a424347..9ea8acb49 100644 --- a/math/catalan/catalannumber.go +++ b/math/catalan/catalannumber.go @@ -12,7 +12,15 @@ import ( f "github.com/TheAlgorithms/Go/math/factorial" ) +func factorial(n int) int { + result, error := f.Iterative(n) + if error != nil { + panic(error) + } + return result +} + // CatalanNumber This function returns the `nth` Catalan number func CatalanNumber(n int) int { - return f.Iterative(n*2) / (f.Iterative(n) * f.Iterative(n+1)) + return factorial(n*2) / (factorial(n) * factorial(n+1)) } diff --git a/math/factorial/factorial.go b/math/factorial/factorial.go index 6b7f5f516..7472da8de 100644 --- a/math/factorial/factorial.go +++ b/math/factorial/factorial.go @@ -8,36 +8,48 @@ // Package factorial describes algorithms Factorials calculations. package factorial +import ( + "errors" +) + +var ErrNegativeArgument = errors.New("input argument must be non-negative integer") + // Iterative returns the iteratively brute forced factorial of n -func Iterative(n int) int { +func Iterative(n int) (int, error) { + if n < 0 { + return 0, ErrNegativeArgument + } result := 1 for i := 2; i <= n; i++ { result *= i } - return result + return result, nil } // Recursive This function recursively computes the factorial of a number -func Recursive(n int) int { - if n == 1 { - return 1 - } else { - return n * Recursive(n-1) +func Recursive(n int) (int, error) { + if n < 0 { + return 0, ErrNegativeArgument } + if n <= 1 { + return 1, nil + } + prev, _ := Recursive(n - 1) + return n * prev, nil } // UsingTree This function finds the factorial of a number using a binary tree -func UsingTree(n int) int { +func UsingTree(n int) (int, error) { if n < 0 { - return 0 + return 0, ErrNegativeArgument } if n == 0 { - return 1 + return 1, nil } if n == 1 || n == 2 { - return n + return n, nil } - return prodTree(2, n) + return prodTree(2, n), nil } func prodTree(l int, r int) int { diff --git a/math/factorial/factorial_test.go b/math/factorial/factorial_test.go index 04eceb973..1d3ed727d 100644 --- a/math/factorial/factorial_test.go +++ b/math/factorial/factorial_test.go @@ -1,81 +1,69 @@ // factorial_test.go // description: Test for calculating factorial -// author(s) [red_byte](https://github.com/i-redbyte) // see factorial.go package factorial import "testing" +import "fmt" -func getTests() []struct { - name string - n int - result int -} { - var tests = []struct { - name string - n int - result int - }{ - {"5!", 5, 120}, - {"3!", 3, 6}, - {"6!", 6, 720}, - {"12!", 12, 479001600}, - {"1!", 1, 1}, - } - return tests -} +type factorialFun func(int) (int, error) -func TestBruteForceFactorial(t *testing.T) { - tests := getTests() - for _, tv := range tests { - t.Run(tv.name, func(t *testing.T) { - result := Iterative(tv.n) - if result != tv.result { - t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) - } - }) - } +var implementations = map[string]factorialFun{ + "Iterative": Iterative, + "Recursive": Recursive, + "UsingTree": UsingTree, } -func TestRecursiveFactorial(t *testing.T) { - tests := getTests() - for _, tv := range tests { - t.Run(tv.name, func(t *testing.T) { - result := Recursive(tv.n) - if result != tv.result { - t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) - } - }) - } +var testCases = []struct { + n int + expected int +}{ + {0, 1}, + {1, 1}, + {2, 2}, + {3, 6}, + {4, 24}, + {5, 120}, + {6, 720}, + {7, 5040}, + {8, 40320}, + {9, 362880}, + {10, 3628800}, + {11, 39916800}, + {12, 479001600}, } -func TestCalculateFactorialUseTree(t *testing.T) { - tests := getTests() - for _, tv := range tests { - t.Run(tv.name, func(t *testing.T) { - result := UsingTree(tv.n) - if result != tv.result { - t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) +func TestFactorial(t *testing.T) { + for implName, implFunction := range implementations { + t.Run(implName+" errors for negative input", func(t *testing.T) { + _, error := implFunction(-1) + if error != ErrNegativeArgument { + t.Errorf("No error captured for negative input") } }) + for _, tc := range testCases { + t.Run(fmt.Sprintf("%s with input %d", implName, tc.n), func(t *testing.T) { + actual, err := implFunction(tc.n) + if err != nil { + t.Errorf("unexpected error captured") + } + if actual != tc.expected { + t.Errorf("Expected: %d, got: %d", tc.expected, actual) + } + }) + } } } -func BenchmarkBruteForceFactorial(b *testing.B) { - for i := 0; i < b.N; i++ { - Iterative(10) - } -} - -func BenchmarkRecursiveFactorial(b *testing.B) { - for i := 0; i < b.N; i++ { - Recursive(10) - } -} - -func BenchmarkCalculateFactorialUseTree(b *testing.B) { - for i := 0; i < b.N; i++ { - Recursive(10) +func BenchmarkFactorial(b *testing.B) { + for _, input := range []int{5, 10, 15} { + for implName, implFunction := range implementations { + b.Run(fmt.Sprintf("%s_%d", implName, input), func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = implFunction(input) + } + }) + } } } From a938a237c5f8d8b2d0f7f7db0861f84b6a2fc725 Mon Sep 17 00:00:00 2001 From: jafar75 Date: Wed, 20 Mar 2024 20:39:53 +0330 Subject: [PATCH 456/488] fix: typo in bellmanford description (#711) --- graph/bellmanford.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/bellmanford.go b/graph/bellmanford.go index c9e791f6d..f130a4e06 100644 --- a/graph/bellmanford.go +++ b/graph/bellmanford.go @@ -1,5 +1,5 @@ // The Bellman–Ford algorithm is an algorithm that computes shortest paths from a -// single source vertex to all of the other vertices in a weighted durected graph. +// single source vertex to all of the other vertices in a weighted directed graph. // It is slower than Dijkstra but capable of handling negative edge weights. // https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm // Implementation is based on the book 'Introduction to Algorithms' (CLRS) From cbaed2300ade20c0526c20f48cf1ac1cbfb8b8c9 Mon Sep 17 00:00:00 2001 From: jafar75 Date: Thu, 28 Mar 2024 14:40:46 +0330 Subject: [PATCH 457/488] feat: add edmond-karp algorithm for max-flow (#712) --- README.md | 1 + graph/edmondkarp.go | 93 ++++++++++++++++++++++++++++++++++++++++ graph/edmondkarp_test.go | 79 ++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 graph/edmondkarp.go create mode 100644 graph/edmondkarp_test.go diff --git a/README.md b/README.md index a7ef32fb5..b55033399 100644 --- a/README.md +++ b/README.md @@ -462,6 +462,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 12. [`NewUnionFind`](./graph/unionfind.go#L24): Initialise a new union find data structure with s nodes 13. [`NotExist`](./graph/depthfirstsearch.go#L12): No description provided. 14. [`Topological`](./graph/topological.go#L7): Topological assumes that graph given is valid and that its possible to get a topological ordering. constraints are array of []int{a, b}, representing an edge going from a to b +15. [`Edmond-Karp`](./graph/edmondkarp.go#L43): Computes the maximum possible flow between a pair of s-t vertices in a weighted graph --- ##### Types diff --git a/graph/edmondkarp.go b/graph/edmondkarp.go new file mode 100644 index 000000000..f6917efcb --- /dev/null +++ b/graph/edmondkarp.go @@ -0,0 +1,93 @@ +// Edmond-Karp algorithm is an implementation of the Ford-Fulkerson method +// to compute max-flow between a pair of source-sink vertices in a weighted graph +// It uses BFS (Breadth First Search) to find the residual paths +// Time Complexity: O(V * E^2) where V is the number of vertices and E is the number of edges +// Space Complexity: O(V + E) Because we keep residual graph in size of the original graph +// Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. 2009. Introduction to Algorithms, Third Edition (3rd. ed.). The MIT Press. + +package graph + +import ( + "math" +) + +// Returns a mapping of vertices as path, if there is any from source to sink +// Otherwise, returns nil +func FindPath(rGraph WeightedGraph, source int, sink int) map[int]int { + queue := make([]int, 0) + marked := make([]bool, len(rGraph)) + marked[source] = true + queue = append(queue, source) + parent := make(map[int]int) + + // BFS loop with saving the path found + for len(queue) > 0 { + v := queue[0] + queue = queue[1:] + for i := 0; i < len(rGraph[v]); i++ { + if !marked[i] && rGraph[v][i] > 0 { + parent[i] = v + // Terminate the BFS, if we reach to sink + if i == sink { + return parent + } + marked[i] = true + queue = append(queue, i) + } + } + } + // source and sink are not in the same connected component + return nil +} + +func EdmondKarp(graph WeightedGraph, source int, sink int) float64 { + // Check graph emptiness + if len(graph) == 0 { + return 0.0 + } + + // Check correct dimensions of the graph slice + for i := 0; i < len(graph); i++ { + if len(graph[i]) != len(graph) { + return 0.0 + } + } + + rGraph := make(WeightedGraph, len(graph)) + for i := 0; i < len(graph); i++ { + rGraph[i] = make([]float64, len(graph)) + } + // Init the residual graph with the same capacities as the original graph + copy(rGraph, graph) + + maxFlow := 0.0 + + for { + parent := FindPath(rGraph, source, sink) + if parent == nil { + break + } + // Finding the max flow over the path returned by BFS + // i.e. finding minimum residual capacity amonth the path edges + pathFlow := math.MaxFloat64 + for v := sink; v != source; v = parent[v] { + u := parent[v] + if rGraph[u][v] < pathFlow { + pathFlow = rGraph[u][v] + } + } + + // update residual capacities of the edges and + // reverse edges along the path + for v := sink; v != source; v = parent[v] { + u := parent[v] + rGraph[u][v] -= pathFlow + rGraph[v][u] += pathFlow + } + + // Update the total flow found so far + maxFlow += pathFlow + } + + return maxFlow +} diff --git a/graph/edmondkarp_test.go b/graph/edmondkarp_test.go new file mode 100644 index 000000000..08e104652 --- /dev/null +++ b/graph/edmondkarp_test.go @@ -0,0 +1,79 @@ +package graph + +import ( + "testing" +) + +func TestEdmondKarp(t *testing.T) { + var edmondKarpTestData = []struct { + description string + graph WeightedGraph + source int + sink int + expected float64 + }{ + { + description: "test empty graph", + graph: nil, + source: 0, + sink: 0, + expected: 0.0, + }, + { + description: "test graph with wrong dimensions", + graph: WeightedGraph{ + {1, 2}, + {0}, + }, + source: 0, + sink: 1, + expected: 0.0, + }, + { + description: "test graph with no edges", + graph: WeightedGraph{ + {0, 0}, + {0, 0}, + }, + source: 0, + sink: 1, + expected: 0.0, + }, + { + description: "test graph with 4 vertices", + graph: WeightedGraph{ + {0, 1000000, 1000000, 0}, + {0, 0, 1, 1000000}, + {0, 0, 0, 1000000}, + {0, 0, 0, 0}, + }, + source: 0, + sink: 3, + expected: 2000000, + }, + { + description: "test graph with 6 vertices and some float64 weights", + graph: WeightedGraph{ + {0, 16, 13.8, 0, 0, 0}, + {0, 0, 10, 12.7, 0, 0}, + {0, 4.2, 0, 0, 14, 0}, + {0, 0, 9.1, 0, 0, 21.3}, + {0, 0, 0, 7.5, 0, 4}, + {0, 0, 0, 0, 0, 0}, + }, + source: 0, + sink: 5, + expected: 24.2, + }, + } + for _, test := range edmondKarpTestData { + t.Run(test.description, func(t *testing.T) { + result := EdmondKarp(test.graph, test.source, test.sink) + + if !almostEqual(test.expected, result) { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expected result:%f\nFound: %f", test.expected, result) + } + }) + } +} From e9d1f3cff35f427f61011d5535d10e595f289490 Mon Sep 17 00:00:00 2001 From: SOZEL <80200848+TruongNhanNguyen@users.noreply.github.com> Date: Wed, 17 Apr 2024 02:51:16 +0700 Subject: [PATCH 458/488] Implement Trapped Rain Water algorithm. (#714) * feat: implement Trapped Rain Water algorithm * chore(tests): add test of empty `heights` --- README.md | 2 +- dynamic/traprainwater.go | 41 +++++++++++++++++++++++++++++++++++ dynamic/traprainwater_test.go | 34 +++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 dynamic/traprainwater.go create mode 100644 dynamic/traprainwater_test.go diff --git a/README.md b/README.md index b55033399..364643711 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 17. [`Max`](./dynamic/knapsack.go#L11): Max function - possible duplicate 18. [`NthCatalanNumber`](./dynamic/catalan.go#L13): NthCatalan returns the n-th Catalan Number Complexity: O(n²) 19. [`NthFibonacci`](./dynamic/fibonacci.go#L6): NthFibonacci returns the nth Fibonacci Number - +20. [`TrapRainWater`](./dynamic/traprainwater.go#L17): Calculate the amount of trapped rainwater between bars represented by an elevation map using dynamic programming. ---
dynamicarray diff --git a/dynamic/traprainwater.go b/dynamic/traprainwater.go new file mode 100644 index 000000000..4f87e1cd7 --- /dev/null +++ b/dynamic/traprainwater.go @@ -0,0 +1,41 @@ +// filename: traprainwater.go +// description: Provides a function to calculate the amount of trapped rainwater between bars represented by an elevation map using dynamic programming. +// details: +// The TrapRainWater function calculates the amount of trapped rainwater between the bars represented by the given elevation map. +// It uses dynamic programming to precompute the maximum height of bars to the left and right of each position. +// Then, it iterates through the array to calculate the amount of trapped rainwater at each position based on the minimum of the left and right maximum heights. +// Finally, it sums up the trapped rainwater for all positions and returns the total amount. +// author(s) [TruongNhanNguyen (SOZEL)](https://github.com/TruongNhanNguyen) +package dynamic + +import "math" + +// TrapRainWater calculates the amount of trapped rainwater between the bars represented by the given elevation map. +// It uses dynamic programming to precompute the maximum height of bars to the left and right of each position. +// Then, it iterates through the array to calculate the amount of trapped rainwater at each position based on the minimum of the left and right maximum heights. +// Finally, it sums up the trapped rainwater for all positions and returns the total amount. +func TrapRainWater(height []int) int { + if len(height) == 0 { + return 0 + } + + leftMax := make([]int, len(height)) + rightMax := make([]int, len(height)) + + leftMax[0] = height[0] + for i := 1; i < len(height); i++ { + leftMax[i] = int(math.Max(float64(leftMax[i-1]), float64(height[i]))) + } + + rightMax[len(height)-1] = height[len(height)-1] + for i := len(height) - 2; i >= 0; i-- { + rightMax[i] = int(math.Max(float64(rightMax[i+1]), float64(height[i]))) + } + + trappedWater := 0 + for i := 0; i < len(height); i++ { + trappedWater += int(math.Min(float64(leftMax[i]), float64(rightMax[i]))) - height[i] + } + + return trappedWater +} diff --git a/dynamic/traprainwater_test.go b/dynamic/traprainwater_test.go new file mode 100644 index 000000000..a031a3077 --- /dev/null +++ b/dynamic/traprainwater_test.go @@ -0,0 +1,34 @@ +package dynamic_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +func TestTrapRainWater(t *testing.T) { + heights := [][]int{ + {}, + {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}, + {4, 2, 0, 3, 2, 5}, + {3, 1, 2, 4, 0, 1, 3, 2, 4}, + } + + expectedResults := []int{ + 0, + 6, + 9, + 13, + } + + for i, height := range heights { + expected := expectedResults[i] + t.Run(fmt.Sprintf("Case %d", i+1), func(t *testing.T) { + result := dynamic.TrapRainWater(height) + if result != expected { + t.Errorf("Expected %d, but got %d", expected, result) + } + }) + } +} From 0d0b97a43fcce5b1cdb5efb0d04afcaa5b98901d Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sat, 20 Apr 2024 08:51:49 +0200 Subject: [PATCH 459/488] chore: update `codecov-action` to `v4` (#704) --- .github/workflows/upload_coverage_report.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upload_coverage_report.yml b/.github/workflows/upload_coverage_report.yml index 2308cc871..b982b25f3 100644 --- a/.github/workflows/upload_coverage_report.yml +++ b/.github/workflows/upload_coverage_report.yml @@ -23,9 +23,17 @@ jobs: - name: Generate code coverage run: | go test -coverprofile="${{ env.REPORT_NAME }}" ./... - - name: Upload coverage to codecov - uses: codecov/codecov-action@v3 + - name: Upload coverage to codecov (tokenless) + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository + uses: codecov/codecov-action@v4 with: files: "${{ env.REPORT_NAME }}" fail_ci_if_error: true + - name: Upload coverage to codecov (with token) + if: "! github.event.pull_request.head.repo.fork " + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: "${{ env.REPORT_NAME }}" + fail_ci_if_error: true ... From c5173f35db0b90d48a7286c3124c7da53a53efcc Mon Sep 17 00:00:00 2001 From: Chandrahas77 <52702137+Chandrahas77@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:27:14 -0400 Subject: [PATCH 460/488] Add railfence cipher (#715) * added rail fence cipher implementation * updated readme * fixed typo --------- Co-authored-by: Rak Laptudirm --- README.md | 13 +++++ cipher/railfence/railfence.go | 75 ++++++++++++++++++++++++ cipher/railfence/railfence_test.go | 91 ++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 cipher/railfence/railfence.go create mode 100644 cipher/railfence/railfence_test.go diff --git a/README.md b/README.md index 364643711..ade5df81a 100644 --- a/README.md +++ b/README.md @@ -1199,6 +1199,19 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 2. [`Encrypt`](./cipher/xor/xor.go#L10): Encrypt encrypts with Xor encryption after converting each character to byte The returned value might not be readable because there is no guarantee which is within the ASCII range If using other type such as string, []int, or some other types, add the statements for converting the type to []byte. 3. [`FuzzXOR`](./cipher/xor/xor_test.go#L108): No description provided. +--- +
+ +##### Package rail fence is a classical type of transposition cipher ref : https://en.wikipedia.org/wiki/Rail_fence_cipher + +--- +##### Functions: + +1. [`Encrypt`](.cipher/railfence/railfence.go#L7): Encrypt encrypts a message using rail fence cipher +2. [`Decrypt`](.cipher/railfence/railfence.go#L44): decrypt decrypts a message using rail fence cipher +3. [`TestEncrypt`](.cipher/railfence/railfence_test.go#L7) Test function for Encrypt +4. [`TestDecrypt`](.cipher/railfence/railfence_test.go#L50) Test function for Decrypt + --- diff --git a/cipher/railfence/railfence.go b/cipher/railfence/railfence.go new file mode 100644 index 000000000..f1ea11928 --- /dev/null +++ b/cipher/railfence/railfence.go @@ -0,0 +1,75 @@ +package railfence + +import ( + "strings" +) + +func Encrypt(text string, rails int) string { + if rails == 1 { + return text + } + + // Create a matrix for the rail fence pattern + matrix := make([][]rune, rails) + for i := range matrix { + matrix[i] = make([]rune, len(text)) + } + + // Fill the matrix + dirDown := false + row, col := 0, 0 + for _, char := range text { + if row == 0 || row == rails-1 { + dirDown = !dirDown + } + matrix[row][col] = char + col++ + if dirDown { + row++ + } else { + row-- + } + } + var result strings.Builder + for _, line := range matrix { + for _, char := range line { + if char != 0 { + result.WriteRune(char) + } + } + } + + return result.String() +} +func Decrypt(cipherText string, rails int) string { + if rails == 1 || rails >= len(cipherText) { + return cipherText + } + + // Placeholder for the decrypted message + decrypted := make([]rune, len(cipherText)) + + // Calculate the zigzag pattern and place characters accordingly + index := 0 + for rail := 0; rail < rails; rail++ { + position := rail + down := true // Direction flag + for position < len(cipherText) { + decrypted[position] = rune(cipherText[index]) + index++ + + // Determine the next position based on the current rail and direction + if rail == 0 || rail == rails-1 { + position += 2 * (rails - 1) + } else if down { + position += 2 * (rails - 1 - rail) + down = false + } else { + position += 2 * rail + down = true + } + } + } + + return string(decrypted) +} diff --git a/cipher/railfence/railfence_test.go b/cipher/railfence/railfence_test.go new file mode 100644 index 000000000..7f7bfa53a --- /dev/null +++ b/cipher/railfence/railfence_test.go @@ -0,0 +1,91 @@ +package railfence + +import ( + "testing" +) + +func TestEncrypt(t *testing.T) { + var railFenceTestData = []struct { + description string + input string + rails int + expected string + }{ + { + "Encrypt with 2 rails", + "hello", + 2, + "hloel", + }, + { + "Encrypt with 3 rails", + "hello world", + 3, + "horel ollwd", + }, + { + "Encrypt with edge case: 1 rail", + "hello", + 1, + "hello", + }, + { + "Encrypt with more rails than letters", + "hi", + 100, + "hi", + }, + } + + for _, test := range railFenceTestData { + t.Run(test.description, func(t *testing.T) { + actual := Encrypt(test.input, test.rails) + if actual != test.expected { + t.Errorf("FAIL: %s - Encrypt(%s, %d) = %s, want %s", test.description, test.input, test.rails, actual, test.expected) + } + }) + } +} + +func TestDecrypt(t *testing.T) { + var railFenceTestData = []struct { + description string + input string + rails int + expected string + }{ + { + "Decrypt with 2 rails", + "hloel", + 2, + "hello", + }, + { + "Decrypt with 3 rails", + "ho l lewrdlo", + 3, + "hld olle wor", + }, + { + "Decrypt with edge case: 1 rail", + "hello", + 1, + "hello", + }, + { + "Decrypt with more rails than letters", + "hi", + 100, + "hi", + }, + } + + for _, test := range railFenceTestData { + t.Run(test.description, func(t *testing.T) { + actual := Decrypt(test.input, test.rails) + if actual != test.expected { + t.Errorf("FAIL: %s - Decrypt(%s, %d) = %s, want %s", test.description, test.input, test.rails, actual, test.expected) + } + }) + } +} From 833a3e55455afff334033b0b33fca0a1f9685e4b Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:34:12 +0200 Subject: [PATCH 461/488] chore: update `actions/setup-go` to `v5` (#718) Co-authored-by: Rak Laptudirm --- .github/workflows/ci.yml | 2 +- .github/workflows/godocmd.yml | 2 +- .github/workflows/upload_coverage_report.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7bc96e6c..534f32036 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '^1.18' - name: Run Golang CI Lint diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml index a4ea126ca..7e7b306e3 100644 --- a/.github/workflows/godocmd.yml +++ b/.github/workflows/godocmd.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: '^1.18' - name: Install GoDocMD diff --git a/.github/workflows/upload_coverage_report.yml b/.github/workflows/upload_coverage_report.yml index b982b25f3..44867a43e 100644 --- a/.github/workflows/upload_coverage_report.yml +++ b/.github/workflows/upload_coverage_report.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: '^1.18' - name: Generate code coverage From 235458219d929bdd0b1b4c344ccbb58b445183de Mon Sep 17 00:00:00 2001 From: jafar75 Date: Thu, 9 May 2024 11:23:42 +0330 Subject: [PATCH 462/488] feat: add next permutation problem (#720) --- README.md | 1 + math/permutation/next_permutation.go | 37 +++++++++++++++++++++ math/permutation/next_permutation_test.go | 40 +++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 math/permutation/next_permutation.go create mode 100644 math/permutation/next_permutation_test.go diff --git a/README.md b/README.md index ade5df81a..ace320588 100644 --- a/README.md +++ b/README.md @@ -834,6 +834,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`GenerateElementSet`](./math/permutation/heaps.go#L37): No description provided. 2. [`Heaps`](./math/permutation/heaps.go#L8): Heap's Algorithm for generating all permutations of n objects +3. [`NextPermutation`](./math/permutation/next_permutation.go#8): A solution to find next permutation of an integer array in constant memory ---
diff --git a/math/permutation/next_permutation.go b/math/permutation/next_permutation.go new file mode 100644 index 000000000..62841bb3d --- /dev/null +++ b/math/permutation/next_permutation.go @@ -0,0 +1,37 @@ +// A practice to find lexicographically next greater permutation of the given array of integers. +// If there does not exist any greater permutation, then print the lexicographically smallest permutation of the given array. +// The implementation below, finds the next permutation in linear time and constant memory and returns in place +// Useful reference: https://www.geeksforgeeks.org/next-permutation/ + +package permutation + +func NextPermutation(nums []int) { + pivot := 0 + for pivot = len(nums) - 2; pivot >= 0; pivot-- { + if nums[pivot] < nums[pivot+1] { + break + } + } + if pivot < 0 { + // current permutation is the last and must be reversed totally + for l, r := 0, len(nums)-1; l < r; l, r = l+1, r-1 { + nums[l], nums[r] = nums[r], nums[l] + } + } else { + succ := 0 + for succ = len(nums) - 1; succ > pivot; succ = succ - 1 { + if nums[succ] > nums[pivot] { + break + } + } + + // Swap the pivot and successor + nums[pivot], nums[succ] = nums[succ], nums[pivot] + + // Reverse the suffix part to minimize it + for l, r := pivot+1, len(nums)-1; l < r; l, r = l+1, r-1 { + nums[l], nums[r] = nums[r], nums[l] + } + } + +} diff --git a/math/permutation/next_permutation_test.go b/math/permutation/next_permutation_test.go new file mode 100644 index 000000000..8246876b4 --- /dev/null +++ b/math/permutation/next_permutation_test.go @@ -0,0 +1,40 @@ +package permutation + +import ( + "reflect" + "testing" +) + +func TestNextPermutation(t *testing.T) { + var nextPermutationTestData = []struct { + description string + numbers []int + next []int + }{ + { + description: "Basic case", + numbers: []int{1, 2, 3}, + next: []int{1, 3, 2}, + }, + { + description: "Should reverse the whole slice", + numbers: []int{3, 2, 1}, + next: []int{1, 2, 3}, + }, + { + description: "A more complex test", + numbers: []int{2, 4, 1, 7, 5, 0}, + next: []int{2, 4, 5, 0, 1, 7}, + }, + } + for _, test := range nextPermutationTestData { + t.Run(test.description, func(t *testing.T) { + NextPermutation(test.numbers) + + if !reflect.DeepEqual(test.numbers, test.next) { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expected result:%v\nFound: %v", test.next, test.numbers) + } + }) + } +} From 2f8c7386d296025e961cd864e83a33caba0b0ab0 Mon Sep 17 00:00:00 2001 From: Rares Date: Sat, 11 May 2024 12:22:46 +0300 Subject: [PATCH 463/488] feat(uniquepaths): add solution for unique paths problem (#716) * feat(uniquepaths): add solution for unique paths problem * fix: Remove extra unused memory --- dynamic/uniquepaths.go | 31 +++++++++++++++++++++++++++++++ dynamic/uniquepaths_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 dynamic/uniquepaths.go create mode 100644 dynamic/uniquepaths_test.go diff --git a/dynamic/uniquepaths.go b/dynamic/uniquepaths.go new file mode 100644 index 000000000..3dc96a8e7 --- /dev/null +++ b/dynamic/uniquepaths.go @@ -0,0 +1,31 @@ +// See https://leetcode.com/problems/unique-paths/ +// author: Rares Mateizer (https://github.com/rares985) +package dynamic + +// UniquePaths implements the solution to the "Unique Paths" problem +func UniquePaths(m, n int) int { + if m <= 0 || n <= 0 { + return 0 + } + + grid := make([][]int, m) + for i := range grid { + grid[i] = make([]int, n) + } + + for i := 0; i < m; i++ { + grid[i][0] = 1 + } + + for j := 0; j < n; j++ { + grid[0][j] = 1 + } + + for i := 1; i < m; i++ { + for j := 1; j < n; j++ { + grid[i][j] = grid[i-1][j] + grid[i][j-1] + } + } + + return grid[m-1][n-1] +} diff --git a/dynamic/uniquepaths_test.go b/dynamic/uniquepaths_test.go new file mode 100644 index 000000000..ac5accbb4 --- /dev/null +++ b/dynamic/uniquepaths_test.go @@ -0,0 +1,28 @@ +package dynamic + +import ( + "testing" +) + +func TestUniquePaths(t *testing.T) { + testCases := map[string]struct { + m int + n int + want int + }{ + "negative sizes": {-1, -1, 0}, + "empty matrix both dimensions": {0, 0, 0}, + "empty matrix one dimension": {0, 1, 0}, + "one element": {1, 1, 1}, + "small matrix": {2, 2, 2}, + "stress test": {1000, 1000, 2874513998398909184}, + } + + for name, test := range testCases { + t.Run(name, func(t *testing.T) { + if got := UniquePaths(test.m, test.n); got != test.want { + t.Errorf("UniquePaths(%v, %v) = %v, want %v", test.m, test.n, got, test.want) + } + }) + } +} From 6fdad95ac55cbdb5d6252c4d3329b0c5e3373571 Mon Sep 17 00:00:00 2001 From: Daniel <67126972+ddaniel27@users.noreply.github.com> Date: Sun, 23 Jun 2024 00:19:07 -0500 Subject: [PATCH 464/488] [Reimplementation] Sieve of eratosthenes (#722) --- math/prime/sieve2.go | 21 +++++++++++++++++++ math/prime/sieve2_test.go | 43 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 math/prime/sieve2.go create mode 100644 math/prime/sieve2_test.go diff --git a/math/prime/sieve2.go b/math/prime/sieve2.go new file mode 100644 index 000000000..2e2e7b116 --- /dev/null +++ b/math/prime/sieve2.go @@ -0,0 +1,21 @@ +/* sieve2.go - Sieve of Eratosthenes + * Algorithm to generate prime numbers up to a limit + * Author: ddaniel27 + */ +package prime + +func SieveEratosthenes(limit int) []int { + primes := make([]int, 0) + sieve := make([]int, limit+1) // make a slice of size limit+1 + + for i := 2; i <= limit; i++ { + if sieve[i] == 0 { // if the number is not marked as composite + primes = append(primes, i) // add it to the list of primes + for j := i * i; j <= limit; j += i { // mark all multiples of i as composite + sieve[j] = 1 + } + } + } + + return primes +} diff --git a/math/prime/sieve2_test.go b/math/prime/sieve2_test.go new file mode 100644 index 000000000..24912e3d0 --- /dev/null +++ b/math/prime/sieve2_test.go @@ -0,0 +1,43 @@ +package prime_test + +import ( + "reflect" + "testing" + + "github.com/TheAlgorithms/Go/math/prime" +) + +func TestSieveEratosthenes(t *testing.T) { + tests := []struct { + name string + limit int + want []int + }{ + { + name: "First 10 primes test", + limit: 30, + want: []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}, + }, + { + name: "First 20 primes test", + limit: 71, + want: []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := prime.SieveEratosthenes(tt.limit) + + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("SieveEratosthenes() = %v, want %v", got, tt.want) + } + }) + } +} + +func BenchmarkSieveEratosthenes(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = prime.SieveEratosthenes(10) + } +} From cddedb6fac5fb2a2ebc26624b14fb03ad04a325e Mon Sep 17 00:00:00 2001 From: Daniel <67126972+ddaniel27@users.noreply.github.com> Date: Tue, 25 Jun 2024 03:11:14 -0500 Subject: [PATCH 465/488] [IMPLEMENTATION] Compressor RLE (#726) * [NEW IMPLEMENTATION] RLE compression algorithm * [FIX] Fix typo * [FIX] Suggestion added --- compression/rlecoding.go | 73 +++++++++++++++ compression/rlecoding_test.go | 161 ++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 compression/rlecoding.go create mode 100644 compression/rlecoding_test.go diff --git a/compression/rlecoding.go b/compression/rlecoding.go new file mode 100644 index 000000000..c08d3e4bd --- /dev/null +++ b/compression/rlecoding.go @@ -0,0 +1,73 @@ +/* +rlecoding.go +description: run length encoding and decoding +details: +Run-length encoding (RLE) is a simple form of data compression in which runs of data are stored as a single data value and count, rather than as the original run. This is useful when the data contains many repeated values. For example, the data "WWWWWWWWWWWWBWWWWWWWWWWWWBBB" can be compressed to "12W1B12W3B". The algorithm is simple and can be implemented in a few lines of code. +author(s) [ddaniel27](https://github.com/ddaniel27) +*/ +package compression + +import ( + "bytes" + "fmt" + "regexp" + "strconv" + "strings" +) + +// RLEncode takes a string and returns its run-length encoding +func RLEncode(data string) string { + var result string + count := 1 + for i := 0; i < len(data); i++ { + if i+1 < len(data) && data[i] == data[i+1] { + count++ + continue + } + result += fmt.Sprintf("%d%c", count, data[i]) + count = 1 + } + return result +} + +// RLEdecode takes a run-length encoded string and returns the original string +func RLEdecode(data string) string { + var result string + regex := regexp.MustCompile(`(\d+)(\w)`) + + for _, match := range regex.FindAllStringSubmatch(data, -1) { + num, _ := strconv.Atoi(match[1]) + result += strings.Repeat(match[2], num) + } + + return result +} + +// RLEncodebytes takes a byte slice and returns its run-length encoding as a byte slice +func RLEncodebytes(data []byte) []byte { + var result []byte + var count byte = 1 + + for i := 0; i < len(data); i++ { + if i+1 < len(data) && data[i] == data[i+1] { + count++ + continue + } + result = append(result, count, data[i]) + count = 1 + } + + return result +} + +// RLEdecodebytes takes a run-length encoded byte slice and returns the original byte slice +func RLEdecodebytes(data []byte) []byte { + var result []byte + + for i := 0; i < len(data); i += 2 { + count := int(data[i]) + result = append(result, bytes.Repeat([]byte{data[i+1]}, count)...) + } + + return result +} diff --git a/compression/rlecoding_test.go b/compression/rlecoding_test.go new file mode 100644 index 000000000..bf9af6bf6 --- /dev/null +++ b/compression/rlecoding_test.go @@ -0,0 +1,161 @@ +package compression_test + +import ( + "bytes" + "testing" + + "github.com/TheAlgorithms/Go/compression" +) + +func TestCompressionRLEncode(t *testing.T) { + tests := []struct { + name string + data string + want string + }{ + { + name: "test 1", + data: "WWWWWWWWWWWWBWWWWWWWWWWWWBBB", + want: "12W1B12W3B", + }, + { + name: "test 2", + data: "AABCCCDEEEE", + want: "2A1B3C1D4E", + }, + { + name: "test 3", + data: "AAAABBBCCDA", + want: "4A3B2C1D1A", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := compression.RLEncode(tt.data); got != tt.want { + t.Errorf("RLEncode() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCompressionRLEDecode(t *testing.T) { + tests := []struct { + name string + data string + want string + }{ + { + name: "test 1", + data: "12W1B12W3B", + want: "WWWWWWWWWWWWBWWWWWWWWWWWWBBB", + }, + { + name: "test 2", + data: "2A1B3C1D4E", + want: "AABCCCDEEEE", + }, + { + name: "test 3", + data: "4A3B2C1D1A", + want: "AAAABBBCCDA", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := compression.RLEdecode(tt.data); got != tt.want { + t.Errorf("RLEdecode() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCompressionRLEncodeBytes(t *testing.T) { + tests := []struct { + name string + data []byte + want []byte + }{ + { + name: "test 1", + data: []byte("WWWWWWWWWWWWBWWWWWWWWWWWWBBB"), + want: []byte{12, 'W', 1, 'B', 12, 'W', 3, 'B'}, + }, + { + name: "test 2", + data: []byte("AABCCCDEEEE"), + want: []byte{2, 'A', 1, 'B', 3, 'C', 1, 'D', 4, 'E'}, + }, + { + name: "test 3", + data: []byte("AAAABBBCCDA"), + want: []byte{4, 'A', 3, 'B', 2, 'C', 1, 'D', 1, 'A'}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := compression.RLEncodebytes(tt.data); !bytes.Equal(got, tt.want) { + t.Errorf("RLEncodebytes() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCompressionRLEDecodeBytes(t *testing.T) { + tests := []struct { + name string + data []byte + want []byte + }{ + { + name: "test 1", + data: []byte{12, 'W', 1, 'B', 12, 'W', 3, 'B'}, + want: []byte("WWWWWWWWWWWWBWWWWWWWWWWWWBBB"), + }, + { + name: "test 2", + data: []byte{2, 'A', 1, 'B', 3, 'C', 1, 'D', 4, 'E'}, + want: []byte("AABCCCDEEEE"), + }, + { + name: "test 3", + data: []byte{4, 'A', 3, 'B', 2, 'C', 1, 'D', 1, 'A'}, + want: []byte("AAAABBBCCDA"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := compression.RLEdecodebytes(tt.data); !bytes.Equal(got, tt.want) { + t.Errorf("RLEdecodebytes() = %v, want %v", got, tt.want) + } + }) + } +} + +/* --- BENCHMARKS --- */ +func BenchmarkRLEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = compression.RLEncode("WWWWWWWWWWWWBWWWWWWWWWWWWBBB") + } +} + +func BenchmarkRLEDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = compression.RLEdecode("12W1B12W3B") + } +} + +func BenchmarkRLEncodeBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = compression.RLEncodebytes([]byte("WWWWWWWWWWWWBWWWWWWWWWWWWBBB")) + } +} + +func BenchmarkRLEDecodeBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = compression.RLEdecodebytes([]byte{12, 'W', 1, 'B', 12, 'W', 3, 'B'}) + } +} From 483431ba65c09114400a4a8967a07cd57de70bf1 Mon Sep 17 00:00:00 2001 From: Daniel <67126972+ddaniel27@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:19:52 -0500 Subject: [PATCH 466/488] [IMPLEMENTATION] RSA algorithm (#727) * [IMPLEMENTATION] RSA algorithm * [UPDATE] Intended keyGen algorithm with randomness * [FIX] comment fixed * [UPDATE] Implement suggestions * [FIX] Implement suggestions --- cipher/rsa/rsa2.go | 123 ++++++++++++++++++++++++++++++++++++++++ cipher/rsa/rsa2_test.go | 49 ++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 cipher/rsa/rsa2.go create mode 100644 cipher/rsa/rsa2_test.go diff --git a/cipher/rsa/rsa2.go b/cipher/rsa/rsa2.go new file mode 100644 index 000000000..2eceddf10 --- /dev/null +++ b/cipher/rsa/rsa2.go @@ -0,0 +1,123 @@ +/* +rsa2.go +description: RSA encryption and decryption including key generation +details: [RSA wiki](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) +author(s): [ddaniel27](https://github.com/ddaniel27) +*/ +package rsa + +import ( + "encoding/binary" + "fmt" + "math/big" + "math/rand" + + "github.com/TheAlgorithms/Go/math/gcd" + "github.com/TheAlgorithms/Go/math/lcm" + "github.com/TheAlgorithms/Go/math/modular" + "github.com/TheAlgorithms/Go/math/prime" +) + +// rsa struct contains the public key, private key and modulus +type rsa struct { + publicKey uint64 + privateKey uint64 + modulus uint64 +} + +// New initializes the RSA algorithm +// returns the RSA object +func New() *rsa { + // The following code generates keys for RSA encryption/decryption + // 1. Choose two large prime numbers, p and q and compute n = p * q + p, q := randomPrime() // p and q stands for prime numbers + modulus := p * q // n stands for common number + + // 2. Compute the totient of n, lcm(p-1, q-1) + totient := uint64(lcm.Lcm(int64(p-1), int64(q-1))) + + // 3. Choose an integer e such that 1 < e < totient(n) and gcd(e, totient(n)) = 1 + publicKey := uint64(2) // e stands for encryption key (public key) + for publicKey < totient { + if gcd.Recursive(int64(publicKey), int64(totient)) == 1 { + break + } + publicKey++ + } + + // 4. Compute d such that d * e ≡ 1 (mod totient(n)) + inv, _ := modular.Inverse(int64(publicKey), int64(totient)) + privateKey := uint64(inv) + + return &rsa{ + publicKey: publicKey, + privateKey: privateKey, + modulus: modulus, + } +} + +// EncryptString encrypts the data using RSA algorithm +// returns the encrypted string +func (rsa *rsa) EncryptString(data string) string { + var nums []byte + + for _, char := range data { + slice := make([]byte, 8) + binary.BigEndian.PutUint64( // convert uint64 to byte slice + slice, + encryptDecryptInt(rsa.publicKey, rsa.modulus, uint64(char)), // encrypt each character + ) + nums = append(nums, slice...) + } + + return string(nums) +} + +// DecryptString decrypts the data using RSA algorithm +// returns the decrypted string +func (rsa *rsa) DecryptString(data string) string { + result := "" + middle := []byte(data) + + for i := 0; i < len(middle); i += 8 { + if i+8 > len(middle) { + break + } + + slice := middle[i : i+8] + num := binary.BigEndian.Uint64(slice) // convert byte slice to uint64 + result += fmt.Sprintf("%c", encryptDecryptInt(rsa.privateKey, rsa.modulus, num)) + } + + return result +} + +// GetPublicKey returns the public key and modulus +func (rsa *rsa) GetPublicKey() (uint64, uint64) { + return rsa.publicKey, rsa.modulus +} + +// GetPrivateKey returns the private key +func (rsa *rsa) GetPrivateKey() uint64 { + return rsa.privateKey +} + +// encryptDecryptInt encrypts or decrypts the data using RSA algorithm +func encryptDecryptInt(e, n, data uint64) uint64 { + pow := new(big.Int).Exp(big.NewInt(int64(data)), big.NewInt(int64(e)), big.NewInt(int64(n))) + return pow.Uint64() +} + +// randomPrime returns two random prime numbers +func randomPrime() (uint64, uint64) { + sieve := prime.SieveEratosthenes(1000) + sieve = sieve[10:] // remove first 10 prime numbers (small numbers) + index1 := rand.Intn(len(sieve)) + index2 := rand.Intn(len(sieve)) + + for index1 == index2 { + index2 = rand.Intn(len(sieve)) + } + + return uint64(sieve[index1]), uint64(sieve[index2]) +} diff --git a/cipher/rsa/rsa2_test.go b/cipher/rsa/rsa2_test.go new file mode 100644 index 000000000..29e15c557 --- /dev/null +++ b/cipher/rsa/rsa2_test.go @@ -0,0 +1,49 @@ +package rsa_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/cipher/rsa" +) + +func TestRSA(t *testing.T) { + tests := []struct { + name string + message string + }{ + { + name: "Encrypt letter 'a' and decrypt it back", + message: "a", + }, + { + name: "Encrypt 'Hello, World!' and decrypt it back", + message: "Hello, World!", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rsa := rsa.New() + encrypted := rsa.EncryptString(tt.message) + decrypted := rsa.DecryptString(encrypted) + if decrypted != tt.message { + t.Errorf("expected %s, got %s", tt.message, decrypted) + } + }) + } +} + +func BenchmarkRSAEncryption(b *testing.B) { + rsa := rsa.New() + for i := 0; i < b.N; i++ { + rsa.EncryptString("Hello, World!") + } +} + +func BenchmarkRSADecryption(b *testing.B) { + rsa := rsa.New() + encrypted := rsa.EncryptString("Hello, World!") + for i := 0; i < b.N; i++ { + rsa.DecryptString(encrypted) + } +} From ee6fef2680d8ebb08519fc83284a9526c114f4e1 Mon Sep 17 00:00:00 2001 From: Manuel Rojas Ramos <59751051+manuelrojas19@users.noreply.github.com> Date: Thu, 18 Jul 2024 05:41:54 -0600 Subject: [PATCH 467/488] Improved HashMap implementation (#729) * Improved HashMap implementation * Renamed Make to New --- structure/hashmap/hashmap.go | 119 +++++++++++++----------------- structure/hashmap/hashmap_test.go | 5 +- 2 files changed, 52 insertions(+), 72 deletions(-) diff --git a/structure/hashmap/hashmap.go b/structure/hashmap/hashmap.go index b0f5dbb1d..591ac8685 100644 --- a/structure/hashmap/hashmap.go +++ b/structure/hashmap/hashmap.go @@ -13,119 +13,100 @@ type node struct { next *node } -// HashMap is golang implementation of hashmap +// HashMap is a Golang implementation of a hashmap type HashMap struct { capacity uint64 size uint64 table []*node } -// New return new HashMap instance -func New() *HashMap { +// DefaultNew returns a new HashMap instance with default values +func DefaultNew() *HashMap { return &HashMap{ capacity: defaultCapacity, table: make([]*node, defaultCapacity), } } -// Make creates a new HashMap instance with input size and capacity -func Make(size, capacity uint64) HashMap { - return HashMap{ +// New creates a new HashMap instance with the specified size and capacity +func New(size, capacity uint64) *HashMap { + return &HashMap{ size: size, capacity: capacity, table: make([]*node, capacity), } } -// Get returns value associated with given key +// Get returns the value associated with the given key func (hm *HashMap) Get(key any) any { - node := hm.getNodeByHash(hm.hash(key)) - + node := hm.getNodeByKey(key) if node != nil { return node.value } - return nil } -// Put puts new key value in hashmap -func (hm *HashMap) Put(key any, value any) any { - return hm.putValue(hm.hash(key), key, value) -} - -// Contains checks if given key is stored in hashmap -func (hm *HashMap) Contains(key any) bool { - node := hm.getNodeByHash(hm.hash(key)) - return node != nil -} - -func (hm *HashMap) putValue(hash uint64, key any, value any) any { - if hm.capacity == 0 { - hm.capacity = defaultCapacity - hm.table = make([]*node, defaultCapacity) - } - - node := hm.getNodeByHash(hash) - - if node == nil { - hm.table[hash] = newNode(key, value) - - } else if node.key == key { - hm.table[hash] = newNodeWithNext(key, value, node) - return value - +// Put inserts a new key-value pair into the hashmap +func (hm *HashMap) Put(key, value any) { + index := hm.hash(key) + if hm.table[index] == nil { + hm.table[index] = &node{key: key, value: value} } else { - hm.resize() - return hm.putValue(hash, key, value) + current := hm.table[index] + for { + if current.key == key { + current.value = value + return + } + if current.next == nil { + break + } + current = current.next + } + current.next = &node{key: key, value: value} } - hm.size++ + if float64(hm.size)/float64(hm.capacity) > 0.75 { + hm.resize() + } +} - return value - +// Contains checks if the given key is stored in the hashmap +func (hm *HashMap) Contains(key any) bool { + return hm.getNodeByKey(key) != nil } -func (hm *HashMap) getNodeByHash(hash uint64) *node { - return hm.table[hash] +// getNodeByKey finds the node associated with the given key +func (hm *HashMap) getNodeByKey(key any) *node { + index := hm.hash(key) + current := hm.table[index] + for current != nil { + if current.key == key { + return current + } + current = current.next + } + return nil } +// resize doubles the capacity of the hashmap and rehashes all existing entries func (hm *HashMap) resize() { + oldTable := hm.table hm.capacity <<= 1 - - tempTable := hm.table - hm.table = make([]*node, hm.capacity) + hm.size = 0 - for i := 0; i < len(tempTable); i++ { - node := tempTable[i] - if node == nil { - continue + for _, head := range oldTable { + for current := head; current != nil; current = current.next { + hm.Put(current.key, current.value) } - - hm.table[hm.hash(node.key)] = node - } -} - -func newNode(key any, value any) *node { - return &node{ - key: key, - value: value, - } -} - -func newNodeWithNext(key any, value any, next *node) *node { - return &node{ - key: key, - value: value, - next: next, } } +// hash generates a hash value for the given key func (hm *HashMap) hash(key any) uint64 { h := fnv.New64a() _, _ = h.Write([]byte(fmt.Sprintf("%v", key))) - hashValue := h.Sum64() - return (hm.capacity - 1) & (hashValue ^ (hashValue >> 16)) } diff --git a/structure/hashmap/hashmap_test.go b/structure/hashmap/hashmap_test.go index 1699f8c25..7b55df0bb 100644 --- a/structure/hashmap/hashmap_test.go +++ b/structure/hashmap/hashmap_test.go @@ -7,8 +7,7 @@ import ( ) func TestHashMap(t *testing.T) { - - mp := hashmap.New() + mp := hashmap.DefaultNew() t.Run("Test 1: Put(10) and checking if Get() is correct", func(t *testing.T) { mp.Put("test", 10) @@ -67,7 +66,7 @@ func TestHashMap(t *testing.T) { }) t.Run("Test 8: Resizing a map", func(t *testing.T) { - mp := hashmap.Make(4, 4) + mp := hashmap.New(4, 4) for i := 0; i < 20; i++ { mp.Put(i, 40) From 32bb6714abae8fbcb6cdfb1939ca780f191eebab Mon Sep 17 00:00:00 2001 From: Ganesh Manchi <62894745+ganeshvenkatasai@users.noreply.github.com> Date: Wed, 24 Jul 2024 19:45:45 +0530 Subject: [PATCH 468/488] feat: add Circle Sort algorithm (#730) * feat: add Circle Sort algorithm * Add test and benchmark for Circle sort algorithm --- sort/circlesort.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 8 ++++++++ 2 files changed, 52 insertions(+) create mode 100644 sort/circlesort.go diff --git a/sort/circlesort.go b/sort/circlesort.go new file mode 100644 index 000000000..c18b0d408 --- /dev/null +++ b/sort/circlesort.go @@ -0,0 +1,44 @@ +// Package sort implements various sorting algorithms. +package sort + +import "github.com/TheAlgorithms/Go/constraints" + +// Circle sorts an array using the circle sort algorithm. +func Circle[T constraints.Ordered](arr []T) []T { + if len(arr) == 0 { + return arr + } + for doSort(arr, 0, len(arr)-1) { + } + return arr +} + +// doSort is the recursive function that implements the circle sort algorithm. +func doSort[T constraints.Ordered](arr []T, left, right int) bool { + if left == right { + return false + } + swapped := false + low := left + high := right + + for low < high { + if arr[low] > arr[high] { + arr[low], arr[high] = arr[high], arr[low] + swapped = true + } + low++ + high-- + } + + if low == high && arr[low] > arr[high+1] { + arr[low], arr[high+1] = arr[high+1], arr[low] + swapped = true + } + + mid := left + (right-left)/2 + leftHalf := doSort(arr, left, mid) + rightHalf := doSort(arr, mid+1, right) + + return swapped || leftHalf || rightHalf +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 63ca010e0..213b17e56 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -190,6 +190,10 @@ func TestTimsort(t *testing.T) { testFramework(t, sort.Timsort[int]) } +func TestCircle(t *testing.T) { + testFramework(t, sort.Circle[int]) +} + // END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { @@ -328,3 +332,7 @@ func BenchmarkCycle(b *testing.B) { func BenchmarkTimsort(b *testing.B) { benchmarkFramework(b, sort.Timsort[int]) } + +func BenchmarkCircle(b *testing.B) { + benchmarkFramework(b, sort.Circle[int]) +} From d7470bafe7617cd885810e3d5e9e4d19b3d8f34a Mon Sep 17 00:00:00 2001 From: Aram Ceballos Date: Sun, 11 Aug 2024 02:40:16 -0700 Subject: [PATCH 469/488] feat: add circular queue array data structure (#731) * feat: add circular queue array data structure * test: add missing error handling --- structure/circularqueue/circularqueue_test.go | 267 ++++++++++++++++++ structure/circularqueue/circularqueuearray.go | 96 +++++++ 2 files changed, 363 insertions(+) create mode 100644 structure/circularqueue/circularqueue_test.go create mode 100644 structure/circularqueue/circularqueuearray.go diff --git a/structure/circularqueue/circularqueue_test.go b/structure/circularqueue/circularqueue_test.go new file mode 100644 index 000000000..0820b0470 --- /dev/null +++ b/structure/circularqueue/circularqueue_test.go @@ -0,0 +1,267 @@ +package circularqueue + +import "testing" + +func TestCircularQueue(t *testing.T) { + t.Run("Size Check", func(t *testing.T) { + _, err := NewCircularQueue[int](-3) + if err == nil { + t.Errorf("Expected error, got nil") + } + + queue, _ := NewCircularQueue[int](5) + expectedSize := 5 + gotSize := queue.Size() + if gotSize != expectedSize { + t.Errorf("Expected size: %v, got: %v\n", expectedSize, gotSize) + } + + if err := queue.Enqueue(1); err != nil { + t.Error(err) + } + if err := queue.Enqueue(2); err != nil { + t.Error(err) + } + if err := queue.Enqueue(3); err != nil { + t.Error(err) + } + if err := queue.Enqueue(4); err != nil { + t.Error(err) + } + if err := queue.Enqueue(5); err != nil { + t.Error(err) + } + + err = queue.Enqueue(6) + if err == nil { + t.Errorf("Expected error, got nil") + } + + expectedSize = 5 + gotSize = queue.Size() + if gotSize != expectedSize { + t.Errorf("Expected size: %v, got: %v\n", expectedSize, gotSize) + } + + if _, err := queue.Dequeue(); err != nil { + t.Error(err) + } + if _, err := queue.Dequeue(); err != nil { + t.Error(err) + } + + err = queue.Enqueue(6) + if err != nil { + t.Errorf("Expected nil, got error: %v\n", err.Error()) + } + + expectedSize = 5 + gotSize = queue.Size() + if gotSize != expectedSize { + t.Errorf("Expected size: %v, got: %v\n", expectedSize, gotSize) + } + }) + t.Run("Enqueue", func(t *testing.T) { + queue, _ := NewCircularQueue[int](10) + + if err := queue.Enqueue(1); err != nil { + t.Error(err) + } + if err := queue.Enqueue(2); err != nil { + t.Error(err) + } + if err := queue.Enqueue(3); err != nil { + t.Error(err) + } + + expected := 1 + got, err := queue.Peek() + if err != nil { + t.Error(err.Error()) + } + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + }) + t.Run("Dequeue", func(t *testing.T) { + queue, _ := NewCircularQueue[string](10) + + if err := queue.Enqueue("one"); err != nil { + t.Error(err) + } + if err := queue.Enqueue("two"); err != nil { + t.Error(err) + } + if err := queue.Enqueue("three"); err != nil { + t.Error(err) + } + + expected := "one" + got, err := queue.Dequeue() + if err != nil { + t.Error(err.Error()) + } + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + + expected = "two" + got, err = queue.Peek() + if err != nil { + t.Error(err.Error()) + } + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + }) + t.Run("Circularity", func(t *testing.T) { + queue, _ := NewCircularQueue[int](10) + + if err := queue.Enqueue(1); err != nil { + t.Error(err) + } + if err := queue.Enqueue(2); err != nil { + t.Error(err) + } + if err := queue.Enqueue(3); err != nil { + t.Error(err) + } + if _, err := queue.Dequeue(); err != nil { + t.Error(err) + } + if _, err := queue.Dequeue(); err != nil { + t.Error(err) + } + if err := queue.Enqueue(4); err != nil { + t.Error(err) + } + if err := queue.Enqueue(5); err != nil { + t.Error(err) + } + if _, err := queue.Dequeue(); err != nil { + t.Error(err) + } + + expected := 4 + got, err := queue.Peek() + if err != nil { + t.Error(err.Error()) + } + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + }) + t.Run("IsFull", func(t *testing.T) { + queue, _ := NewCircularQueue[bool](2) + if err := queue.Enqueue(false); err != nil { + t.Error(err) + } + if err := queue.Enqueue(true); err != nil { + t.Error(err) + } + + expected := true + got := queue.IsFull() + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + + if _, err := queue.Dequeue(); err != nil { + t.Error(err) + } + if _, err := queue.Dequeue(); err != nil { + t.Error(err) + } + + expected = false + got = queue.IsFull() + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + }) + t.Run("IsEmpty", func(t *testing.T) { + queue, _ := NewCircularQueue[float64](2) + + expected := true + got := queue.IsEmpty() + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + + if err := queue.Enqueue(1.0); err != nil { + t.Error(err) + } + + expected = false + got = queue.IsEmpty() + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + + }) + t.Run("Peak", func(t *testing.T) { + queue, _ := NewCircularQueue[rune](10) + + if err := queue.Enqueue('a'); err != nil { + t.Error(err) + } + if err := queue.Enqueue('b'); err != nil { + t.Error(err) + } + if err := queue.Enqueue('c'); err != nil { + t.Error(err) + } + + expected := 'a' + got, err := queue.Peek() + if err != nil { + t.Error(err.Error()) + } + + if got != expected { + t.Errorf("Expected: %v got: %v\n", expected, got) + } + }) +} + +// BenchmarkCircularQueue benchmarks the CircularQueue implementation. +func BenchmarkCircularQueue(b *testing.B) { + b.Run("Enqueue", func(b *testing.B) { + queue, _ := NewCircularQueue[int](1000) + for i := 0; i < b.N; i++ { + if err := queue.Enqueue(i); err != nil { + b.Error(err) + } + } + }) + + b.Run("Dequeue", func(b *testing.B) { + queue, _ := NewCircularQueue[int](1000) + for i := 0; i < 1000; i++ { + if err := queue.Enqueue(i); err != nil { + b.Error(err) + } + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := queue.Dequeue(); err != nil { + b.Error(err) + } + } + }) + + b.Run("Peek", func(b *testing.B) { + queue, _ := NewCircularQueue[int](1000) + for i := 0; i < 1000; i++ { + if err := queue.Enqueue(i); err != nil { + b.Error(err) + } + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := queue.Peek(); err != nil { + b.Error(err) + } + } + }) +} diff --git a/structure/circularqueue/circularqueuearray.go b/structure/circularqueue/circularqueuearray.go new file mode 100644 index 000000000..97447fa4a --- /dev/null +++ b/structure/circularqueue/circularqueuearray.go @@ -0,0 +1,96 @@ +// circularqueuearray.go +// description: Implementation of a circular queue data structure +// details: +// This file contains the implementation of a circular queue data structure +// using generics in Go. The circular queue supports basic operations such as +// enqueue, dequeue, peek, and checks for full and empty states. +// author(s): [Aram Ceballos](https://github.com/aramceballos) +// ref: https://www.programiz.com/dsa/circular-queue +// ref: https://en.wikipedia.org/wiki/Circular_buffer + +// Package queue provides an implementation of a circular queue data structure. +package circularqueue + +// errors package: Provides functions to create and manipulate error values +import ( + "errors" +) + +// CircularQueue represents a circular queue data structure. +type CircularQueue[T any] struct { + items []T + front int + rear int + size int +} + +// NewCircularQueue creates a new CircularQueue with the given size. +// Returns an error if the size is less than or equal to 0. +func NewCircularQueue[T any](size int) (*CircularQueue[T], error) { + if size <= 0 { + return nil, errors.New("size must be greater than 0") + } + return &CircularQueue[T]{ + items: make([]T, size), + front: -1, + rear: -1, + size: size, + }, nil +} + +// Enqueue adds an item to the rear of the queue. +// Returns an error if the queue is full. +func (cq *CircularQueue[T]) Enqueue(item T) error { + if cq.IsFull() { + return errors.New("queue is full") + } + if cq.IsEmpty() { + cq.front = 0 + } + cq.rear = (cq.rear + 1) % cq.size + cq.items[cq.rear] = item + return nil +} + +// Dequeue removes and returns the item from the front of the queue. +// Returns an error if the queue is empty. +func (cq *CircularQueue[T]) Dequeue() (T, error) { + if cq.IsEmpty() { + var zeroValue T + return zeroValue, errors.New("queue is empty") + } + retVal := cq.items[cq.front] + if cq.front == cq.rear { + cq.front = -1 + cq.rear = -1 + } else { + cq.front = (cq.front + 1) % cq.size + } + return retVal, nil +} + +// IsFull checks if the queue is full. +func (cq *CircularQueue[T]) IsFull() bool { + return (cq.front == 0 && cq.rear == cq.size-1) || cq.front == cq.rear+1 +} + +// IsEmpty checks if the queue is empty. +func (cq *CircularQueue[T]) IsEmpty() bool { + return cq.front == -1 && cq.rear == -1 +} + +// Peek returns the item at the front of the queue without removing it. +// Returns an error if the queue is empty. +func (cq *CircularQueue[T]) Peek() (T, error) { + if cq.IsEmpty() { + var zeroValue T + return zeroValue, errors.New("queue is empty") + } + + return cq.items[cq.front], nil +} + +// Size returns the size of the queue. +func (cq *CircularQueue[T]) Size() int { + return cq.size +} From 662e8e9e96d9c8d473b70fab27de9b3af54a1c22 Mon Sep 17 00:00:00 2001 From: Alok Menghrajani <441307+alokmenghrajani@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:13:06 +0200 Subject: [PATCH 470/488] nit: fix code comment in binarytodecimal.go and in decimaltobinary.go (#733) --- README.md | 4 ++-- conversion/binarytodecimal.go | 2 +- conversion/decimaltobinary.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ace320588..51f244249 100644 --- a/README.md +++ b/README.md @@ -229,8 +229,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. 1. [`Base64Decode`](./conversion/base64.go#L57): Base64Decode decodes the received input base64 string into a byte slice. The implementation follows the RFC4648 standard, which is documented at https://datatracker.ietf.org/doc/html/rfc4648#section-4 2. [`Base64Encode`](./conversion/base64.go#L19): Base64Encode encodes the received input bytes slice into a base64 string. The implementation follows the RFC4648 standard, which is documented at https://datatracker.ietf.org/doc/html/rfc4648#section-4 -3. [`BinaryToDecimal`](./conversion/binarytodecimal.go#L25): BinaryToDecimal() function that will take Binary number as string, and return it's Decimal equivalent as integer. -4. [`DecimalToBinary`](./conversion/decimaltobinary.go#L32): DecimalToBinary() function that will take Decimal number as int, and return it's Binary equivalent as string. +3. [`BinaryToDecimal`](./conversion/binarytodecimal.go#L25): BinaryToDecimal() function that will take Binary number as string, and return its Decimal equivalent as integer. +4. [`DecimalToBinary`](./conversion/decimaltobinary.go#L32): DecimalToBinary() function that will take Decimal number as int, and return its Binary equivalent as string. 5. [`FuzzBase64Encode`](./conversion/base64_test.go#L113): No description provided. 6. [`HEXToRGB`](./conversion/rgbhex.go#L10): HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) into the individual components: red, green and blue 7. [`IntToRoman`](./conversion/inttoroman.go#L17): IntToRoman converts an integer value to a roman numeral string. An error is returned if the integer is not between 1 and 3999. diff --git a/conversion/binarytodecimal.go b/conversion/binarytodecimal.go index bc67745fd..6181d3bc2 100644 --- a/conversion/binarytodecimal.go +++ b/conversion/binarytodecimal.go @@ -21,7 +21,7 @@ import ( var isValid = regexp.MustCompile("^[0-1]{1,}$").MatchString // BinaryToDecimal() function that will take Binary number as string, -// and return it's Decimal equivalent as integer. +// and return its Decimal equivalent as an integer. func BinaryToDecimal(binary string) (int, error) { if !isValid(binary) { return -1, errors.New("not a valid binary string") diff --git a/conversion/decimaltobinary.go b/conversion/decimaltobinary.go index 63ef8b1c0..e74765708 100644 --- a/conversion/decimaltobinary.go +++ b/conversion/decimaltobinary.go @@ -28,7 +28,7 @@ func Reverse(str string) string { } // DecimalToBinary() function that will take Decimal number as int, -// and return it's Binary equivalent as string. +// and return its Binary equivalent as a string. func DecimalToBinary(num int) (string, error) { if num < 0 { return "", errors.New("integer must have +ve value") From 24c7f1f5ede01e1a7b0f68a35a878889a8dc4045 Mon Sep 17 00:00:00 2001 From: Carter <102479896+Carter907@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:04:56 -0400 Subject: [PATCH 471/488] feat: add determinant implementation for matrix (#732) * feat: add determinant implementation for matrix Added the Determinant method for the Matrix struct under math/matrix. This method returns the determinant of the matrix. * fix: determinant spelling and linting Fixed the spelling error in determinant.go. Fixed ineffectual error assignment in determinant_test.go. * test: add test for matrix determinant Added a test case for single-element matrix. --------- Co-authored-by: Rak Laptudirm --- math/matrix/determinant.go | 59 +++++++++++++ math/matrix/determinant_test.go | 142 ++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+) create mode 100644 math/matrix/determinant.go create mode 100644 math/matrix/determinant_test.go diff --git a/math/matrix/determinant.go b/math/matrix/determinant.go new file mode 100644 index 000000000..d2570f8f8 --- /dev/null +++ b/math/matrix/determinant.go @@ -0,0 +1,59 @@ +// determinant.go +// description: This method finds the determinant of a matrix. +// details: For a theoretical explanation as for what the determinant +// represents, see the [Wikipedia Article](https://en.wikipedia.org/wiki/Determinant) +// author [Carter907](https://github.com/Carter907) +// see determinant_test.go + +package matrix + +import ( + "errors" +) + +// Calculates the determinant of the matrix. +// This method only works for square matrices (e.i. matrices with equal rows and columns). +func (mat Matrix[T]) Determinant() (T, error) { + + var determinant T = 0 + var elements = mat.elements + if mat.rows != mat.columns { + + return 0, errors.New("Matrix rows and columns must equal in order to find the determinant.") + } + + // Specify base cases for different sized matrices. + switch mat.rows { + case 1: + return elements[0][0], nil + case 2: + return elements[0][0]*elements[1][1] - elements[1][0]*elements[0][1], nil + default: + for i := 0; i < mat.rows; i++ { + + var initialValue T = 0 + minor := New(mat.rows-1, mat.columns-1, initialValue) + // Fill the contents of minor excluding the 0th row and the ith column. + for j, minor_i := 1, 0; j < mat.rows && minor_i < minor.rows; j, minor_i = j+1, minor_i+1 { + for k, minor_j := 0, 0; k < mat.rows && minor_j < minor.rows; k, minor_j = k+1, minor_j+1 { + if k != i { + minor.elements[minor_i][minor_j] = elements[j][k] + } else { + minor_j-- // Decrement the column of minor to account for skipping the ith column of the matrix. + } + } + } + + if i%2 == 0 { + minor_det, _ := minor.Determinant() + + determinant += elements[0][i] * minor_det + } else { + minor_det, _ := minor.Determinant() + + determinant += elements[0][i] * minor_det + } + } + return determinant, nil + } +} diff --git a/math/matrix/determinant_test.go b/math/matrix/determinant_test.go new file mode 100644 index 000000000..801058ff2 --- /dev/null +++ b/math/matrix/determinant_test.go @@ -0,0 +1,142 @@ +package matrix_test + +import ( + "errors" + "math" + "math/rand" + "testing" + + "github.com/TheAlgorithms/Go/math/matrix" +) + +// Test different matrix contents +func TestMatrixDeterminant(t *testing.T) { + // Find Determinant of a 2 by 2 matrix. + matrix1, err := matrix.NewFromElements([][]int{ + {3, 8}, + {4, 6}, + }) + if err != nil { + t.Fatalf("Error creating 3 by 3 matrix: %v", err) + } + determinant, err := matrix1.Determinant() + if err != nil { + t.Fatalf("Error returned from 3 by 3 matrix: %v", err) + } + if determinant != -14 { + t.Fatalf("Determinant returned for a 3 by 3 matrix was %d; wanted -14", determinant) + } + + // Find Dertminant of a 1 by 1 matrix + expectedValue := rand.Intn(math.MaxInt) + matrix2, err := matrix.NewFromElements([][]int{ + {expectedValue}, + }) + if err != nil { + t.Fatalf("Error creating 1 by 1 matrix: %v", err) + } + determinant, err = matrix2.Determinant() + if err != nil { + t.Fatalf("Error returned from 1 by 1 matrix: %v", err) + } + if determinant != expectedValue { + t.Fatalf("Determinant returned for a 1 by 1 matrix was %d; wanted %d", determinant, expectedValue) + } + +} + +func TestEmptyMatrix(t *testing.T) { + emptyElements := [][]int{} + matrix, err := matrix.NewFromElements(emptyElements) + + if err != nil { + t.Fatalf("Error creating Matrix with empty elements: %v", err) + } + + determinant, err := matrix.Determinant() + + if err != nil { + t.Fatalf("Determinant returned an error for empty matrix: %v", err) + } + + // Check that 0 is returned from an empty matrix. + expectedValue := 0 + if determinant != expectedValue { + t.Errorf("Determinant returned from empty matrix was %d; wanted %d", determinant, expectedValue) + } + +} + +func TestNonSquareMatrix(t *testing.T) { + // Creating non-square matrix for testing. + initialValue := 0 + initialRows := 4 + initialCols := 2 + + nonSquareMatrix := matrix.New(initialRows, initialCols, initialValue) + + determinant, err := nonSquareMatrix.Determinant() + // Check if non square matrix returns an error. + if err == nil { + t.Fatalf("No error was returned for a non-square matrix") + } + + // Check if the correct error was returned. + expectedError := errors.New("Matrix rows and columns must equal in order to find the determinant.") + + if err.Error() != expectedError.Error() { + t.Errorf("Error returned from non-square matrix was \n\"%v\"; \nwanted \n\"%v\"", err, expectedError) + } + + // Check if the determinant of the non-square matrix is 0. + if determinant != 0 { + t.Errorf("Determinant of non-square matrix was not 0 but was %d", determinant) + } + +} + +// Test matrix returned from matrix.New +func TestDefaultMatrix(t *testing.T) { + initialValue := 0 + initialRows := 3 + initialCols := 3 + defaultMatrix := matrix.New(initialRows, initialCols, initialValue) + + determinant, err := defaultMatrix.Determinant() + + if err != nil { + t.Fatalf("Error finding the determinant of 3 by 3 default matrix: %v.", err) + } + expectedValue := 0 + if determinant != expectedValue { + t.Errorf("Determinant of the default matrix with an initial value 0 was %d; wanted %d.", initialValue, expectedValue) + } +} + +// Benchmark a 3 by 3 matrix for computational throughput +func BenchmarkSmallMatrixDeterminant(b *testing.B) { + // Create a 3 by 3 matrix for benchmarking + rows := 3 + columns := 3 + initialValue := 0 + matrix := matrix.New(rows, columns, initialValue) + + for i := 0; i < b.N; i++ { + _, _ = matrix.Determinant() + } +} + +// Benchmark a 10 by 10 matrix for computational throughput. +func BenchmarkMatrixDeterminant(b *testing.B) { + // Create a 10 by 10 matrix for benchmarking + rows := 10 + columns := 10 + initialValue := 0 + matrix := matrix.New(rows, columns, initialValue) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, _ = matrix.Determinant() + } +} From 67eebcba7b384f69aa1e8c9d2bee48f9966953f0 Mon Sep 17 00:00:00 2001 From: Y L <86551259+soondubu137@users.noreply.github.com> Date: Sun, 8 Sep 2024 15:27:10 -0500 Subject: [PATCH 472/488] feat: add Kahn's algorithm for topological sort (#735) * feat: implemented kahn's algorithm * doc: added doc for graph/kahn.go * test: added tests for graph/kahn.go --- graph/kahn.go | 66 ++++++++++++++++++++++++++ graph/kahn_test.go | 115 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 graph/kahn.go create mode 100644 graph/kahn_test.go diff --git a/graph/kahn.go b/graph/kahn.go new file mode 100644 index 000000000..6f9d44d71 --- /dev/null +++ b/graph/kahn.go @@ -0,0 +1,66 @@ +// Kahn's algorithm computes a topological ordering of a directed acyclic graph (DAG). +// Time Complexity: O(V + E) +// Space Complexity: O(V + E) +// Reference: https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm +// see graph.go, topological.go, kahn_test.go + +package graph + +// Kahn's algorithm computes a topological ordering of a directed acyclic graph (DAG). +// `n` is the number of vertices, +// `dependencies` is a list of directed edges, where each pair [a, b] represents +// a directed edge from a to b (i.e. b depends on a). +// Vertices are assumed to be labelled 0, 1, ..., n-1. +// If the graph is not a DAG, the function returns nil. +func Kahn(n int, dependencies [][]int) []int { + g := Graph{vertices: n, Directed: true} + // track the in-degree (number of incoming edges) of each vertex + inDegree := make([]int, n) + + // populate g with edges, increase the in-degree counts accordingly + for _, d := range dependencies { + // make sure we don't add the same edge twice + if _, ok := g.edges[d[0]][d[1]]; !ok { + g.AddEdge(d[0], d[1]) + inDegree[d[1]]++ + } + } + + // queue holds all vertices with in-degree 0 + // these vertices have no dependency and thus can be ordered first + queue := make([]int, 0, n) + + for i := 0; i < n; i++ { + if inDegree[i] == 0 { + queue = append(queue, i) + } + } + + // order holds a valid topological order + order := make([]int, 0, n) + + // process the dependency-free vertices + // every time we process a vertex, we "remove" it from the graph + for len(queue) > 0 { + // pop the first vertex from the queue + vtx := queue[0] + queue = queue[1:] + // add the vertex to the topological order + order = append(order, vtx) + // "remove" all the edges coming out of this vertex + // every time we remove an edge, the corresponding in-degree reduces by 1 + // if all dependencies on a vertex is removed, enqueue the vertex + for neighbour := range g.edges[vtx] { + inDegree[neighbour]-- + if inDegree[neighbour] == 0 { + queue = append(queue, neighbour) + } + } + } + + // if the graph is a DAG, order should contain all the certices + if len(order) != n { + return nil + } + return order +} diff --git a/graph/kahn_test.go b/graph/kahn_test.go new file mode 100644 index 000000000..71536b4f6 --- /dev/null +++ b/graph/kahn_test.go @@ -0,0 +1,115 @@ +package graph + +import ( + "testing" +) + +func TestKahn(t *testing.T) { + testCases := []struct { + name string + n int + dependencies [][]int + wantNil bool + }{ + { + "linear graph", + 3, + [][]int{{0, 1}, {1, 2}}, + false, + }, + { + "diamond graph", + 4, + [][]int{{0, 1}, {0, 2}, {1, 3}, {2, 3}}, + false, + }, + { + "star graph", + 5, + [][]int{{0, 1}, {0, 2}, {0, 3}, {0, 4}}, + false, + }, + { + "disconnected graph", + 5, + [][]int{{0, 1}, {0, 2}, {3, 4}}, + false, + }, + { + "cycle graph 1", + 4, + [][]int{{0, 1}, {1, 2}, {2, 3}, {3, 0}}, + true, + }, + { + "cycle graph 2", + 4, + [][]int{{0, 1}, {1, 2}, {2, 0}, {2, 3}}, + true, + }, + { + "single node graph", + 1, + [][]int{}, + false, + }, + { + "empty graph", + 0, + [][]int{}, + false, + }, + { + "redundant dependencies", + 4, + [][]int{{0, 1}, {1, 2}, {1, 2}, {2, 3}}, + false, + }, + { + "island vertex", + 4, + [][]int{{0, 1}, {0, 2}}, + false, + }, + { + "more complicated graph", + 14, + [][]int{{1, 9}, {2, 0}, {3, 2}, {4, 5}, {4, 6}, {4, 7}, {6, 7}, + {7, 8}, {9, 4}, {10, 0}, {10, 1}, {10, 12}, {11, 13}, + {12, 0}, {12, 11}, {13, 5}}, + false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := Kahn(tc.n, tc.dependencies) + if tc.wantNil { + if actual != nil { + t.Errorf("Kahn(%d, %v) = %v; want nil", tc.n, tc.dependencies, actual) + } + } else { + if actual == nil { + t.Errorf("Kahn(%d, %v) = nil; want valid order", tc.n, tc.dependencies) + } else { + seen := make([]bool, tc.n) + positions := make([]int, tc.n) + for i, v := range actual { + seen[v] = true + positions[v] = i + } + for i, v := range seen { + if !v { + t.Errorf("missing vertex %v", i) + } + } + for _, d := range tc.dependencies { + if positions[d[0]] > positions[d[1]] { + t.Errorf("dependency %v not satisfied", d) + } + } + } + } + }) + } +} From 495cff8b21625552eb173351fb99345ae49682a6 Mon Sep 17 00:00:00 2001 From: Y L <86551259+soondubu137@users.noreply.github.com> Date: Sun, 8 Sep 2024 15:41:20 -0500 Subject: [PATCH 473/488] fix: added path compression to UnionFind (#734) * fix: implemented path compression in Find & removed unnecessary return value of Union * feat: added a few test cases * fix: modified kruskal implementation to conform to the updated Union method * fix: changed to pointer receivers --------- Co-authored-by: Rak Laptudirm --- graph/kruskal.go | 2 +- graph/unionfind.go | 45 ++++++++++++++++++++++------------------- graph/unionfind_test.go | 23 ++++++++++++++------- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/graph/kruskal.go b/graph/kruskal.go index 193e3f236..1b0328da3 100644 --- a/graph/kruskal.go +++ b/graph/kruskal.go @@ -42,7 +42,7 @@ func KruskalMST(n int, edges []Edge) ([]Edge, int) { // Add the weight of the edge to the total cost cost += edge.Weight // Merge the sets containing the start and end vertices of the current edge - u = u.Union(int(edge.Start), int(edge.End)) + u.Union(int(edge.Start), int(edge.End)) } } diff --git a/graph/unionfind.go b/graph/unionfind.go index 7a922f3cc..42714ab39 100644 --- a/graph/unionfind.go +++ b/graph/unionfind.go @@ -3,12 +3,13 @@ // is used to efficiently maintain connected components in a graph that undergoes dynamic changes, // such as edges being added or removed over time // Worst Case Time Complexity: The time complexity of find operation is nearly constant or -//O(α(n)), where where α(n) is the inverse Ackermann function +//O(α(n)), where α(n) is the inverse Ackermann function // practically, this is a very slowly growing function making the time complexity for find //operation nearly constant. // The time complexity of the union operation is also nearly constant or O(α(n)) // Worst Case Space Complexity: O(n), where n is the number of nodes or element in the structure // Reference: https://www.scaler.com/topics/data-structures/disjoint-set/ +// https://en.wikipedia.org/wiki/Disjoint-set_data_structure // Author: Mugdha Behere[https://github.com/MugdhaBehere] // see: unionfind.go, unionfind_test.go @@ -17,43 +18,45 @@ package graph // Defining the union-find data structure type UnionFind struct { parent []int - size []int + rank []int } // Initialise a new union find data structure with s nodes func NewUnionFind(s int) UnionFind { parent := make([]int, s) - size := make([]int, s) - for k := 0; k < s; k++ { - parent[k] = k - size[k] = 1 + rank := make([]int, s) + for i := 0; i < s; i++ { + parent[i] = i + rank[i] = 1 } - return UnionFind{parent, size} + return UnionFind{parent, rank} } -// to find the root of the set to which the given element belongs, the Find function serves the purpose -func (u UnionFind) Find(q int) int { - for q != u.parent[q] { - q = u.parent[q] +// Find finds the root of the set to which the given element belongs. +// It performs path compression to make future Find operations faster. +func (u *UnionFind) Find(q int) int { + if q != u.parent[q] { + u.parent[q] = u.Find(u.parent[q]) } - return q + return u.parent[q] } -// to merge two sets to which the given elements belong, the Union function serves the purpose -func (u UnionFind) Union(a, b int) UnionFind { - rootP := u.Find(a) - rootQ := u.Find(b) +// Union merges the sets, if not already merged, to which the given elements belong. +// It performs union by rank to keep the tree as flat as possible. +func (u *UnionFind) Union(p, q int) { + rootP := u.Find(p) + rootQ := u.Find(q) if rootP == rootQ { - return u + return } - if u.size[rootP] < u.size[rootQ] { + if u.rank[rootP] < u.rank[rootQ] { u.parent[rootP] = rootQ - u.size[rootQ] += u.size[rootP] + } else if u.rank[rootP] > u.rank[rootQ] { + u.parent[rootQ] = rootP } else { u.parent[rootQ] = rootP - u.size[rootP] += u.size[rootQ] + u.rank[rootP]++ } - return u } diff --git a/graph/unionfind_test.go b/graph/unionfind_test.go index b95547649..35eea59d4 100644 --- a/graph/unionfind_test.go +++ b/graph/unionfind_test.go @@ -8,10 +8,10 @@ func TestUnionFind(t *testing.T) { u := NewUnionFind(10) // Creating a Union-Find data structure with 10 elements //union operations - u = u.Union(0, 1) - u = u.Union(2, 3) - u = u.Union(4, 5) - u = u.Union(6, 7) + u.Union(0, 1) + u.Union(2, 3) + u.Union(4, 5) + u.Union(6, 7) // Testing the parent of specific elements t.Run("Test Find", func(t *testing.T) { @@ -20,12 +20,21 @@ func TestUnionFind(t *testing.T) { } }) - u = u.Union(1, 5) // Additional union operation - u = u.Union(3, 7) // Additional union operation + u.Union(1, 5) // Additional union operation + u.Union(3, 7) // Additional union operation // Testing the parent of specific elements after more union operations t.Run("Test Find after Union", func(t *testing.T) { - if u.Find(0) != u.Find(5) || u.Find(2) != u.Find(7) { + if u.Find(0) != u.Find(5) || u.Find(1) != u.Find(4) || u.Find(2) != u.Find(7) || u.Find(3) != u.Find(6) { + t.Error("Union operation not functioning correctly") + } + }) + + u.Union(3, 7) // Repeated union operation + + // Testing that repeated union operations are idempotent + t.Run("Test Find after repeated Union", func(t *testing.T) { + if u.Find(2) != u.Find(6) || u.Find(2) != u.Find(7) || u.Find(3) != u.Find(6) || u.Find(3) != u.Find(7) { t.Error("Union operation not functioning correctly") } }) From 822634f03786e88d2024fe25b77e24ea83d2686e Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 16 Oct 2024 20:25:55 +0200 Subject: [PATCH 474/488] Keep GitHub Actions up to date with GitHub's Dependabot (#746) --- .github/dependabot.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..be006de9a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Keep GitHub Actions up to date with GitHub's Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + groups: + github-actions: + patterns: + - "*" # Group all Actions updates into a single larger pull request + schedule: + interval: weekly From ff32defde291d698018b827e8e84a7be89d8989a Mon Sep 17 00:00:00 2001 From: "Daniel." <67126972+ddaniel27@users.noreply.github.com> Date: Sun, 20 Oct 2024 02:33:33 -0500 Subject: [PATCH 475/488] fix: code style (#743) Co-authored-by: Rak Laptudirm --- dynamic/subsetsum_test.go | 7 ++----- math/matrix/matrix_test.go | 4 ++-- math/matrix/strassenmatrixmultiply_test.go | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/dynamic/subsetsum_test.go b/dynamic/subsetsum_test.go index 2fdfb6cc5..acb24f18e 100644 --- a/dynamic/subsetsum_test.go +++ b/dynamic/subsetsum_test.go @@ -1,9 +1,6 @@ package dynamic -import ( - "fmt" - "testing" -) +import "testing" func TestSubsetSum(t *testing.T) { @@ -74,7 +71,7 @@ func TestSubsetSum(t *testing.T) { for i := range subsetSumTestData { - t.Run(fmt.Sprintf(subsetSumTestData[i].description), func(t *testing.T) { + t.Run(subsetSumTestData[i].description, func(t *testing.T) { array := subsetSumTestData[i].array sum := subsetSumTestData[i].sum diff --git a/math/matrix/matrix_test.go b/math/matrix/matrix_test.go index 1425bf933..b8c0f7c72 100644 --- a/math/matrix/matrix_test.go +++ b/math/matrix/matrix_test.go @@ -32,7 +32,7 @@ func TestNewFromElements(t *testing.T) { for j := 0; j < len(validElements[0]); j++ { err := expectedm1.Set(i, j, validElements[i][j]) if err != nil { - t.Errorf("copyMatrix.Set error: " + err.Error()) + t.Errorf("copyMatrix.Set error: %s", err.Error()) } } } @@ -73,7 +73,7 @@ func TestMatrixGet(t *testing.T) { matrix := matrix.New(3, 3, 0) err := matrix.Set(1, 1, 42) // Set a specific value for testing if err != nil { - t.Errorf("copyMatrix.Set error: " + err.Error()) + t.Errorf("copyMatrix.Set error: %s", err.Error()) } // Test case 1: Valid Get val1, err1 := matrix.Get(1, 1) diff --git a/math/matrix/strassenmatrixmultiply_test.go b/math/matrix/strassenmatrixmultiply_test.go index a3e58d87a..b47b4c8fc 100644 --- a/math/matrix/strassenmatrixmultiply_test.go +++ b/math/matrix/strassenmatrixmultiply_test.go @@ -66,7 +66,7 @@ func TestStrassenMatrixMultiply(t *testing.T) { } } func TestMatrixMultiplication(t *testing.T) { - rand.Seed(time.Now().UnixNano()) + rand.New(rand.NewSource(time.Now().UnixNano())) // Generate random matrices for testing size := 1 << (rand.Intn(8) + 1) // tests for matrix with n as power of 2 @@ -103,7 +103,7 @@ func TestMatrixMultiplication(t *testing.T) { } func MakeRandomMatrix[T constraints.Integer](rows, columns int) matrix.Matrix[T] { - rand.Seed(time.Now().UnixNano()) + rand.New(rand.NewSource(time.Now().UnixNano())) matrixData := make([][]T, rows) for i := 0; i < rows; i++ { From b9f7d554227aeca6215ddd7ad500e63821564ae4 Mon Sep 17 00:00:00 2001 From: "Daniel." <67126972+ddaniel27@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:09:07 -0500 Subject: [PATCH 476/488] [IMPLEMENTATION] DSA algorithm implementation (#737) Co-authored-by: Rak Laptudirm --- cipher/dsa/dsa.go | 196 +++++++++++++++++++++++++++++++++++++++++ cipher/dsa/dsa_test.go | 114 ++++++++++++++++++++++++ 2 files changed, 310 insertions(+) create mode 100644 cipher/dsa/dsa.go create mode 100644 cipher/dsa/dsa_test.go diff --git a/cipher/dsa/dsa.go b/cipher/dsa/dsa.go new file mode 100644 index 000000000..7d4eb574a --- /dev/null +++ b/cipher/dsa/dsa.go @@ -0,0 +1,196 @@ +/* +dsa.go +description: DSA encryption and decryption including key generation +details: [DSA wiki](https://en.wikipedia.org/wiki/Digital_Signature_Algorithm) +author(s): [ddaniel27](https://github.com/ddaniel27) +*/ +package dsa + +import ( + "crypto/rand" + "io" + "math/big" +) + +const ( + numMRTests = 64 // Number of Miller-Rabin tests + L = 1024 // Number of bits in p + N = 160 // Number of bits in q +) + +type ( + // parameters represents the DSA parameters + parameters struct { + P, Q, G *big.Int + } + + // dsa represents the DSA + dsa struct { + parameters + pubKey *big.Int // public key (y) + privKey *big.Int // private key (x) + } +) + +// New creates a new DSA instance +func New() *dsa { + d := new(dsa) + d.dsaParameterGeneration() + d.keyGen() + return d +} + +// Parameter generation for DSA +// 1. FIPS 186-4 specifies that the L and N values must be (1024, 160), (2048, 224), or (3072, 256) +// 2. Choose a N-bit prime q +// 3. Choose a L-bit prime p such that p-1 is a multiple of q +// 4. Choose an integer h randomly from the range [2, p-2] +// 5. Compute g = h^((p-1)/q) mod p +// 6. Return (p, q, g) +func (dsa *dsa) dsaParameterGeneration() { + var err error + p, q, bigInt := new(big.Int), new(big.Int), new(big.Int) + one, g, h := big.NewInt(1), big.NewInt(1), big.NewInt(2) + pBytes := make([]byte, L/8) + + // GPLoop is a label for the loop + // We use this loop to change the prime q if we don't find a prime p +GPLoop: + for { + // 2. Choose a N-bit prime q + q, err = rand.Prime(rand.Reader, N) + if err != nil { + panic(err) + } + + for i := 0; i < 4*L; i++ { + // 3. Choose a L-bit prime p such that p-1 is a multiple of q + // In this case we generate a random number of L bits + if _, err := io.ReadFull(rand.Reader, pBytes); err != nil { + panic(err) + } + + // This are the minimum conditions for p being a possible prime + pBytes[len(pBytes)-1] |= 1 // p is odd + pBytes[0] |= 0x80 // p has the highest bit set + p.SetBytes(pBytes) + + // Instead of using (p-1)%q == 0 + // We ensure that p-1 is a multiple of q and validates if p is prime + bigInt.Mod(p, q) + bigInt.Sub(bigInt, one) + p.Sub(p, bigInt) + if p.BitLen() < L || !p.ProbablyPrime(numMRTests) { // Check if p is prime and has L bits + continue + } + + dsa.P = p + dsa.Q = q + break GPLoop + } + } + + // 4. Choose an integer h randomly from the range [2, p-2]. Commonly, h = 2 + // 5. Compute g = h^((p-1)/q) mod p. In case g == 1, increment h until g != 1 + pm1 := new(big.Int).Sub(p, one) + + for g.Cmp(one) == 0 { + g.Exp(h, new(big.Int).Div(pm1, q), p) + h.Add(h, one) + } + + dsa.G = g +} + +// keyGen is key generation for DSA +// 1. Choose a random integer x from the range [1, q-1] +// 2. Compute y = g^x mod p +func (dsa *dsa) keyGen() { + // 1. Choose a random integer x from the range [1, q-1] + x, err := rand.Int(rand.Reader, new(big.Int).Sub(dsa.Q, big.NewInt(1))) + if err != nil { + panic(err) + } + + dsa.privKey = x + + // 2. Compute y = g^x mod p + dsa.pubKey = new(big.Int).Exp(dsa.G, x, dsa.P) +} + +// Sign is signature generation for DSA +// 1. Choose a random integer k from the range [1, q-1] +// 2. Compute r = (g^k mod p) mod q +// 3. Compute s = (k^-1 * (H(m) + x*r)) mod q +func Sign(m []byte, p, q, g, x *big.Int) (r, s *big.Int) { + // 1. Choose a random integer k from the range [1, q-1] + k, err := rand.Int(rand.Reader, new(big.Int).Sub(q, big.NewInt(1))) + if err != nil { + panic(err) + } + + // 2. Compute r = (g^k mod p) mod q + r = new(big.Int).Exp(g, k, p) + r.Mod(r, q) + + // 3. Compute s = (k^-1 * (H(m) + x*r)) mod q + h := new(big.Int).SetBytes(m) // This should be the hash of the message + s = new(big.Int).ModInverse(k, q) // k^-1 mod q + s.Mul( + s, + new(big.Int).Add( // (H(m) + x*r) + h, + new(big.Int).Mul(x, r), + ), + ) + s.Mod(s, q) // mod q + + return r, s +} + +// Verify is signature verification for DSA +// 1. Compute w = s^-1 mod q +// 2. Compute u1 = (H(m) * w) mod q +// 3. Compute u2 = (r * w) mod q +// 4. Compute v = ((g^u1 * y^u2) mod p) mod q +// 5. If v == r, the signature is valid +func Verify(m []byte, r, s, p, q, g, y *big.Int) bool { + // 1. Compute w = s^-1 mod q + w := new(big.Int).ModInverse(s, q) + + // 2. Compute u1 = (H(m) * w) mod q + h := new(big.Int).SetBytes(m) // This should be the hash of the message + u1 := new(big.Int).Mul(h, w) + u1.Mod(u1, q) + + // 3. Compute u2 = (r * w) mod q + u2 := new(big.Int).Mul(r, w) + u2.Mod(u2, q) + + // 4. Compute v = ((g^u1 * y^u2) mod p) mod q + v := new(big.Int).Exp(g, u1, p) + v.Mul( + v, + new(big.Int).Exp(y, u2, p), + ) + v.Mod(v, p) + v.Mod(v, q) + + // 5. If v == r, the signature is valid + return v.Cmp(r) == 0 +} + +// GetPublicKey returns the public key (y) +func (dsa *dsa) GetPublicKey() *big.Int { + return dsa.pubKey +} + +// GetParameters returns the DSA parameters (p, q, g) +func (dsa *dsa) GetParameters() parameters { + return dsa.parameters +} + +// GetPrivateKey returns the private Key (x) +func (dsa *dsa) GetPrivateKey() *big.Int { + return dsa.privKey +} diff --git a/cipher/dsa/dsa_test.go b/cipher/dsa/dsa_test.go new file mode 100644 index 000000000..3ef1930e4 --- /dev/null +++ b/cipher/dsa/dsa_test.go @@ -0,0 +1,114 @@ +package dsa_test + +import ( + "math/big" + "testing" + + "github.com/TheAlgorithms/Go/cipher/dsa" +) + +func TestDSA(t *testing.T) { + tests := []struct { + name string + message string + alter bool + want bool + }{ + { + name: "valid signature", + message: "Hello, world!", + alter: false, + want: true, + }, + { + name: "invalid signature", + message: "Hello, world!", + alter: true, + want: false, + }, + } + // Generate a DSA key pair + dsaInstance := dsa.New() + pubKey := dsaInstance.GetPublicKey() + params := dsaInstance.GetParameters() + privKey := dsaInstance.GetPrivateKey() + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + // Sign the message + r, s := dsa.Sign( + []byte(tt.message), + params.P, + params.Q, + params.G, + privKey, + ) + + if tt.alter { + // Alter the signature + r.Add(r, big.NewInt(1)) + } + + // Verify the signature + if got := dsa.Verify( + []byte(tt.message), + r, + s, + params.P, + params.Q, + params.G, + pubKey, + ); got != tt.want { + t.Errorf("got %v, want %v", got, tt.want) + } + }) + } +} + +/* ------------------- BENCHMARKS ------------------- */ +func BenchmarkDSANew(b *testing.B) { + for i := 0; i < b.N; i++ { + dsa.New() + } +} + +func BenchmarkDSASign(b *testing.B) { + dsaInstance := dsa.New() + params := dsaInstance.GetParameters() + privKey := dsaInstance.GetPrivateKey() + for i := 0; i < b.N; i++ { + dsa.Sign( + []byte("Hello, World!"), + params.P, + params.Q, + params.G, + privKey, + ) + } +} + +func BenchmarkDSAVerify(b *testing.B) { + dsaInstance := dsa.New() + pubKey := dsaInstance.GetPublicKey() + params := dsaInstance.GetParameters() + privKey := dsaInstance.GetPrivateKey() + r, s := dsa.Sign( + []byte("Hello, World!"), + params.P, + params.Q, + params.G, + privKey, + ) + for i := 0; i < b.N; i++ { + dsa.Verify( + []byte("Hello, World!"), + r, + s, + params.P, + params.Q, + params.G, + pubKey, + ) + } +} From e64d1f5b3ea70a7f183f72bae57843e690c68952 Mon Sep 17 00:00:00 2001 From: Alireza Azadi <53966167+alirezaazadi@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:39:39 +0200 Subject: [PATCH 477/488] feat: add string hamming distance algorithm (#747) * feat: add string hamming distance algorithm * refactor: use only a double quote for a single package import --------- Co-authored-by: Rak Laptudirm --- strings/hamming/hammingdistance.go | 31 ++++++++++++++ strings/hamming/hammingdistance_test.go | 56 +++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 strings/hamming/hammingdistance.go create mode 100644 strings/hamming/hammingdistance_test.go diff --git a/strings/hamming/hammingdistance.go b/strings/hamming/hammingdistance.go new file mode 100644 index 000000000..a8c41f3fd --- /dev/null +++ b/strings/hamming/hammingdistance.go @@ -0,0 +1,31 @@ +/* +This algorithm calculates the hamming distance between two equal length strings. +The Hamming distance between two equal-length strings of symbols is the number of positions +at which the corresponding symbols are different: +https://en.wikipedia.org/wiki/Hamming_distance + +Note that we didn't consider strings as an array of bytes, therefore, we didn't use the XOR operator. +In this case, we used a simple loop to compare each character of the strings, and if they are different, +we increment the hamming distance by 1. + +Parameters: two strings to compare +Output: distance between both strings */ + +package hamming + +import "errors" + +func Distance(str1, str2 string) (int, error) { + if len(str1) != len(str2) { + return -1, errors.New("strings must have a same length") + } + + hammingDistance := 0 + for i := 0; i < len(str1); i++ { + if str1[i] != str2[i] { + hammingDistance++ + } + } + + return hammingDistance, nil +} diff --git a/strings/hamming/hammingdistance_test.go b/strings/hamming/hammingdistance_test.go new file mode 100644 index 000000000..663c4daee --- /dev/null +++ b/strings/hamming/hammingdistance_test.go @@ -0,0 +1,56 @@ +package hamming + +import "testing" + +var testCases = []struct { + name string + string1 string + string2 string + expected int +}{ + { + "empty strings", + "", + "", + 0, + }, + { + "single character strings", + "A", + "A", + 0, + }, + { + "two different strings with a same length", + "TestString 1", + "TestString 2", + 1, + }, + { + "two different strings with a different length", + "TestString1", + "TestString", + -1, + }, + { + "two same strings with a same length", + "TestString", + "TestString", + 0, + }, +} + +func TestHammingDistance(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual, err := Distance(tc.string1, tc.string2) + if err != nil { + if tc.expected != -1 { + t.Fatalf("Expected no error, but got %v", err) + } + } else if actual != tc.expected { + t.Errorf("Expected Hamming distance between strings: '%s' and '%s' is %v, but got: %v", tc.string1, tc.string2, tc.expected, actual) + } + }) + } +} From 94689d8100f678a90dce5b8d265366394d739fde Mon Sep 17 00:00:00 2001 From: Aadish Jain <121042282+mapcrafter2048@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:14:42 +0530 Subject: [PATCH 478/488] Adding Kosaraju's Algorithm to find strongly connected components (#745) * Add time and space complexity information to various algorithms * Added the implementation of Kosaraju algorithm * Revert "Add time and space complexity information to various algorithms" This reverts commit 51915ff37134d326bf630615b0a1c37205abe5d9. --------- Co-authored-by: Rak Laptudirm --- graph/kosaraju.go | 92 +++++++++++++++++++++++++++++++++++ graph/kosaraju_test.go | 106 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 graph/kosaraju.go create mode 100644 graph/kosaraju_test.go diff --git a/graph/kosaraju.go b/graph/kosaraju.go new file mode 100644 index 000000000..d36949e5f --- /dev/null +++ b/graph/kosaraju.go @@ -0,0 +1,92 @@ +// kosaraju.go +// description: Implementation of Kosaraju's algorithm to find Strongly Connected Components (SCCs) in a directed graph. +// details: The algorithm consists of three steps: +// 1. Perform DFS and fill the stack with vertices in the order of their finish times. +// 2. Create a transposed graph by reversing all edges. +// 3. Perform DFS on the transposed graph in the order defined by the stack to find SCCs. +// time: O(V + E), where V is the number of vertices and E is the number of edges in the graph. +// space: O(V), where V is the number of vertices in the graph. +// ref link: https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm +// author: mapcrafter2048 + +package graph + +// Kosaraju returns a list of Strongly Connected Components (SCCs). +func (g *Graph) Kosaraju() [][]int { + stack := []int{} + visited := make([]bool, g.vertices) + + // Step 1: Perform DFS and fill stack based on finish times. + for i := 0; i < g.vertices; i++ { + if !visited[i] { + g.fillOrder(i, visited, &stack) + } + } + + // Step 2: Create a transposed graph. + transposed := g.transpose() + + // Step 3: Perform DFS on the transposed graph in the order defined by the stack. + visited = make([]bool, g.vertices) + var sccs [][]int + + for len(stack) > 0 { + // Pop vertex from stack + v := stack[len(stack)-1] + stack = stack[:len(stack)-1] + + // Perform DFS if not already visited. + if !visited[v] { + scc := []int{} + transposed.dfs(v, visited, &scc) + sccs = append(sccs, scc) + } + } + + return sccs +} + +// Helper function to fill the stack with vertices in the order of their finish times. +func (g *Graph) fillOrder(v int, visited []bool, stack *[]int) { + visited[v] = true + + for neighbor := range g.edges[v] { + if !visited[neighbor] { + g.fillOrder(neighbor, visited, stack) + } + } + + // Push the current vertex to the stack after exploring all neighbors. + *stack = append(*stack, v) +} + +// Helper function to create a transposed (reversed) graph. +func (g *Graph) transpose() *Graph { + transposed := &Graph{ + vertices: g.vertices, + edges: make(map[int]map[int]int), + } + + for v, neighbors := range g.edges { + for neighbor := range neighbors { + if transposed.edges[neighbor] == nil { + transposed.edges[neighbor] = make(map[int]int) + } + transposed.edges[neighbor][v] = 1 // Add the reversed edge + } + } + + return transposed +} + +// Helper DFS function used in the transposed graph to collect SCCs. +func (g *Graph) dfs(v int, visited []bool, scc *[]int) { + visited[v] = true + *scc = append(*scc, v) + + for neighbor := range g.edges[v] { + if !visited[neighbor] { + g.dfs(neighbor, visited, scc) + } + } +} diff --git a/graph/kosaraju_test.go b/graph/kosaraju_test.go new file mode 100644 index 000000000..360b72a3e --- /dev/null +++ b/graph/kosaraju_test.go @@ -0,0 +1,106 @@ +package graph + +import ( + "reflect" + "sort" + "testing" +) + +func TestKosaraju(t *testing.T) { + tests := []struct { + name string + vertices int + edges map[int][]int + expected [][]int + }{ + { + name: "Single SCC", + vertices: 5, + edges: map[int][]int{ + 0: {1}, + 1: {2}, + 2: {0, 3}, + 3: {4}, + 4: {}, + }, + expected: [][]int{{4}, {3}, {0, 2, 1}}, + }, + { + name: "Multiple SCCs", + vertices: 8, + edges: map[int][]int{ + 0: {1}, + 1: {2}, + 2: {0, 3}, + 3: {4}, + 4: {5}, + 5: {3, 6}, + 6: {7}, + 7: {6}, + }, + expected: [][]int{{6, 7}, {3, 4, 5}, {0, 2, 1}}, + }, + { + name: "Disconnected graph", + vertices: 4, + edges: map[int][]int{ + 0: {1}, + 1: {}, + 2: {3}, + 3: {}, + }, + expected: [][]int{{1}, {0}, {3}, {2}}, + }, + { + name: "No edges", + vertices: 3, + edges: map[int][]int{ + 0: {}, + 1: {}, + 2: {}, + }, + expected: [][]int{{0}, {1}, {2}}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Initializing graph + graph := &Graph{ + vertices: tt.vertices, + edges: make(map[int]map[int]int), + } + for v, neighbors := range tt.edges { + graph.edges[v] = make(map[int]int) + for _, neighbor := range neighbors { + graph.edges[v][neighbor] = 1 + } + } + + // Running Kosaraju's algorithm to get the SCCs + result := graph.Kosaraju() + + // Sort the expected and result SCCs to ensure order doesn't matter + sortSlices(tt.expected) + sortSlices(result) + + // Compare the sorted SCCs + if !reflect.DeepEqual(result, tt.expected) { + t.Errorf("expected %v, got %v", tt.expected, result) + } + }) + } +} + +// Utility function to sort the slices and their contents +func sortSlices(s [][]int) { + for _, inner := range s { + sort.Ints(inner) + } + sort.Slice(s, func(i, j int) bool { + if len(s[i]) == 0 || len(s[j]) == 0 { + return len(s[i]) < len(s[j]) + } + return s[i][0] < s[j][0] + }) +} From 4263dac181736e937c735d380a15bd7e75b0fc30 Mon Sep 17 00:00:00 2001 From: Aadish Jain <121042282+mapcrafter2048@users.noreply.github.com> Date: Sat, 16 Nov 2024 21:39:37 +0530 Subject: [PATCH 479/488] Add time and space complexity information to various algorithms (#744) * Add time and space complexity information to various algorithms * Added the implementation of Kosaraju algorithm * Added some style issues in articulationpoints.go * Formatted code with gofmt -s to meet style requirements --------- Co-authored-by: Rak Laptudirm --- cache/lru.go | 7 ++ checksum/crc8.go | 2 + checksum/luhn.go | 2 + cipher/caesar/caesar.go | 4 + .../diffiehellman/diffiehellmankeyexchange.go | 4 + cipher/polybius/polybius.go | 4 + cipher/railfence/railfence.go | 6 + cipher/rot13/rot13.go | 4 + cipher/rsa/rsa.go | 2 + cipher/rsa/rsa2.go | 2 + cipher/transposition/transposition.go | 2 + cipher/xor/xor.go | 4 + compression/huffmancoding.go | 2 + compression/rlecoding.go | 3 + conversion/base64.go | 2 + conversion/binarytodecimal.go | 2 + conversion/decimaltobinary.go | 2 + conversion/inttoroman.go | 6 + conversion/rgbhex.go | 2 + conversion/romantoint.go | 2 + dynamic/abbreviation.go | 2 + dynamic/binomialcoefficient.go | 5 + dynamic/catalan.go | 4 +- dynamic/coinchange.go | 6 + dynamic/editdistance.go | 2 + dynamic/fibonacci.go | 4 + dynamic/knapsack.go | 3 + dynamic/longestcommonsubsequence.go | 3 + dynamic/longestincreasingsubsequence.go | 6 + dynamic/longestpalindromicsubsequence.go | 2 + dynamic/matrixmultiplication.go | 2 + dynamic/rodcutting.go | 2 + dynamic/subsetsum.go | 3 +- dynamic/traprainwater.go | 2 + dynamic/uniquepaths.go | 2 + graph/articulationpoints.go | 107 ++++++++---------- graph/bellmanford.go | 2 + graph/breadthfirstsearch.go | 4 +- graph/coloring/backtracking.go | 2 + graph/coloring/bfs.go | 2 + graph/coloring/bipartite.go | 16 ++- graph/coloring/greedy.go | 2 + graph/cycle.go | 2 + graph/depthfirstsearch.go | 6 + graph/dijkstra.go | 7 ++ graph/floydwarshall.go | 2 + graph/lowestcommonancestor.go | 2 + graph/topological.go | 7 ++ hashing/sha256/sha256.go | 2 + math/aliquotsum.go | 2 + math/armstrong/isarmstrong.go | 2 + math/binary/abs.go | 5 + math/binary/arithmeticmean.go | 2 + math/binary/bitcounter.go | 2 + math/binary/checkisnumberpoweroftwo.go | 2 + math/binary/fast_inverse_sqrt.go | 2 + math/binary/logarithm.go | 2 + math/binary/rbc.go | 2 + math/binary/reversebits.go | 2 + math/binary/sqrt.go | 2 + math/binary/xorsearch.go | 2 + math/binomialcoefficient.go | 2 + math/catalan/catalannumber.go | 2 + math/factorial/factorial.go | 2 + math/fibonacci/fibonacci.go | 2 + math/gcd/extended.go | 2 + math/gcd/extendedgcd.go | 5 + math/gcd/gcd.go | 3 + math/gcd/gcditerative.go | 3 + math/geometry/distance.go | 2 + math/krishnamurthy.go | 2 + math/liouville.go | 2 + math/matrix/add.go | 5 + math/matrix/checkequal.go | 3 + math/matrix/copy.go | 6 + math/matrix/determinant.go | 2 + math/matrix/multiply.go | 5 + math/matrix/strassenmatrixmultiply.go | 2 + math/max/bitwisemax.go | 2 + math/median.go | 2 + math/mobius.go | 2 + math/mode.go | 2 + math/modular/exponentiation.go | 2 + math/modular/inverse.go | 2 + math/moserdebruijnsequence/sequence.go | 2 + math/pascal/pascaltriangle.go | 2 + math/perfectnumber.go | 2 + math/permutation/heaps.go | 5 + math/permutation/next_permutation.go | 2 + math/pi/montecarlopi.go | 2 + math/pi/spigotpi.go | 2 + math/pollard.go | 2 + math/power/powvialogarithm.go | 2 + math/prime/millerrabintest.go | 3 +- math/prime/primecheck.go | 2 + math/prime/primefactorization.go | 5 + math/prime/sieve2.go | 2 + math/prime/twin.go | 2 + math/pronicnumber.go | 6 +- other/nested/nestedbrackets.go | 3 + other/password/generator.go | 3 + search/jump.go | 2 + sort/bogosort.go | 3 +- sort/combSort.go | 3 + sort/countingsort.go | 3 + sort/exchangesort.go | 3 + sort/heapsort.go | 6 + sort/insertionsort.go | 6 + sort/mergesort.go | 6 + sort/patiencesort.go | 3 + sort/pigeonholesort.go | 2 + sort/quicksort.go | 3 + sort/radixsort.go | 3 + sort/simplesort.go | 3 + 114 files changed, 385 insertions(+), 72 deletions(-) diff --git a/cache/lru.go b/cache/lru.go index 8c27cfc1f..b9578a9fe 100644 --- a/cache/lru.go +++ b/cache/lru.go @@ -1,3 +1,10 @@ +// lru.go +// description : Least Recently Used (LRU) cache +// details : A Least Recently Used (LRU) cache is a type of cache algorithm used to manage memory within a computer. The LRU algorithm is designed to remove the least recently used items first when the cache reaches its limit. +// time complexity : O(1) +// space complexity : O(n) +// ref : https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU) + package cache import ( diff --git a/checksum/crc8.go b/checksum/crc8.go index fc73a9a40..29c6214b5 100644 --- a/checksum/crc8.go +++ b/checksum/crc8.go @@ -3,6 +3,8 @@ // details: // A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks // and storage devices to detect accidental changes to raw data. +// time complexity: O(n) +// space complexity: O(1) // See more [CRC](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) // author(s) [red_byte](https://github.com/i-redbyte) // see crc8_test.go diff --git a/checksum/luhn.go b/checksum/luhn.go index e9f7dd6b1..b28236d95 100644 --- a/checksum/luhn.go +++ b/checksum/luhn.go @@ -1,6 +1,8 @@ // lunh.go // description: Luhn algorithm // details: is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers, etc [Lunh](https://en.wikipedia.org/wiki/Luhn_algorithm) +// time complexity: O(n) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see lunh_test.go diff --git a/cipher/caesar/caesar.go b/cipher/caesar/caesar.go index 8c1cb47f7..f2f945e71 100644 --- a/cipher/caesar/caesar.go +++ b/cipher/caesar/caesar.go @@ -1,4 +1,8 @@ // Package caesar is the shift cipher +// description: Caesar cipher +// details : Caesar cipher is a type of substitution cipher in which each letter in the plaintext is shifted a certain number of places down the alphabet. +// time complexity: O(n) +// space complexity: O(n) // ref: https://en.wikipedia.org/wiki/Caesar_cipher package caesar diff --git a/cipher/diffiehellman/diffiehellmankeyexchange.go b/cipher/diffiehellman/diffiehellmankeyexchange.go index 2621e3cca..8a779efd4 100644 --- a/cipher/diffiehellman/diffiehellmankeyexchange.go +++ b/cipher/diffiehellman/diffiehellmankeyexchange.go @@ -1,4 +1,8 @@ // Package diffiehellman implements Diffie-Hellman Key Exchange Algorithm +// description: Diffie-Hellman key exchange +// details : Diffie-Hellman key exchange is a method of securely exchanging cryptographic keys over a public channel by combining private keys of two parties to generate a shared secret key. +// time complexity: O(log(n)) +// space complexity: O(1) // for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI package diffiehellman diff --git a/cipher/polybius/polybius.go b/cipher/polybius/polybius.go index 7b57ab344..e022dabae 100644 --- a/cipher/polybius/polybius.go +++ b/cipher/polybius/polybius.go @@ -1,4 +1,8 @@ // Package polybius is encrypting method with polybius square +// description: Polybius square +// details : The Polybius algorithm is a simple algorithm that is used to encode a message by converting each letter to a pair of numbers. +// time complexity: O(n) +// space complexity: O(n) // ref: https://en.wikipedia.org/wiki/Polybius_square#Hybrid_Polybius_Playfair_Cipher package polybius diff --git a/cipher/railfence/railfence.go b/cipher/railfence/railfence.go index f1ea11928..aeeaed3fa 100644 --- a/cipher/railfence/railfence.go +++ b/cipher/railfence/railfence.go @@ -1,3 +1,9 @@ +// railfence.go +// description: Rail Fence Cipher +// details: The rail fence cipher is a an encryption algorithm that uses a rail fence pattern to encode a message. it is a type of transposition cipher that rearranges the characters of the plaintext to form the ciphertext. +// time complexity: O(n) +// space complexity: O(n) +// ref: https://en.wikipedia.org/wiki/Rail_fence_cipher package railfence import ( diff --git a/cipher/rot13/rot13.go b/cipher/rot13/rot13.go index 9b822332b..d50d97c53 100644 --- a/cipher/rot13/rot13.go +++ b/cipher/rot13/rot13.go @@ -1,4 +1,8 @@ // Package rot13 is a simple letter substitution cipher that replaces a letter with the 13th letter after it in the alphabet. +// description: ROT13 +// details: ROT13 is a simple letter substitution cipher that replaces a letter with the 13th letter after it in the alphabet. it is a special case of the Caesar cipher +// time complexity: O(n) +// space complexity: O(n) // ref: https://en.wikipedia.org/wiki/ROT13 package rot13 diff --git a/cipher/rsa/rsa.go b/cipher/rsa/rsa.go index 44cf767b3..1eb506e2c 100644 --- a/cipher/rsa/rsa.go +++ b/cipher/rsa/rsa.go @@ -6,6 +6,8 @@ // thus both the Encrypt and Decrypt are not a production // ready implementation. The OpenSSL implementation of RSA // also adds a padding which is not present in this algorithm. +// time complexity: O(n) +// space complexity: O(n) // author(s) [Taj](https://github.com/tjgurwara99) // see rsa_test.go diff --git a/cipher/rsa/rsa2.go b/cipher/rsa/rsa2.go index 2eceddf10..18b6e1391 100644 --- a/cipher/rsa/rsa2.go +++ b/cipher/rsa/rsa2.go @@ -2,6 +2,8 @@ rsa2.go description: RSA encryption and decryption including key generation details: [RSA wiki](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) +time complexity: O(n) +space complexity: O(1) author(s): [ddaniel27](https://github.com/ddaniel27) */ package rsa diff --git a/cipher/transposition/transposition.go b/cipher/transposition/transposition.go index 6365ffa4a..7a18293ea 100644 --- a/cipher/transposition/transposition.go +++ b/cipher/transposition/transposition.go @@ -2,6 +2,8 @@ // description: Transposition cipher // details: // Implementation "Transposition cipher" is a method of encryption by which the positions held by units of plaintext (which are commonly characters or groups of characters) are shifted according to a regular system, so that the ciphertext constitutes a permutation of the plaintext [Transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher) +// time complexity: O(n) +// space complexity: O(n) // author(s) [red_byte](https://github.com/i-redbyte) // see transposition_test.go diff --git a/cipher/xor/xor.go b/cipher/xor/xor.go index 0296c97ce..61181b1aa 100644 --- a/cipher/xor/xor.go +++ b/cipher/xor/xor.go @@ -1,4 +1,8 @@ // Package xor is an encryption algorithm that operates the exclusive disjunction(XOR) +// description: XOR encryption +// details: The XOR encryption is an algorithm that operates the exclusive disjunction(XOR) on each character of the plaintext with a given key +// time complexity: O(n) +// space complexity: O(n) // ref: https://en.wikipedia.org/wiki/XOR_cipher package xor diff --git a/compression/huffmancoding.go b/compression/huffmancoding.go index f6515872e..ecdaa1fb2 100644 --- a/compression/huffmancoding.go +++ b/compression/huffmancoding.go @@ -3,6 +3,8 @@ // details: // We implement the linear-time 2-queue method described here https://en.wikipedia.org/wiki/Huffman_coding. // It assumes that the list of symbol-frequencies is sorted. +// time complexity: O(n) +// space complexity: O(n) // author(s) [pedromsrocha](https://github.com/pedromsrocha) // see also huffmancoding_test.go diff --git a/compression/rlecoding.go b/compression/rlecoding.go index c08d3e4bd..9aa9399bb 100644 --- a/compression/rlecoding.go +++ b/compression/rlecoding.go @@ -3,6 +3,9 @@ rlecoding.go description: run length encoding and decoding details: Run-length encoding (RLE) is a simple form of data compression in which runs of data are stored as a single data value and count, rather than as the original run. This is useful when the data contains many repeated values. For example, the data "WWWWWWWWWWWWBWWWWWWWWWWWWBBB" can be compressed to "12W1B12W3B". The algorithm is simple and can be implemented in a few lines of code. +time complexity: O(n) +space complexity: O(n) +ref: https://en.wikipedia.org/wiki/Run-length_encoding author(s) [ddaniel27](https://github.com/ddaniel27) */ package compression diff --git a/conversion/base64.go b/conversion/base64.go index 8828f6a7a..bf3a383c5 100644 --- a/conversion/base64.go +++ b/conversion/base64.go @@ -1,6 +1,8 @@ // base64.go // description: The base64 encoding algorithm as defined in the RFC4648 standard. // author: [Paul Leydier] (https://github.com/paul-leydier) +// time complexity: O(n) +// space complexity: O(n) // ref: https://datatracker.ietf.org/doc/html/rfc4648#section-4 // ref: https://en.wikipedia.org/wiki/Base64 // see base64_test.go diff --git a/conversion/binarytodecimal.go b/conversion/binarytodecimal.go index 6181d3bc2..aa308e6a8 100644 --- a/conversion/binarytodecimal.go +++ b/conversion/binarytodecimal.go @@ -9,6 +9,8 @@ Date: 19-Oct-2021 // https://en.wikipedia.org/wiki/Decimal // Function receives a Binary Number as string and returns the Decimal number as integer. // Supported Binary number range is 0 to 2^(31-1). +// time complexity: O(n) +// space complexity: O(1) package conversion diff --git a/conversion/decimaltobinary.go b/conversion/decimaltobinary.go index e74765708..54153b0d2 100644 --- a/conversion/decimaltobinary.go +++ b/conversion/decimaltobinary.go @@ -8,6 +8,8 @@ Date: 14-Oct-2021 // https://en.wikipedia.org/wiki/Binary_number // Function receives a integer as a Decimal number and returns the Binary number. // Supported integer value range is 0 to 2^(31 -1). +// time complexity: O(log(n)) +// space complexity: O(1) package conversion diff --git a/conversion/inttoroman.go b/conversion/inttoroman.go index c1764db1f..1b9c39a0e 100644 --- a/conversion/inttoroman.go +++ b/conversion/inttoroman.go @@ -1,3 +1,9 @@ +// inttoroman.go +// description: Convert an integer to a roman numeral +// details: This program converts an integer to a roman numeral. The program uses a lookup array to convert the integer to a roman numeral. +// time complexity: O(1) +// space complexity: O(1) + package conversion import ( diff --git a/conversion/rgbhex.go b/conversion/rgbhex.go index d050edc8d..3d7265d2c 100644 --- a/conversion/rgbhex.go +++ b/conversion/rgbhex.go @@ -1,5 +1,7 @@ // rgbhex.go // description: convert hex input to red, green and blue and vice versa +// time complexity: O(1) +// space complexity: O(1) // author(s) [darmiel](https://github.com/darmiel) // see rgbhex_test.go diff --git a/conversion/romantoint.go b/conversion/romantoint.go index dda0000f3..629952320 100644 --- a/conversion/romantoint.go +++ b/conversion/romantoint.go @@ -3,6 +3,8 @@ // Function receives a string as a roman number and outputs an integer // Maximum output will be 3999 // Only standard form is supported +// time complexity: O(n) +// space complexity: O(1) package conversion diff --git a/dynamic/abbreviation.go b/dynamic/abbreviation.go index ebfe92171..e5b7ad6e9 100644 --- a/dynamic/abbreviation.go +++ b/dynamic/abbreviation.go @@ -11,6 +11,8 @@ // Given a = "ABcde" and b = "ABCD" // We can capitalize "c" and "d" in a to get "ABCde" then delete all the lowercase letters (which is only "e") in a to get "ABCD" which equals b. // Author: [duongoku](https://github.com/duongoku) +// Time Complexity: O(n*m) where n is the length of a and m is the length of b +// Space Complexity: O(n*m) where n is the length of a and m is the length of b // See abbreviation_test.go for test cases package dynamic diff --git a/dynamic/binomialcoefficient.go b/dynamic/binomialcoefficient.go index b26dbcbbf..fed664fd5 100644 --- a/dynamic/binomialcoefficient.go +++ b/dynamic/binomialcoefficient.go @@ -1,3 +1,8 @@ +// binomialcoefficient.go +// description: Implementation of the binomial coefficient using dynamic programming +// details: The binomial coefficient C(n, k) is the number of ways to choose a subset of k elements from a set of n elements. The binomial coefficient is calculated using the formula C(n, k) = C(n-1, k-1) + C(n-1, k) with base cases C(n, 0) = C(n, n) = 1. +// time complexity: O(n*k) where n is the number of elements and k is the number of elements to choose +// space complexity: O(n*k) where n is the number of elements and k is the number of elements to choose package dynamic import "github.com/TheAlgorithms/Go/math/min" diff --git a/dynamic/catalan.go b/dynamic/catalan.go index 7e0076fba..2f53c3edb 100644 --- a/dynamic/catalan.go +++ b/dynamic/catalan.go @@ -1,5 +1,7 @@ //The Catalan numbers are a sequence of positive integers that appear in many counting -//problems in combinatorics. +// problems in combinatorics. +// time complexity: O(n²) +// space complexity: O(n) //reference: https://brilliant.org/wiki/catalan-numbers/ package dynamic diff --git a/dynamic/coinchange.go b/dynamic/coinchange.go index 1098ea4e1..2ba6064ab 100644 --- a/dynamic/coinchange.go +++ b/dynamic/coinchange.go @@ -1,3 +1,9 @@ +// coinchange.go +// description: Implementation of the coin change problem using dynamic programming +// details: The coin change problem is a problem that asks for the number of ways to make change for a given amount of money using a given set of coins. The problem can be solved using dynamic programming. +// time complexity: O(n*m) where n is the number of coins and m is the amount of money +// space complexity: O(m) where m is the amount of money + package dynamic // CoinChange finds the number of possible combinations of coins diff --git a/dynamic/editdistance.go b/dynamic/editdistance.go index 92abe9583..6d4778a3e 100644 --- a/dynamic/editdistance.go +++ b/dynamic/editdistance.go @@ -1,4 +1,6 @@ // EDIT DISTANCE PROBLEM +// time complexity: O(m * n) where m and n are lengths of the strings, first and second respectively. +// space complexity: O(m * n) where m and n are lengths of the strings, first and second respectively. // https://www.geeksforgeeks.org/edit-distance-dp-5/ // https://leetcode.com/problems/edit-distance/ diff --git a/dynamic/fibonacci.go b/dynamic/fibonacci.go index 288b82b1c..6025b59f0 100644 --- a/dynamic/fibonacci.go +++ b/dynamic/fibonacci.go @@ -1,3 +1,7 @@ +// fibonacci.go +// description: Implementation of the Fibonacci sequence using dynamic programming +// time complexity: O(n) +// space complexity: O(1) package dynamic // https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/ diff --git a/dynamic/knapsack.go b/dynamic/knapsack.go index b07bf6b40..6b637ca54 100644 --- a/dynamic/knapsack.go +++ b/dynamic/knapsack.go @@ -2,6 +2,9 @@ package dynamic // Knapsack Problem // https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ +// https://en.wikipedia.org/wiki/Knapsack_problem +// time complexity: O(n*maxWeight) +// space complexity: O(n*maxWeight) import ( "math" diff --git a/dynamic/longestcommonsubsequence.go b/dynamic/longestcommonsubsequence.go index 739aeb8c1..087d986e0 100644 --- a/dynamic/longestcommonsubsequence.go +++ b/dynamic/longestcommonsubsequence.go @@ -1,6 +1,9 @@ // LONGEST COMMON SUBSEQUENCE // DP - 4 // https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/ +// https://leetcode.com/problems/longest-common-subsequence/ +// time complexity: O(m*n) where m and n are lengths of the strings +// space complexity: O(m*n) where m and n are lengths of the strings package dynamic diff --git a/dynamic/longestincreasingsubsequence.go b/dynamic/longestincreasingsubsequence.go index cce099510..a1e70e53f 100644 --- a/dynamic/longestincreasingsubsequence.go +++ b/dynamic/longestincreasingsubsequence.go @@ -1,3 +1,9 @@ +// longestincreasingsubsequence.go +// description: Implementation of the Longest Increasing Subsequence using dynamic programming +// reference: https://en.wikipedia.org/wiki/Longest_increasing_subsequence +// time complexity: O(n^2) +// space complexity: O(n) + package dynamic import ( diff --git a/dynamic/longestpalindromicsubsequence.go b/dynamic/longestpalindromicsubsequence.go index bc5df07b6..700fb8f87 100644 --- a/dynamic/longestpalindromicsubsequence.go +++ b/dynamic/longestpalindromicsubsequence.go @@ -1,4 +1,6 @@ // longest palindromic subsequence +// time complexity: O(n^2) +// space complexity: O(n^2) // http://www.geeksforgeeks.org/dynamic-programming-set-12-longest-palindromic-subsequence/ package dynamic diff --git a/dynamic/matrixmultiplication.go b/dynamic/matrixmultiplication.go index 373936e62..10fccdbda 100644 --- a/dynamic/matrixmultiplication.go +++ b/dynamic/matrixmultiplication.go @@ -1,6 +1,8 @@ // matrix chain multiplication problem // https://en.wikipedia.org/wiki/Matrix_chain_multiplication // www.geeksforgeeks.org/dynamic_programming-set-8-matrix-chain-multiplication/ +// time complexity: O(n^3) +// space complexity: O(n^2) package dynamic diff --git a/dynamic/rodcutting.go b/dynamic/rodcutting.go index ce721e18b..4d37f4ecc 100644 --- a/dynamic/rodcutting.go +++ b/dynamic/rodcutting.go @@ -1,6 +1,8 @@ // Solution to Rod cutting problem // https://en.wikipedia.org/wiki/Cutting_stock_problem // http://www.geeksforgeeks.org/dynamic-programming-set-13-cutting-a-rod/ +// time complexity: O(n^2) +// space complexity: O(n) package dynamic diff --git a/dynamic/subsetsum.go b/dynamic/subsetsum.go index 1f7da69b8..db04c32de 100644 --- a/dynamic/subsetsum.go +++ b/dynamic/subsetsum.go @@ -1,7 +1,8 @@ //Given a set of non-negative integers, and a (positive) value sum, //determine if there is a subset of the given set with sum //equal to given sum. -//Complexity: O(n*sum) +// time complexity: O(n*sum) +// space complexity: O(n*sum) //references: https://www.geeksforgeeks.org/subset-sum-problem-dp-25/ package dynamic diff --git a/dynamic/traprainwater.go b/dynamic/traprainwater.go index 4f87e1cd7..3b1c6a966 100644 --- a/dynamic/traprainwater.go +++ b/dynamic/traprainwater.go @@ -5,6 +5,8 @@ // It uses dynamic programming to precompute the maximum height of bars to the left and right of each position. // Then, it iterates through the array to calculate the amount of trapped rainwater at each position based on the minimum of the left and right maximum heights. // Finally, it sums up the trapped rainwater for all positions and returns the total amount. +// time complexity: O(n) +// space complexity: O(n) // author(s) [TruongNhanNguyen (SOZEL)](https://github.com/TruongNhanNguyen) package dynamic diff --git a/dynamic/uniquepaths.go b/dynamic/uniquepaths.go index 3dc96a8e7..978a81c7e 100644 --- a/dynamic/uniquepaths.go +++ b/dynamic/uniquepaths.go @@ -1,4 +1,6 @@ // See https://leetcode.com/problems/unique-paths/ +// time complexity: O(m*n) where m and n are the dimensions of the grid +// space complexity: O(m*n) where m and n are the dimensions of the grid // author: Rares Mateizer (https://github.com/rares985) package dynamic diff --git a/graph/articulationpoints.go b/graph/articulationpoints.go index 618107890..26b3a6b78 100644 --- a/graph/articulationpoints.go +++ b/graph/articulationpoints.go @@ -1,56 +1,48 @@ +// Package graph provides algorithms to analyze graph structures. package graph import "github.com/TheAlgorithms/Go/math/min" +// apHelper stores auxiliary data used to identify articulation points in a graph. type apHelper struct { - is_ap []bool - visited []bool - child_cnt []int - discovery_time []int - earliest_discovery []int + isAP []bool + visited []bool + childCount []int + discoveryTime []int + earliestDiscovery []int } -// ArticulationPoint is a function to identify articulation points in a graph. -// The function takes the graph as an argument and returns a boolean slice -// which indicates whether a vertex is an articulation point or not. +// ArticulationPoint identifies articulation points in a graph. It returns a boolean slice +// where each element indicates whether a vertex is an articulation point. // Worst Case Time Complexity: O(|V| + |E|) // Auxiliary Space: O(|V|) -// reference: https://en.wikipedia.org/wiki/Biconnected_component and https://cptalks.quora.com/Cut-Vertex-Articulation-point +// Reference: https://en.wikipedia.org/wiki/Biconnected_component and https://cptalks.quora.com/Cut-Vertex-Articulation-point func ArticulationPoint(graph *Graph) []bool { - // time variable to keep track of the time of discovery_time of a vertex + // Time variable to keep track of the discovery time of a vertex time := 0 - //initialize all the variables + // Initialize apHelper instance with the required data structures apHelperInstance := &apHelper{ - is_ap: make([]bool, graph.vertices), - visited: make([]bool, graph.vertices), - child_cnt: make([]int, graph.vertices), - // integer slice to store the discovery time of a vertex as we traverse - // the graph in a depth first manner - discovery_time: make([]int, graph.vertices), - // integer slice to store the earliest discovered vertex reachable from a vertex - earliest_discovery: make([]int, graph.vertices), + isAP: make([]bool, graph.vertices), + visited: make([]bool, graph.vertices), + childCount: make([]int, graph.vertices), + discoveryTime: make([]int, graph.vertices), + earliestDiscovery: make([]int, graph.vertices), } - articulationPointHelper( - apHelperInstance, - 0, - -1, - &time, - graph, - ) - if apHelperInstance.child_cnt[0] == 1 { - // if the root has only one child, it is not an articulation point - apHelperInstance.is_ap[0] = false + // Start traversal from the root (0) + articulationPointHelper(apHelperInstance, 0, -1, &time, graph) + + // Check if the root has only one child, making it non-articulate + if apHelperInstance.childCount[0] == 1 { + apHelperInstance.isAP[0] = false } - return apHelperInstance.is_ap + return apHelperInstance.isAP } -// articulationPointHelper is a recursive function to traverse the graph -// and mark articulation points. Based on the depth first search transversal -// of the graph, however modified to keep track and update the -// `child_cnt`, `discovery_time` and `earliest_discovery` slices defined above +// articulationPointHelper recursively traverses the graph using DFS and marks articulation points. +// It updates `childCount`, `discoveryTime`, and `earliestDiscovery` slices for the given vertex. func articulationPointHelper( apHelperInstance *apHelper, vertex int, @@ -60,41 +52,38 @@ func articulationPointHelper( ) { apHelperInstance.visited[vertex] = true - // Mark the time of discovery of a vertex - // set the earliest discovery time to the discovered time - // increment the time - apHelperInstance.discovery_time[vertex] = *time - apHelperInstance.earliest_discovery[vertex] = apHelperInstance.discovery_time[vertex] + // Set discovery and earliest discovery times for the vertex + apHelperInstance.discoveryTime[vertex] = *time + apHelperInstance.earliestDiscovery[vertex] = *time *time++ - for next_vertex := range graph.edges[vertex] { - if next_vertex == parent { + for nextVertex := range graph.edges[vertex] { + if nextVertex == parent { continue } - if apHelperInstance.visited[next_vertex] { - apHelperInstance.earliest_discovery[vertex] = min.Int( - apHelperInstance.earliest_discovery[vertex], - apHelperInstance.discovery_time[next_vertex], + if apHelperInstance.visited[nextVertex] { + // Update the earliest discovery time to the smallest reachable discovery time + apHelperInstance.earliestDiscovery[vertex] = min.Int( + apHelperInstance.earliestDiscovery[vertex], + apHelperInstance.discoveryTime[nextVertex], ) continue } - apHelperInstance.child_cnt[vertex]++ - articulationPointHelper( - apHelperInstance, - next_vertex, - vertex, - time, - graph, - ) - apHelperInstance.earliest_discovery[vertex] = min.Int( - apHelperInstance.earliest_discovery[vertex], - apHelperInstance.earliest_discovery[next_vertex], + // Increment child count and perform recursive traversal for DFS + apHelperInstance.childCount[vertex]++ + articulationPointHelper(apHelperInstance, nextVertex, vertex, time, graph) + + // Update the earliest discovery time post DFS + apHelperInstance.earliestDiscovery[vertex] = min.Int( + apHelperInstance.earliestDiscovery[vertex], + apHelperInstance.earliestDiscovery[nextVertex], ) - if apHelperInstance.earliest_discovery[next_vertex] >= apHelperInstance.discovery_time[vertex] { - apHelperInstance.is_ap[vertex] = true - } + // Mark vertex as articulation point if condition meets + if apHelperInstance.earliestDiscovery[nextVertex] >= apHelperInstance.discoveryTime[vertex] { + apHelperInstance.isAP[vertex] = true + } } } diff --git a/graph/bellmanford.go b/graph/bellmanford.go index f130a4e06..d1db29c5c 100644 --- a/graph/bellmanford.go +++ b/graph/bellmanford.go @@ -3,6 +3,8 @@ // It is slower than Dijkstra but capable of handling negative edge weights. // https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm // Implementation is based on the book 'Introduction to Algorithms' (CLRS) +// time complexity: O(V*E) where V is the number of vertices and E is the number of edges in the graph +// space complexity: O(V) where V is the number of vertices in the graph package graph diff --git a/graph/breadthfirstsearch.go b/graph/breadthfirstsearch.go index 7325c06a3..bac2f04cc 100644 --- a/graph/breadthfirstsearch.go +++ b/graph/breadthfirstsearch.go @@ -3,8 +3,8 @@ package graph // BreadthFirstSearch is an algorithm for traversing and searching graph data structures. // It starts at an arbitrary node of a graph, and explores all of the neighbor nodes // at the present depth prior to moving on to the nodes at the next depth level. -// Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) -// Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) +// Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) where |V| is the number of vertices and |E| is the number of edges in the graph and b is the branching factor of the graph (the average number of successors of a node). d is the depth of the goal node. +// Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) where |V| is the number of vertices and |E| is the number of edges in the graph and b is the branching factor of the graph (the average number of successors of a node). d is the depth of the goal node. // reference: https://en.wikipedia.org/wiki/Breadth-first_search func BreadthFirstSearch(start, end, nodes int, edges [][]int) (isConnected bool, distance int) { queue := make([]int, 0) diff --git a/graph/coloring/backtracking.go b/graph/coloring/backtracking.go index 1ae657d45..885b79e28 100644 --- a/graph/coloring/backtracking.go +++ b/graph/coloring/backtracking.go @@ -1,4 +1,6 @@ // This file contains the graph coloring implementation using backtracking +// time complexity: O(V^V) where V is the number of vertices in the graph +// space complexity: O(V) where V is the number of vertices in the graph // Author(s): [Shivam](https://github.com/Shivam010) package coloring diff --git a/graph/coloring/bfs.go b/graph/coloring/bfs.go index d73b0ed31..22f0bc899 100644 --- a/graph/coloring/bfs.go +++ b/graph/coloring/bfs.go @@ -1,4 +1,6 @@ // This file contains the graph coloring implementation using BFS +// time complexity: O(V+E) where V is the number of vertices and E is the number of edges in the graph +// space complexity: O(V) where V is the number of vertices in the graph // Author(s): [Shivam](https://github.com/Shivam010) package coloring diff --git a/graph/coloring/bipartite.go b/graph/coloring/bipartite.go index f27c7dc54..1f0e3c62c 100644 --- a/graph/coloring/bipartite.go +++ b/graph/coloring/bipartite.go @@ -1,7 +1,13 @@ package coloring +// Bipartite.go +// description: Implementation of the Bipartite graph coloring algorithm +// details: A bipartite graph is a graph whose vertices can be divided into two disjoint sets U and V such that every edge connects a vertex in U to one in V. The Bipartite graph coloring algorithm is used to determine if a graph is bipartite or not. +// time complexity: O(V+E) where V is the number of vertices and E is the number of edges in the graph +// space complexity: O(V) where V is the number of vertices in the graph + func (g *Graph) TryBipartiteColoring() map[int]Color { - // 0 is uncolored, 1/2 is colors + // 0 is uncolored, 1/2 are colors colors := make(map[int]Color) visited := make(map[int]bool) @@ -10,8 +16,8 @@ func (g *Graph) TryBipartiteColoring() map[int]Color { visited[i] = false } - var color_node func(int) - color_node = func(s int) { + var colorNode func(int) + colorNode = func(s int) { visited[s] = true coloring := []Color{0, 2, 1} @@ -20,7 +26,7 @@ func (g *Graph) TryBipartiteColoring() map[int]Color { colors[n] = coloring[colors[s]] } if !visited[n] { - color_node(n) + colorNode(n) } } } @@ -28,7 +34,7 @@ func (g *Graph) TryBipartiteColoring() map[int]Color { for i := range g.edges { if colors[i] == 0 { colors[i] = 1 - color_node(i) + colorNode(i) } } diff --git a/graph/coloring/greedy.go b/graph/coloring/greedy.go index 907395d96..07ca6af1b 100644 --- a/graph/coloring/greedy.go +++ b/graph/coloring/greedy.go @@ -1,4 +1,6 @@ // This file contains the graph coloring implementation using Greedy Approach. +// time complexity: O(V^2) where V is the number of vertices in the graph +// space complexity: O(V) where V is the number of vertices in the graph // Author(s): [Shivam](https://github.com/Shivam010) package coloring diff --git a/graph/cycle.go b/graph/cycle.go index cf45d1854..c55cd6bed 100644 --- a/graph/cycle.go +++ b/graph/cycle.go @@ -1,5 +1,7 @@ // cycle.go // this file handle algorithm that related to cycle in graph +// time complexity: O(V+E) where V is the number of vertices and E is the number of edges in the graph +// space complexity: O(V) where V is the number of vertices in the graph // reference: https://en.wikipedia.org/wiki/Cycle_(graph_theory) // [kiarash hajian](https://github.com/kiarash8112) diff --git a/graph/depthfirstsearch.go b/graph/depthfirstsearch.go index c035c79f5..76bed3106 100644 --- a/graph/depthfirstsearch.go +++ b/graph/depthfirstsearch.go @@ -1,3 +1,9 @@ +// depthfirstsearch.go +// description: this file contains the implementation of the depth first search algorithm +// details: Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures. The algorithm starts at the root node and explores as far as possible along each branch before backtracking. +// time complexity: O(n) +// space complexity: O(n) + package graph func GetIdx(target int, nodes []int) int { diff --git a/graph/dijkstra.go b/graph/dijkstra.go index 685cf02e8..ad7a8a778 100644 --- a/graph/dijkstra.go +++ b/graph/dijkstra.go @@ -1,3 +1,10 @@ +// dijkstra.go +// description: this file contains the implementation of the Dijkstra algorithm +// details: Dijkstra's algorithm is an algorithm for finding the shortest paths between nodes in a graph, which may represent, for example, road networks. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later. The algorithm exists in many variants; Dijkstra's original variant found the shortest path between two nodes, but a more common variant fixes a single node as the "source" node and finds shortest paths from the source to all other nodes in the graph, producing a shortest-path tree. +// time complexity: O((V+E) log V) where V is the number of vertices and E is the number of edges in the graph +// space complexity: O(V) where V is the number of vertices in the graph +// reference: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + package graph import "github.com/TheAlgorithms/Go/sort" diff --git a/graph/floydwarshall.go b/graph/floydwarshall.go index 33b97a2c1..9544e587b 100644 --- a/graph/floydwarshall.go +++ b/graph/floydwarshall.go @@ -1,4 +1,6 @@ // Floyd-Warshall algorithm +// time complexity: O(V^3) where V is the number of vertices in the graph +// space complexity: O(V^2) where V is the number of vertices in the graph // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm package graph diff --git a/graph/lowestcommonancestor.go b/graph/lowestcommonancestor.go index 8ce575187..891bac50d 100644 --- a/graph/lowestcommonancestor.go +++ b/graph/lowestcommonancestor.go @@ -3,6 +3,8 @@ // detail: // Let `T` be a tree. The LCA of `u` and `v` in T is the shared ancestor of `u` and `v` // that is located farthest from the root. +// time complexity: O(n log n) where n is the number of vertices in the tree +// space complexity: O(n log n) where n is the number of vertices in the tree // references: [cp-algorithms](https://cp-algorithms.com/graph/lca_binary_lifting.html) // author(s) [Dat](https://github.com/datbeohbbh) // see lowestcommonancestor_test.go for a test implementation. diff --git a/graph/topological.go b/graph/topological.go index 9e99470b7..8cd1856e0 100644 --- a/graph/topological.go +++ b/graph/topological.go @@ -1,3 +1,10 @@ +// topological.go +// description: Topological sort +// details: Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u v, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG. +// time complexity: O(V+E) where V is the number of vertices and E is the number of edges in the graph +// space complexity: O(V) where V is the number of vertices in the graph +// reference: https://en.wikipedia.org/wiki/Topological_sorting + package graph // Topological assumes that graph given is valid and that its diff --git a/hashing/sha256/sha256.go b/hashing/sha256/sha256.go index 9061f3801..0dd38a557 100644 --- a/hashing/sha256/sha256.go +++ b/hashing/sha256/sha256.go @@ -1,5 +1,7 @@ // sha256.go // description: The sha256 cryptographic hash function as defined in the RFC6234 standard. +// time complexity: O(n) +// space complexity: O(n) // author: [Paul Leydier] (https://github.com/paul-leydier) // ref: https://datatracker.ietf.org/doc/html/rfc6234 // ref: https://en.wikipedia.org/wiki/SHA-2 diff --git a/math/aliquotsum.go b/math/aliquotsum.go index 6e3af6cc0..cc6bd326a 100644 --- a/math/aliquotsum.go +++ b/math/aliquotsum.go @@ -5,6 +5,8 @@ // is the sum of all proper divisors of n, // that is, all divisors of n other than n itself // wikipedia: https://en.wikipedia.org/wiki/Aliquot_sum +// time complexity: O(n) +// space complexity: O(1) // author: Akshay Dubey (https://github.com/itsAkshayDubey) // see aliquotsum_test.go diff --git a/math/armstrong/isarmstrong.go b/math/armstrong/isarmstrong.go index 68055dee8..851b9612a 100644 --- a/math/armstrong/isarmstrong.go +++ b/math/armstrong/isarmstrong.go @@ -1,6 +1,8 @@ // isarmstrong.go // description: Checks if the given number is armstrong number or not // details: An Armstrong number is a n-digit number that is equal to the sum of each of its digits taken to the nth power. +// time complexity: O(log(n)) +// space complexity: O(1) // ref: https://mathlair.allfunandgames.ca/armstrong.php // author: Kavitha J diff --git a/math/binary/abs.go b/math/binary/abs.go index 9762c7c8a..5c95fa5e8 100644 --- a/math/binary/abs.go +++ b/math/binary/abs.go @@ -1,3 +1,8 @@ +// abs.go +// description: returns absolute value using binary operation +// time complexity: O(1) +// space complexity: O(1) + package binary // Abs returns absolute value using binary operation diff --git a/math/binary/arithmeticmean.go b/math/binary/arithmeticmean.go index 9fa56560e..f7812b6be 100644 --- a/math/binary/arithmeticmean.go +++ b/math/binary/arithmeticmean.go @@ -2,6 +2,8 @@ // description: Arithmetic mean // details: // The most common type of average is the arithmetic mean. If n numbers are given, each number denoted by ai (where i = 1,2, ..., n), the arithmetic mean is the sum of the as divided by n or - [Arithmetic mean](https://en.wikipedia.org/wiki/Average#Arithmetic_mean) +// time complexity: O(1) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see arithmeticmean_test.go diff --git a/math/binary/bitcounter.go b/math/binary/bitcounter.go index 33e24256d..baf8dcd7b 100644 --- a/math/binary/bitcounter.go +++ b/math/binary/bitcounter.go @@ -2,6 +2,8 @@ // description: Counts the number of set bits in a number // details: // For unsigned integer number N, return the number of bits set to 1 - [Bit numbering](https://en.wikipedia.org/wiki/Bit_numbering) +// time complexity: O(log(n)) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see bitcounter_test.go diff --git a/math/binary/checkisnumberpoweroftwo.go b/math/binary/checkisnumberpoweroftwo.go index 29c023e5a..d836396f5 100644 --- a/math/binary/checkisnumberpoweroftwo.go +++ b/math/binary/checkisnumberpoweroftwo.go @@ -2,6 +2,8 @@ // description: Is the number a power of two // details: // Checks if a number is a power of two- [Power of two](https://en.wikipedia.org/wiki/Power_of_two) +// time complexity: O(1) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see checkisnumberpoweroftwo_test.go diff --git a/math/binary/fast_inverse_sqrt.go b/math/binary/fast_inverse_sqrt.go index 24ee41a82..c8689b451 100644 --- a/math/binary/fast_inverse_sqrt.go +++ b/math/binary/fast_inverse_sqrt.go @@ -1,4 +1,6 @@ // Calculating the inverse square root +// time complexity: O(1) +// space complexity: O(1) // [See more](https://en.wikipedia.org/wiki/Fast_inverse_square_root) package binary diff --git a/math/binary/logarithm.go b/math/binary/logarithm.go index 205b0235b..3d73ac428 100644 --- a/math/binary/logarithm.go +++ b/math/binary/logarithm.go @@ -1,4 +1,6 @@ // author(s) [red_byte](https://github.com/i-redbyte) +// time complexity: O(1) +// space complexity: O(1) // see logarithm_test.go package binary diff --git a/math/binary/rbc.go b/math/binary/rbc.go index c0a6e78f1..b6ef45f68 100644 --- a/math/binary/rbc.go +++ b/math/binary/rbc.go @@ -2,6 +2,8 @@ // description: Reflected binary code (RBC) // details: // The reflected binary code (RBC), also known just as reflected binary (RB) or Gray code after Frank Gray, is an ordering of the binary numeral system such that two successive values differ in only one bit (binary digit). - [RBC](https://en.wikipedia.org/wiki/Gray_code) +// time complexity: O(n) +// space complexity: O(n) // author(s) [red_byte](https://github.com/i-redbyte) // see rbc_test.go diff --git a/math/binary/reversebits.go b/math/binary/reversebits.go index f4367cc94..751fbcfd5 100644 --- a/math/binary/reversebits.go +++ b/math/binary/reversebits.go @@ -2,6 +2,8 @@ // description: Reverse bits // details: // Reverse the bits of an integer number +// time complexity: O(log(n)) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see reversebits_test.go diff --git a/math/binary/sqrt.go b/math/binary/sqrt.go index 520338eb6..8c967bf91 100644 --- a/math/binary/sqrt.go +++ b/math/binary/sqrt.go @@ -3,6 +3,8 @@ // details: // Calculating the square root using binary operations and a magic number 0x5f3759df [See more](https://en.wikipedia.org/wiki/Fast_inverse_square_root) // author(s) [red_byte](https://github.com/i-redbyte) +// time complexity: O(1) +// space complexity: O(1) // see sqrt_test.go package binary diff --git a/math/binary/xorsearch.go b/math/binary/xorsearch.go index b16b7846b..9e914da83 100644 --- a/math/binary/xorsearch.go +++ b/math/binary/xorsearch.go @@ -2,6 +2,8 @@ // description: Find a missing number in a sequence // details: // Given an array A containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. - [xor](https://en.wikipedia.org/wiki/Exclusive_or) +// time complexity: O(n) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see xorsearch_test.go diff --git a/math/binomialcoefficient.go b/math/binomialcoefficient.go index d3c123a6f..614f4b7db 100644 --- a/math/binomialcoefficient.go +++ b/math/binomialcoefficient.go @@ -4,6 +4,8 @@ // a binomial coefficient C(n,k) gives number ways // in which k objects can be chosen from n objects. // wikipedia: https://en.wikipedia.org/wiki/Binomial_coefficient +// time complexity: O(k) or O(n-k) whichever is smaller (O(n) in worst case) +// space complexity: O(1) // author: Akshay Dubey (https://github.com/itsAkshayDubey) // see binomialcoefficient_test.go diff --git a/math/catalan/catalannumber.go b/math/catalan/catalannumber.go index 9ea8acb49..5f81cb9f4 100644 --- a/math/catalan/catalannumber.go +++ b/math/catalan/catalannumber.go @@ -2,6 +2,8 @@ // description: Returns the Catalan number // details: // In combinatorial mathematics, the Catalan numbers are a sequence of natural numbers that occur in various counting problems, often involving recursively defined objects. - [Catalan number](https://en.wikipedia.org/wiki/Catalan_number) +// time complexity: O(n) +// space complexity: O(1) // The input is the number of the Catalan number n, at the output we get the value of the number // author(s) [red_byte](https://github.com/i-redbyte) // see catalannumber_test.go diff --git a/math/factorial/factorial.go b/math/factorial/factorial.go index 7472da8de..6703e6c75 100644 --- a/math/factorial/factorial.go +++ b/math/factorial/factorial.go @@ -2,6 +2,8 @@ // description: Calculating factorial // details: // The factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n - [Factorial](https://en.wikipedia.org/wiki/Factorial) +// time complexity: O(n) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see factorial_test.go diff --git a/math/fibonacci/fibonacci.go b/math/fibonacci/fibonacci.go index 92e69ae08..c2fd1b2e2 100644 --- a/math/fibonacci/fibonacci.go +++ b/math/fibonacci/fibonacci.go @@ -2,6 +2,8 @@ // description: Get the nth Fibonacci Number // details: // In mathematics, the Fibonacci numbers, commonly denoted Fn, form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. [Fibonacci number](https://en.wikipedia.org/wiki/Fibonacci_number) +// time complexity: O(log n) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see fibonacci_test.go diff --git a/math/gcd/extended.go b/math/gcd/extended.go index eea32e9e9..229630141 100644 --- a/math/gcd/extended.go +++ b/math/gcd/extended.go @@ -3,6 +3,8 @@ // details: // A simple implementation of Extended GCD algorithm, that returns GCD, a and b // which solves ax + by = gcd(a, b) +// time complexity: O(log(min(a, b))) where a and b are the two numbers +// space complexity: O(log(min(a, b))) where a and b are the two numbers // author(s) [Taj](https://github.com/tjgurwara99) // see extended_test.go diff --git a/math/gcd/extendedgcd.go b/math/gcd/extendedgcd.go index 004a91ead..0f5a750dc 100644 --- a/math/gcd/extendedgcd.go +++ b/math/gcd/extendedgcd.go @@ -1,3 +1,8 @@ +// extendedgcd.go +// description: Implementation of Extended GCD Algorithm +// time complexity: O(log(min(a, b))) where a and b are the two numbers +// space complexity: O(log(min(a, b))) where a and b are the two numbers + package gcd // ExtendedRecursive finds and returns gcd(a, b), x, y satisfying a*x + b*y = gcd(a, b). diff --git a/math/gcd/gcd.go b/math/gcd/gcd.go index e76e8396f..2045d0901 100644 --- a/math/gcd/gcd.go +++ b/math/gcd/gcd.go @@ -1,3 +1,6 @@ +// time complexity: O(log(min(a, b))) where a and b are the two numbers +// space complexity: O(1) + package gcd // Recursive finds and returns the greatest common divisor of a given integer. diff --git a/math/gcd/gcditerative.go b/math/gcd/gcditerative.go index e87dfce6f..96c217cfa 100644 --- a/math/gcd/gcditerative.go +++ b/math/gcd/gcditerative.go @@ -1,3 +1,6 @@ +// time complexity: O(log(min(a, b))) where a and b are the two numbers +// space complexity: O(1) + package gcd // Iterative Faster iterative version of GcdRecursive without holding up too much of the stack diff --git a/math/geometry/distance.go b/math/geometry/distance.go index 5b1c3c82e..0baf64562 100644 --- a/math/geometry/distance.go +++ b/math/geometry/distance.go @@ -1,5 +1,7 @@ // distance.go // Find Euclidean distance between two points +// time complexity: O(n) where n is the number of dimensions +// space complexity: O(1) // author(s) [Chetan Patil](https://github.com/Chetan07j) // Package geometry contains geometric algorithms diff --git a/math/krishnamurthy.go b/math/krishnamurthy.go index 641dfbf92..63bb6dbf6 100644 --- a/math/krishnamurthy.go +++ b/math/krishnamurthy.go @@ -2,6 +2,8 @@ // description: A program which contains the function that returns true if a given number is Krishnamurthy number or not. // details: A number is a Krishnamurthy number if the sum of all the factorials of the digits is equal to the number. // Ex: 1! = 1, 145 = 1! + 4! + 5! +// time complexity: O(log n) +// space complexity: O(1) // author(s): [GooMonk](https://github.com/GooMonk) // see krishnamurthy_test.go package math diff --git a/math/liouville.go b/math/liouville.go index 908a4deac..55d2c95f4 100644 --- a/math/liouville.go +++ b/math/liouville.go @@ -6,6 +6,8 @@ // λ(n) = +1 if n is a positive integer with an even number of prime factors. // λ(n) = −1 if n is a positive integer with an odd number of prime factors. // wikipedia: https://en.wikipedia.org/wiki/Liouville_function +// time complexity: O(log n) +// space complexity: O(1) // author: Akshay Dubey (https://github.com/itsAkshayDubey) // see liouville_test.go diff --git a/math/matrix/add.go b/math/matrix/add.go index 34fdf98be..d5d79efdd 100644 --- a/math/matrix/add.go +++ b/math/matrix/add.go @@ -1,3 +1,8 @@ +// add.go +// description: Add two matrices +// time complexity: O(n^2) +// space complexity: O(n^2) + package matrix import ( diff --git a/math/matrix/checkequal.go b/math/matrix/checkequal.go index c6bde8597..005c657af 100644 --- a/math/matrix/checkequal.go +++ b/math/matrix/checkequal.go @@ -3,6 +3,9 @@ package matrix // CheckEqual checks if the current matrix is equal to another matrix (m2). // Two matrices are considered equal if they have the same dimensions and // all their elements are equal. +// time complexity: O(n*m) where n and m are the dimensions of the matrix +// space complexity: O(1) + func (m1 Matrix[T]) CheckEqual(m2 Matrix[T]) bool { if !m1.MatchDimensions(m2) { return false diff --git a/math/matrix/copy.go b/math/matrix/copy.go index 2b9949750..11afb9237 100644 --- a/math/matrix/copy.go +++ b/math/matrix/copy.go @@ -1,3 +1,9 @@ +// copy.go +// description: Copy a matrix +// details: This function creates a new matrix with the same dimensions as the original matrix and copies all the elements from the original matrix to the new matrix. +// time complexity: O(n*m) where n and m are the dimensions of the matrix +// space complexity: O(n*m) where n and m are the dimensions of the matrix + package matrix import "sync" diff --git a/math/matrix/determinant.go b/math/matrix/determinant.go index d2570f8f8..371b1fa0a 100644 --- a/math/matrix/determinant.go +++ b/math/matrix/determinant.go @@ -2,6 +2,8 @@ // description: This method finds the determinant of a matrix. // details: For a theoretical explanation as for what the determinant // represents, see the [Wikipedia Article](https://en.wikipedia.org/wiki/Determinant) +// time complexity: O(n!) where n is the number of rows and columns in the matrix. +// space complexity: O(n^2) where n is the number of rows and columns in the matrix. // author [Carter907](https://github.com/Carter907) // see determinant_test.go diff --git a/math/matrix/multiply.go b/math/matrix/multiply.go index 718a1b068..f59213da6 100644 --- a/math/matrix/multiply.go +++ b/math/matrix/multiply.go @@ -1,3 +1,8 @@ +// multiply.go +// description: Implementation of matrix multiplication +// time complexity: O(n^3) where n is the number of rows in the first matrix +// space complexity: O(n^2) where n is the number of rows in the first matrix + package matrix import ( diff --git a/math/matrix/strassenmatrixmultiply.go b/math/matrix/strassenmatrixmultiply.go index 86fb47809..9b5f01fdf 100644 --- a/math/matrix/strassenmatrixmultiply.go +++ b/math/matrix/strassenmatrixmultiply.go @@ -4,6 +4,8 @@ // This program takes two matrices as input and performs matrix multiplication // using the Strassen algorithm, which is an optimized divide-and-conquer // approach. It allows for efficient multiplication of large matrices. +// time complexity: O(n^2.81) +// space complexity: O(n^2) // author(s): Mohit Raghav(https://github.com/mohit07raghav19) // See strassenmatrixmultiply_test.go for test cases package matrix diff --git a/math/max/bitwisemax.go b/math/max/bitwisemax.go index b6c3a4623..a54f94654 100644 --- a/math/max/bitwisemax.go +++ b/math/max/bitwisemax.go @@ -3,6 +3,8 @@ // details: // implementation of finding the maximum of two numbers using only binary operations without using conditions // author(s) [red_byte](https://github.com/i-redbyte) +// time complexity: O(1) +// space complexity: O(1) // see bitwiseMax_test.go package max diff --git a/math/median.go b/math/median.go index d8cd02796..1b9dac834 100644 --- a/math/median.go +++ b/math/median.go @@ -1,5 +1,7 @@ // author(s) [jo3zeph](https://github.com/jo3zeph) // description: Find the median from a set of values +// time complexity: O(n log n) +// space complexity: O(1) // see median_test.go package math diff --git a/math/mobius.go b/math/mobius.go index 76b50da14..0f9fac639 100644 --- a/math/mobius.go +++ b/math/mobius.go @@ -7,6 +7,8 @@ // μ(n) = −1 if n is a square-free positive integer with an odd number of prime factors. // μ(n) = 0 if n has a squared prime factor. // wikipedia: https://en.wikipedia.org/wiki/M%C3%B6bius_function +// time complexity: O(n) +// space complexity: O(1) // author: Akshay Dubey (https://github.com/itsAkshayDubey) // see mobius_test.go diff --git a/math/mode.go b/math/mode.go index 164084bb6..87f233304 100644 --- a/math/mode.go +++ b/math/mode.go @@ -1,5 +1,7 @@ // mode.go // author(s): [CalvinNJK] (https://github.com/CalvinNJK) +// time complexity: O(n) +// space complexity: O(n) // description: Finding Mode Value In an Array // see mode.go diff --git a/math/modular/exponentiation.go b/math/modular/exponentiation.go index f71a8d3ff..85a397e4f 100644 --- a/math/modular/exponentiation.go +++ b/math/modular/exponentiation.go @@ -2,6 +2,8 @@ // description: Implementation of Modular Exponentiation Algorithm // details: // A simple implementation of Modular Exponentiation - [Modular Exponenetation wiki](https://en.wikipedia.org/wiki/Modular_exponentiation) +// time complexity: O(log(n)) where n is the exponent +// space complexity: O(1) // author(s) [Taj](https://github.com/tjgurwara99) // see exponentiation_test.go diff --git a/math/modular/inverse.go b/math/modular/inverse.go index 819ffda8d..f20d70b11 100644 --- a/math/modular/inverse.go +++ b/math/modular/inverse.go @@ -2,6 +2,8 @@ // description: Implementation of Modular Inverse Algorithm // details: // A simple implementation of Modular Inverse - [Modular Inverse wiki](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse) +// time complexity: O(log(min(a, b))) where a and b are the two numbers +// space complexity: O(1) // author(s) [Taj](https://github.com/tjgurwara99) // see inverse_test.go diff --git a/math/moserdebruijnsequence/sequence.go b/math/moserdebruijnsequence/sequence.go index dd846b5a1..09d2c7776 100644 --- a/math/moserdebruijnsequence/sequence.go +++ b/math/moserdebruijnsequence/sequence.go @@ -1,5 +1,7 @@ // The Moser-de Bruijn sequence is the sequence obtained by // adding up the distinct powers of the number 4 (For example 1, 4, 16, 64, etc). +// time complexity: O(n) +// space complexity: O(n) // You can get more details on https://en.wikipedia.org/wiki/Moser%E2%80%93de_Bruijn_sequence. package moserdebruijnsequence diff --git a/math/pascal/pascaltriangle.go b/math/pascal/pascaltriangle.go index 12f227fd0..742b735d7 100644 --- a/math/pascal/pascaltriangle.go +++ b/math/pascal/pascaltriangle.go @@ -16,6 +16,8 @@ //1 10 45 120 210 252 210 120 45 10 1 //... // author(s) [red_byte](https://github.com/i-redbyte) +// time complexity: O(n^2) +// space complexity: O(n^2) // see pascaltriangle_test.go package pascal diff --git a/math/perfectnumber.go b/math/perfectnumber.go index e21c89b64..37be71a2b 100644 --- a/math/perfectnumber.go +++ b/math/perfectnumber.go @@ -7,6 +7,8 @@ // A number is called perfect, if it is a sum of its proper divisors, // cf. https://en.wikipedia.org/wiki/Perfect_number, // https://mathworld.wolfram.com/PerfectNumber.html +// time complexity: O(sqrt(n)) +// space complexity: O(1) // https://oeis.org/A000396 // author(s) [Piotr Idzik](https://github.com/vil02) // see perfectnumber_test.go diff --git a/math/permutation/heaps.go b/math/permutation/heaps.go index f3d79f464..5f4ebaed3 100644 --- a/math/permutation/heaps.go +++ b/math/permutation/heaps.go @@ -1,3 +1,8 @@ +// heaps.go +// description: Implementation of Heap's Algorithm for generating all permutations of n objects +// time complexity: O(n!) +// space complexity: O(n) + package permutation import ( diff --git a/math/permutation/next_permutation.go b/math/permutation/next_permutation.go index 62841bb3d..6aff11296 100644 --- a/math/permutation/next_permutation.go +++ b/math/permutation/next_permutation.go @@ -1,6 +1,8 @@ // A practice to find lexicographically next greater permutation of the given array of integers. // If there does not exist any greater permutation, then print the lexicographically smallest permutation of the given array. // The implementation below, finds the next permutation in linear time and constant memory and returns in place +// time complexity: O(n) +// space complexity: O(1) // Useful reference: https://www.geeksforgeeks.org/next-permutation/ package permutation diff --git a/math/pi/montecarlopi.go b/math/pi/montecarlopi.go index 7bbadf01c..a2e140f08 100644 --- a/math/pi/montecarlopi.go +++ b/math/pi/montecarlopi.go @@ -2,6 +2,8 @@ // description: Calculating pi by the Monte Carlo method // details: // implementations of Monte Carlo Algorithm for the calculating of Pi - [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method) +// time complexity: O(n) +// space complexity: O(1) // author(s): [red_byte](https://github.com/i-redbyte), [Paul Leydier] (https://github.com/paul-leydier) // see montecarlopi_test.go diff --git a/math/pi/spigotpi.go b/math/pi/spigotpi.go index 6274176e4..349602a32 100644 --- a/math/pi/spigotpi.go +++ b/math/pi/spigotpi.go @@ -2,6 +2,8 @@ // description: A Spigot Algorithm for the Digits of Pi // details: // implementation of Spigot Algorithm for the Digits of Pi - [Spigot algorithm](https://en.wikipedia.org/wiki/Spigot_algorithm) +// time complexity: O(n) +// space complexity: O(n) // author(s) [red_byte](https://github.com/i-redbyte) // see spigotpi_test.go diff --git a/math/pollard.go b/math/pollard.go index 434a0f24f..a2cc42df1 100644 --- a/math/pollard.go +++ b/math/pollard.go @@ -2,6 +2,8 @@ // description: Pollard's rho algorithm // details: // implementation of Pollard's rho algorithm for integer factorization-[Pollard's rho algorithm](https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm) +// time complexity: O(n^(1/4)) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see pollard_test.go diff --git a/math/power/powvialogarithm.go b/math/power/powvialogarithm.go index df1de157f..c2a395e3b 100644 --- a/math/power/powvialogarithm.go +++ b/math/power/powvialogarithm.go @@ -2,6 +2,8 @@ // description: Powers in terms of logarithms // details: // implementation of exponentiation using exponent and logarithm, without using loops - [Powers via logarithms wiki](https://en.wikipedia.org/wiki/Exponentiation#Powers_via_logarithms) +// time complexity: O(1) +// space complexity: O(1) // author(s) [red_byte](https://github.com/i-redbyte) // see powvialogarithm_test.go diff --git a/math/prime/millerrabintest.go b/math/prime/millerrabintest.go index 1f3a2ef72..5357bc45c 100644 --- a/math/prime/millerrabintest.go +++ b/math/prime/millerrabintest.go @@ -2,7 +2,8 @@ // One of the implementations is deterministic and the other is probabilistic. // The Miller-Rabin test is one of the simplest and fastest known primality // tests and is widely used. -// +// time complexity: O(k * log(n)^3) +// space complexity: O(1) // Authors: // [Taj](https://github.com/tjgurwara99) // [Rak](https://github.com/raklaptudirm) diff --git a/math/prime/primecheck.go b/math/prime/primecheck.go index 3e2a97280..7671c9cd0 100644 --- a/math/prime/primecheck.go +++ b/math/prime/primecheck.go @@ -3,6 +3,8 @@ package prime // A primality test is an algorithm for determining whether an input number is prime. Among other // fields of mathematics, it is used for cryptography. Unlike integer factorization, primality // tests do not generally give prime factors, only stating whether the input number is prime or not. +// time complexity: O(sqrt(n)) +// space complexity: O(1) // Source - Wikipedia https://en.wikipedia.org/wiki/Primality_test // TrialDivision tests whether a number is prime by trying to divide it by the numbers less than it. diff --git a/math/prime/primefactorization.go b/math/prime/primefactorization.go index c25522871..43479e439 100644 --- a/math/prime/primefactorization.go +++ b/math/prime/primefactorization.go @@ -1,3 +1,8 @@ +// primefactorization.go +// description: Prime factorization of a number +// time complexity: O(sqrt(n)) +// space complexity: O(sqrt(n)) + package prime // Factorize is a function that computes the exponents diff --git a/math/prime/sieve2.go b/math/prime/sieve2.go index 2e2e7b116..881ca20f5 100644 --- a/math/prime/sieve2.go +++ b/math/prime/sieve2.go @@ -1,5 +1,7 @@ /* sieve2.go - Sieve of Eratosthenes * Algorithm to generate prime numbers up to a limit + * time complexity: O(n log log n) + * space complexity: O(n) * Author: ddaniel27 */ package prime diff --git a/math/prime/twin.go b/math/prime/twin.go index 1326746e4..dfd861510 100644 --- a/math/prime/twin.go +++ b/math/prime/twin.go @@ -4,6 +4,8 @@ // For any integer n, twin prime is (n + 2) // if and only if both n and (n + 2) both are prime // wikipedia: https://en.wikipedia.org/wiki/Twin_prime +// time complexity: O(log n) +// space complexity: O(1) // author: Akshay Dubey (https://github.com/itsAkshayDubey) // see twin_test.go diff --git a/math/pronicnumber.go b/math/pronicnumber.go index 90850d28e..47d25d17c 100644 --- a/math/pronicnumber.go +++ b/math/pronicnumber.go @@ -4,18 +4,20 @@ // Pronic number: For any integer n, if there exists integer m // such that n = m * (m + 1) then n is called a pronic number. // wikipedia: https://en.wikipedia.org/wiki/Pronic_number +// time complexity: O(1) +// space complexity: O(1) // author: Akshay Dubey (https://github.com/itsAkshayDubey) // see pronicnumber_test.go package math -import stdMath "math" +import "math" // PronicNumber returns true if argument passed to the function is pronic and false otherwise. func PronicNumber(n int) bool { if n < 0 || n%2 == 1 { return false } - x := int(stdMath.Sqrt(float64(n))) + x := int(math.Sqrt(float64(n))) return n == x*(x+1) } diff --git a/other/nested/nestedbrackets.go b/other/nested/nestedbrackets.go index ec912938c..7f220a332 100644 --- a/other/nested/nestedbrackets.go +++ b/other/nested/nestedbrackets.go @@ -17,6 +17,9 @@ package nested // **Note** Providing characters other then brackets would return false, // despite brackets sequence in the string. Make sure to filter // input before usage. +// time complexity: O(n) +// space complexity: O(n) + func IsBalanced(input string) bool { if len(input) == 0 { return true diff --git a/other/password/generator.go b/other/password/generator.go index 46237364f..71bfdbd65 100644 --- a/other/password/generator.go +++ b/other/password/generator.go @@ -3,6 +3,9 @@ // This length is not fixed if you generate multiple passwords for the same range // Package password contains functions to help generate random passwords +// time complexity: O(n) +// space complexity: O(n) + package password import ( diff --git a/search/jump.go b/search/jump.go index 163dea55d..169620d9a 100644 --- a/search/jump.go +++ b/search/jump.go @@ -5,6 +5,8 @@ // before performing a linear search // reference: https://en.wikipedia.org/wiki/Jump_search // see jump_test.go for a test implementation, test function TestJump +// time complexity: O(sqrt(n)) +// space complexity: O(1) package search diff --git a/sort/bogosort.go b/sort/bogosort.go index a37d18ff8..165397155 100644 --- a/sort/bogosort.go +++ b/sort/bogosort.go @@ -1,7 +1,8 @@ // This is a pure Go implementation of the bogosort algorithm, // also known as permutation sort, stupid sort, slowsort, shotgun sort, or monkey sort. // Bogosort generates random permutations until it guesses the correct one. - +// worst-case time complexity: O((n+1)!) +// best-case time complexity: O(n) // More info on: https://en.wikipedia.org/wiki/Bogosort package sort diff --git a/sort/combSort.go b/sort/combSort.go index 76e523e34..15c3e8bab 100644 --- a/sort/combSort.go +++ b/sort/combSort.go @@ -1,4 +1,7 @@ // Implementation of comb sort algorithm, an improvement of bubble sort +// average time complexity: O(n^2 / 2^p) where p is the number of increments +// worst time complexity: O(n^2) +// space complexity: O(1) // Reference: https://www.geeksforgeeks.org/comb-sort/ package sort diff --git a/sort/countingsort.go b/sort/countingsort.go index d55a13798..55fbac7c0 100644 --- a/sort/countingsort.go +++ b/sort/countingsort.go @@ -1,6 +1,9 @@ // countingsort.go // description: Implementation of counting sort algorithm // details: A simple counting sort algorithm implementation +// worst-case time complexity: O(n + k) where n is the number of elements in the input array and k is the range of the input +// average-case time complexity: O(n + k) where n is the number of elements in the input array and k is the range of the input +// space complexity: O(n + k) // author [Phil](https://github.com/pschik) // see sort_test.go for a test implementation, test function TestQuickSort diff --git a/sort/exchangesort.go b/sort/exchangesort.go index cbf6b9b00..43ada90df 100644 --- a/sort/exchangesort.go +++ b/sort/exchangesort.go @@ -1,4 +1,7 @@ // Implementation of exchange sort algorithm, a variant of bubble sort +// average time complexity: O(n^2) +// worst time complexity: O(n^2) +// space complexity: O(1) // Reference: https://en.wikipedia.org/wiki/Sorting_algorithm#Exchange_sort package sort diff --git a/sort/heapsort.go b/sort/heapsort.go index 741b4e4e8..f4e581306 100644 --- a/sort/heapsort.go +++ b/sort/heapsort.go @@ -1,3 +1,9 @@ +// heapsort.go +// description: Implementation of heap sort algorithm +// worst-case time complexity: O(n log n) +// average-case time complexity: O(n log n) +// space complexity: O(1) + package sort import "github.com/TheAlgorithms/Go/constraints" diff --git a/sort/insertionsort.go b/sort/insertionsort.go index 13e45eeb9..55ac3130f 100644 --- a/sort/insertionsort.go +++ b/sort/insertionsort.go @@ -1,3 +1,9 @@ +// insertionsort.go +// description: Implementation of insertion sort algorithm +// worst-case time complexity: O(n^2) +// average-case time complexity: O(n^2) +// space complexity: O(1) + package sort import "github.com/TheAlgorithms/Go/constraints" diff --git a/sort/mergesort.go b/sort/mergesort.go index 9a875b428..550b13eea 100644 --- a/sort/mergesort.go +++ b/sort/mergesort.go @@ -1,3 +1,9 @@ +// mergesort.go +// description: Implementation of merge sort algorithm +// worst-case time complexity: O(n log n) +// average-case time complexity: O(n log n) +// space complexity: O(n) + package sort import ( diff --git a/sort/patiencesort.go b/sort/patiencesort.go index 746c84931..f1b2b46f2 100644 --- a/sort/patiencesort.go +++ b/sort/patiencesort.go @@ -4,6 +4,9 @@ // GeeksForGeeks article : https://www.geeksforgeeks.org/patience-sorting/ // Wikipedia article: https://en.wikipedia.org/wiki/Patience_sorting // authors [guuzaa](https://github.com/guuzaa) +// worst-case time complexity: O(n log n) +// average time complexity: O(n log n) +// space complexity: O(n) // see patiencesort.go package sort diff --git a/sort/pigeonholesort.go b/sort/pigeonholesort.go index 12941cdc9..5e735c8fd 100644 --- a/sort/pigeonholesort.go +++ b/sort/pigeonholesort.go @@ -1,5 +1,7 @@ // Pigeonhole algorithm's working at wikipedia. // https://en.wikipedia.org/wiki/Pigeonhole_sort +// time complexity: O(n + N) where n is the number of elements in the array and N is the range of input +// space complexity: O(N) package sort diff --git a/sort/quicksort.go b/sort/quicksort.go index 576db395a..8b05fe786 100644 --- a/sort/quicksort.go +++ b/sort/quicksort.go @@ -2,6 +2,9 @@ // description: Implementation of in-place quicksort algorithm // details: // A simple in-place quicksort algorithm implementation. [Wikipedia](https://en.wikipedia.org/wiki/Quicksort) +// worst time complexity: O(n^2) +// average time complexity: O(n log n) +// space complexity: O(log n) // author(s) [Taj](https://github.com/tjgurwara99) // see sort_test.go for a test implementation, test function TestQuickSort. diff --git a/sort/radixsort.go b/sort/radixsort.go index 4dbd21d64..28ddee8bf 100644 --- a/sort/radixsort.go +++ b/sort/radixsort.go @@ -2,6 +2,9 @@ // description: Implementation of in-place radixsort algorithm // details: // A simple in-place quicksort algorithm implementation. [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort) +// worst time complexity: O(n * k) where n is the number of elements in the input array and k is the number of digits in the largest number +// average time complexity: O(n * k) where n is the number of elements in the input array and k is the number of digits in the largest number +// space complexity: O(n) package sort diff --git a/sort/simplesort.go b/sort/simplesort.go index ec54c1db0..fc60f33de 100644 --- a/sort/simplesort.go +++ b/sort/simplesort.go @@ -5,6 +5,9 @@ // An improved version is included with slight changes to make the sort slightly more efficient // reference: https://arxiv.org/abs/2110.01111v1 // see sort_test.go for a test implementation, test function TestSimple and TestImprovedSimple +// worst-case time complexity: O(n^2) +// average-case time complexity: O(n^2) +// space complexity: O(1) package sort From fba7aba226c0b56694c06bf46b9480b0a1201816 Mon Sep 17 00:00:00 2001 From: Simon Waldherr Date: Tue, 26 Nov 2024 19:54:03 +0100 Subject: [PATCH 480/488] add md5 hashing (#764) --- hashing/md5/md5.go | 118 ++++++++++++++++++++++++++++++++++++++++ hashing/md5/md5_test.go | 42 ++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 hashing/md5/md5.go create mode 100644 hashing/md5/md5_test.go diff --git a/hashing/md5/md5.go b/hashing/md5/md5.go new file mode 100644 index 000000000..5fad61ef4 --- /dev/null +++ b/hashing/md5/md5.go @@ -0,0 +1,118 @@ +// md5.go +// description: The MD5 hashing function as defined in RFC 1321. +// author: Simon Waldherr +// ref: https://datatracker.ietf.org/doc/html/rfc1321 +// see md5_test.go for testing + +package md5 + +import ( + "encoding/binary" +) + +// Constants for MD5 +var ( + s = [64]uint32{ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, + } + + K = [64]uint32{ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, + } +) + +// leftRotate rotates x left by n bits +func leftRotate(x, n uint32) uint32 { + return (x << n) | (x >> (32 - n)) +} + +// pad pads the input message so that its length is congruent to 448 modulo 512 +func pad(message []byte) []byte { + originalLength := len(message) * 8 + message = append(message, 0x80) + for (len(message)*8)%512 != 448 { + message = append(message, 0x00) + } + + lengthBytes := make([]byte, 8) + binary.LittleEndian.PutUint64(lengthBytes, uint64(originalLength)) + message = append(message, lengthBytes...) + + return message +} + +// Hash computes the MD5 hash of the input message +func Hash(message []byte) [16]byte { + message = pad(message) + + // Initialize MD5 state variables + a0, b0, c0, d0 := uint32(0x67452301), uint32(0xefcdab89), uint32(0x98badcfe), uint32(0x10325476) + + // Process the message in successive 512-bit chunks + for i := 0; i < len(message); i += 64 { + chunk := message[i : i+64] + var M [16]uint32 + for j := 0; j < 16; j++ { + M[j] = binary.LittleEndian.Uint32(chunk[j*4 : (j+1)*4]) + } + + // Initialize hash value for this chunk + A, B, C, D := a0, b0, c0, d0 + + // Main loop + for i := 0; i < 64; i++ { + var F, g uint32 + if i < 16 { + F = (B & C) | ((^B) & D) + g = uint32(i) + } else if i < 32 { + F = (D & B) | ((^D) & C) + g = uint32((5*i + 1) % 16) + } else if i < 48 { + F = B ^ C ^ D + g = uint32((3*i + 5) % 16) + } else { + F = C ^ (B | (^D)) + g = uint32((7 * i) % 16) + } + F = F + A + K[i] + M[g] + A = D + D = C + C = B + B = B + leftRotate(F, s[i]) + } + + // Add this chunk's hash to result so far + a0 += A + b0 += B + c0 += C + d0 += D + } + + // Produce the final hash value (digest) + var digest [16]byte + binary.LittleEndian.PutUint32(digest[0:4], a0) + binary.LittleEndian.PutUint32(digest[4:8], b0) + binary.LittleEndian.PutUint32(digest[8:12], c0) + binary.LittleEndian.PutUint32(digest[12:16], d0) + + return digest +} diff --git a/hashing/md5/md5_test.go b/hashing/md5/md5_test.go new file mode 100644 index 000000000..b013c0bb3 --- /dev/null +++ b/hashing/md5/md5_test.go @@ -0,0 +1,42 @@ +// md5_test.go +// description: Tests for the MD5 hashing function as defined in RFC 1321. +// author: Simon Waldherr + +package md5 + +import ( + "encoding/hex" + "testing" +) + +// Helper function to convert hash output to hex string for comparison +func toHexString(hash [16]byte) string { + return hex.EncodeToString(hash[:]) +} + +// Test vectors for MD5 (from RFC 1321 and other known sources) +var tests = []struct { + input string + expected string +}{ + {"", "d41d8cd98f00b204e9800998ecf8427e"}, + {"a", "0cc175b9c0f1b6a831c399e269772661"}, + {"abc", "900150983cd24fb0d6963f7d28e17f72"}, + {"message digest", "f96b697d7cb7938d525a2f31aaf161d0"}, + {"abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"}, + {"12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a"}, +} + +// TestHash verifies that the Hash function produces the correct MD5 hash values +func TestHash(t *testing.T) { + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + result := Hash([]byte(tt.input)) + resultHex := toHexString(result) + if resultHex != tt.expected { + t.Errorf("MD5(%q) = %s; want %s", tt.input, resultHex, tt.expected) + } + }) + } +} From 8a1abce2779fe7cee417a4aab28ddf4eb2cda713 Mon Sep 17 00:00:00 2001 From: Simon Waldherr Date: Tue, 26 Nov 2024 19:57:44 +0100 Subject: [PATCH 481/488] add sha1 hashing (#763) Co-authored-by: Rak Laptudirm --- hashing/sha1/sha1.go | 110 ++++++++++++++++++++++++++++++++++++++ hashing/sha1/sha1_test.go | 42 +++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 hashing/sha1/sha1.go create mode 100644 hashing/sha1/sha1_test.go diff --git a/hashing/sha1/sha1.go b/hashing/sha1/sha1.go new file mode 100644 index 000000000..ba30fe615 --- /dev/null +++ b/hashing/sha1/sha1.go @@ -0,0 +1,110 @@ +// sha1.go +// description: The SHA-1 hashing function as defined in RFC 3174. +// author: Simon Waldherr +// ref: https://datatracker.ietf.org/doc/html/rfc3174 +// see sha1_test.go for testing + +package sha1 + +import ( + "encoding/binary" // Used for interacting with uint at the byte level +) + +// Constants for SHA-1 +const ( + h0 uint32 = 0x67452301 + h1 uint32 = 0xEFCDAB89 + h2 uint32 = 0x98BADCFE + h3 uint32 = 0x10325476 + h4 uint32 = 0xC3D2E1F0 +) + +// pad pads the input message so that its length is congruent to 448 modulo 512 +func pad(message []byte) []byte { + originalLength := len(message) * 8 + message = append(message, 0x80) + for (len(message)*8)%512 != 448 { + message = append(message, 0x00) + } + + lengthBytes := make([]byte, 8) + binary.BigEndian.PutUint64(lengthBytes, uint64(originalLength)) + message = append(message, lengthBytes...) + + return message +} + +// leftRotate rotates x left by n bits +func leftRotate(x, n uint32) uint32 { + return (x << n) | (x >> (32 - n)) +} + +// Hash computes the SHA-1 hash of the input message +func Hash(message []byte) [20]byte { + message = pad(message) + + // Initialize variables + a, b, c, d, e := h0, h1, h2, h3, h4 + + // Process the message in successive 512-bit chunks + for i := 0; i < len(message); i += 64 { + var w [80]uint32 + chunk := message[i : i+64] + + // Break chunk into sixteen 32-bit big-endian words + for j := 0; j < 16; j++ { + w[j] = binary.BigEndian.Uint32(chunk[j*4 : (j+1)*4]) + } + + // Extend the sixteen 32-bit words into eighty 32-bit words + for j := 16; j < 80; j++ { + w[j] = leftRotate(w[j-3]^w[j-8]^w[j-14]^w[j-16], 1) + } + + // Initialize hash value for this chunk + A, B, C, D, E := a, b, c, d, e + + // Main loop + for j := 0; j < 80; j++ { + var f, k uint32 + switch { + case j < 20: + f = (B & C) | ((^B) & D) + k = 0x5A827999 + case j < 40: + f = B ^ C ^ D + k = 0x6ED9EBA1 + case j < 60: + f = (B & C) | (B & D) | (C & D) + k = 0x8F1BBCDC + default: + f = B ^ C ^ D + k = 0xCA62C1D6 + } + + temp := leftRotate(A, 5) + f + E + k + w[j] + E = D + D = C + C = leftRotate(B, 30) + B = A + A = temp + } + + // Add this chunk's hash to result so far + a += A + b += B + c += C + d += D + e += E + } + + // Produce the final hash value (digest) + var digest [20]byte + binary.BigEndian.PutUint32(digest[0:4], a) + binary.BigEndian.PutUint32(digest[4:8], b) + binary.BigEndian.PutUint32(digest[8:12], c) + binary.BigEndian.PutUint32(digest[12:16], d) + binary.BigEndian.PutUint32(digest[16:20], e) + + return digest +} diff --git a/hashing/sha1/sha1_test.go b/hashing/sha1/sha1_test.go new file mode 100644 index 000000000..f7d1d2079 --- /dev/null +++ b/hashing/sha1/sha1_test.go @@ -0,0 +1,42 @@ +// sha1_test.go +// description: Tests for the SHA-1 hashing function as defined in RFC 3174. +// author: Simon Waldherr + +package sha1 + +import ( + "encoding/hex" + "testing" +) + +// Helper function to convert hash output to hex string for comparison +func toHexString(hash [20]byte) string { + return hex.EncodeToString(hash[:]) +} + +// Test vectors for SHA-1 (from RFC 3174 and other known sources) +var tests = []struct { + input string + expected string +}{ + {"", "da39a3ee5e6b4b0d3255bfef95601890afd80709"}, + {"a", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"}, + {"abc", "a9993e364706816aba3e25717850c26c9cd0d89d"}, + {"message digest", "c12252ceda8be8994d5fa0290a47231c1d16aae3"}, + {"abcdefghijklmnopqrstuvwxyz", "32d10c7b8cf96570ca04ce37f2a19d84240d3a89"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "761c457bf73b14d27e9e9265c46f4b4dda11f940"}, + {"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "fecfd28bbc9345891a66d7c1b8ff46e60192d284"}, +} + +// TestHash verifies that the Hash function produces the correct SHA-1 hash values +func TestHash(t *testing.T) { + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + result := Hash([]byte(tt.input)) + resultHex := toHexString(result) + if resultHex != tt.expected { + t.Errorf("SHA-1(%q) = %s; want %s", tt.input, resultHex, tt.expected) + } + }) + } +} From 82b6e969824f0ee9c36c875857d44563bdfbcfc7 Mon Sep 17 00:00:00 2001 From: Simon Waldherr Date: Wed, 27 Nov 2024 22:35:20 +0100 Subject: [PATCH 482/488] add odd-even-sort (#762) * add sleepsort and odd-even-sort * Delete sort/sleepsort.go * remove sleep sort from sorts_test.go --- sort/oddevensort.go | 39 +++++++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 4 ++++ 2 files changed, 43 insertions(+) create mode 100644 sort/oddevensort.go diff --git a/sort/oddevensort.go b/sort/oddevensort.go new file mode 100644 index 000000000..5e98ef409 --- /dev/null +++ b/sort/oddevensort.go @@ -0,0 +1,39 @@ +// oddevensort.go +// Implementation of Odd-Even Sort (Brick Sort) +// Reference: https://en.wikipedia.org/wiki/Odd%E2%80%93even_sort + +package sort + +import "github.com/TheAlgorithms/Go/constraints" + +// OddEvenSort performs the odd-even sort algorithm on the given array. +// It is a variation of bubble sort that compares adjacent pairs, alternating +// between odd and even indexed elements in each pass until the array is sorted. +func OddEvenSort[T constraints.Ordered](arr []T) []T { + if len(arr) == 0 { // handle empty array + return arr + } + + swapped := true + for swapped { + swapped = false + + // Perform "odd" indexed pass + for i := 1; i < len(arr)-1; i += 2 { + if arr[i] > arr[i+1] { + arr[i], arr[i+1] = arr[i+1], arr[i] + swapped = true + } + } + + // Perform "even" indexed pass + for i := 0; i < len(arr)-1; i += 2 { + if arr[i] > arr[i+1] { + arr[i], arr[i+1] = arr[i+1], arr[i] + swapped = true + } + } + } + + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 213b17e56..a04f19eb0 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -194,6 +194,10 @@ func TestCircle(t *testing.T) { testFramework(t, sort.Circle[int]) } +func TestOddEvenSort(t *testing.T) { + testFramework(t, sort.OddEvenSort[int]) +} + // END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { From fd6061413348363ef5527b67bc80c60189708311 Mon Sep 17 00:00:00 2001 From: Laurent Egbakou <26142591+egbakou@users.noreply.github.com> Date: Tue, 31 Dec 2024 10:58:51 +0100 Subject: [PATCH 483/488] refactor(structure:linkedlist): renamed variable in singlylinkedlist.go (#772) Co-authored-by: Rak Laptudirm --- structure/linkedlist/singlylinkedlist.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/structure/linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go index 9f951737f..57b09b104 100644 --- a/structure/linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -125,14 +125,14 @@ func (ll *Singly[T]) Count() int { // Reverse reverses the list. func (ll *Singly[T]) Reverse() { - var prev, Next *Node[T] + var prev, next *Node[T] cur := ll.Head for cur != nil { - Next = cur.Next + next = cur.Next cur.Next = prev prev = cur - cur = Next + cur = next } ll.Head = prev From 8c8abd99022d6ac2378a1e94156250cf5d4310ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Dec 2024 15:38:50 +0530 Subject: [PATCH 484/488] chore(deps): bump the github-actions group across 1 directory with 5 updates (#770) Bumps the github-actions group with 5 updates in the / directory: | Package | From | To | | --- | --- | --- | | [actions/checkout](https://github.com/actions/checkout) | `3` | `4` | | [actions/setup-go](https://github.com/actions/setup-go) | `3` | `5` | | [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) | `3` | `6` | | [actions/stale](https://github.com/actions/stale) | `4` | `9` | | [codecov/codecov-action](https://github.com/codecov/codecov-action) | `4` | `5` | Updates `actions/checkout` from 3 to 4 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) Updates `actions/setup-go` from 3 to 5 - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v3...v5) Updates `golangci/golangci-lint-action` from 3 to 6 - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/v3...v6) Updates `actions/stale` from 4 to 9 - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v4...v9) Updates `codecov/codecov-action` from 4 to 5 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: golangci/golangci-lint-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rak Laptudirm --- .github/workflows/ci.yml | 2 +- .github/workflows/citk.yml | 4 ++-- .github/workflows/stale.yml | 2 +- .github/workflows/upload_coverage_report.yml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 534f32036..7a5ce1939 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: with: go-version: '^1.18' - name: Run Golang CI Lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v6 with: version: latest args: -E gofmt diff --git a/.github/workflows/citk.yml b/.github/workflows/citk.yml index ce9360c36..4b675f239 100644 --- a/.github/workflows/citk.yml +++ b/.github/workflows/citk.yml @@ -10,11 +10,11 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: "^1.18" - name: Checkout branch diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 126bd7ad4..8118ebf78 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -6,7 +6,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v4 + - uses: actions/stale@v9 with: stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' diff --git a/.github/workflows/upload_coverage_report.yml b/.github/workflows/upload_coverage_report.yml index 44867a43e..50ce54650 100644 --- a/.github/workflows/upload_coverage_report.yml +++ b/.github/workflows/upload_coverage_report.yml @@ -25,13 +25,13 @@ jobs: go test -coverprofile="${{ env.REPORT_NAME }}" ./... - name: Upload coverage to codecov (tokenless) if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: files: "${{ env.REPORT_NAME }}" fail_ci_if_error: true - name: Upload coverage to codecov (with token) if: "! github.event.pull_request.head.repo.fork " - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: "${{ env.REPORT_NAME }}" From 137d8209d21bb07915408e773f00ef5eeb80b132 Mon Sep 17 00:00:00 2001 From: Aadish Jain <121042282+mapcrafter2048@users.noreply.github.com> Date: Tue, 31 Dec 2024 19:27:56 +0530 Subject: [PATCH 485/488] Added main and test files for converting hexadecimal to binary and hexadecimal to decimal (#768) * Added main and test files for converting hexadecimal to binary and hexadecimal to decimal * Added functionality instead of using predefined function --------- Co-authored-by: Rak Laptudirm --- conversion/hexadecimaltobinary.go | 78 +++++++++++++++++++++++++ conversion/hexadecimaltobinary_test.go | 46 +++++++++++++++ conversion/hexadecimaltodecimal.go | 57 ++++++++++++++++++ conversion/hexadecimaltodecimal_test.go | 52 +++++++++++++++++ 4 files changed, 233 insertions(+) create mode 100644 conversion/hexadecimaltobinary.go create mode 100644 conversion/hexadecimaltobinary_test.go create mode 100644 conversion/hexadecimaltodecimal.go create mode 100644 conversion/hexadecimaltodecimal_test.go diff --git a/conversion/hexadecimaltobinary.go b/conversion/hexadecimaltobinary.go new file mode 100644 index 000000000..a0d262df6 --- /dev/null +++ b/conversion/hexadecimaltobinary.go @@ -0,0 +1,78 @@ +/* +Author: mapcrafter2048 +GitHub: https://github.com/mapcrafter2048 +*/ + +// This algorithm will convert any Hexadecimal number(0-9, A-F, a-f) to Binary number(0 or 1). +// https://en.wikipedia.org/wiki/Hexadecimal +// https://en.wikipedia.org/wiki/Binary_number +// Function receives a Hexadecimal Number as string and returns the Binary number as string. +// Supported Hexadecimal number range is 0 to 7FFFFFFFFFFFFFFF. + +package conversion + +import ( + "errors" + "regexp" + "strings" +) + +var isValidHex = regexp.MustCompile("^[0-9A-Fa-f]+$").MatchString + +// hexToBinary() function that will take Hexadecimal number as string, +// and return its Binary equivalent as a string. +func hexToBinary(hex string) (string, error) { + // Trim any leading or trailing whitespace + hex = strings.TrimSpace(hex) + + // Check if the hexadecimal string is empty + if hex == "" { + return "", errors.New("input string is empty") + } + + // Check if the hexadecimal string is valid + if !isValidHex(hex) { + return "", errors.New("invalid hexadecimal string: " + hex) + } + + // Parse the hexadecimal string to an integer + var decimal int64 + for i := 0; i < len(hex); i++ { + char := hex[i] + var value int64 + if char >= '0' && char <= '9' { + value = int64(char - '0') + } else if char >= 'A' && char <= 'F' { + value = int64(char - 'A' + 10) + } else if char >= 'a' && char <= 'f' { + value = int64(char - 'a' + 10) + } else { + return "", errors.New("invalid character in hexadecimal string: " + string(char)) + } + decimal = decimal*16 + value + } + + // Convert the integer to a binary string without using predefined functions + var binaryBuilder strings.Builder + if decimal == 0 { + binaryBuilder.WriteString("0") + } else { + for decimal > 0 { + bit := decimal % 2 + if bit == 0 { + binaryBuilder.WriteString("0") + } else { + binaryBuilder.WriteString("1") + } + decimal = decimal / 2 + } + } + + // Reverse the binary string since the bits are added in reverse order + binaryRunes := []rune(binaryBuilder.String()) + for i, j := 0, len(binaryRunes)-1; i < j; i, j = i+1, j-1 { + binaryRunes[i], binaryRunes[j] = binaryRunes[j], binaryRunes[i] + } + + return string(binaryRunes), nil +} diff --git a/conversion/hexadecimaltobinary_test.go b/conversion/hexadecimaltobinary_test.go new file mode 100644 index 000000000..c2dee9712 --- /dev/null +++ b/conversion/hexadecimaltobinary_test.go @@ -0,0 +1,46 @@ +package conversion + +import ( + "testing" +) + +func TestHexToBinary(t *testing.T) { + tests := []struct { + hex string + want string + wantErr bool + }{ + {"", "", true}, + {"G123", "", true}, + {"12XZ", "", true}, + {"1", "1", false}, + {"A", "1010", false}, + {"10", "10000", false}, + {"1A", "11010", false}, + {"aB", "10101011", false}, + {"0Ff", "11111111", false}, + {" 1A ", "11010", false}, + {"0001A", "11010", false}, + {"7FFFFFFFFFFFFFFF", "111111111111111111111111111111111111111111111111111111111111111", false}, + } + + for _, tt := range tests { + t.Run(tt.hex, func(t *testing.T) { + got, err := hexToBinary(tt.hex) + if (err != nil) != tt.wantErr { + t.Errorf("hexToBinary(%q) error = %v, wantErr %v", tt.hex, err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("hexToBinary(%q) = %v, want %v", tt.hex, got, tt.want) + } + }) + } +} + +func BenchmarkHexToBinary(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = hexToBinary("7FFFFFFFFFFFFFFF") + } +} diff --git a/conversion/hexadecimaltodecimal.go b/conversion/hexadecimaltodecimal.go new file mode 100644 index 000000000..f0d7a81d3 --- /dev/null +++ b/conversion/hexadecimaltodecimal.go @@ -0,0 +1,57 @@ +/* +Author: mapcrafter2048 +GitHub: https://github.com/mapcrafter2048 +*/ + +// This algorithm will convert any Hexadecimal number(0-9, A-F, a-f) to Decimal number(0-9). +// https://en.wikipedia.org/wiki/Hexadecimal +// https://en.wikipedia.org/wiki/Decimal +// Function receives a Hexadecimal Number as string and returns the Decimal number as integer. +// Supported Hexadecimal number range is 0 to 7FFFFFFFFFFFFFFF. + +package conversion + +import ( + "fmt" + "regexp" + "strings" +) + +var isValidHexadecimal = regexp.MustCompile("^[0-9A-Fa-f]+$").MatchString + +// hexToDecimal converts a hexadecimal string to a decimal integer. +func hexToDecimal(hexStr string) (int64, error) { + + hexStr = strings.TrimSpace(hexStr) + + if len(hexStr) == 0 { + return 0, fmt.Errorf("input string is empty") + } + + // Check if the string has a valid hexadecimal prefix + if len(hexStr) > 2 && (hexStr[:2] == "0x" || hexStr[:2] == "0X") { + hexStr = hexStr[2:] + } + + // Validate the hexadecimal string + if !isValidHexadecimal(hexStr) { + return 0, fmt.Errorf("invalid hexadecimal string") + } + + var decimalValue int64 + for _, char := range hexStr { + var digit int64 + if char >= '0' && char <= '9' { + digit = int64(char - '0') + } else if char >= 'A' && char <= 'F' { + digit = int64(char - 'A' + 10) + } else if char >= 'a' && char <= 'f' { + digit = int64(char - 'a' + 10) + } else { + return 0, fmt.Errorf("invalid character in hexadecimal string: %c", char) + } + decimalValue = decimalValue*16 + digit + } + + return decimalValue, nil +} diff --git a/conversion/hexadecimaltodecimal_test.go b/conversion/hexadecimaltodecimal_test.go new file mode 100644 index 000000000..4f399fe46 --- /dev/null +++ b/conversion/hexadecimaltodecimal_test.go @@ -0,0 +1,52 @@ +package conversion + +import ( + "testing" +) + +func TestHexToDecimal(t *testing.T) { + tests := []struct { + hex string + want int64 + wantErr bool + }{ + {"", 0, true}, + {"G123", 0, true}, + {"123Z", 0, true}, + {"1", 1, false}, + {"A", 10, false}, + {"10", 16, false}, + {"1A", 26, false}, + {"aB", 171, false}, + {"0Ff", 255, false}, + {" 1A ", 26, false}, + {"0x1A", 26, false}, + {"0X1A", 26, false}, + {"1A", 26, false}, + {"7FFFFFFFFFFFFFFF", 9223372036854775807, false}, + {"0001A", 26, false}, + {"0000007F", 127, false}, + {"0", 0, false}, + {"0x0", 0, false}, + } + + for _, tt := range tests { + t.Run(tt.hex, func(t *testing.T) { + got, err := hexToDecimal(tt.hex) + if (err != nil) != tt.wantErr { + t.Errorf("hexToDecimal(%q) error = %v, wantErr %v", tt.hex, err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("hexToDecimal(%q) = %v, want %v", tt.hex, got, tt.want) + } + }) + } +} + +func BenchmarkHexToDecimal(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = hexToDecimal("7FFFFFFFFFFFFFFF") + } +} From 6d6b06e6bb2121db10ce3ebf26888f9b7305d6d0 Mon Sep 17 00:00:00 2001 From: "Daniel." <67126972+ddaniel27@users.noreply.github.com> Date: Fri, 10 Jan 2025 02:39:46 -0500 Subject: [PATCH 486/488] Project Euler: First Twenty solutions (#771) * Project Euler: First Ten solutions * 11 to 15 * 16 to 20 --- project_euler/problem_1/problem1.go | 24 +++ project_euler/problem_1/problem1_test.go | 45 ++++ project_euler/problem_10/problem10.go | 23 +++ project_euler/problem_10/problem10_test.go | 40 ++++ project_euler/problem_11/problem11.go | 80 +++++++ project_euler/problem_11/problem11_test.go | 29 +++ project_euler/problem_12/problem12.go | 46 +++++ project_euler/problem_12/problem12_test.go | 31 +++ project_euler/problem_13/problem13.go | 150 ++++++++++++++ project_euler/problem_13/problem13_test.go | 27 +++ project_euler/problem_14/problem14.go | 56 +++++ project_euler/problem_14/problem14_test.go | 31 +++ project_euler/problem_15/problem15.go | 42 ++++ project_euler/problem_15/problem15_test.go | 34 +++ project_euler/problem_16/problem16.go | 33 +++ project_euler/problem_16/problem16_test.go | 30 +++ project_euler/problem_17/input.go | 8 + project_euler/problem_17/problem17.go | 31 +++ project_euler/problem_17/problem17_test.go | 30 +++ project_euler/problem_18/edge.go | 100 +++++++++ project_euler/problem_18/input.go | 42 ++++ project_euler/problem_18/leaf.go | 75 +++++++ project_euler/problem_18/problem18.go | 63 ++++++ project_euler/problem_18/problem18_test.go | 42 ++++ project_euler/problem_18/root.go | 62 ++++++ project_euler/problem_18/tree.go | 229 +++++++++++++++++++++ project_euler/problem_19/problem19.go | 63 ++++++ project_euler/problem_19/problem19_test.go | 29 +++ project_euler/problem_2/problem2.go | 30 +++ project_euler/problem_2/problem2_test.go | 45 ++++ project_euler/problem_20/problem20.go | 37 ++++ project_euler/problem_20/problem20_test.go | 31 +++ project_euler/problem_3/problem3.go | 24 +++ project_euler/problem_3/problem3_test.go | 40 ++++ project_euler/problem_4/problem4.go | 33 +++ project_euler/problem_4/problem4_test.go | 33 +++ project_euler/problem_5/problem5.go | 33 +++ project_euler/problem_5/problem5_test.go | 45 ++++ project_euler/problem_6/problem6.go | 33 +++ project_euler/problem_6/problem6_test.go | 40 ++++ project_euler/problem_7/problem7.go | 27 +++ project_euler/problem_7/problem7_test.go | 40 ++++ project_euler/problem_8/problem8.go | 33 +++ project_euler/problem_8/problem8_test.go | 40 ++++ project_euler/problem_9/problem9.go | 29 +++ project_euler/problem_9/problem9_test.go | 33 +++ 46 files changed, 2121 insertions(+) create mode 100644 project_euler/problem_1/problem1.go create mode 100644 project_euler/problem_1/problem1_test.go create mode 100644 project_euler/problem_10/problem10.go create mode 100644 project_euler/problem_10/problem10_test.go create mode 100644 project_euler/problem_11/problem11.go create mode 100644 project_euler/problem_11/problem11_test.go create mode 100644 project_euler/problem_12/problem12.go create mode 100644 project_euler/problem_12/problem12_test.go create mode 100644 project_euler/problem_13/problem13.go create mode 100644 project_euler/problem_13/problem13_test.go create mode 100644 project_euler/problem_14/problem14.go create mode 100644 project_euler/problem_14/problem14_test.go create mode 100644 project_euler/problem_15/problem15.go create mode 100644 project_euler/problem_15/problem15_test.go create mode 100644 project_euler/problem_16/problem16.go create mode 100644 project_euler/problem_16/problem16_test.go create mode 100644 project_euler/problem_17/input.go create mode 100644 project_euler/problem_17/problem17.go create mode 100644 project_euler/problem_17/problem17_test.go create mode 100644 project_euler/problem_18/edge.go create mode 100644 project_euler/problem_18/input.go create mode 100644 project_euler/problem_18/leaf.go create mode 100644 project_euler/problem_18/problem18.go create mode 100644 project_euler/problem_18/problem18_test.go create mode 100644 project_euler/problem_18/root.go create mode 100644 project_euler/problem_18/tree.go create mode 100644 project_euler/problem_19/problem19.go create mode 100644 project_euler/problem_19/problem19_test.go create mode 100644 project_euler/problem_2/problem2.go create mode 100644 project_euler/problem_2/problem2_test.go create mode 100644 project_euler/problem_20/problem20.go create mode 100644 project_euler/problem_20/problem20_test.go create mode 100644 project_euler/problem_3/problem3.go create mode 100644 project_euler/problem_3/problem3_test.go create mode 100644 project_euler/problem_4/problem4.go create mode 100644 project_euler/problem_4/problem4_test.go create mode 100644 project_euler/problem_5/problem5.go create mode 100644 project_euler/problem_5/problem5_test.go create mode 100644 project_euler/problem_6/problem6.go create mode 100644 project_euler/problem_6/problem6_test.go create mode 100644 project_euler/problem_7/problem7.go create mode 100644 project_euler/problem_7/problem7_test.go create mode 100644 project_euler/problem_8/problem8.go create mode 100644 project_euler/problem_8/problem8_test.go create mode 100644 project_euler/problem_9/problem9.go create mode 100644 project_euler/problem_9/problem9_test.go diff --git a/project_euler/problem_1/problem1.go b/project_euler/problem_1/problem1.go new file mode 100644 index 000000000..e41fbf468 --- /dev/null +++ b/project_euler/problem_1/problem1.go @@ -0,0 +1,24 @@ +/** + * Problem 1 - Multiples of 3 and 5 + * + * @see {@link https://projecteuler.net/problem=1} + * + * If we list all the natural numbers below 10 that are multiples of 3 or 5, + * we get 3, 5, 6 and 9. The sum of these multiples is 23. + * Find the sum of all the multiples of 3 or 5 below 1000. + * + * @author ddaniel27 + */ +package problem1 + +func Problem1(n uint) uint { + sum := uint(0) + + for i := uint(1); i < n; i++ { + if i%3 == 0 || i%5 == 0 { + sum += i + } + } + + return sum +} diff --git a/project_euler/problem_1/problem1_test.go b/project_euler/problem_1/problem1_test.go new file mode 100644 index 000000000..c2d649b02 --- /dev/null +++ b/project_euler/problem_1/problem1_test.go @@ -0,0 +1,45 @@ +package problem1 + +import "testing" + +// Tests +func TestProblem1_Func(t *testing.T) { + tests := []struct { + name string + threshold uint + want uint + }{ + { + name: "Testcase 1 - threshold 10", + threshold: 10, + want: 23, + }, + { + name: "Testcase 2 - threshold 100", + threshold: 100, + want: 2318, + }, + { + name: "Testcase 3 - threshold 1000", + threshold: 1000, + want: 233168, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem1(tt.threshold) + + if n != tt.want { + t.Errorf("Problem1() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem1(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem1(1000) + } +} diff --git a/project_euler/problem_10/problem10.go b/project_euler/problem_10/problem10.go new file mode 100644 index 000000000..342c79d24 --- /dev/null +++ b/project_euler/problem_10/problem10.go @@ -0,0 +1,23 @@ +/** +* Problem 10 - Summation of primes +* @see {@link https://projecteuler.net/problem=10} +* +* The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. +* Find the sum of all the primes below two million. +* +* @author ddaniel27 + */ +package problem10 + +import "github.com/TheAlgorithms/Go/math/prime" + +func Problem10(n int) uint { + sum := uint(0) + sieve := prime.SieveEratosthenes(n) + + for _, v := range sieve { + sum += uint(v) + } + + return sum +} diff --git a/project_euler/problem_10/problem10_test.go b/project_euler/problem_10/problem10_test.go new file mode 100644 index 000000000..d82e6f29e --- /dev/null +++ b/project_euler/problem_10/problem10_test.go @@ -0,0 +1,40 @@ +package problem10 + +import "testing" + +// Tests +func TestProblem10_Func(t *testing.T) { + tests := []struct { + name string + input int + want uint + }{ + { + name: "Testcase 1 - input 10", + input: 10, + want: 17, + }, + { + name: "Testcase 2 - input 2000000", + input: 2000000, + want: 142913828922, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem10(tt.input) + + if n != tt.want { + t.Errorf("Problem10() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem10(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem10(2000000) + } +} diff --git a/project_euler/problem_11/problem11.go b/project_euler/problem_11/problem11.go new file mode 100644 index 000000000..5ddaea8e2 --- /dev/null +++ b/project_euler/problem_11/problem11.go @@ -0,0 +1,80 @@ +/** +* Problem 11 - Largest product in a grid +* @see {@link https://projecteuler.net/problem=11} +* +* In the 20×20 grid below, four numbers along a diagonal line have been marked in red. +* +* The product of these numbers is 26 × 63 × 78 × 14 = 1788696. +* +* What is the greatest product of four adjacent numbers in the same direction +* (up, down, left, right, or diagonally) in the 20×20 grid? +* +* @author ddaniel27 + */ +package problem11 + +var grid = [20][20]uint{ + {8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8}, + {49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0}, + {81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65}, + {52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91}, + {22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80}, + {24, 47, 32, 60, 99, 3, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50}, + {32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70}, + {67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21}, + {24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72}, + {21, 36, 23, 9, 75, 0, 76, 44, 20, 45, 35, 14, 0, 61, 33, 97, 34, 31, 33, 95}, + {78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92}, + {16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 0, 17, 54, 24, 36, 29, 85, 57}, + {86, 56, 0, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58}, + {19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40}, + {4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66}, + {88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69}, + {4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76, 36}, + {20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 4, 36, 16}, + {20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54}, + {1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48}, +} + +func Problem11() uint { + max := uint(0) + + for i := 0; i < 20; i++ { + for j := 0; j < 20; j++ { + + // Vertical + if i+3 < 20 { + product := grid[i][j] * grid[i+1][j] * grid[i+2][j] * grid[i+3][j] + if product > max { + max = product + } + } + + // Horizontal + if j+3 < 20 { + product := grid[i][j] * grid[i][j+1] * grid[i][j+2] * grid[i][j+3] + if product > max { + max = product + } + } + + if i+3 < 20 && j+3 < 20 { + // Diagonal + product := grid[i][j] * grid[i+1][j+1] * grid[i+2][j+2] * grid[i+3][j+3] + if product > max { + max = product + } + } + + if i+3 < 20 && j-3 >= 0 { + // Diagonal + product := grid[i][j] * grid[i+1][j-1] * grid[i+2][j-2] * grid[i+3][j-3] + if product > max { + max = product + } + } + } + } + + return max +} diff --git a/project_euler/problem_11/problem11_test.go b/project_euler/problem_11/problem11_test.go new file mode 100644 index 000000000..b6ae99e05 --- /dev/null +++ b/project_euler/problem_11/problem11_test.go @@ -0,0 +1,29 @@ +package problem11 + +import "testing" + +// Tests +func TestProblem11_Func(t *testing.T) { + testCases := []struct { + name string + expected uint + }{ + {"Test Case 1", 70600674}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := Problem11() + if actual != tc.expected { + t.Errorf("Expected: %v, but got %v", tc.expected, actual) + } + }) + } +} + +// Benchmark +func BenchmarkProblem11_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem11() + } +} diff --git a/project_euler/problem_12/problem12.go b/project_euler/problem_12/problem12.go new file mode 100644 index 000000000..803add5b7 --- /dev/null +++ b/project_euler/problem_12/problem12.go @@ -0,0 +1,46 @@ +/** +* Problem 12 - Highly divisible triangular number +* @see {@link https://projecteuler.net/problem=12} +* +* The sequence of triangle numbers is generated by adding the natural numbers. +* So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. +* The first ten terms would be: +* +* 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ... +* +* Let us list the factors of the first seven triangle numbers: +* +* 1: 1 +* 3: 1,3 +* 6: 1,2,3,6 +* 10: 1,2,5,10 +* 15: 1,3,5,15 +* 21: 1,3,7,21 +* 28: 1,2,4,7,14,28 +* +* We can see that 28 is the first triangle number to have over five divisors. +* What is the value of the first triangle number to have over five hundred divisors? +* +* @author ddaniel27 + */ +package problem12 + +func Problem12(limit uint) uint { + triangle := uint(0) + for i := uint(1); ; i++ { + triangle += i + if numDivisors(triangle) >= limit { + return triangle + } + } +} + +func numDivisors(n uint) uint { + divisors := uint(0) + for i := uint(1); i*i <= n; i++ { + if n%i == 0 { + divisors += 2 + } + } + return divisors +} diff --git a/project_euler/problem_12/problem12_test.go b/project_euler/problem_12/problem12_test.go new file mode 100644 index 000000000..2659fb1e9 --- /dev/null +++ b/project_euler/problem_12/problem12_test.go @@ -0,0 +1,31 @@ +package problem12 + +import "testing" + +func TestProblem12_Func(t *testing.T) { + tests := []struct { + name string + input uint + want uint + }{ + {"Test Case 1", 6, 28}, + {"Test Case 2", 7, 36}, + {"Test Case 3", 11, 120}, + {"Test Case 4", 500, 76576500}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := Problem12(tt.input) + if actual != tt.want { + t.Errorf("Expected: %v, but got %v", tt.want, actual) + } + }) + } +} + +func BenchmarkProblem12_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem12(500) + } +} diff --git a/project_euler/problem_13/problem13.go b/project_euler/problem_13/problem13.go new file mode 100644 index 000000000..d5669d271 --- /dev/null +++ b/project_euler/problem_13/problem13.go @@ -0,0 +1,150 @@ +/** +* Problem 13 - Large sum +* @see {@link https://projecteuler.net/problem=13} +* +* Work out the first ten digits of the sum of the following one-hundred 50-digit numbers. +* +* @author ddaniel27 + */ +package problem13 + +var numbers = [100]string{ + "37107287533902102798797998220837590246510135740250", + "46376937677490009712648124896970078050417018260538", + "74324986199524741059474233309513058123726617309629", + "91942213363574161572522430563301811072406154908250", + "23067588207539346171171980310421047513778063246676", + "89261670696623633820136378418383684178734361726757", + "28112879812849979408065481931592621691275889832738", + "44274228917432520321923589422876796487670272189318", + "47451445736001306439091167216856844588711603153276", + "70386486105843025439939619828917593665686757934951", + "62176457141856560629502157223196586755079324193331", + "64906352462741904929101432445813822663347944758178", + "92575867718337217661963751590579239728245598838407", + "58203565325359399008402633568948830189458628227828", + "80181199384826282014278194139940567587151170094390", + "35398664372827112653829987240784473053190104293586", + "86515506006295864861532075273371959191420517255829", + "71693888707715466499115593487603532921714970056938", + "54370070576826684624621495650076471787294438377604", + "53282654108756828443191190634694037855217779295145", + "36123272525000296071075082563815656710885258350721", + "45876576172410976447339110607218265236877223636045", + "17423706905851860660448207621209813287860733969412", + "81142660418086830619328460811191061556940512689692", + "51934325451728388641918047049293215058642563049483", + "62467221648435076201727918039944693004732956340691", + "15732444386908125794514089057706229429197107928209", + "55037687525678773091862540744969844508330393682126", + "18336384825330154686196124348767681297534375946515", + "80386287592878490201521685554828717201219257766954", + "78182833757993103614740356856449095527097864797581", + "16726320100436897842553539920931837441497806860984", + "48403098129077791799088218795327364475675590848030", + "87086987551392711854517078544161852424320693150332", + "59959406895756536782107074926966537676326235447210", + "69793950679652694742597709739166693763042633987085", + "41052684708299085211399427365734116182760315001271", + "65378607361501080857009149939512557028198746004375", + "35829035317434717326932123578154982629742552737307", + "94953759765105305946966067683156574377167401875275", + "88902802571733229619176668713819931811048770190271", + "25267680276078003013678680992525463401061632866526", + "36270218540497705585629946580636237993140746255962", + "24074486908231174977792365466257246923322810917141", + "91430288197103288597806669760892938638285025333403", + "34413065578016127815921815005561868836468420090470", + "23053081172816430487623791969842487255036638784583", + "11487696932154902810424020138335124462181441773470", + "63783299490636259666498587618221225225512486764533", + "67720186971698544312419572409913959008952310058822", + "95548255300263520781532296796249481641953868218774", + "76085327132285723110424803456124867697064507995236", + "37774242535411291684276865538926205024910326572967", + "23701913275725675285653248258265463092207058596522", + "29798860272258331913126375147341994889534765745501", + "18495701454879288984856827726077713721403798879715", + "38298203783031473527721580348144513491373226651381", + "34829543829199918180278916522431027392251122869539", + "40957953066405232632538044100059654939159879593635", + "29746152185502371307642255121183693803580388584903", + "41698116222072977186158236678424689157993532961922", + "62467957194401269043877107275048102390895523597457", + "23189706772547915061505504953922979530901129967519", + "86188088225875314529584099251203829009407770775672", + "11306739708304724483816533873502340845647058077308", + "82959174767140363198008187129011875491310547126581", + "97623331044818386269515456334926366572897563400500", + "42846280183517070527831839425882145521227251250327", + "55121603546981200581762165212827652751691296897789", + "32238195734329339946437501907836945765883352399886", + "75506164965184775180738168837861091527357929701337", + "62177842752192623401942399639168044983993173312731", + "32924185707147349566916674687634660915035914677504", + "99518671430235219628894890102423325116913619626622", + "73267460800591547471830798392868535206946944540724", + "76841822524674417161514036427982273348055556214818", + "97142617910342598647204516893989422179826088076852", + "87783646182799346313767754307809363333018982642090", + "10848802521674670883215120185883543223812876952786", + "71329612474782464538636993009049310363619763878039", + "62184073572399794223406235393808339651327408011116", + "66627891981488087797941876876144230030984490851411", + "60661826293682836764744779239180335110989069790714", + "85786944089552990653640447425576083659976645795096", + "66024396409905389607120198219976047599490197230297", + "64913982680032973156037120041377903785566085089252", + "16730939319872750275468906903707539413042652315011", + "94809377245048795150954100921645863754710598436791", + "78639167021187492431995700641917969777599028300699", + "15368713711936614952811305876380278410754449733078", + "40789923115535562561142322423255033685442488917353", + "44889911501440648020369068063960672322193204149535", + "41503128880339536053299340368006977710650566631954", + "81234880673210146739058568557934581403627822703280", + "82616570773948327592232845941706525094512325230608", + "22918802058777319719839450180888072429661980811197", + "77158542502016545090413245809786882778948721859617", + "72107838435069186155435662884062257473692284509516", + "20849603980134001723930671666823555245252804609722", + "53503534226472524250874054075591789781264330331690", +} + +func Problem13() string { + sum := "0" + + for _, n := range numbers { + sum = add(sum, n) + } + + return sum[:10] +} + +func add(a, b string) string { + if len(a) < len(b) { + a, b = b, a + } + + carry := 0 + sum := make([]byte, len(a)+1) + + for i := 0; i < len(a); i++ { + d := int(a[len(a)-1-i] - '0') + if i < len(b) { + d += int(b[len(b)-1-i] - '0') + } + d += carry + + sum[len(sum)-1-i] = byte(d%10) + '0' + carry = d / 10 + } + + if carry > 0 { + sum[0] = byte(carry) + '0' + } else { + sum = sum[1:] + } + + return string(sum) +} diff --git a/project_euler/problem_13/problem13_test.go b/project_euler/problem_13/problem13_test.go new file mode 100644 index 000000000..e776cbb04 --- /dev/null +++ b/project_euler/problem_13/problem13_test.go @@ -0,0 +1,27 @@ +package problem13 + +import "testing" + +func TestProblem13_Func(t *testing.T) { + tests := []struct { + name string + expected string + }{ + {"Test Case 1", "5537376230"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := Problem13() + if actual != tt.expected { + t.Errorf("Expected: %v, but got %v", tt.expected, actual) + } + }) + } +} + +func BenchmarkProblem13_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem13() + } +} diff --git a/project_euler/problem_14/problem14.go b/project_euler/problem_14/problem14.go new file mode 100644 index 000000000..aa5702c12 --- /dev/null +++ b/project_euler/problem_14/problem14.go @@ -0,0 +1,56 @@ +/** +* Problem 14 - Longest Collatz sequence +* @see {@link https://projecteuler.net/problem=14} +* +* The following iterative sequence is defined for the set of positive integers: +* n → n/2 (n is even) +* n → 3n + 1 (n is odd) +* +* Using the rule above and starting with 13, we generate the following sequence: +* 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 +* +* Which starting number, under one million, produces the longest chain? +* +* NOTE: Once the chain starts the terms are allowed to go above one million. +* +* @author ddaniel27 + */ +package problem14 + +type dict map[uint64]uint64 + +var dictionary = dict{ + 1: 1, +} + +func Problem14(limit uint64) uint64 { + for i := uint64(2); i <= limit; i++ { + weightNextNode(i) + } + + var max, maxWeight uint64 + for k, v := range dictionary { + if v > maxWeight { + max = k + maxWeight = v + } + } + + return max +} + +func weightNextNode(current uint64) uint64 { + var next, weight uint64 + if current%2 == 0 { + next = current / 2 + } else { + next = (3 * current) + 1 + } + if v, ok := dictionary[next]; !ok { + weight = weightNextNode(next) + 1 + } else { + weight = v + 1 + } + dictionary[current] = weight + return weight +} diff --git a/project_euler/problem_14/problem14_test.go b/project_euler/problem_14/problem14_test.go new file mode 100644 index 000000000..801ff0fdd --- /dev/null +++ b/project_euler/problem_14/problem14_test.go @@ -0,0 +1,31 @@ +package problem14 + +import "testing" + +// Tests +func TestProblem14_Func(t *testing.T) { + tests := []struct { + name string + input uint64 + want uint64 + }{ + {"Input 30", 30, 27}, + {"Input 1e6", 1e6, 837799}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := Problem14(tt.input) + if got != tt.want { + t.Errorf("Problem14() = %v, want %v", got, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem14_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem14(1e6) + } +} diff --git a/project_euler/problem_15/problem15.go b/project_euler/problem_15/problem15.go new file mode 100644 index 000000000..6adbd6977 --- /dev/null +++ b/project_euler/problem_15/problem15.go @@ -0,0 +1,42 @@ +/** +* Problem 15 - Lattice paths +* @see {@link https://projecteuler.net/problem=15} +* +* Starting in the top left corner of a 2×2 grid, +* and only being able to move to the right and down, +* there are exactly 6 routes to the bottom right corner. +* +* How many such routes are there through a 20×20 grid? +* +* @author ddaniel27 + */ +package problem15 + +import ( + "github.com/TheAlgorithms/Go/math/factorial" +) + +func Problem15(gridSize int) int { + /** + Author note: + We can solve this problem using combinatorics. + Here is a good blog post that explains the solution: + + [link](https://stemhash.com/counting-lattice-paths/) + + Btw, I'm not related to the author of the blog post. + + After some simplification, we can see that the solution is: + (2n)! / (n!)^2 + + We can use the factorial package to calculate the factorials. + */ + + n := gridSize + + numerator, _ := factorial.Iterative(2 * n) + denominator, _ := factorial.Iterative(n) + denominator *= denominator + + return numerator / denominator +} diff --git a/project_euler/problem_15/problem15_test.go b/project_euler/problem_15/problem15_test.go new file mode 100644 index 000000000..a5b729428 --- /dev/null +++ b/project_euler/problem_15/problem15_test.go @@ -0,0 +1,34 @@ +package problem15 + +import "testing" + +// Tests +func TestProblem15_Func(t *testing.T) { + tests := []struct { + name string + input int + want int + }{ + {"Input 2", 2, 6}, + // This test case is disabled + // because it needs a big integer to run successfully + // and factorial package doesn't support it + // {"Input 20", 20, 137846528820}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := Problem15(tt.input) + if got != tt.want { + t.Errorf("Problem15() = %v, want %v", got, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem15_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem15(20) + } +} diff --git a/project_euler/problem_16/problem16.go b/project_euler/problem_16/problem16.go new file mode 100644 index 000000000..cc0471c66 --- /dev/null +++ b/project_euler/problem_16/problem16.go @@ -0,0 +1,33 @@ +/** +* Problem 16 - Power digit sum +* @see {@link https://projecteuler.net/problem=16} +* +* 2^15 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26. +* +* What is the sum of the digits of the number 2^1000? +* +* @author ddaniel27 + */ +package problem16 + +import ( + "math/big" +) + +func Problem16(exponent int64) int64 { + var result big.Int + + bigTwo := big.NewInt(2) + bigExponent := big.NewInt(exponent) + + result.Exp(bigTwo, bigExponent, nil) + + resultStr := result.String() + + var sum int64 + for _, digit := range resultStr { + sum += int64(digit - '0') + } + + return sum +} diff --git a/project_euler/problem_16/problem16_test.go b/project_euler/problem_16/problem16_test.go new file mode 100644 index 000000000..31e3f9a02 --- /dev/null +++ b/project_euler/problem_16/problem16_test.go @@ -0,0 +1,30 @@ +package problem16 + +import "testing" + +// Tests +func TestProblem16_Func(t *testing.T) { + tests := []struct { + name string + exponent int64 + want int64 + }{ + {"2^15", 15, 26}, + {"2^1000", 1000, 1366}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Problem16(tt.exponent); got != tt.want { + t.Errorf("Problem16() = %v, want %v", got, tt.want) + } + }) + } +} + +// Benchmark +func BenchmarkProblem16_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem16(1000) + } +} diff --git a/project_euler/problem_17/input.go b/project_euler/problem_17/input.go new file mode 100644 index 000000000..3a16f8c3a --- /dev/null +++ b/project_euler/problem_17/input.go @@ -0,0 +1,8 @@ +/** +* I put this code in a separate file because it is too long. +* Also it took me a lot of time to parsing this input from +* a random html page, so, I don't want to lose it. + */ +package problem17 + +const INPUT = "One Two Three Four Five Six Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen Sixteen Seventeen Eighteen Nineteen Twenty Twenty one Twenty two Twenty three Twenty four Twenty five Twenty six Twenty seven Twenty eight Twenty nine Thirty Thirty one Thirty two Thirty three Thirty four Thirty five Thirty six Thirty seven Thirty eight Thirty nine Forty Forty one Forty two Forty three Forty four Forty five Forty six Forty seven Forty eight Forty nine Fifty Fifty one Fifty two Fifty three Fifty four Fifty five Fifty six Fifty seven Fifty eight Fifty nine Sixty Sixty one Sixty two Sixty three Sixty four Sixty five Sixty six Sixty seven Sixty eight Sixty nine Seventy Seventy one Seventy two Seventy three Seventy four Seventy five Seventy six Seventy seven Seventy eight Seventy nine Eighty Eighty one Eighty two Eighty three Eighty four Eighty five Eighty six Eighty seven Eighty eight Eighty nine Ninety Ninety one Ninety two Ninety three Ninety four Ninety five Ninety six Ninety seven Ninety eight Ninety nine One hundred One hundred and one One hundred and two One hundred and three One hundred and four One hundred and five One hundred and six One hundred and seven One hundred and eight One hundred and nine One hundred and ten One hundred and eleven One hundred and twelve One hundred and thirteen One hundred and fourteen One hundred and fifteen One hundred and sixteen One hundred and seventeen One hundred and eighteen One hundred and nineteen One hundred and twenty One hundred and twenty one One hundred and twenty two One hundred and twenty three One hundred and twenty four One hundred and twenty five One hundred and twenty six One hundred and twenty seven One hundred and twenty eight One hundred and twenty nine One hundred and thirty One hundred and thirty one One hundred and thirty two One hundred and thirty three One hundred and thirty four One hundred and thirty five One hundred and thirty six One hundred and thirty seven One hundred and thirty eight One hundred and thirty nine One hundred and forty One hundred and forty one One hundred and forty two One hundred and forty three One hundred and forty four One hundred and forty five One hundred and forty six One hundred and forty seven One hundred and forty eight One hundred and forty nine One hundred and fifty One hundred and fifty one One hundred and fifty two One hundred and fifty three One hundred and fifty four One hundred and fifty five One hundred and fifty six One hundred and fifty seven One hundred and fifty eight One hundred and fifty nine One hundred and sixty One hundred and sixty one One hundred and sixty two One hundred and sixty three One hundred and sixty four One hundred and sixty five One hundred and sixty six One hundred and sixty seven One hundred and sixty eight One hundred and sixty nine One hundred and seventy One hundred and seventy one One hundred and seventy two One hundred and seventy three One hundred and seventy four One hundred and seventy five One hundred and seventy six One hundred and seventy seven One hundred and seventy eight One hundred and seventy nine One hundred and eighty One hundred and eighty one One hundred and eighty two One hundred and eighty three One hundred and eighty four One hundred and eighty five One hundred and eighty six One hundred and eighty seven One hundred and eighty eight One hundred and eighty nine One hundred and ninety One hundred and ninety one One hundred and ninety two One hundred and ninety three One hundred and ninety four One hundred and ninety five One hundred and ninety six One hundred and ninety seven One hundred and ninety eight One hundred and ninety nine Two hundred Two hundred and one Two hundred and two Two hundred and three Two hundred and four Two hundred and five Two hundred and six Two hundred and seven Two hundred and eight Two hundred and nine Two hundred and ten Two hundred and eleven Two hundred and twelve Two hundred and thirteen Two hundred and fourteen Two hundred and fifteen Two hundred and sixteen Two hundred and seventeen Two hundred and eighteen Two hundred and nineteen Two hundred and twenty Two hundred and twenty one Two hundred and twenty two Two hundred and twenty three Two hundred and twenty four Two hundred and twenty five Two hundred and twenty six Two hundred and twenty seven Two hundred and twenty eight Two hundred and twenty nine Two hundred and thirty Two hundred and thirty one Two hundred and thirty two Two hundred and thirty three Two hundred and thirty four Two hundred and thirty five Two hundred and thirty six Two hundred and thirty seven Two hundred and thirty eight Two hundred and thirty nine Two hundred and forty Two hundred and forty one Two hundred and forty two Two hundred and forty three Two hundred and forty four Two hundred and forty five Two hundred and forty six Two hundred and forty seven Two hundred and forty eight Two hundred and forty nine Two hundred and fifty Two hundred and fifty one Two hundred and fifty two Two hundred and fifty three Two hundred and fifty four Two hundred and fifty five Two hundred and fifty six Two hundred and fifty seven Two hundred and fifty eight Two hundred and fifty nine Two hundred and sixty Two hundred and sixty one Two hundred and sixty two Two hundred and sixty three Two hundred and sixty four Two hundred and sixty five Two hundred and sixty six Two hundred and sixty seven Two hundred and sixty eight Two hundred and sixty nine Two hundred and seventy Two hundred and seventy one Two hundred and seventy two Two hundred and seventy three Two hundred and seventy four Two hundred and seventy five Two hundred and seventy six Two hundred and seventy seven Two hundred and seventy eight Two hundred and seventy nine Two hundred and eighty Two hundred and eighty one Two hundred and eighty two Two hundred and eighty three Two hundred and eighty four Two hundred and eighty five Two hundred and eighty six Two hundred and eighty seven Two hundred and eighty eight Two hundred and eighty nine Two hundred and ninety Two hundred and ninety one Two hundred and ninety two Two hundred and ninety three Two hundred and ninety four Two hundred and ninety five Two hundred and ninety six Two hundred and ninety seven Two hundred and ninety eight Two hundred and ninety nine Three hundred Three hundred and one Three hundred and two Three hundred and three Three hundred and four Three hundred and five Three hundred and six Three hundred and seven Three hundred and eight Three hundred and nine Three hundred and ten Three hundred and eleven Three hundred and twelve Three hundred and thirteen Three hundred and fourteen Three hundred and fifteen Three hundred and sixteen Three hundred and seventeen Three hundred and eighteen Three hundred and nineteen Three hundred and twenty Three hundred and twenty one Three hundred and twenty two Three hundred and twenty three Three hundred and twenty four Three hundred and twenty five Three hundred and twenty six Three hundred and twenty seven Three hundred and twenty eight Three hundred and twenty nine Three hundred and thirty Three hundred and thirty one Three hundred and thirty two Three hundred and thirty three Three hundred and thirty four Three hundred and thirty five Three hundred and thirty six Three hundred and thirty seven Three hundred and thirty eight Three hundred and thirty nine Three hundred and forty Three hundred and forty one Three hundred and forty two Three hundred and forty three Three hundred and forty four Three hundred and forty five Three hundred and forty six Three hundred and forty seven Three hundred and forty eight Three hundred and forty nine Three hundred and fifty Three hundred and fifty one Three hundred and fifty two Three hundred and fifty three Three hundred and fifty four Three hundred and fifty five Three hundred and fifty six Three hundred and fifty seven Three hundred and fifty eight Three hundred and fifty nine Three hundred and sixty Three hundred and sixty one Three hundred and sixty two Three hundred and sixty three Three hundred and sixty four Three hundred and sixty five Three hundred and sixty six Three hundred and sixty seven Three hundred and sixty eight Three hundred and sixty nine Three hundred and seventy Three hundred and seventy one Three hundred and seventy two Three hundred and seventy three Three hundred and seventy four Three hundred and seventy five Three hundred and seventy six Three hundred and seventy seven Three hundred and seventy eight Three hundred and seventy nine Three hundred and eighty Three hundred and eighty one Three hundred and eighty two Three hundred and eighty three Three hundred and eighty four Three hundred and eighty five Three hundred and eighty six Three hundred and eighty seven Three hundred and eighty eight Three hundred and eighty nine Three hundred and ninety Three hundred and ninety one Three hundred and ninety two Three hundred and ninety three Three hundred and ninety four Three hundred and ninety five Three hundred and ninety six Three hundred and ninety seven Three hundred and ninety eight Three hundred and ninety nine Four hundred Four hundred and one Four hundred and two Four hundred and three Four hundred and four Four hundred and five Four hundred and six Four hundred and seven Four hundred and eight Four hundred and nine Four hundred and ten Four hundred and eleven Four hundred and twelve Four hundred and thirteen Four hundred and fourteen Four hundred and fifteen Four hundred and sixteen Four hundred and seventeen Four hundred and eighteen Four hundred and nineteen Four hundred and twenty Four hundred and twenty one Four hundred and twenty two Four hundred and twenty three Four hundred and twenty four Four hundred and twenty five Four hundred and twenty six Four hundred and twenty seven Four hundred and twenty eight Four hundred and twenty nine Four hundred and thirty Four hundred and thirty one Four hundred and thirty two Four hundred and thirty three Four hundred and thirty four Four hundred and thirty five Four hundred and thirty six Four hundred and thirty seven Four hundred and thirty eight Four hundred and thirty nine Four hundred and forty Four hundred and forty one Four hundred and forty two Four hundred and forty three Four hundred and forty four Four hundred and forty five Four hundred and forty six Four hundred and forty seven Four hundred and forty eight Four hundred and forty nine Four hundred and fifty Four hundred and fifty one Four hundred and fifty two Four hundred and fifty three Four hundred and fifty four Four hundred and fifty five Four hundred and fifty six Four hundred and fifty seven Four hundred and fifty eight Four hundred and fifty nine Four hundred and sixty Four hundred and sixty one Four hundred and sixty two Four hundred and sixty three Four hundred and sixty four Four hundred and sixty five Four hundred and sixty six Four hundred and sixty seven Four hundred and sixty eight Four hundred and sixty nine Four hundred and seventy Four hundred and seventy one Four hundred and seventy two Four hundred and seventy three Four hundred and seventy four Four hundred and seventy five Four hundred and seventy six Four hundred and seventy seven Four hundred and seventy eight Four hundred and seventy nine Four hundred and eighty Four hundred and eighty one Four hundred and eighty two Four hundred and eighty three Four hundred and eighty four Four hundred and eighty five Four hundred and eighty six Four hundred and eighty seven Four hundred and eighty eight Four hundred and eighty nine Four hundred and ninety Four hundred and ninety one Four hundred and ninety two Four hundred and ninety three Four hundred and ninety four Four hundred and ninety five Four hundred and ninety six Four hundred and ninety seven Four hundred and ninety eight Four hundred and ninety nine Five hundred Five hundred and one Five hundred and two Five hundred and three Five hundred and four Five hundred and five Five hundred and six Five hundred and seven Five hundred and eight Five hundred and nine Five hundred and ten Five hundred and eleven Five hundred and twelve Five hundred and thirteen Five hundred and fourteen Five hundred and fifteen Five hundred and sixteen Five hundred and seventeen Five hundred and eighteen Five hundred and nineteen Five hundred and twenty Five hundred and twenty one Five hundred and twenty two Five hundred and twenty three Five hundred and twenty four Five hundred and twenty five Five hundred and twenty six Five hundred and twenty seven Five hundred and twenty eight Five hundred and twenty nine Five hundred and thirty Five hundred and thirty one Five hundred and thirty two Five hundred and thirty three Five hundred and thirty four Five hundred and thirty five Five hundred and thirty six Five hundred and thirty seven Five hundred and thirty eight Five hundred and thirty nine Five hundred and forty Five hundred and forty one Five hundred and forty two Five hundred and forty three Five hundred and forty four Five hundred and forty five Five hundred and forty six Five hundred and forty seven Five hundred and forty eight Five hundred and forty nine Five hundred and fifty Five hundred and fifty one Five hundred and fifty two Five hundred and fifty three Five hundred and fifty four Five hundred and fifty five Five hundred and fifty six Five hundred and fifty seven Five hundred and fifty eight Five hundred and fifty nine Five hundred and sixty Five hundred and sixty one Five hundred and sixty two Five hundred and sixty three Five hundred and sixty four Five hundred and sixty five Five hundred and sixty six Five hundred and sixty seven Five hundred and sixty eight Five hundred and sixty nine Five hundred and seventy Five hundred and seventy one Five hundred and seventy two Five hundred and seventy three Five hundred and seventy four Five hundred and seventy five Five hundred and seventy six Five hundred and seventy seven Five hundred and seventy eight Five hundred and seventy nine Five hundred and eighty Five hundred and eighty one Five hundred and eighty two Five hundred and eighty three Five hundred and eighty four Five hundred and eighty five Five hundred and eighty six Five hundred and eighty seven Five hundred and eighty eight Five hundred and eighty nine Five hundred and ninety Five hundred and ninety one Five hundred and ninety two Five hundred and ninety three Five hundred and ninety four Five hundred and ninety five Five hundred and ninety six Five hundred and ninety seven Five hundred and ninety eight Five hundred and ninety nine Six hundred Six hundred and one Six hundred and two Six hundred and three Six hundred and four Six hundred and five Six hundred and six Six hundred and seven Six hundred and eight Six hundred and nine Six hundred and ten Six hundred and eleven Six hundred and twelve Six hundred and thirteen Six hundred and fourteen Six hundred and fifteen Six hundred and sixteen Six hundred and seventeen Six hundred and eighteen Six hundred and nineteen Six hundred and twenty Six hundred and twenty one Six hundred and twenty two Six hundred and twenty three Six hundred and twenty four Six hundred and twenty five Six hundred and twenty six Six hundred and twenty seven Six hundred and twenty eight Six hundred and twenty nine Six hundred and thirty Six hundred and thirty one Six hundred and thirty two Six hundred and thirty three Six hundred and thirty four Six hundred and thirty five Six hundred and thirty six Six hundred and thirty seven Six hundred and thirty eight Six hundred and thirty nine Six hundred and forty Six hundred and forty one Six hundred and forty two Six hundred and forty three Six hundred and forty four Six hundred and forty five Six hundred and forty six Six hundred and forty seven Six hundred and forty eight Six hundred and forty nine Six hundred and fifty Six hundred and fifty one Six hundred and fifty two Six hundred and fifty three Six hundred and fifty four Six hundred and fifty five Six hundred and fifty six Six hundred and fifty seven Six hundred and fifty eight Six hundred and fifty nine Six hundred and sixty Six hundred and sixty one Six hundred and sixty two Six hundred and sixty three Six hundred and sixty four Six hundred and sixty five Six hundred and sixty six Six hundred and sixty seven Six hundred and sixty eight Six hundred and sixty nine Six hundred and seventy Six hundred and seventy one Six hundred and seventy two Six hundred and seventy three Six hundred and seventy four Six hundred and seventy five Six hundred and seventy six Six hundred and seventy seven Six hundred and seventy eight Six hundred and seventy nine Six hundred and eighty Six hundred and eighty one Six hundred and eighty two Six hundred and eighty three Six hundred and eighty four Six hundred and eighty five Six hundred and eighty six Six hundred and eighty seven Six hundred and eighty eight Six hundred and eighty nine Six hundred and ninety Six hundred and ninety one Six hundred and ninety two Six hundred and ninety three Six hundred and ninety four Six hundred and ninety five Six hundred and ninety six Six hundred and ninety seven Six hundred and ninety eight Six hundred and ninety nine Seven hundred Seven hundred and one Seven hundred and two Seven hundred and three Seven hundred and four Seven hundred and five Seven hundred and six Seven hundred and seven Seven hundred and eight Seven hundred and nine Seven hundred and ten Seven hundred and eleven Seven hundred and twelve Seven hundred and thirteen Seven hundred and fourteen Seven hundred and fifteen Seven hundred and sixteen Seven hundred and seventeen Seven hundred and eighteen Seven hundred and nineteen Seven hundred and twenty Seven hundred and twenty one Seven hundred and twenty two Seven hundred and twenty three Seven hundred and twenty four Seven hundred and twenty five Seven hundred and twenty six Seven hundred and twenty seven Seven hundred and twenty eight Seven hundred and twenty nine Seven hundred and thirty Seven hundred and thirty one Seven hundred and thirty two Seven hundred and thirty three Seven hundred and thirty four Seven hundred and thirty five Seven hundred and thirty six Seven hundred and thirty seven Seven hundred and thirty eight Seven hundred and thirty nine Seven hundred and forty Seven hundred and forty one Seven hundred and forty two Seven hundred and forty three Seven hundred and forty four Seven hundred and forty five Seven hundred and forty six Seven hundred and forty seven Seven hundred and forty eight Seven hundred and forty nine Seven hundred and fifty Seven hundred and fifty one Seven hundred and fifty two Seven hundred and fifty three Seven hundred and fifty four Seven hundred and fifty five Seven hundred and fifty six Seven hundred and fifty seven Seven hundred and fifty eight Seven hundred and fifty nine Seven hundred and sixty Seven hundred and sixty one Seven hundred and sixty two Seven hundred and sixty three Seven hundred and sixty four Seven hundred and sixty five Seven hundred and sixty six Seven hundred and sixty seven Seven hundred and sixty eight Seven hundred and sixty nine Seven hundred and seventy Seven hundred and seventy one Seven hundred and seventy two Seven hundred and seventy three Seven hundred and seventy four Seven hundred and seventy five Seven hundred and seventy six Seven hundred and seventy seven Seven hundred and seventy eight Seven hundred and seventy nine Seven hundred and eighty Seven hundred and eighty one Seven hundred and eighty two Seven hundred and eighty three Seven hundred and eighty four Seven hundred and eighty five Seven hundred and eighty six Seven hundred and eighty seven Seven hundred and eighty eight Seven hundred and eighty nine Seven hundred and ninety Seven hundred and ninety one Seven hundred and ninety two Seven hundred and ninety three Seven hundred and ninety four Seven hundred and ninety five Seven hundred and ninety six Seven hundred and ninety seven Seven hundred and ninety eight Seven hundred and ninety nine Eight hundred Eight hundred and one Eight hundred and two Eight hundred and three Eight hundred and four Eight hundred and five Eight hundred and six Eight hundred and seven Eight hundred and eight Eight hundred and nine Eight hundred and ten Eight hundred and eleven Eight hundred and twelve Eight hundred and thirteen Eight hundred and fourteen Eight hundred and fifteen Eight hundred and sixteen Eight hundred and seventeen Eight hundred and eighteen Eight hundred and nineteen Eight hundred and twenty Eight hundred and twenty one Eight hundred and twenty two Eight hundred and twenty three Eight hundred and twenty four Eight hundred and twenty five Eight hundred and twenty six Eight hundred and twenty seven Eight hundred and twenty eight Eight hundred and twenty nine Eight hundred and thirty Eight hundred and thirty one Eight hundred and thirty two Eight hundred and thirty three Eight hundred and thirty four Eight hundred and thirty five Eight hundred and thirty six Eight hundred and thirty seven Eight hundred and thirty eight Eight hundred and thirty nine Eight hundred and forty Eight hundred and forty one Eight hundred and forty two Eight hundred and forty three Eight hundred and forty four Eight hundred and forty five Eight hundred and forty six Eight hundred and forty seven Eight hundred and forty eight Eight hundred and forty nine Eight hundred and fifty Eight hundred and fifty one Eight hundred and fifty two Eight hundred and fifty three Eight hundred and fifty four Eight hundred and fifty five Eight hundred and fifty six Eight hundred and fifty seven Eight hundred and fifty eight Eight hundred and fifty nine Eight hundred and sixty Eight hundred and sixty one Eight hundred and sixty two Eight hundred and sixty three Eight hundred and sixty four Eight hundred and sixty five Eight hundred and sixty six Eight hundred and sixty seven Eight hundred and sixty eight Eight hundred and sixty nine Eight hundred and seventy Eight hundred and seventy one Eight hundred and seventy two Eight hundred and seventy three Eight hundred and seventy four Eight hundred and seventy five Eight hundred and seventy six Eight hundred and seventy seven Eight hundred and seventy eight Eight hundred and seventy nine Eight hundred and eighty Eight hundred and eighty one Eight hundred and eighty two Eight hundred and eighty three Eight hundred and eighty four Eight hundred and eighty five Eight hundred and eighty six Eight hundred and eighty seven Eight hundred and eighty eight Eight hundred and eighty nine Eight hundred and ninety Eight hundred and ninety one Eight hundred and ninety two Eight hundred and ninety three Eight hundred and ninety four Eight hundred and ninety five Eight hundred and ninety six Eight hundred and ninety seven Eight hundred and ninety eight Eight hundred and ninety nine Nine hundred Nine hundred and one Nine hundred and two Nine hundred and three Nine hundred and four Nine hundred and five Nine hundred and six Nine hundred and seven Nine hundred and eight Nine hundred and nine Nine hundred and ten Nine hundred and eleven Nine hundred and twelve Nine hundred and thirteen Nine hundred and fourteen Nine hundred and fifteen Nine hundred and sixteen Nine hundred and seventeen Nine hundred and eighteen Nine hundred and nineteen Nine hundred and twenty Nine hundred and twenty one Nine hundred and twenty two Nine hundred and twenty three Nine hundred and twenty four Nine hundred and twenty five Nine hundred and twenty six Nine hundred and twenty seven Nine hundred and twenty eight Nine hundred and twenty nine Nine hundred and thirty Nine hundred and thirty one Nine hundred and thirty two Nine hundred and thirty three Nine hundred and thirty four Nine hundred and thirty five Nine hundred and thirty six Nine hundred and thirty seven Nine hundred and thirty eight Nine hundred and thirty nine Nine hundred and forty Nine hundred and forty one Nine hundred and forty two Nine hundred and forty three Nine hundred and forty four Nine hundred and forty five Nine hundred and forty six Nine hundred and forty seven Nine hundred and forty eight Nine hundred and forty nine Nine hundred and fifty Nine hundred and fifty one Nine hundred and fifty two Nine hundred and fifty three Nine hundred and fifty four Nine hundred and fifty five Nine hundred and fifty six Nine hundred and fifty seven Nine hundred and fifty eight Nine hundred and fifty nine Nine hundred and sixty Nine hundred and sixty one Nine hundred and sixty two Nine hundred and sixty three Nine hundred and sixty four Nine hundred and sixty five Nine hundred and sixty six Nine hundred and sixty seven Nine hundred and sixty eight Nine hundred and sixty nine Nine hundred and seventy Nine hundred and seventy one Nine hundred and seventy two Nine hundred and seventy three Nine hundred and seventy four Nine hundred and seventy five Nine hundred and seventy six Nine hundred and seventy seven Nine hundred and seventy eight Nine hundred and seventy nine Nine hundred and eighty Nine hundred and eighty one Nine hundred and eighty two Nine hundred and eighty three Nine hundred and eighty four Nine hundred and eighty five Nine hundred and eighty six Nine hundred and eighty seven Nine hundred and eighty eight Nine hundred and eighty nine Nine hundred and ninety Nine hundred and ninety one Nine hundred and ninety two Nine hundred and ninety three Nine hundred and ninety four Nine hundred and ninety five Nine hundred and ninety six Nine hundred and ninety seven Nine hundred and ninety eight Nine hundred and ninety nine One thousand" diff --git a/project_euler/problem_17/problem17.go b/project_euler/problem_17/problem17.go new file mode 100644 index 000000000..a5e2beee7 --- /dev/null +++ b/project_euler/problem_17/problem17.go @@ -0,0 +1,31 @@ +/** +* Problem 17 - Number letter counts +* @see {@link https://projecteuler.net/problem=17} +* +* If the numbers 1 to 5 are written out in words: one, two, three, four, five, +* then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total. +* +* If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, +* how many letters would be used? +* +* NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) +* contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. +* The use of "and" when writing out numbers is in compliance with British usage. +* +* @author ddaniel27 + */ +package problem17 + +import "strings" + +func Problem17(input string) int { + var sum int + + parsed := strings.Split(input, " ") + + for _, word := range parsed { + sum += len(word) + } + + return sum +} diff --git a/project_euler/problem_17/problem17_test.go b/project_euler/problem_17/problem17_test.go new file mode 100644 index 000000000..13cf68bf4 --- /dev/null +++ b/project_euler/problem_17/problem17_test.go @@ -0,0 +1,30 @@ +package problem17 + +import "testing" + +// Tests +func TestProblem17_Func(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"1 to 5", "one two three four five", 19}, + {"1 to 1000", INPUT, 21124}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Problem17(tt.input); got != tt.want { + t.Errorf("Problem17() = %v, want %v", got, tt.want) + } + }) + } +} + +// Benchmark +func BenchmarkProblem17_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem17(INPUT) + } +} diff --git a/project_euler/problem_18/edge.go b/project_euler/problem_18/edge.go new file mode 100644 index 000000000..90f44b082 --- /dev/null +++ b/project_euler/problem_18/edge.go @@ -0,0 +1,100 @@ +package problem18 + +type Edge struct { + ID int + NodeValue NodeValue + NodeLeft Node + NodeRight Node + Parent Node +} + +func (n *Edge) Value() NodeValue { + return n.NodeValue +} + +func (n *Edge) Left() Node { + return n.NodeLeft +} + +func (n *Edge) Right() Node { + return n.NodeRight +} + +func (n *Edge) Kind() string { + return "edge" +} + +func (n *Edge) CreateChild(value NodeValue, id int) Node { + // When the left child is nil, it's a left edge + if n.NodeLeft == nil { + return &Edge{ + ID: id, + NodeValue: value, + Parent: n, + NodeLeft: nil, + NodeRight: nil, + } + } + + // When the left child is a leaf, it's a right edge + if n.NodeLeft.Kind() == "leaf" { + return &Edge{ + ID: id, + NodeValue: value, + Parent: n, + NodeLeft: nil, + NodeRight: nil, + } + } + + return &Leaf{ + ID: id, + NodeValue: value, + Parent: n, + NodeLeft: nil, + NodeRight: nil, + } +} + +func (n *Edge) GetID() int { + return n.ID +} + +func (n *Edge) Insert(node Node) { + // If Left is nil, always simply insert the node + if n.NodeLeft == nil { + node.SetParent(n) + n.NodeLeft = node + + return + } + + // If Right is nil, insert the node + n.NodeRight = node + + // If the node to insert is an edge, set the parent + if node.Kind() == "edge" { + node.SetParent(n) + + return + } + + // If the node to insert is a leaf, send it to the sibling right + n.Parent.Right().Insert(node) +} + +func (n *Edge) HasSpace() bool { + return n.NodeLeft == nil || n.NodeRight == nil +} + +func (n *Edge) LeftIsNil() bool { + return n.NodeLeft == nil +} + +func (n *Edge) RightIsNil() bool { + return n.NodeRight == nil +} + +func (n *Edge) SetParent(node Node) { + n.Parent = node +} diff --git a/project_euler/problem_18/input.go b/project_euler/problem_18/input.go new file mode 100644 index 000000000..e11dcc41f --- /dev/null +++ b/project_euler/problem_18/input.go @@ -0,0 +1,42 @@ +package problem18 + +import "strings" + +const problem18_input_string = ` +75 +95 64 +17 47 82 +18 35 87 10 +20 04 82 47 65 +19 01 23 75 03 34 +88 02 77 73 07 63 67 +99 65 04 28 06 16 70 92 +41 41 26 56 83 40 80 70 33 +41 48 72 33 47 32 37 16 94 29 +53 71 44 65 25 43 91 52 97 51 14 +70 11 33 28 77 73 17 78 39 68 17 57 +91 71 52 38 17 14 91 43 58 50 27 29 48 +63 66 04 68 89 53 67 30 73 16 69 87 40 31 +04 62 98 27 23 09 70 98 73 93 38 53 60 04 23 +` + +var problem18_input_parsed_string []string = strings.Split( + strings.Trim( + strings.ReplaceAll(problem18_input_string, "\n", " "), + " ", + ), + " ") + +const problem18_test_string = ` +3 +7 4 +2 4 6 +8 5 9 3 +` + +var problem18_test_parsed_string []string = strings.Split( + strings.Trim( + strings.ReplaceAll(problem18_test_string, "\n", " "), + " ", + ), + " ") diff --git a/project_euler/problem_18/leaf.go b/project_euler/problem_18/leaf.go new file mode 100644 index 000000000..8dd452602 --- /dev/null +++ b/project_euler/problem_18/leaf.go @@ -0,0 +1,75 @@ +package problem18 + +type Leaf struct { + ID int + NodeValue NodeValue + NodeLeft *Leaf + NodeRight *Leaf + Parent Node +} + +func (n *Leaf) Value() NodeValue { + return n.NodeValue +} + +func (n *Leaf) Left() Node { + if n.NodeLeft != nil { + n.NodeLeft.Parent = n // Leaf is the parent of its left child always + } + + return n.NodeLeft +} + +func (n *Leaf) Right() Node { + return n.NodeRight +} + +func (n *Leaf) Kind() string { + return "leaf" +} + +func (n *Leaf) CreateChild(value NodeValue, id int) Node { + // Leafs only have leaf children + return &Leaf{ + ID: id, + NodeValue: value, + Parent: n, + NodeLeft: nil, + NodeRight: nil, + } +} + +func (n *Leaf) GetID() int { + return n.ID +} + +func (n *Leaf) Insert(node Node) { + // If Left is nil, always simply insert the node + if n.NodeLeft == nil { + node.SetParent(n) + n.NodeLeft = node.(*Leaf) + + return + } + + // If Right is nil, insert the node + n.NodeRight = node.(*Leaf) + // Send it to the sibling right + n.Parent.Right().Insert(node) +} + +func (n *Leaf) HasSpace() bool { + return n.NodeLeft == nil || n.NodeRight == nil +} + +func (n *Leaf) LeftIsNil() bool { + return n.NodeLeft == nil +} + +func (n *Leaf) RightIsNil() bool { + return n.NodeRight == nil +} + +func (n *Leaf) SetParent(node Node) { + n.Parent = node +} diff --git a/project_euler/problem_18/problem18.go b/project_euler/problem_18/problem18.go new file mode 100644 index 000000000..1775c6bd0 --- /dev/null +++ b/project_euler/problem_18/problem18.go @@ -0,0 +1,63 @@ +/** +* Problem 18 - Maximum path sum I +* @see {@link https://projecteuler.net/problem=18} +* +* By starting at the top of the triangle below and +* moving to adjacent numbers on the row below, +* the maximum total from top to bottom is 23. +* +* 3 +* 7 4 +* 2 4 6 +* 8 5 9 3 +* +* That is, 3 + 7 + 4 + 9 = 23. +* +* Find the maximum total from top to bottom of the triangle below: +* [refer to the problem link] +* +* NOTE: As there are only 16384 routes, it is possible +* to solve this problem by trying every route. +* However, Problem 67, is the same challenge with a triangle +* containing one-hundred rows; it cannot be solved by brute force, +* and requires a clever method! ;o) +* +* @author ddaniel27 + */ +package problem18 + +import "strconv" + +type ( + NodeValue int + NodeType string + + Node interface { + Value() NodeValue + GetID() int + Left() Node + Right() Node + LeftIsNil() bool + RightIsNil() bool + HasSpace() bool + Kind() string + SetParent(Node) + CreateChild(NodeValue, int) Node + Insert(Node) + } +) + +func Problem18(input []string, deep int) int { + tree := &Tree{} + + for _, num := range input { + v, err := strconv.Atoi(num) + if err != nil { + panic(err) + } + + tree.BFSInsert(NodeValue(v)) + } + + return tree.MaxPathValueSearch(deep) +} diff --git a/project_euler/problem_18/problem18_test.go b/project_euler/problem_18/problem18_test.go new file mode 100644 index 000000000..50baab2ed --- /dev/null +++ b/project_euler/problem_18/problem18_test.go @@ -0,0 +1,42 @@ +package problem18 + +import "testing" + +// Tests +func TestProblem18_Func(t *testing.T) { + tests := []struct { + name string + input []string + deep int + expected int + }{ + { + name: "Test case 1", + input: problem18_test_parsed_string, + deep: 2, + expected: 23, + }, + { + name: "Test case 2", + input: problem18_input_parsed_string, + deep: 2, + expected: 1074, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual := Problem18(test.input, test.deep) + if actual != test.expected { + t.Errorf("Expected %d, but got %d", test.expected, actual) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem18_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem18(problem18_input_parsed_string, 2) + } +} diff --git a/project_euler/problem_18/root.go b/project_euler/problem_18/root.go new file mode 100644 index 000000000..4ee018629 --- /dev/null +++ b/project_euler/problem_18/root.go @@ -0,0 +1,62 @@ +package problem18 + +type Root struct { + ID int + NodeValue NodeValue + NodeLeft *Edge + NodeRight *Edge +} + +func (n *Root) Value() NodeValue { + return n.NodeValue +} + +func (n *Root) Left() Node { + return n.NodeLeft +} + +func (n *Root) Right() Node { + return n.NodeRight +} + +func (n *Root) Kind() string { + return "root" +} + +func (n *Root) CreateChild(value NodeValue, id int) Node { + return &Edge{ + ID: id, + NodeValue: value, + Parent: n, + NodeLeft: nil, + NodeRight: nil, + } +} + +func (n *Root) GetID() int { + return n.ID +} + +func (n *Root) Insert(node Node) { + if n.NodeLeft == nil { + n.NodeLeft = node.(*Edge) + } else { + n.NodeRight = node.(*Edge) + } +} + +func (n *Root) HasSpace() bool { + return n.NodeLeft == nil || n.NodeRight == nil +} + +func (n *Root) LeftIsNil() bool { + return n.NodeLeft == nil +} + +func (n *Root) RightIsNil() bool { + return n.NodeRight == nil +} + +func (n *Root) SetParent(node Node) { + panic("Root node cannot have a parent") +} diff --git a/project_euler/problem_18/tree.go b/project_euler/problem_18/tree.go new file mode 100644 index 000000000..6f98f3b1c --- /dev/null +++ b/project_euler/problem_18/tree.go @@ -0,0 +1,229 @@ +package problem18 + +import ( + "fmt" + "strings" +) + +type Tree struct { + Root *Root + Nodes map[int]struct{} + ID int +} + +func (t *Tree) BFSInsert(value NodeValue) { + t.Nodes = make(map[int]struct{}) // Reset the nodes map + + if t.Root == nil { + t.Root = &Root{NodeValue: value, ID: 0} + t.ID = 1 + return + } + + queue := make([]Node, 0) + queue = append(queue, t.Root) + t.isInQueue(t.Root.GetID()) + + head := 0 + + for head < len(queue) { + current := queue[head] + head++ + childNode := current.CreateChild(value, t.ID) + + if current.HasSpace() { + current.Insert(childNode) + t.ID++ + return + } + + if !t.isInQueue(current.Left().GetID()) { // Avoid duplicates + queue = append(queue, current.Left()) + } + if !t.isInQueue(current.Right().GetID()) { + queue = append(queue, current.Right()) + } + } +} + +// MaxPathValueSearch is a method that searches the maximum path value in a tree +// given a certain depth +func (r *Tree) MaxPathValueSearch(deep int) int { + if r.Root == nil { + return 0 + } + + type DFSNode struct { + Node Node + StepsLeft int + Sum int + } + + var pivot Node = r.Root + pivotEnded := false + maxPathValue := int(pivot.Value()) + + stack := make([]DFSNode, 0) + + for !pivotEnded { + stack = append(stack, DFSNode{Node: pivot, StepsLeft: deep, Sum: maxPathValue}) + + for len(stack) > 0 { + current := stack[len(stack)-1] + stack = stack[:len(stack)-1] + + // If we run out of steps, we check the sum of the path, + // update the maxPathValue if necessary and continue + if current.StepsLeft == 0 { + if current.Sum > maxPathValue { + maxPathValue = current.Sum + pivot = current.Node + } + continue + } + + if !current.Node.RightIsNil() { + stack = append(stack, DFSNode{ + Node: current.Node.Right(), + StepsLeft: current.StepsLeft - 1, + Sum: current.Sum + int(current.Node.Right().Value()), + }) + } + + // If the left child is nil, we have reached the end of the path + if !current.Node.LeftIsNil() { + stack = append(stack, DFSNode{ + Node: current.Node.Left(), + StepsLeft: current.StepsLeft - 1, + Sum: current.Sum + int(current.Node.Left().Value()), + }) + } else { + if current.Sum > maxPathValue { + maxPathValue = current.Sum + pivot = current.Node + } + } + } + + // If we don't have reached the end of the left side of the tree, + // we continue with the search using the pivot node + // We use the left child only because how the tree is built + if pivot.LeftIsNil() { + pivotEnded = true + } + } + + return maxPathValue +} + +// PrintReport is a method that prints a report of the tree +// Node by node +func (t *Tree) PrintReport() { + t.Nodes = make(map[int]struct{}) + if t.Root == nil { + return + } + + queue := make([]Node, 0) + queue = append(queue, t.Root) + + head := 0 + + for head < len(queue) { + current := queue[head] + head++ + + print("ID:", current.GetID()) + print(", Current node:", current.Value()) + + if !current.LeftIsNil() { + print(", Left Child:", current.Left().Value()) + + if !t.isInQueue(current.Left().GetID()) { + queue = append(queue, current.Left()) + } + } + + if !current.RightIsNil() { + print(", Right Child:", current.Right().Value()) + + if !t.isInQueue(current.Right().GetID()) { + queue = append(queue, current.Right()) + } + } + + println() + } +} + +// PrintPyramid is a method that prints the tree as a pyramid +func (t *Tree) PrintPyramid() { + t.Nodes = make(map[int]struct{}) + if t.Root == nil { + return + } + + queue := []Node{t.Root} + levels := []int{0} + outputByLevel := []string{} + + head := 0 + currentLevel := 0 + + output := "" + + for head < len(queue) { + current := queue[head] + level := levels[head] + head++ + + // Level change + if level > currentLevel { + currentLevel = level + outputByLevel = append(outputByLevel, output+"\n") + output = "" + } + + // Add current node to the output + if current.Value() < 10 { + output += fmt.Sprintf("0%d ", current.Value()) + } else { + output += fmt.Sprintf("%d ", current.Value()) + } + + // Add children to the queue + if !current.LeftIsNil() { + if !t.isInQueue(current.Left().GetID()) { + queue = append(queue, current.Left()) + levels = append(levels, level+1) + } + } + + if !current.RightIsNil() { + if !t.isInQueue(current.Right().GetID()) { + queue = append(queue, current.Right()) + levels = append(levels, level+1) + } + } + } + // Add the last level + outputByLevel = append(outputByLevel, output+"\n") + + totalLevels := len(outputByLevel) + + // Print the pyramid + for i, level := range outputByLevel { + str := strings.Repeat(" ", 2*(totalLevels-i)) + level + print(str) + } +} + +// isInQueue is a method that avoids duplicates in the tree +func (n *Tree) isInQueue(nv int) bool { + if _, ok := n.Nodes[nv]; ok { + return true + } + + n.Nodes[nv] = struct{}{} + return false +} diff --git a/project_euler/problem_19/problem19.go b/project_euler/problem_19/problem19.go new file mode 100644 index 000000000..9a86f0dea --- /dev/null +++ b/project_euler/problem_19/problem19.go @@ -0,0 +1,63 @@ +package problem19 + +/** +* Problem 19 - Counting Sundays +* @see {@link https://projecteuler.net/problem=19} +* +* You are given the following information, +* but you may prefer to do some research for yourself. +* +* 1 Jan 1900 was a Monday. +* Thirty days has September, +* April, June and November. +* All the rest have thirty-one, +* Saving February alone, +* Which has twenty-eight, rain or shine. +* And on leap years, twenty-nine. +* A leap year occurs on any year evenly divisible by 4, +* but not on a century unless it is divisible by 400. +* +* How many Sundays fell on the first of the month during +* the twentieth century (1 Jan 1901 to 31 Dec 2000)? +* +* @author ddaniel27 + */ + +func Problem19() int { + count := 0 + dayOfWeek := 2 // 1 Jan 1901 was a Tuesday + + for year := 1901; year <= 2000; year++ { + for month := 1; month <= 12; month++ { + if dayOfWeek == 0 { + count++ + } + + daysInMonth := 31 + switch month { + case 4, 6, 9, 11: + daysInMonth = 30 + case 2: + if IsLeapYear(year) { + daysInMonth = 29 + } else { + daysInMonth = 28 + } + } + + dayOfWeek = (dayOfWeek + daysInMonth) % 7 + } + } + + return count +} + +func IsLeapYear(year int) bool { + if year%4 == 0 { + if year%100 == 0 { + return year%400 == 0 + } + return true + } + return false +} diff --git a/project_euler/problem_19/problem19_test.go b/project_euler/problem_19/problem19_test.go new file mode 100644 index 000000000..d26c10938 --- /dev/null +++ b/project_euler/problem_19/problem19_test.go @@ -0,0 +1,29 @@ +package problem19 + +import "testing" + +// Tests +func TestProblem19_Func(t *testing.T) { + tests := []struct { + name string + expected int + }{ + {"Problem 19 - Counting Sundays", 171}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := Problem19() + if got != test.expected { + t.Errorf("Problem19() = got %v, want %v", got, test.expected) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem19_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem19() + } +} diff --git a/project_euler/problem_2/problem2.go b/project_euler/problem_2/problem2.go new file mode 100644 index 000000000..e8eaeb85e --- /dev/null +++ b/project_euler/problem_2/problem2.go @@ -0,0 +1,30 @@ +/** +* Problem 2 - Even Fibonacci numbers +* @see {@link https://projecteuler.net/problem=2} +* +* Each new term in the Fibonacci sequence is generated by adding the previous two terms. +* By starting with 1 and 2, the first 10 terms will be: +* +* 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... +* +* By considering the terms in the Fibonacci sequence whose values do not exceed four million, +* find the sum of the even-valued terms. +* +* @author ddaniel27 + */ +package problem2 + +func Problem2(n uint) uint { + sum := uint(0) + a, b := uint(1), uint(2) + + for b < n { + if b%2 == 0 { + sum += b + } + + a, b = b, a+b + } + + return sum +} diff --git a/project_euler/problem_2/problem2_test.go b/project_euler/problem_2/problem2_test.go new file mode 100644 index 000000000..32c3834c6 --- /dev/null +++ b/project_euler/problem_2/problem2_test.go @@ -0,0 +1,45 @@ +package problem2 + +import "testing" + +// Tests +func TestProblem2_Func(t *testing.T) { + tests := []struct { + name string + input uint + want uint + }{ + { + name: "Testcase 1 - input 10", + input: 10, + want: 10, + }, + { + name: "Testcase 2 - input 100", + input: 100, + want: 44, + }, + { + name: "Testcase 3 - input 4e6", + input: 4e6, + want: 4613732, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem2(tt.input) + + if n != tt.want { + t.Errorf("Problem2() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem2(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem2(4e6) + } +} diff --git a/project_euler/problem_20/problem20.go b/project_euler/problem_20/problem20.go new file mode 100644 index 000000000..fc731da6b --- /dev/null +++ b/project_euler/problem_20/problem20.go @@ -0,0 +1,37 @@ +/** +* Problem 20 - Factorial digit sum +* @see {@link https://projecteuler.net/problem=20} +* +* n! means n × (n − 1) × ... × 3 × 2 × 1 +* +* For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, +* and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27. +* +* Find the sum of the digits in the number 100! +* +* @author ddaniel27 + */ +package problem20 + +import "math/big" + +func Problem20(input int) int { + factorial := bigFactorial(input) + sum := 0 + for _, digit := range factorial.String() { + sum += int(digit - '0') + } + return sum +} + +// bigFactorial returns the factorial of n as a big.Int +// Use big package to handle large numbers +func bigFactorial(n int) *big.Int { + if n < 0 { + return big.NewInt(0) + } + if n == 0 { + return big.NewInt(1) + } + return big.NewInt(0).Mul(big.NewInt(int64(n)), bigFactorial(n-1)) +} diff --git a/project_euler/problem_20/problem20_test.go b/project_euler/problem_20/problem20_test.go new file mode 100644 index 000000000..f1ac574c6 --- /dev/null +++ b/project_euler/problem_20/problem20_test.go @@ -0,0 +1,31 @@ +package problem20 + +import "testing" + +// Tests +func TestProblem20_Func(t *testing.T) { + tests := []struct { + name string + input int + expected int + }{ + {"Problem 20 - Factorial digit sum", 10, 27}, + {"Problem 20 - Factorial digit sum", 100, 648}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := Problem20(test.input) + if got != test.expected { + t.Errorf("Problem20() = got %v, want %v", got, test.expected) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem20_Func(b *testing.B) { + for i := 0; i < b.N; i++ { + Problem20(100) + } +} diff --git a/project_euler/problem_3/problem3.go b/project_euler/problem_3/problem3.go new file mode 100644 index 000000000..f13525fb6 --- /dev/null +++ b/project_euler/problem_3/problem3.go @@ -0,0 +1,24 @@ +/** +* Problem 3 - Largest prime factor +* @see {@link https://projecteuler.net/problem=3} +* +* The prime factors of 13195 are 5, 7, 13 and 29. +* What is the largest prime factor of the number 600851475143 ? +* +* @author ddaniel27 + */ +package problem3 + +func Problem3(n uint) uint { + i := uint(2) + + for n > 1 { + if n%i == 0 { + n /= i + } else { + i++ + } + } + + return i +} diff --git a/project_euler/problem_3/problem3_test.go b/project_euler/problem_3/problem3_test.go new file mode 100644 index 000000000..d00379f8e --- /dev/null +++ b/project_euler/problem_3/problem3_test.go @@ -0,0 +1,40 @@ +package problem3 + +import "testing" + +// Tests +func TestProblem3_Func(t *testing.T) { + tests := []struct { + name string + input uint + want uint + }{ + { + name: "Testcase 1 - input 13195", + input: 13195, + want: 29, + }, + { + name: "Testcase 2 - input 600851475143", + input: 600851475143, + want: 6857, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem3(tt.input) + + if n != tt.want { + t.Errorf("Problem3() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem3(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem3(600851475143) + } +} diff --git a/project_euler/problem_4/problem4.go b/project_euler/problem_4/problem4.go new file mode 100644 index 000000000..b48d81e41 --- /dev/null +++ b/project_euler/problem_4/problem4.go @@ -0,0 +1,33 @@ +/** +* Problem 4 - Largest palindrome product +* @see {@link https://projecteuler.net/problem=4} +* +* A palindromic number reads the same both ways. +* The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99. +* Find the largest palindrome made from the product of two 3-digit numbers. +* +* @author ddaniel27 + */ +package problem4 + +import ( + "fmt" + + "github.com/TheAlgorithms/Go/strings/palindrome" +) + +func Problem4() uint { + max := uint(0) + + for i := 999; i >= 100; i-- { + for j := 999; j >= 100; j-- { + n := uint(i * j) + + if palindrome.IsPalindrome(fmt.Sprintf("%d", n)) && n > max { + max = n + } + } + } + + return max +} diff --git a/project_euler/problem_4/problem4_test.go b/project_euler/problem_4/problem4_test.go new file mode 100644 index 000000000..6b91fd2b0 --- /dev/null +++ b/project_euler/problem_4/problem4_test.go @@ -0,0 +1,33 @@ +package problem4 + +import "testing" + +// Tests +func TestProblem4_Func(t *testing.T) { + tests := []struct { + name string + want uint + }{ + { + name: "Testcase 1", + want: 906609, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem4() + + if n != tt.want { + t.Errorf("Problem4() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem4(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem4() + } +} diff --git a/project_euler/problem_5/problem5.go b/project_euler/problem_5/problem5.go new file mode 100644 index 000000000..dad415738 --- /dev/null +++ b/project_euler/problem_5/problem5.go @@ -0,0 +1,33 @@ +/** +* Problem 5 - Smallest multiple +* @see {@link https://projecteuler.net/problem=5} +* +* 2520 is the smallest number that can be divided by +* each of the numbers from 1 to 10 without any remainder. +* What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? +* +* @author ddaniel27 + */ +package problem5 + +func Problem5(limit uint) uint { + n := limit * limit + + for { + if isDivisible(n, limit) { + return n + } + + n++ + } +} + +func isDivisible(n, limit uint) bool { + for i := uint(1); i <= limit; i++ { + if n%i != 0 { + return false + } + } + + return true +} diff --git a/project_euler/problem_5/problem5_test.go b/project_euler/problem_5/problem5_test.go new file mode 100644 index 000000000..43e7d8ec9 --- /dev/null +++ b/project_euler/problem_5/problem5_test.go @@ -0,0 +1,45 @@ +package problem5 + +import "testing" + +// Tests +func TestProblem5_Func(t *testing.T) { + tests := []struct { + name string + input uint + want uint + }{ + { + name: "Testcase 1 - input 10", + input: 10, + want: 2520, + }, + { + name: "Testcase 2 - input 20", + input: 20, + want: 232792560, + }, + { + name: "Testcase 3 - input 5", + input: 5, + want: 60, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem5(tt.input) + + if n != tt.want { + t.Errorf("Problem5() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem5(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem5(20) + } +} diff --git a/project_euler/problem_6/problem6.go b/project_euler/problem_6/problem6.go new file mode 100644 index 000000000..83287b87d --- /dev/null +++ b/project_euler/problem_6/problem6.go @@ -0,0 +1,33 @@ +/** +* Problem 6 - Sum square difference +* @see {@link https://projecteuler.net/problem=6} +* +* The sum of the squares of the first ten natural numbers is, +* 1^2 + 2^2 + ... + 10^2 = 385 +* +* The square of the sum of the first ten natural numbers is, +* (1 + 2 + ... + 10)^2 = 55^2 = 3025 +* +* Hence the difference between the sum of the squares of the first ten natural numbers +* and the square of the sum is 3025 − 385 = 2640. +* +* Find the difference between the sum of the squares of the first one hundred natural numbers +* and the square of the sum. +* +* @author ddaniel27 + */ +package problem6 + +func Problem6(n uint) uint { + sumOfSquares := uint(0) + squareOfSum := uint(0) + + for i := uint(1); i <= n; i++ { + sumOfSquares += i * i + squareOfSum += i + } + + squareOfSum *= squareOfSum + + return squareOfSum - sumOfSquares +} diff --git a/project_euler/problem_6/problem6_test.go b/project_euler/problem_6/problem6_test.go new file mode 100644 index 000000000..afa4e5fb7 --- /dev/null +++ b/project_euler/problem_6/problem6_test.go @@ -0,0 +1,40 @@ +package problem6 + +import "testing" + +// Tests +func TestProblem6_Func(t *testing.T) { + tests := []struct { + name string + input uint + want uint + }{ + { + name: "Testcase 1 - input 10", + input: 10, + want: 2640, + }, + { + name: "Testcase 2 - input 100", + input: 100, + want: 25164150, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem6(tt.input) + + if n != tt.want { + t.Errorf("Problem6() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem6(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem6(100) + } +} diff --git a/project_euler/problem_7/problem7.go b/project_euler/problem_7/problem7.go new file mode 100644 index 000000000..481844fed --- /dev/null +++ b/project_euler/problem_7/problem7.go @@ -0,0 +1,27 @@ +/** +* Problem 7 - 10001st prime +* @see {@link https://projecteuler.net/problem=7} +* +* By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, +* we can see that the 6th prime is 13. +* +* What is the 10 001st prime number? +* +* @author ddaniel27 + */ +package problem7 + +import "github.com/TheAlgorithms/Go/math/prime" + +func Problem7(n uint) int64 { + count, i := uint(0), int64(1) + + for count < n { + i++ + if prime.OptimizedTrialDivision(i) { + count++ + } + } + + return i +} diff --git a/project_euler/problem_7/problem7_test.go b/project_euler/problem_7/problem7_test.go new file mode 100644 index 000000000..d2ab03e74 --- /dev/null +++ b/project_euler/problem_7/problem7_test.go @@ -0,0 +1,40 @@ +package problem7 + +import "testing" + +// Tests +func TestProblem7_Func(t *testing.T) { + tests := []struct { + name string + input uint + want int64 + }{ + { + name: "Testcase 1 - input 6", + input: 6, + want: 13, + }, + { + name: "Testcase 2 - input 10001", + input: 10001, + want: 104743, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem7(tt.input) + + if n != tt.want { + t.Errorf("Problem7() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem7(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem7(10001) + } +} diff --git a/project_euler/problem_8/problem8.go b/project_euler/problem_8/problem8.go new file mode 100644 index 000000000..0c800dcdb --- /dev/null +++ b/project_euler/problem_8/problem8.go @@ -0,0 +1,33 @@ +/** +* Problem 8 - Largest product in a series +* @see {@link https://projecteuler.net/problem=8} +* +* The four adjacent digits in the 1000-digit number that +* have the greatest product are 9 × 9 × 8 × 9 = 5832. +* Find the thirteen adjacent digits in the 1000-digit number +* that have the greatest product. What is the value of this product? +* +* @author ddaniel27 + */ +package problem8 + +const number = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450" + +func Problem8(window int) uint { + max := uint(0) + + for i := 0; i < len(number)-window; i++ { + product := uint(1) + + for j := 0; j < window; j++ { + n := uint(number[i+j] - '0') + product *= n + } + + if product > max { + max = product + } + } + + return max +} diff --git a/project_euler/problem_8/problem8_test.go b/project_euler/problem_8/problem8_test.go new file mode 100644 index 000000000..eecde4bc6 --- /dev/null +++ b/project_euler/problem_8/problem8_test.go @@ -0,0 +1,40 @@ +package problem8 + +import "testing" + +// Tests +func TestProblem8_Func(t *testing.T) { + tests := []struct { + name string + input int + want uint + }{ + { + name: "Testcase 1 - input 4", + input: 4, + want: 5832, + }, + { + name: "Testcase 2 - input 13", + input: 13, + want: 23514624000, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem8(tt.input) + + if n != tt.want { + t.Errorf("Problem8() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem8(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem8(13) + } +} diff --git a/project_euler/problem_9/problem9.go b/project_euler/problem_9/problem9.go new file mode 100644 index 000000000..0f784c022 --- /dev/null +++ b/project_euler/problem_9/problem9.go @@ -0,0 +1,29 @@ +/** +* Problem 9 - Special Pythagorean triplet +* @see {@link https://projecteuler.net/problem=9} +* +* A Pythagorean triplet is a set of three natural numbers, a < b < c, for which, +* a^2 + b^2 = c^2 +* +* For example, 3^2 + 4^2 = 9 + 16 = 25 = 5^2. +* +* There exists exactly one Pythagorean triplet for which a + b + c = 1000. +* Find the product abc. +* +* @author ddaniel27 + */ +package problem9 + +func Problem9() uint { + for a := uint(1); a < 1000; a++ { + for b := a + 1; b < 1000; b++ { + c := 1000 - a - b + + if a*a+b*b == c*c { + return a * b * c + } + } + } + + return 0 +} diff --git a/project_euler/problem_9/problem9_test.go b/project_euler/problem_9/problem9_test.go new file mode 100644 index 000000000..d75226103 --- /dev/null +++ b/project_euler/problem_9/problem9_test.go @@ -0,0 +1,33 @@ +package problem9 + +import "testing" + +// Tests +func TestProblem9_Func(t *testing.T) { + tests := []struct { + name string + want uint + }{ + { + name: "Testcase 1", + want: 31875000, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := Problem9() + + if n != tt.want { + t.Errorf("Problem9() = %v, want %v", n, tt.want) + } + }) + } +} + +// Benchmarks +func BenchmarkProblem9(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Problem9() + } +} From e8cbbce8349a730ec1d94ff32a77ad3d975b3bdd Mon Sep 17 00:00:00 2001 From: Sublics <142167785+lyqio@users.noreply.github.com> Date: Sun, 12 Jan 2025 09:50:44 +0000 Subject: [PATCH 487/488] add stooge sort (#774) --- sort/sorts_test.go | 8 ++++++++ sort/stooge_sort.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 sort/stooge_sort.go diff --git a/sort/sorts_test.go b/sort/sorts_test.go index a04f19eb0..f2394c334 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -198,6 +198,10 @@ func TestOddEvenSort(t *testing.T) { testFramework(t, sort.OddEvenSort[int]) } +func TestStooge(t *testing.T) { + testFramework(t, sort.Stooge[int]) +} + // END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { @@ -340,3 +344,7 @@ func BenchmarkTimsort(b *testing.B) { func BenchmarkCircle(b *testing.B) { benchmarkFramework(b, sort.Circle[int]) } + +func BenchmarkStooge(b *testing.B) { + benchmarkFramework(b, sort.Stooge[int]) +} diff --git a/sort/stooge_sort.go b/sort/stooge_sort.go new file mode 100644 index 000000000..45d2206c4 --- /dev/null +++ b/sort/stooge_sort.go @@ -0,0 +1,34 @@ +// implementation of the Stooge sort +// more info at https://en.wikipedia.org/wiki/Stooge_sort +// worst-case time complexity O(n^2.709511) +// worst-case space complexity O(n) + +package sort + +import ( + "github.com/TheAlgorithms/Go/constraints" + + // math imported for floor division + "math" +) + +func innerStooge[T constraints.Ordered](arr []T, i int32, j int32) []T { + if arr[i] > arr[j] { + arr[i], arr[j] = arr[j], arr[i] + } + if (j - i + 1) > 2 { + t := int32(math.Floor(float64(j-i+1) / 3.0)) + arr = innerStooge(arr, i, j-t) + arr = innerStooge(arr, i+t, j) + arr = innerStooge(arr, i, j-t) + } + return arr +} + +func Stooge[T constraints.Ordered](arr []T) []T { + if len(arr) == 0 { + return arr + } + + return innerStooge(arr, 0, int32(len(arr)-1)) +} From 5ba447ec5ff3d1213de65b92e726ee74c5d5cc19 Mon Sep 17 00:00:00 2001 From: Ganesh Manchi <62894745+ganeshvenkatasai@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:21:13 +0530 Subject: [PATCH 488/488] Add Dynamic Programming Algorithms (#776) * Add dynamic programming problem implementations and their tests * Fix bugs and improve test cases for dynamic programming algorithms * Fix linters * Modify Dice Throw Test Function Name --- dynamic/burstballoons.go | 31 ++++++++++ dynamic/burstballoons_test.go | 33 +++++++++++ dynamic/dicethrow.go | 33 +++++++++++ dynamic/dicethrow_test.go | 42 ++++++++++++++ dynamic/eggdropping.go | 47 +++++++++++++++ dynamic/eggdropping_test.go | 35 +++++++++++ dynamic/interleavingstrings.go | 36 ++++++++++++ dynamic/interleavingstrings_test.go | 38 ++++++++++++ dynamic/longestarithmeticsubsequence.go | 34 +++++++++++ dynamic/longestarithmeticsubsequence_test.go | 38 ++++++++++++ dynamic/longestpalindromicsubstring.go | 43 ++++++++++++++ dynamic/longestpalindromicsubstring_test.go | 37 ++++++++++++ dynamic/maxsubarraysum.go | 22 +++++++ dynamic/maxsubarraysum_test.go | 37 ++++++++++++ dynamic/optimalbst.go | 61 ++++++++++++++++++++ dynamic/optimalbst_test.go | 35 +++++++++++ dynamic/partitionproblem.go | 30 ++++++++++ dynamic/partitionproblem_test.go | 39 +++++++++++++ dynamic/tilingproblem.go | 22 +++++++ dynamic/tilingproblem_test.go | 38 ++++++++++++ dynamic/wildcardmatching.go | 33 +++++++++++ dynamic/wildcardmatching_test.go | 44 ++++++++++++++ dynamic/wordbreak.go | 28 +++++++++ dynamic/wordbreak_test.go | 40 +++++++++++++ 24 files changed, 876 insertions(+) create mode 100644 dynamic/burstballoons.go create mode 100644 dynamic/burstballoons_test.go create mode 100644 dynamic/dicethrow.go create mode 100644 dynamic/dicethrow_test.go create mode 100644 dynamic/eggdropping.go create mode 100644 dynamic/eggdropping_test.go create mode 100644 dynamic/interleavingstrings.go create mode 100644 dynamic/interleavingstrings_test.go create mode 100644 dynamic/longestarithmeticsubsequence.go create mode 100644 dynamic/longestarithmeticsubsequence_test.go create mode 100644 dynamic/longestpalindromicsubstring.go create mode 100644 dynamic/longestpalindromicsubstring_test.go create mode 100644 dynamic/maxsubarraysum.go create mode 100644 dynamic/maxsubarraysum_test.go create mode 100644 dynamic/optimalbst.go create mode 100644 dynamic/optimalbst_test.go create mode 100644 dynamic/partitionproblem.go create mode 100644 dynamic/partitionproblem_test.go create mode 100644 dynamic/tilingproblem.go create mode 100644 dynamic/tilingproblem_test.go create mode 100644 dynamic/wildcardmatching.go create mode 100644 dynamic/wildcardmatching_test.go create mode 100644 dynamic/wordbreak.go create mode 100644 dynamic/wordbreak_test.go diff --git a/dynamic/burstballoons.go b/dynamic/burstballoons.go new file mode 100644 index 000000000..492b00d8c --- /dev/null +++ b/dynamic/burstballoons.go @@ -0,0 +1,31 @@ +package dynamic + +import "github.com/TheAlgorithms/Go/math/max" + +// MaxCoins returns the maximum coins we can collect by bursting the balloons +func MaxCoins(nums []int) int { + n := len(nums) + if n == 0 { + return 0 + } + + nums = append([]int{1}, nums...) + nums = append(nums, 1) + + dp := make([][]int, n+2) + for i := range dp { + dp[i] = make([]int, n+2) + } + + for length := 1; length <= n; length++ { + for left := 1; left+length-1 <= n; left++ { + right := left + length - 1 + for k := left; k <= right; k++ { + coins := nums[left-1] * nums[k] * nums[right+1] + dp[left][right] = max.Int(dp[left][right], dp[left][k-1]+dp[k+1][right]+coins) + } + } + } + + return dp[1][n] +} diff --git a/dynamic/burstballoons_test.go b/dynamic/burstballoons_test.go new file mode 100644 index 000000000..c36e08824 --- /dev/null +++ b/dynamic/burstballoons_test.go @@ -0,0 +1,33 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseBurstBalloons struct { + nums []int + expected int +} + +func getBurstBalloonsTestCases() []testCaseBurstBalloons { + return []testCaseBurstBalloons{ + {[]int{3, 1, 5, 8}, 167}, // Maximum coins from [3,1,5,8] + {[]int{1, 5}, 10}, // Maximum coins from [1,5] + {[]int{1}, 1}, // Single balloon + {[]int{}, 0}, // No balloons + } + +} + +func TestMaxCoins(t *testing.T) { + t.Run("Burst Balloons test cases", func(t *testing.T) { + for _, tc := range getBurstBalloonsTestCases() { + actual := dynamic.MaxCoins(tc.nums) + if actual != tc.expected { + t.Errorf("MaxCoins(%v) = %d; expected %d", tc.nums, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/dicethrow.go b/dynamic/dicethrow.go new file mode 100644 index 000000000..69711ca14 --- /dev/null +++ b/dynamic/dicethrow.go @@ -0,0 +1,33 @@ +// dicethrow.go +// description: Solves the Dice Throw Problem using dynamic programming +// reference: https://www.geeksforgeeks.org/dice-throw-problem/ +// time complexity: O(m * n) +// space complexity: O(m * n) + +package dynamic + +// DiceThrow returns the number of ways to get sum `sum` using `m` dice with `n` faces +func DiceThrow(m, n, sum int) int { + dp := make([][]int, m+1) + for i := range dp { + dp[i] = make([]int, sum+1) + } + + for i := 1; i <= n; i++ { + if i <= sum { + dp[1][i] = 1 + } + } + + for i := 2; i <= m; i++ { + for j := 1; j <= sum; j++ { + for k := 1; k <= n; k++ { + if j-k >= 0 { + dp[i][j] += dp[i-1][j-k] + } + } + } + } + + return dp[m][sum] +} diff --git a/dynamic/dicethrow_test.go b/dynamic/dicethrow_test.go new file mode 100644 index 000000000..dad25e533 --- /dev/null +++ b/dynamic/dicethrow_test.go @@ -0,0 +1,42 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseDiceThrow struct { + numDice int + numFaces int + targetSum int + expected int +} + +// getDiceThrowTestCases provides the test cases for DiceThrow +func getDiceThrowTestCases() []testCaseDiceThrow { + return []testCaseDiceThrow{ + {2, 6, 7, 6}, // Two dice, six faces each, sum = 7 + {1, 6, 3, 1}, // One die, six faces, sum = 3 + {3, 4, 5, 6}, // Three dice, four faces each, sum = 5 + {1, 6, 1, 1}, // One die, six faces, sum = 1 + {2, 6, 12, 1}, // Two dice, six faces each, sum = 12 + {3, 6, 18, 1}, // Three dice, six faces each, sum = 18 + {2, 6, 20, 0}, // Two dice, six faces each, sum = 20 (impossible) + {1, 1, 1, 1}, // One die, one face, sum = 1 + {1, 1, 2, 0}, // One die, one face, sum = 2 (impossible) + {2, 1, 2, 1}, // Two dice, one face each, sum = 2 + } +} + +// TestDiceThrow tests the DiceThrow function with basic test cases +func TestDiceThrow(t *testing.T) { + t.Run("Basic test cases", func(t *testing.T) { + for _, tc := range getDiceThrowTestCases() { + actual := dynamic.DiceThrow(tc.numDice, tc.numFaces, tc.targetSum) + if actual != tc.expected { + t.Errorf("DiceThrow(%d, %d, %d) = %d; expected %d", tc.numDice, tc.numFaces, tc.targetSum, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/eggdropping.go b/dynamic/eggdropping.go new file mode 100644 index 000000000..b6d379389 --- /dev/null +++ b/dynamic/eggdropping.go @@ -0,0 +1,47 @@ +package dynamic + +import ( + "github.com/TheAlgorithms/Go/math/max" + "github.com/TheAlgorithms/Go/math/min" +) + +// EggDropping finds the minimum number of attempts needed to find the critical floor +// with `eggs` number of eggs and `floors` number of floors +func EggDropping(eggs, floors int) int { + // Edge case: If there are no floors, no attempts needed + if floors == 0 { + return 0 + } + // Edge case: If there is one floor, one attempt needed + if floors == 1 { + return 1 + } + // Edge case: If there is one egg, need to test all floors one by one + if eggs == 1 { + return floors + } + + // Initialize DP table + dp := make([][]int, eggs+1) + for i := range dp { + dp[i] = make([]int, floors+1) + } + + // Fill the DP table for 1 egg + for j := 1; j <= floors; j++ { + dp[1][j] = j + } + + // Fill the DP table for more than 1 egg + for i := 2; i <= eggs; i++ { + for j := 2; j <= floors; j++ { + dp[i][j] = int(^uint(0) >> 1) // initialize with a large number + for x := 1; x <= j; x++ { + // Recurrence relation to fill the DP table + res := max.Int(dp[i-1][x-1], dp[i][j-x]) + 1 + dp[i][j] = min.Int(dp[i][j], res) + } + } + } + return dp[eggs][floors] +} diff --git a/dynamic/eggdropping_test.go b/dynamic/eggdropping_test.go new file mode 100644 index 000000000..5e3232f70 --- /dev/null +++ b/dynamic/eggdropping_test.go @@ -0,0 +1,35 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseEggDropping struct { + eggs int + floors int + expected int +} + +func getEggDroppingTestCases() []testCaseEggDropping { + return []testCaseEggDropping{ + {1, 10, 10}, // One egg, need to test all floors + {2, 10, 4}, // Two eggs and ten floors + {3, 14, 4}, // Three eggs and fourteen floors + {2, 36, 8}, // Two eggs and thirty-six floors + {2, 0, 0}, // Two eggs, zero floors + } + +} + +func TestEggDropping(t *testing.T) { + t.Run("Egg Dropping test cases", func(t *testing.T) { + for _, tc := range getEggDroppingTestCases() { + actual := dynamic.EggDropping(tc.eggs, tc.floors) + if actual != tc.expected { + t.Errorf("EggDropping(%d, %d) = %d; expected %d", tc.eggs, tc.floors, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/interleavingstrings.go b/dynamic/interleavingstrings.go new file mode 100644 index 000000000..da13840b2 --- /dev/null +++ b/dynamic/interleavingstrings.go @@ -0,0 +1,36 @@ +// interleavingstrings.go +// description: Solves the Interleaving Strings problem using dynamic programming +// reference: https://en.wikipedia.org/wiki/Interleaving_strings +// time complexity: O(m*n) +// space complexity: O(m*n) + +package dynamic + +// IsInterleave checks if string `s1` and `s2` can be interleaved to form string `s3` +func IsInterleave(s1, s2, s3 string) bool { + if len(s1)+len(s2) != len(s3) { + return false + } + + dp := make([][]bool, len(s1)+1) + for i := range dp { + dp[i] = make([]bool, len(s2)+1) + } + + dp[0][0] = true + for i := 1; i <= len(s1); i++ { + dp[i][0] = dp[i-1][0] && s1[i-1] == s3[i-1] + } + + for j := 1; j <= len(s2); j++ { + dp[0][j] = dp[0][j-1] && s2[j-1] == s3[j-1] + } + + for i := 1; i <= len(s1); i++ { + for j := 1; j <= len(s2); j++ { + dp[i][j] = (dp[i-1][j] && s1[i-1] == s3[i+j-1]) || (dp[i][j-1] && s2[j-1] == s3[i+j-1]) + } + } + + return dp[len(s1)][len(s2)] +} diff --git a/dynamic/interleavingstrings_test.go b/dynamic/interleavingstrings_test.go new file mode 100644 index 000000000..a1559e932 --- /dev/null +++ b/dynamic/interleavingstrings_test.go @@ -0,0 +1,38 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseInterleaving struct { + s1, s2, s3 string + expected bool +} + +func getInterleavingTestCases() []testCaseInterleaving { + return []testCaseInterleaving{ + {"aab", "axy", "aaxaby", true}, // Valid interleaving + {"aab", "axy", "abaaxy", false}, // Invalid interleaving + {"", "", "", true}, // All empty strings + {"abc", "", "abc", true}, // Only s1 matches s3 + {"", "xyz", "xyz", true}, // Only s2 matches s3 + {"abc", "xyz", "abxcyz", true}, // Valid interleaving + {"aaa", "aaa", "aaaaaa", true}, // Identical strings + {"aaa", "aaa", "aaaaaaa", false}, // Extra character + {"abc", "def", "abcdef", true}, // Concatenation order + {"abc", "def", "adbcef", true}, // Valid mixed interleaving + } +} + +func TestIsInterleave(t *testing.T) { + t.Run("Interleaving Strings test cases", func(t *testing.T) { + for _, tc := range getInterleavingTestCases() { + actual := dynamic.IsInterleave(tc.s1, tc.s2, tc.s3) + if actual != tc.expected { + t.Errorf("IsInterleave(%q, %q, %q) = %v; expected %v", tc.s1, tc.s2, tc.s3, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/longestarithmeticsubsequence.go b/dynamic/longestarithmeticsubsequence.go new file mode 100644 index 000000000..a187b9cea --- /dev/null +++ b/dynamic/longestarithmeticsubsequence.go @@ -0,0 +1,34 @@ +// longestarithmeticsubsequence.go +// description: Implementation of the Longest Arithmetic Subsequence problem +// reference: https://en.wikipedia.org/wiki/Longest_arithmetic_progression +// time complexity: O(n^2) +// space complexity: O(n^2) + +package dynamic + +// LongestArithmeticSubsequence returns the length of the longest arithmetic subsequence +func LongestArithmeticSubsequence(nums []int) int { + n := len(nums) + if n <= 1 { + return n + } + + dp := make([]map[int]int, n) + for i := range dp { + dp[i] = make(map[int]int) + } + + maxLength := 1 + + for i := 1; i < n; i++ { + for j := 0; j < i; j++ { + diff := nums[i] - nums[j] + dp[i][diff] = dp[j][diff] + 1 + if dp[i][diff]+1 > maxLength { + maxLength = dp[i][diff] + 1 + } + } + } + + return maxLength +} diff --git a/dynamic/longestarithmeticsubsequence_test.go b/dynamic/longestarithmeticsubsequence_test.go new file mode 100644 index 000000000..2a971fbd7 --- /dev/null +++ b/dynamic/longestarithmeticsubsequence_test.go @@ -0,0 +1,38 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseLongestArithmeticSubsequence struct { + nums []int + expected int +} + +func getLongestArithmeticSubsequenceTestCases() []testCaseLongestArithmeticSubsequence { + return []testCaseLongestArithmeticSubsequence{ + {[]int{3, 6, 9, 12}, 4}, // Arithmetic sequence of length 4 + {[]int{9, 4, 7, 2, 10}, 3}, // Arithmetic sequence of length 3 + {[]int{20, 1, 15, 3, 10, 5, 8}, 4}, // Arithmetic sequence of length 4 + {[]int{1, 2, 3, 4, 5}, 5}, // Arithmetic sequence of length 5 + {[]int{10, 7, 4, 1}, 4}, // Arithmetic sequence of length 4 + {[]int{1, 5, 7, 8, 5, 3, 4, 3, 1, 2}, 4}, // Arithmetic sequence of length 4 + {[]int{1, 3, 5, 7, 9}, 5}, // Arithmetic sequence of length 5 + {[]int{5, 10, 15, 20}, 4}, // Arithmetic sequence of length 4 + {[]int{1}, 1}, // Single element, length is 1 + {[]int{}, 0}, // Empty array, length is 0 + } +} + +func TestLongestArithmeticSubsequence(t *testing.T) { + t.Run("Longest Arithmetic Subsequence test cases", func(t *testing.T) { + for _, tc := range getLongestArithmeticSubsequenceTestCases() { + actual := dynamic.LongestArithmeticSubsequence(tc.nums) + if actual != tc.expected { + t.Errorf("LongestArithmeticSubsequence(%v) = %v; expected %v", tc.nums, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/longestpalindromicsubstring.go b/dynamic/longestpalindromicsubstring.go new file mode 100644 index 000000000..01d105629 --- /dev/null +++ b/dynamic/longestpalindromicsubstring.go @@ -0,0 +1,43 @@ +// longestpalindromicsubstring.go +// description: Implementation of finding the longest palindromic substring +// reference: https://en.wikipedia.org/wiki/Longest_palindromic_substring +// time complexity: O(n^2) +// space complexity: O(n^2) + +package dynamic + +// LongestPalindromicSubstring returns the longest palindromic substring in the input string +func LongestPalindromicSubstring(s string) string { + n := len(s) + if n == 0 { + return "" + } + + dp := make([][]bool, n) + for i := range dp { + dp[i] = make([]bool, n) + } + + start := 0 + maxLength := 1 + for i := 0; i < n; i++ { + dp[i][i] = true + } + + for length := 2; length <= n; length++ { + for i := 0; i < n-length+1; i++ { + j := i + length - 1 + if length == 2 { + dp[i][j] = (s[i] == s[j]) + } else { + dp[i][j] = (s[i] == s[j]) && dp[i+1][j-1] + } + + if dp[i][j] && length > maxLength { + maxLength = length + start = i + } + } + } + return s[start : start+maxLength] +} diff --git a/dynamic/longestpalindromicsubstring_test.go b/dynamic/longestpalindromicsubstring_test.go new file mode 100644 index 000000000..e8424eabe --- /dev/null +++ b/dynamic/longestpalindromicsubstring_test.go @@ -0,0 +1,37 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseLongestPalindromicSubstring struct { + s string + expected string +} + +func getLongestPalindromicSubstringTestCases() []testCaseLongestPalindromicSubstring { + return []testCaseLongestPalindromicSubstring{ + {"babad", "bab"}, // Example with multiple palindromes + {"cbbd", "bb"}, // Example with longest even palindrome + {"a", "a"}, // Single character, palindrome is itself + {"", ""}, // Empty string, no palindrome + {"racecar", "racecar"}, // Whole string is a palindrome + {"abcba", "abcba"}, // Palindrome in the middle + {"aabbcc", "aa"}, // Multiple substrings, longest "aa" + {"madam", "madam"}, // Full palindrome string + {"forgeeksskeegfor", "geeksskeeg"}, // Complex palindrome in the middle + } +} + +func TestLongestPalindromicSubstring(t *testing.T) { + t.Run("Longest Palindromic Substring test cases", func(t *testing.T) { + for _, tc := range getLongestPalindromicSubstringTestCases() { + actual := dynamic.LongestPalindromicSubstring(tc.s) + if actual != tc.expected { + t.Errorf("LongestPalindromicSubstring(%q) = %q; expected %q", tc.s, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/maxsubarraysum.go b/dynamic/maxsubarraysum.go new file mode 100644 index 000000000..4e283e1b9 --- /dev/null +++ b/dynamic/maxsubarraysum.go @@ -0,0 +1,22 @@ +// maxsubarraysum.go +// description: Implementation of Kadane's algorithm for Maximum Subarray Sum +// reference: https://en.wikipedia.org/wiki/Maximum_subarray_problem +// time complexity: O(n) +// space complexity: O(1) + +package dynamic + +import "github.com/TheAlgorithms/Go/math/max" + +// MaxSubArraySum returns the sum of the maximum subarray in the input array +func MaxSubArraySum(nums []int) int { + maxSum := nums[0] + currentSum := nums[0] + + for i := 1; i < len(nums); i++ { + currentSum = max.Int(nums[i], currentSum+nums[i]) + maxSum = max.Int(maxSum, currentSum) + } + + return maxSum +} diff --git a/dynamic/maxsubarraysum_test.go b/dynamic/maxsubarraysum_test.go new file mode 100644 index 000000000..20492c3f7 --- /dev/null +++ b/dynamic/maxsubarraysum_test.go @@ -0,0 +1,37 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseMaxSubArraySum struct { + nums []int + expected int +} + +func getMaxSubArraySumTestCases() []testCaseMaxSubArraySum { + return []testCaseMaxSubArraySum{ + {[]int{-2, -3, 4, -1, -2, 1, 5, -3}, 7}, // Kadane's algorithm example + {[]int{-1, -2, -3, -4}, -1}, // All negative numbers, max single element + {[]int{5, 4, -1, 7, 8}, 23}, // Positive numbers with a large sum + {[]int{-2, 1, -3, 4, -1, 2, 1, -5, 4}, 6}, // Mixed with a maximum subarray of length 4 + {[]int{1, 2, 3, 4, 5}, 15}, // All positive numbers, sum is the entire array + {[]int{-1, -2, -3, -4, -5}, -1}, // Only negative numbers, largest single element + {[]int{0, 0, 0, 0, 0}, 0}, // Array of zeros, maximum subarray is zero + {[]int{3}, 3}, // Single positive number + {[]int{-1}, -1}, // Single negative number + } +} + +func TestMaxSubArraySum(t *testing.T) { + t.Run("Max SubArray Sum test cases", func(t *testing.T) { + for _, tc := range getMaxSubArraySumTestCases() { + actual := dynamic.MaxSubArraySum(tc.nums) + if actual != tc.expected { + t.Errorf("MaxSubArraySum(%v) = %v; expected %v", tc.nums, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/optimalbst.go b/dynamic/optimalbst.go new file mode 100644 index 000000000..b80f2163c --- /dev/null +++ b/dynamic/optimalbst.go @@ -0,0 +1,61 @@ +package dynamic + +import "github.com/TheAlgorithms/Go/math/min" + +// OptimalBST returns the minimum cost of constructing a Binary Search Tree +func OptimalBST(keys []int, freq []int, n int) int { + // Initialize DP table with size n x n + dp := make([][]int, n) + for i := range dp { + dp[i] = make([]int, n) + } + + // Base case: single key cost + for i := 0; i < n; i++ { + dp[i][i] = freq[i] + } + + // Build the DP table for sequences of length 2 to n + for length := 2; length <= n; length++ { + for i := 0; i < n-length+1; i++ { + j := i + length - 1 + dp[i][j] = int(^uint(0) >> 1) // Initialize with a large value + sum := sum(freq, i, j) + + // Try every key as root and compute cost + for k := i; k <= j; k++ { + // Left cost: dp[i][k-1] is valid only if k > i + var leftCost int + if k > i { + leftCost = dp[i][k-1] + } else { + leftCost = 0 + } + + // Right cost: dp[k+1][j] is valid only if k < j + var rightCost int + if k < j { + rightCost = dp[k+1][j] + } else { + rightCost = 0 + } + + // Total cost for root k + cost := sum + leftCost + rightCost + + // Update dp[i][j] with the minimum cost + dp[i][j] = min.Int(dp[i][j], cost) + } + } + } + return dp[0][n-1] +} + +// Helper function to sum the frequencies +func sum(freq []int, i, j int) int { + total := 0 + for k := i; k <= j; k++ { + total += freq[k] + } + return total +} diff --git a/dynamic/optimalbst_test.go b/dynamic/optimalbst_test.go new file mode 100644 index 000000000..362b45449 --- /dev/null +++ b/dynamic/optimalbst_test.go @@ -0,0 +1,35 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseOptimalBST struct { + keys []int + freq []int + n int + expected int +} + +func getOptimalBSTTestCases() []testCaseOptimalBST { + return []testCaseOptimalBST{ + {[]int{10, 12, 20}, []int{34, 8, 50}, 3, 142}, // Example with 3 keys + {[]int{10, 20, 30, 40, 50}, []int{10, 20, 30, 40, 50}, 5, 300}, // Example with 5 keys + {[]int{10}, []int{100}, 1, 100}, // Single key case + } +} + +func TestOptimalBST(t *testing.T) { + t.Run("Optimal Binary Search Tree test cases", func(t *testing.T) { + for _, tc := range getOptimalBSTTestCases() { + t.Run("testing optimal BST", func(t *testing.T) { + actual := dynamic.OptimalBST(tc.keys, tc.freq, tc.n) + if actual != tc.expected { + t.Errorf("OptimalBST(%v, %v, %d) = %d; expected %d", tc.keys, tc.freq, tc.n, actual, tc.expected) + } + }) + } + }) +} diff --git a/dynamic/partitionproblem.go b/dynamic/partitionproblem.go new file mode 100644 index 000000000..bb3ca5496 --- /dev/null +++ b/dynamic/partitionproblem.go @@ -0,0 +1,30 @@ +// partitionproblem.go +// description: Solves the Partition Problem using dynamic programming +// reference: https://en.wikipedia.org/wiki/Partition_problem +// time complexity: O(n*sum) +// space complexity: O(n*sum) + +package dynamic + +// PartitionProblem checks whether the given set can be partitioned into two subsets +// such that the sum of the elements in both subsets is the same. +func PartitionProblem(nums []int) bool { + sum := 0 + for _, num := range nums { + sum += num + } + if sum%2 != 0 { + return false + } + + target := sum / 2 + dp := make([]bool, target+1) + dp[0] = true + + for _, num := range nums { + for i := target; i >= num; i-- { + dp[i] = dp[i] || dp[i-num] + } + } + return dp[target] +} diff --git a/dynamic/partitionproblem_test.go b/dynamic/partitionproblem_test.go new file mode 100644 index 000000000..c85742ecf --- /dev/null +++ b/dynamic/partitionproblem_test.go @@ -0,0 +1,39 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +// testCasePartitionProblem holds the test cases for the Partition Problem +type testCasePartitionProblem struct { + nums []int + expected bool +} + +// getPartitionProblemTestCases returns a list of test cases for the Partition Problem +func getPartitionProblemTestCases() []testCasePartitionProblem { + return []testCasePartitionProblem{ + {[]int{1, 5, 11, 5}, true}, // Example with a partitionable set + {[]int{1, 2, 3, 5}, false}, // Example where partition is not possible + {[]int{1, 2, 5}, false}, // Set cannot be partitioned into two subsets + {[]int{2, 2, 2, 2}, true}, // Even split possible with equal elements + {[]int{7, 3, 2, 1}, false}, // Set cannot be partitioned + {[]int{}, true}, // Empty set, can be partitioned trivially + {[]int{1}, false}, // Single element, cannot be partitioned + {[]int{10, 10, 10, 10}, true}, // Equal elements, partitionable + } +} + +// TestPartitionProblem tests the PartitionProblem function with different test cases +func TestPartitionProblem(t *testing.T) { + t.Run("Partition Problem test cases", func(t *testing.T) { + for _, tc := range getPartitionProblemTestCases() { + actual := dynamic.PartitionProblem(tc.nums) + if actual != tc.expected { + t.Errorf("PartitionProblem(%v) = %v; expected %v", tc.nums, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/tilingproblem.go b/dynamic/tilingproblem.go new file mode 100644 index 000000000..0407f320d --- /dev/null +++ b/dynamic/tilingproblem.go @@ -0,0 +1,22 @@ +// tilingproblem.go +// description: Solves the Tiling Problem using dynamic programming +// reference: https://en.wikipedia.org/wiki/Tiling_problem +// time complexity: O(n) +// space complexity: O(n) + +package dynamic + +// TilingProblem returns the number of ways to tile a 2xN grid using 2x1 dominoes +func TilingProblem(n int) int { + if n <= 1 { + return 1 + } + dp := make([]int, n+1) + dp[0] = 1 + dp[1] = 1 + + for i := 2; i <= n; i++ { + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} diff --git a/dynamic/tilingproblem_test.go b/dynamic/tilingproblem_test.go new file mode 100644 index 000000000..4f103cd21 --- /dev/null +++ b/dynamic/tilingproblem_test.go @@ -0,0 +1,38 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseTilingProblem struct { + n int + expected int +} + +func getTilingProblemTestCases() []testCaseTilingProblem { + return []testCaseTilingProblem{ + {1, 1}, // Base case: 1 way to tile a 2x1 grid + {2, 2}, // 2 ways to tile a 2x2 grid + {3, 3}, // 3 ways to tile a 2x3 grid + {4, 5}, // 5 ways to tile a 2x4 grid + {5, 8}, // 8 ways to tile a 2x5 grid + {6, 13}, // 13 ways to tile a 2x6 grid + {10, 89}, // 89 ways to tile a 2x10 grid + {0, 1}, // Edge case: 1 way to tile a 2x0 grid (no tiles) + {7, 21}, // 21 ways to tile a 2x7 grid + {8, 34}, // 34 ways to tile a 2x8 grid + } +} + +func TestTilingProblem(t *testing.T) { + t.Run("Tiling Problem test cases", func(t *testing.T) { + for _, tc := range getTilingProblemTestCases() { + actual := dynamic.TilingProblem(tc.n) + if actual != tc.expected { + t.Errorf("TilingProblem(%d) = %d; expected %d", tc.n, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/wildcardmatching.go b/dynamic/wildcardmatching.go new file mode 100644 index 000000000..26b4530af --- /dev/null +++ b/dynamic/wildcardmatching.go @@ -0,0 +1,33 @@ +// wildcardmatching.go +// description: Solves the Wildcard Matching problem using dynamic programming +// reference: https://en.wikipedia.org/wiki/Wildcard_matching +// time complexity: O(m*n) +// space complexity: O(m*n) + +package dynamic + +// IsMatch checks if the string `s` matches the wildcard pattern `p` +func IsMatch(s, p string) bool { + dp := make([][]bool, len(s)+1) + for i := range dp { + dp[i] = make([]bool, len(p)+1) + } + + dp[0][0] = true + for j := 1; j <= len(p); j++ { + if p[j-1] == '*' { + dp[0][j] = dp[0][j-1] + } + } + + for i := 1; i <= len(s); i++ { + for j := 1; j <= len(p); j++ { + if p[j-1] == s[i-1] || p[j-1] == '?' { + dp[i][j] = dp[i-1][j-1] + } else if p[j-1] == '*' { + dp[i][j] = dp[i-1][j] || dp[i][j-1] + } + } + } + return dp[len(s)][len(p)] +} diff --git a/dynamic/wildcardmatching_test.go b/dynamic/wildcardmatching_test.go new file mode 100644 index 000000000..cc6cd4fde --- /dev/null +++ b/dynamic/wildcardmatching_test.go @@ -0,0 +1,44 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +// testCaseWildcardMatching holds the test cases for the Wildcard Matching problem +type testCaseWildcardMatching struct { + s string + p string + expected bool +} + +// getWildcardMatchingTestCases returns a list of test cases for the Wildcard Matching problem +func getWildcardMatchingTestCases() []testCaseWildcardMatching { + return []testCaseWildcardMatching{ + {"aa", "a*", true}, // '*' can match zero or more characters + {"aa", "a", false}, // No match due to no wildcard + {"ab", "?*", true}, // '?' matches any single character, '*' matches remaining + {"abcd", "a*d", true}, // '*' matches the characters between 'a' and 'd' + {"abcd", "a*c", false}, // No match as 'c' doesn't match the last character 'd' + {"abc", "*", true}, // '*' matches the entire string + {"abc", "a*c", true}, // '*' matches 'b' + {"abc", "a?c", true}, // '?' matches 'b' + {"abc", "a?d", false}, // '?' cannot match 'd' + {"", "", true}, // Both strings empty, so they match + {"a", "?", true}, // '?' matches any single character + {"a", "*", true}, // '*' matches any number of characters, including one + } +} + +// TestIsMatch tests the IsMatch function with various test cases +func TestIsMatch(t *testing.T) { + t.Run("Wildcard Matching test cases", func(t *testing.T) { + for _, tc := range getWildcardMatchingTestCases() { + actual := dynamic.IsMatch(tc.s, tc.p) + if actual != tc.expected { + t.Errorf("IsMatch(%q, %q) = %v; expected %v", tc.s, tc.p, actual, tc.expected) + } + } + }) +} diff --git a/dynamic/wordbreak.go b/dynamic/wordbreak.go new file mode 100644 index 000000000..6d7ad5d58 --- /dev/null +++ b/dynamic/wordbreak.go @@ -0,0 +1,28 @@ +// wordbreak.go +// description: Solves the Word Break Problem using dynamic programming +// reference: https://en.wikipedia.org/wiki/Word_break_problem +// time complexity: O(n^2) +// space complexity: O(n) + +package dynamic + +// WordBreak checks if the input string can be segmented into words from a dictionary +func WordBreak(s string, wordDict []string) bool { + wordSet := make(map[string]bool) + for _, word := range wordDict { + wordSet[word] = true + } + + dp := make([]bool, len(s)+1) + dp[0] = true + + for i := 1; i <= len(s); i++ { + for j := 0; j < i; j++ { + if dp[j] && wordSet[s[j:i]] { + dp[i] = true + break + } + } + } + return dp[len(s)] +} diff --git a/dynamic/wordbreak_test.go b/dynamic/wordbreak_test.go new file mode 100644 index 000000000..afcf62cb6 --- /dev/null +++ b/dynamic/wordbreak_test.go @@ -0,0 +1,40 @@ +package dynamic_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +type testCaseWordBreak struct { + s string + wordDict []string + expected bool +} + +func getWordBreakTestCases() []testCaseWordBreak { + return []testCaseWordBreak{ + {"leetcode", []string{"leet", "code"}, true}, // "leetcode" can be segmented into "leet" and "code" + {"applepenapple", []string{"apple", "pen"}, true}, // "applepenapple" can be segmented into "apple", "pen", "apple" + {"catsanddog", []string{"cats", "dog", "sand", "and", "cat"}, true}, // "catsanddog" can be segmented into "cats", "and", "dog" + {"bb", []string{"a", "b", "bbb", "aaaa", "aaa"}, true}, // "bb" can be segmented into "b" and "b" + {"", []string{"cat", "dog", "sand", "and"}, true}, // Empty string can always be segmented (empty words) + {"applepie", []string{"apple", "pie"}, true}, // "applepie" can be segmented into "apple" and "pie" + {"catsandog", []string{"cats", "dog", "sand", "and", "cat"}, false}, // "catsandog" cannot be segmented + {"ilovecoding", []string{"i", "love", "coding"}, true}, // "ilovecoding" can be segmented into "i", "love", "coding" + {"cars", []string{"car", "ca", "rs"}, true}, // "cars" can be segmented into "car" and "s" + {"pen", []string{"pen", "pencil"}, true}, // "pen" is a direct match + {"apple", []string{"orange", "banana"}, false}, // "apple" is not in the word dictionary + } +} + +func TestWordBreak(t *testing.T) { + t.Run("Word Break test cases", func(t *testing.T) { + for _, tc := range getWordBreakTestCases() { + actual := dynamic.WordBreak(tc.s, tc.wordDict) + if actual != tc.expected { + t.Errorf("WordBreak(%q, %v) = %v; expected %v", tc.s, tc.wordDict, actual, tc.expected) + } + } + }) +}

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%0DLnuBf$Q@v$;d>Ja_C;yAzuhBJZLe^45&z2=n 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 literal 0 HcmV?d00001 diff --git a/datastructures/linkedlist/cyclicallylinkedlist/Readme.md b/datastructures/linkedlist/cyclicallylinkedlist/Readme.md new file mode 100644 index 000000000..f42b63377 --- /dev/null +++ b/datastructures/linkedlist/cyclicallylinkedlist/Readme.md @@ -0,0 +1,12 @@ +# Linked Cyclic List +*** +## What is it? +*** +Loop lists are single or doubly-linked lists that chase their own tail: +A points to B, B points to C, C points to D, and D points to A. +They are better suited for cyclic data such as train schedules. +These lists are missing the first and last items. +Therefore, it is necessary to introduce the concept of the current position. + +This picture shows similar lists: +![Alt text](./Linked_Cyclic_List.jpg?raw=true) diff --git a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go b/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go new file mode 100644 index 000000000..454088c86 --- /dev/null +++ b/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go @@ -0,0 +1,144 @@ +// Package cyclicallylinkedlist demonstration of Linked List Cycle in golang + +package cyclicallylinkedlist + +import "fmt" + +// Node of List. +type ClNode struct { + Val interface{} + prev *ClNode + next *ClNode +} + +// The Cycling list in this implementation is addressed +// by means of the element located at the current position. +type ClList struct { + Size int + CurrentItem *ClNode +} + +// Create new list. +func NewList() *ClList { + return &ClList{0, nil} +} + +// Create new node. +func NewNode(val interface{}) *ClNode { + return &ClNode{val, nil, nil} +} + +// Inserting the first node is a special case. It will +// point to itself. For other cases, the node will be added +// to the end of the list. End of the list is prev field of +// current item. Complexity O(1). +func (cl *ClList) Add(val interface{}) { + n := NewNode(val) + cl.Size++ + if cl.CurrentItem == nil { + n.prev = n + n.next = n + cl.CurrentItem = n + } else { + n.prev = cl.CurrentItem.prev + n.next = cl.CurrentItem + cl.CurrentItem.prev.next = n + cl.CurrentItem.prev = n + } +} + +// Rotate list by P places. +// This method is interesting for optimization. +// For first optimization we must decrease +// P value so that it ranges from 0 to N-1. +// For this we need to use the operation of +// division modulo. But be careful if P is less than 0. +// if it is - make it positive. This can be done without +// violating the meaning of the number by adding to it +// a multiple of N. Now you can decrease P modulo N to +// rotate the list by the minimum number of places. +// We use the fact that moving forward in a circle by P +// places is the same as moving N - P places back. +// Therefore, if P > N / 2, you can turn the list by N-P places back. +// Complexity O(n). +func (cl *ClList) Rotate(places int) { + if cl.Size > 0 { + if places < 0 { + multiple := cl.Size - 1 - places/cl.Size + places += multiple * cl.Size + } + places %= cl.Size + + if places > cl.Size/2 { + places = cl.Size - places + for i := 0; i < places; i++ { + cl.CurrentItem = cl.CurrentItem.prev + } + } else if places == 0 { + return + } else { + for i := 0; i < places; i++ { + cl.CurrentItem = cl.CurrentItem.next + } + + } + } +} + +// Delete the current item. +func (cl *ClList) Delete() bool { + var deleted bool + var prevItem, thisItem, nextItem *ClNode + + if cl.Size == 0 { + return deleted + } + + deleted = true + thisItem = cl.CurrentItem + nextItem = thisItem.next + prevItem = thisItem.prev + + if cl.Size == 1 { + cl.CurrentItem = nil + } else { + cl.CurrentItem = nextItem + nextItem.prev = prevItem + prevItem.next = nextItem + } + cl.Size-- + + return deleted +} + +// Destroy all items in the list. +func (cl *ClList) Destroy() { + for cl.Delete() { + continue + } +} + +// Show list body. +func (cl *ClList) Walk() *ClNode { + var start *ClNode + start = cl.CurrentItem + + for i := 0; i < cl.Size; i++ { + fmt.Printf("%v \n", start.Val) + start = start.next + } + return start +} + +// https://en.wikipedia.org/wiki/Josephus_problem +// This is a struct-based solution for Josephus problem. +func JosephusProblem(cl *ClList, k int) int { + for cl.Size > 1 { + cl.Rotate(k) + cl.Delete() + cl.Rotate(-1) + } + retval := cl.CurrentItem.Val.(int) + cl.Destroy() + return retval +} diff --git a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go b/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go new file mode 100644 index 000000000..10eb1f88c --- /dev/null +++ b/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go @@ -0,0 +1,129 @@ +package cyclicallylinkedlist + +import ( + "reflect" + "testing" +) + +func fillList(list *ClList, n int) { + for i := 1; i <= n; i++ { + list.Add(i) + } +} + +func TestAdd(t *testing.T) { + list := NewList() + fillList(list, 3) + + want := []interface{}{1, 2, 3} + var got []interface{} + var start *ClNode + start = list.CurrentItem + + for i := 0; i < list.Size; i++ { + got = append(got, start.Val) + start = start.next + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got: %v, want: %v", got, want) + } +} + +func TestWalk(t *testing.T) { + list := NewList() + fillList(list, 3) + + want := 1 + got := list.Walk() + + if got.Val != want { + t.Errorf("got: %v, want: nil", got) + } +} + +func TestRotate(t *testing.T) { + type testCase struct { + param int + wantToReturn int + } + list := NewList() + fillList(list, 3) + + testCases := []testCase{ + {1, 2}, + {3, 2}, + {6, 2}, + {7, 3}, + {-2, 1}, + {5, 3}, + {8, 2}, + {-8, 3}, + } + for idx, tCase := range testCases { + list.Rotate(tCase.param) + got := list.CurrentItem.Val + if got != tCase.wantToReturn { + t.Errorf("got: %v, want: %v for test id %v", got, tCase.wantToReturn, idx) + } + } +} + +func TestDelete(t *testing.T) { + list := NewList() + fillList(list, 3) + + want := 2 + wantSize := 2 + list.Delete() + got := list.CurrentItem.Val + if want != got { + t.Errorf("got: %v, want: %v", got, want) + } + if wantSize != list.Size { + t.Errorf("got: %v, want: %v", got, want) + } +} + +func TestDestroy(t *testing.T) { + list := NewList() + fillList(list, 3) + wantSize := 0 + list.Destroy() + + got := list.CurrentItem + + if got != nil { + t.Errorf("got: %v, want: nil", got) + } + + if wantSize != list.Size { + t.Errorf("got: %v, want: %v", got, wantSize) + } +} + +func TestJosephusProblem(t *testing.T) { + type testCase struct { + param int + wantToReturn int + listCount int + } + + testCases := []testCase{ + {5, 4, 8}, + {3, 8, 8}, + {8, 5, 8}, + {8, 5, 8}, + {2, 14, 14}, + {13, 56, 58}, + {7, 5, 5}, + } + + for _, tCase := range testCases { + list := NewList() + fillList(list, tCase.listCount) + got := JosephusProblem(list, tCase.param) + if got != tCase.wantToReturn { + t.Errorf("got: %v, want: %v", got, tCase.wantToReturn) + } + } +} From afad8ff632a01d7eb44454ac6ec5f85ec15ff62f Mon Sep 17 00:00:00 2001 From: Taj Date: Sat, 4 Sep 2021 06:10:43 +0100 Subject: [PATCH 217/488] Fix: A few structural changes to the repository and added missing tests and fixed some failing tests (#325) * fix: RSA algorithm * fix: rename xor cipher directory for better readability * fix: sorting algorithms failing tests * fix: linting issues * fix: run gofmt * fix: linting issues * Update golang_lint_and_test.yml * Add Taj to CODEOWNERS --- .github/CODEOWNERS | 2 +- .github/workflows/golang_lint_and_test.yml | 3 +- README.md | 6 +- ciphers/rsa/rsa.go | 54 ++++ ciphers/rsa/rsa_test.go | 79 +++++ ciphers/rsa_cipher/rsacipher.go | 195 ------------ ciphers/rsa_cipher/rsacipher_test.go | 81 ----- .../{xor_cipher/xorcipher.go => xor/xor.go} | 0 .../xorcipher_test.go => xor/xor_test.go} | 0 data_structures/queue/queue_test.go | 52 ++- data_structures/queue/queuearray.go | 8 +- data_structures/queue/queuelinkedlist.go | 8 +- .../queue/queuelinklistwithlist.go | 7 +- data_structures/stack/stack_test.go | 60 ++-- data_structures/stack/stackarray.go | 6 +- data_structures/stack/stacklinkedlist.go | 1 - .../stack/stacklinkedlistwithlist.go | 4 +- genetic_algorithm/geneticalgorithm.go | 4 +- math/gcd/extended.go | 18 ++ math/gcd/extended_test.go | 29 ++ math/gcd/extendedgcd_test.go | 25 +- .../exponentiation.go} | 17 +- .../exponentiation_test.go} | 15 +- math/modular/inverse.go | 27 ++ math/modular/inverse_test.go | 29 ++ math/prime/millerrabinprimalitytest.go | 12 +- math/prime/millerrabinprimalitytest_test.go | 41 +++ math/prime/primecheck_test.go | 27 -- math/sieve/sieve.go | 22 ++ math/sieve/sieve_test.go | 18 ++ other/nested_brackets/nestedbrackets.go | 2 +- {sorts => sort}/bubblesort.go | 2 +- sort/doc.go | 2 + {sorts => sort}/heapsort.go | 3 +- {sorts => sort}/insertionsort.go | 3 +- {sorts => sort}/mergesort.go | 3 +- sort/quicksort.go | 33 ++ {sorts => sort}/radixsort.go | 5 +- {sorts => sort}/selectionsort.go | 3 +- {sorts => sort}/shellsort.go | 3 +- sort/sorts_test.go | 296 ++++++++++++++++++ sorts/quicksort.go | 26 -- sorts/sorts_test.go | 138 -------- sorts/sorts_testcases.go | 75 ----- 44 files changed, 770 insertions(+), 674 deletions(-) create mode 100644 ciphers/rsa/rsa.go create mode 100644 ciphers/rsa/rsa_test.go delete mode 100644 ciphers/rsa_cipher/rsacipher.go delete mode 100644 ciphers/rsa_cipher/rsacipher_test.go rename ciphers/{xor_cipher/xorcipher.go => xor/xor.go} (100%) rename ciphers/{xor_cipher/xorcipher_test.go => xor/xor_test.go} (100%) create mode 100644 math/gcd/extended.go create mode 100644 math/gcd/extended_test.go rename math/{modular_arithmetic/modularexponentiation.go => modular/exponentiation.go} (59%) rename math/{modular_arithmetic/modularexponentiation_test.go => modular/exponentiation_test.go} (82%) create mode 100644 math/modular/inverse.go create mode 100644 math/modular/inverse_test.go create mode 100644 math/prime/millerrabinprimalitytest_test.go rename {sorts => sort}/bubblesort.go (96%) create mode 100644 sort/doc.go rename {sorts => sort}/heapsort.go (92%) rename {sorts => sort}/insertionsort.go (79%) rename {sorts => sort}/mergesort.go (87%) create mode 100644 sort/quicksort.go rename {sorts => sort}/radixsort.go (96%) rename {sorts => sort}/selectionsort.go (73%) rename {sorts => sort}/shellsort.go (73%) create mode 100644 sort/sorts_test.go delete mode 100644 sorts/quicksort.go delete mode 100644 sorts/sorts_test.go delete mode 100644 sorts/sorts_testcases.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 496ff7a76..4a0788d2e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,5 +7,5 @@ # Order is important. The last matching pattern has the most precedence. -* @siriak @raklaptudirm +* @siriak @raklaptudirm @tjgurwara99 /.* @cclauss diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index 89c4193a2..f34210f85 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -15,5 +15,6 @@ jobs: # Required: the version of golangci-lint is required and must be # specified without patch version: we always use the latest patch version. # https://github.com/golangci/golangci-lint/releases - version: v1.39 + version: latest + args: -E gofmt - run: go test ./... diff --git a/README.md b/README.md index 06abef133..64f387fe2 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Diffie Hellman Key Exchange](./ciphers/diffie_hellman_key_exchange/) * [Polybius](./ciphers/polybius/) * [Rot13](./ciphers/rot13/) -* [Rsa Cipher](./ciphers/rsa_cipher/) -* [Xor Cipher](./ciphers/xor_cipher/) +* [Rsa](./ciphers/rsa/) +* [Xor](./ciphers/xor/) ## Conversions * [Roman To Integer](./conversions/roman_to_integer/) @@ -64,7 +64,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ## Math * [Gcd](./math/gcd/) * [Lcm](./math/lcm/) -* [Modular Arithmetic](./math/modular_arithmetic/) +* [Modular](./math/modular/) * [Permutation](./math/permutation/) * [Power](./math/power/) * [Prime](./math/prime/) diff --git a/ciphers/rsa/rsa.go b/ciphers/rsa/rsa.go new file mode 100644 index 000000000..44cf767b3 --- /dev/null +++ b/ciphers/rsa/rsa.go @@ -0,0 +1,54 @@ +// rsa.go +// description: Simple RSA algorithm implementation +// details: +// A simple RSA Encryption and Decryption algorithm. +// It uses prime numbers that fit in int64 datatypes and +// thus both the Encrypt and Decrypt are not a production +// ready implementation. The OpenSSL implementation of RSA +// also adds a padding which is not present in this algorithm. +// author(s) [Taj](https://github.com/tjgurwara99) +// see rsa_test.go + +// Package rsa shows a simple implementation of RSA algorithm +package rsa + +import ( + "errors" + + modular "github.com/TheAlgorithms/Go/math/modular" +) + +// ErrorFailedToEncrypt Raised when Encrypt function fails to encrypt the message +var ErrorFailedToEncrypt = errors.New("failed to Encrypt") + +// ErrorFailedToDecrypt Raised when Decrypt function fails to decrypt the encrypted message +var ErrorFailedToDecrypt = errors.New("failed to Decrypt") + +// Encrypt encrypts based on the RSA algorithm - uses modular exponentitation in math directory +func Encrypt(message []rune, publicExponent, modulus int64) ([]rune, error) { + var encrypted []rune + + for _, letter := range message { + encryptedLetter, err := modular.Exponentiation(int64(letter), publicExponent, modulus) + if err != nil { + return nil, ErrorFailedToEncrypt + } + encrypted = append(encrypted, rune(encryptedLetter)) + } + + return encrypted, nil +} + +// Decrypt decrypts encrypted rune slice based on the RSA algorithm +func Decrypt(encrypted []rune, privateExponent, modulus int64) (string, error) { + var decrypted []rune + + for _, letter := range encrypted { + decryptedLetter, err := modular.Exponentiation(int64(letter), privateExponent, modulus) + if err != nil { + return "", ErrorFailedToDecrypt + } + decrypted = append(decrypted, rune(decryptedLetter)) + } + return string(decrypted), nil +} diff --git a/ciphers/rsa/rsa_test.go b/ciphers/rsa/rsa_test.go new file mode 100644 index 000000000..daeb5d4d7 --- /dev/null +++ b/ciphers/rsa/rsa_test.go @@ -0,0 +1,79 @@ +// rsa_test.go +// description: Test for RSA Encrypt and Decrypt algorithms +// author(s) [Taj](https://github.com/tjgurwara99) +// see rsa.go + +package rsa + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/gcd" + "github.com/TheAlgorithms/Go/math/lcm" + "github.com/TheAlgorithms/Go/math/modular" +) + +var rsaTestData = []struct { + description string + input string +}{ + { + "Encrypt letter 'a'", + "a", + }, + { + "Encrypt 'hello world'", + "hello world", + }, + { + "Encrypt full sentence", + "the quick brown fox jumps over the lazy dog.", + }, + { + "Encrypt full sentence from rsacipher.go main function", + "I think RSA is really great", + }, +} + +func TestEncryptDecrypt(t *testing.T) { + // Both prime numbers + p := int64(61) + q := int64(53) + + n := p * q + + delta := lcm.Lcm(p-1, q-1) + + e := int64(17) // Coprime with delta + + if gcd.Recursive(e, delta) != 1 { + t.Fatal("Algorithm failed in preamble stage:\n\tPrime numbers are chosed statically and it shouldn't fail at this stage") + } + + d, err := modular.Inverse(e, delta) + + if err != nil { + t.Fatalf("Algorithm failed in preamble stage:\n\tProblem with a modular directory dependency: %v", err) + } + + for _, test := range rsaTestData { + t.Run(test.description, func(t *testing.T) { + + message := []rune(test.input) + encrypted, err := Encrypt(message, e, n) + if err != nil { + t.Fatalf("Failed to Encrypt test string:\n\tDescription: %v\n\tErrMessage: %v", test.description, err) + } + + decrypted, err := Decrypt(encrypted, d, n) + if err != nil { + t.Fatalf("Failed to Decrypt test message:\n\tDescription: %v\n\tErrMessage: %v", test.description, err) + } + + if actual := test.input; actual != decrypted { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expecting %v, actual %v", decrypted, actual) + } + }) + } +} diff --git a/ciphers/rsa_cipher/rsacipher.go b/ciphers/rsa_cipher/rsacipher.go deleted file mode 100644 index 145ca3e78..000000000 --- a/ciphers/rsa_cipher/rsacipher.go +++ /dev/null @@ -1,195 +0,0 @@ -package rsacipher - -import ( - "fmt" - "math" - "math/rand" - "strconv" - "strings" -) - -func generatePrimes(limit int) int { - /* - generate primes by factoring - relies on the 30k+i, though better formulae exist - where k >=0 and i = (1,7,11,13,17,13,19,23,29) - */ - primes := prime(limit) - var choice []int - choice = append(choice, 1, 7, 11, 13, 17, 19, 23, 29) - for { - k := rand.Intn(int(limit / 30)) - i := choice[rand.Intn(len(choice))] - c := 30*k + i - found := true - for _, v := range primes { - if c%v == 0 { - found = false - break - } - } - if found { - return c - } - } -} -func prime(limit int) (primes []int) { - sqrtLimit := int(math.Ceil(math.Sqrt(float64(limit)))) - exit := false - primes = append(primes, 2, 3, 5) - lastIndex := 2 - for primes[lastIndex] < sqrtLimit { - if exit { - break - } - for i := primes[lastIndex] + 2; i < primes[lastIndex]*primes[lastIndex]; i += 2 { - found := true - for _, v := range primes { - if i%v == 0 { - found = false - break - } - } - if found { - primes = append(primes, i) - lastIndex++ - if i >= sqrtLimit { - exit = true - break - } - } - - } - } - return -} -func lcm(a, b int) int { - //complexity depends on gcd - return int((a * b) / gcd(a, b)) - -} -func gcd(a, b int) int { - //complexity not clear - for b != 0 { - t := b - b = a % b - a = t - } - return a -} -func modularMultiplicativeInverse(e, delta int) int { - //runs in O(n) where n = delta - e = e % delta - for i := 1; i < delta; i++ { - if (i*e)%delta == 1 { - return i - } - } - return 0 -} - -func modularExponentiation(b, e, mod int) int { - //runs in O(log(n)) where n = e - if mod == 1 { - return 0 - } - r := 1 - b = b % mod - for e > 0 { - if e%2 == 1 { - r = (r * b) % mod - } - e = e >> 1 - b = (b * b) % mod - } - return r -} - -// EncryptRSA main encryption function for RSA -func EncryptRSA(message []int, e, n int) []int { - //runs in O(k*log(n)) where k = len(message) and n = e - var ciphertext []int - for _, v := range message { - ciphertext = append(ciphertext, modularExponentiation(v, e, n)) - } - return ciphertext -} - -// DecryptRSA main decryption function for RSA -func DecryptRSA(ciphertext []int, d, n int) []int { - //runs in O(k*log(n)) where k = len(ciphertext) and n = d - var message []int - for _, v := range ciphertext { - message = append(message, modularExponentiation(v, d, n)) - } - return message -} -func toASCII(slice []rune) []int { - //runs in O(n) where n = len(slice) - var converted []int - for _, v := range slice { - converted = append(converted, int(v)) - } - return converted -} - -// ToRune convert a string to rune -func ToRune(slice []int) string { - //runs in O(n) where n = len(slice) - // var str string - var str strings.Builder - for i, v := range slice { - if i != len(slice)-1 { - str.WriteString(fmt.Sprintf("%d ", v)) - } else { - str.WriteString(fmt.Sprint(v)) - } - - } - return str.String() -} - -// Compare ... Added for manual comparison but didn't work -func Compare(str string) []int { - a := strings.Split(str, " ") - fmt.Printf("%v", a) - var b []int - for _, v := range a { - temp, _ := strconv.Atoi(v) - b = append(b, temp) - } - return b -} - -// func main() { -// rand.Seed(time.Now().UTC().UnixNano()) -// bits := 17 - -// p := generatePrimes(1 << bits) -// q := generatePrimes(1 << bits) -// for p == q { -// q = generatePrimes(1 << bits) -// } - -// n := p * q - -// delta := lcm(p-1, q-1) - -// e := generatePrimes(delta) -// d := modularMultiplicativeInverse(e, delta) - -// fmt.Printf("%v \n%v \n%v \n%v\n", p, q, e, d) - -// str := "I think RSA is really great" -// message := []rune(str) -// asciiSlice := toASCII(message) - -// fmt.Printf("asciiSlice : %v \n", asciiSlice) -// encrypted := encryptRSA(asciiSlice, e, n) -// fmt.Printf("encrypted : %v \n", encrypted) -// decrypted := decryptRSA(encrypted, d, n) -// fmt.Printf("decrypted : %v \n", decrypted) -// fmt.Printf("cleartext : %v \n", toRune(decrypted)) -// //switched to atom - -// } diff --git a/ciphers/rsa_cipher/rsacipher_test.go b/ciphers/rsa_cipher/rsacipher_test.go deleted file mode 100644 index 3f98a495f..000000000 --- a/ciphers/rsa_cipher/rsacipher_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package rsacipher - -import ( - "math/rand" - "reflect" - "testing" - "time" -) - -var rsaTestData = []struct { - description string - input string -}{ - { - "Encrypt letter 'a'", - "a", - }, - { - "Encrypt 'hello world'", - "hello world", - }, - { - "Encrypt full sentence", - "the quick brown fox jumps over the lazy dog.", - }, - { - "Encrypt full sentence from rsacipher.go main function", - "I think RSA is really great", - }, -} - -func TestModularExponentiation(t *testing.T) { - t.Run("Test for modular exponentiation", func(t *testing.T) { - expected := 2 - actual := modularExponentiation(2, 5, 3) - if actual != expected { - t.Errorf("Actual: %d and Expected: %d", actual, expected) - } - }) - t.Run("Test 2 for modular exponentiation", func(t *testing.T) { - expected := 1099 - actual := modularExponentiation(200405, 5, 1342) - if actual != expected { - t.Errorf("Actual: %d and Expected: %d", actual, expected) - } - }) -} - -// This test is not consistent - consider commenting out until we find the problem -func TestRSACipher(t *testing.T) { - rand.Seed(time.Now().UTC().UnixNano()) - bits := 17 - - p := generatePrimes(1 << bits) - q := generatePrimes(1 << bits) - for p == q { - q = generatePrimes(1 << bits) - } - n := p * q - - delta := lcm(p-1, q-1) - - e := generatePrimes(delta) - d := modularMultiplicativeInverse(e, delta) - - for _, test := range rsaTestData { - t.Run(test.description, func(t *testing.T) { - - message := []rune(test.input) - expected := toASCII(message) - - encrypted := EncryptRSA(expected, e, n) - decrypted := DecryptRSA(encrypted, d, n) - - if actual := decrypted; !reflect.DeepEqual(actual, expected) { - t.Logf("FAIL: %s", test.description) - t.Fatalf("Expecting %v, actual %v", expected, ToRune(actual)) - } - }) - } -} diff --git a/ciphers/xor_cipher/xorcipher.go b/ciphers/xor/xor.go similarity index 100% rename from ciphers/xor_cipher/xorcipher.go rename to ciphers/xor/xor.go diff --git a/ciphers/xor_cipher/xorcipher_test.go b/ciphers/xor/xor_test.go similarity index 100% rename from ciphers/xor_cipher/xorcipher_test.go rename to ciphers/xor/xor_test.go diff --git a/data_structures/queue/queue_test.go b/data_structures/queue/queue_test.go index 0e20afe5c..469fede41 100644 --- a/data_structures/queue/queue_test.go +++ b/data_structures/queue/queue_test.go @@ -145,7 +145,6 @@ func TestQueue(t *testing.T) { }) - }) // Handle Queue Linked-List With Container/List (STL) @@ -154,101 +153,92 @@ func TestQueue(t *testing.T) { queue: list.New(), } - t.Run("List Enqueue", func(t *testing.T) { listQueue.Enqueue("Snap") listQueue.Enqueue(123) listQueue.Enqueue(true) listQueue.Enqueue(212.545454) - if listQueue.Len() != 4{ - t.Errorf("List Enqueue is not correct expected %d but got %d",4, listQueue.Len()) + if listQueue.Len() != 4 { + t.Errorf("List Enqueue is not correct expected %d but got %d", 4, listQueue.Len()) } }) - t.Run("List Dequeue", func(t *testing.T) { - err := listQueue.Dequeue() - if err != nil{ + if err != nil { t.Error("got an unexpected error ", err) } - if listQueue.Len() != 3{ - t.Errorf("List Dequeue is not correct expected %d but got %d",3, listQueue.Len()) + if listQueue.Len() != 3 { + t.Errorf("List Dequeue is not correct expected %d but got %d", 3, listQueue.Len()) } }) t.Run("List Front", func(t *testing.T) { - err := listQueue.Dequeue() - if err != nil{ + if err != nil { t.Error("got an unexpected error ", err) } - result , err := listQueue.Front() + result, err := listQueue.Front() - if err != nil{ + if err != nil { t.Error("got an unexpected error ", err) } - if result != true{ - t.Errorf("List Front is not correct expected %v but got %v",true, result) + if result != true { + t.Errorf("List Front is not correct expected %v but got %v", true, result) } }) t.Run("List Back", func(t *testing.T) { - - err := listQueue.Dequeue() - if err != nil{ + if err != nil { t.Error("got an unexpected error ", err) } - result , err := listQueue.Back() + result, err := listQueue.Back() - if err != nil{ + if err != nil { t.Error("got an unexpected error ", err) } - if result != 212.545454{ - t.Errorf("List Back is not correct expected %v but got %v",212.545454, result) + if result != 212.545454 { + t.Errorf("List Back is not correct expected %v but got %v", 212.545454, result) } }) - t.Run("List Length", func(t *testing.T) { listQueue.Enqueue("Snap") - err := listQueue.Dequeue() - if err != nil{ + if err != nil { t.Error("got an unexpected error ", err) } - if listQueue.Len() != 1{ - t.Errorf("List Length is not correct expected %v but got %v",1, listQueue.Len() ) + if listQueue.Len() != 1 { + t.Errorf("List Length is not correct expected %v but got %v", 1, listQueue.Len()) } }) - t.Run("List Empty", func(t *testing.T) { err := listQueue.Dequeue() - if err != nil{ + if err != nil { t.Error("got an unexpected error ", err) } - if !listQueue.Empty(){ - t.Errorf("List Empty is not correct expected %v but got %v",true, listQueue.Empty() ) + if !listQueue.Empty() { + t.Errorf("List Empty is not correct expected %v but got %v", true, listQueue.Empty()) } }) diff --git a/data_structures/queue/queuearray.go b/data_structures/queue/queuearray.go index 215e30159..27d0cf609 100644 --- a/data_structures/queue/queuearray.go +++ b/data_structures/queue/queuearray.go @@ -9,12 +9,10 @@ package queue - var ListQueue []interface{} - // EnQueue it will be added new value into our list -func EnQueue(n interface{}) { +func EnQueue(n interface{}) { ListQueue = append(ListQueue, n) } @@ -27,7 +25,7 @@ func DeQueue() interface{} { // FrontQueue return the Front value func FrontQueue() interface{} { - return ListQueue[0] + return ListQueue[0] } // BackQueue return the Back value @@ -43,4 +41,4 @@ func LenQueue() int { // IsEmptyQueue check our list is empty or not func IsEmptyQueue() bool { return len(ListQueue) == 0 -} \ No newline at end of file +} diff --git a/data_structures/queue/queuelinkedlist.go b/data_structures/queue/queuelinkedlist.go index c3935e33e..7c7dbc4d1 100644 --- a/data_structures/queue/queuelinkedlist.go +++ b/data_structures/queue/queuelinkedlist.go @@ -27,13 +27,13 @@ func (ll *Queue) enqueue(n interface{}) { var newNode Node // create new Node newNode.Data = n // set the data - if ll.tail != nil{ + if ll.tail != nil { ll.tail.Next = &newNode } ll.tail = &newNode - if ll.head == nil{ + if ll.head == nil { ll.head = &newNode } ll.length++ @@ -41,14 +41,14 @@ func (ll *Queue) enqueue(n interface{}) { // dequeue it will be removed the first value into queue (First In First Out) func (ll *Queue) dequeue() interface{} { - if ll.isEmpty(){ + if ll.isEmpty() { return -1 // if is empty return -1 } data := ll.head.Data ll.head = ll.head.Next - if ll.head == nil{ + if ll.head == nil { ll.tail = nil } diff --git a/data_structures/queue/queuelinklistwithlist.go b/data_structures/queue/queuelinklistwithlist.go index 3a0c9cb64..c1216c3a9 100644 --- a/data_structures/queue/queuelinklistwithlist.go +++ b/data_structures/queue/queuelinklistwithlist.go @@ -9,7 +9,6 @@ package queue - // container/list: is used as linked-list // fmt: used to return fmt.Errorf for the error part import ( @@ -27,7 +26,6 @@ func (lq *LQueue) Enqueue(value interface{}) { lq.queue.PushBack(value) } - // Dequeue will be removed the first value that input (First In First Out - FIFO) func (lq *LQueue) Dequeue() error { @@ -42,7 +40,7 @@ func (lq *LQueue) Dequeue() error { } // Front it will return the front value -func (lq *LQueue) Front() (interface{}, error) { +func (lq *LQueue) Front() (interface{}, error) { if !lq.Empty() { val := lq.queue.Front().Value return val, nil @@ -52,7 +50,7 @@ func (lq *LQueue) Front() (interface{}, error) { } // Back it will return the back value -func (lq *LQueue) Back() (interface{}, error) { +func (lq *LQueue) Back() (interface{}, error) { if !lq.Empty() { val := lq.queue.Back().Value return val, nil @@ -70,4 +68,3 @@ func (lq *LQueue) Len() int { func (lq *LQueue) Empty() bool { return lq.queue.Len() == 0 } - diff --git a/data_structures/stack/stack_test.go b/data_structures/stack/stack_test.go index d1e69750e..1e31dbc6b 100644 --- a/data_structures/stack/stack_test.go +++ b/data_structures/stack/stack_test.go @@ -16,7 +16,7 @@ import ( ) // TestStackLinkedList for testing Stack with LinkedList -func TestStackLinkedList(t *testing.T) { +func TestStackLinkedList(t *testing.T) { var newStack Stack newStack.push(1) @@ -24,25 +24,23 @@ func TestStackLinkedList(t *testing.T) { t.Run("Stack Push", func(t *testing.T) { result := newStack.show() - expected := []interface{}{2,1} - for x := range result{ - if result[x] != expected[x]{ + expected := []interface{}{2, 1} + for x := range result { + if result[x] != expected[x] { t.Errorf("Stack Push is not work, got %v but expected %v", result, expected) } } }) - t.Run("Stack isEmpty", func(t *testing.T) { - if newStack.isEmpty(){ + if newStack.isEmpty() { t.Error("Stack isEmpty is returned true but expected false", newStack.isEmpty()) } }) - t.Run("Stack Length", func(t *testing.T) { - if newStack.len() != 2{ + if newStack.len() != 2 { t.Error("Stack Length should be 2 but got", newStack.len()) } }) @@ -51,7 +49,7 @@ func TestStackLinkedList(t *testing.T) { pop := newStack.pop() t.Run("Stack Pop", func(t *testing.T) { - if pop != 1{ + if pop != 1 { t.Error("Stack Pop should return 1 but is returned", pop) } @@ -61,23 +59,22 @@ func TestStackLinkedList(t *testing.T) { newStack.push(23) newStack.push(99) t.Run("Stack Peak", func(t *testing.T) { - if newStack.peak() != 99{ + if newStack.peak() != 99 { t.Error("Stack Peak should return 99 but got ", newStack.peak()) } }) } - // TestStackArray for testing Stack with Array -func TestStackArray(t *testing.T) { +func TestStackArray(t *testing.T) { t.Run("Stack With Array", func(t *testing.T) { stackPush(2) stackPush(3) t.Run("Stack Push", func(t *testing.T) { - if !reflect.DeepEqual([]interface{}{3,2}, stackArray){ - t.Errorf("Stack Push is not work we expected %v but got %v", []interface{}{3,2}, stackArray) + if !reflect.DeepEqual([]interface{}{3, 2}, stackArray) { + t.Errorf("Stack Push is not work we expected %v but got %v", []interface{}{3, 2}, stackArray) } }) @@ -101,13 +98,13 @@ func TestStackArray(t *testing.T) { }) t.Run("Stack Length", func(t *testing.T) { - if stackLength() != 3{ + if stackLength() != 3 { t.Errorf("Stack Length is not work we expected %v but got %v", 3, stackLength()) } }) t.Run("Stack Empty", func(t *testing.T) { - if stackEmpty() == true{ + if stackEmpty() == true { t.Errorf("Stack Emtpy is not work we expected %v but got %v", false, stackEmpty()) } @@ -115,36 +112,29 @@ func TestStackArray(t *testing.T) { stackPop() stackPop() - if stackEmpty() == false{ + if stackEmpty() == false { t.Errorf("Stack Emtpy is not work we expected %v but got %v", true, stackEmpty()) } }) }) } - - - - - // TestStackLinkedListWithList for testing Stack with Container/List Library (STL) -func TestStackLinkedListWithList(t *testing.T) { +func TestStackLinkedListWithList(t *testing.T) { stackList := &SList{ stack: list.New(), } - t.Run("Stack Push", func(t *testing.T) { stackList.Push(2) stackList.Push(3) - if stackList.Length() != 2{ + if stackList.Length() != 2 { t.Errorf("Stack Push is not work we expected %v but got %v", 2, stackList.Length()) } }) - t.Run("Stack Pop", func(t *testing.T) { pop, _ := stackList.Pop() @@ -153,8 +143,6 @@ func TestStackLinkedListWithList(t *testing.T) { } }) - - t.Run("Stack Peak", func(t *testing.T) { stackList.Push(2) @@ -166,26 +154,26 @@ func TestStackLinkedListWithList(t *testing.T) { }) t.Run("Stack Length", func(t *testing.T) { - if stackList.Length() != 3{ + if stackList.Length() != 3 { t.Errorf("Stack Length is not work we expected %v but got %v", 3, stackList.Length()) } }) t.Run("Stack Empty", func(t *testing.T) { - if stackList.Empty() == true{ + if stackList.Empty() == true { t.Errorf("Stack Emtpy is not work we expected %v but got %v", false, stackList.Empty()) } - d1 , err := stackList.Pop() - d2 , _ := stackList.Pop() - d3 , _ := stackList.Pop() + d1, err := stackList.Pop() + d2, _ := stackList.Pop() + d3, _ := stackList.Pop() - if err != nil{ + if err != nil { t.Errorf("got an unexpected error %v, pop1: %v, pop2: %v, pop3: %v", err, d1, d2, d3) } - if stackList.Empty() == false{ + if stackList.Empty() == false { t.Errorf("Stack Emtpy is not work we expected %v but got %v", true, stackList.Empty()) } }) -} \ No newline at end of file +} diff --git a/data_structures/stack/stackarray.go b/data_structures/stack/stackarray.go index 300698d4b..197871cd6 100644 --- a/data_structures/stack/stackarray.go +++ b/data_structures/stack/stackarray.go @@ -17,7 +17,7 @@ func stackPush(n interface{}) { } // stackLength return length of array -func stackLength() int { +func stackLength() int { return len(stackArray) } @@ -27,7 +27,7 @@ func stackPeak() interface{} { } // stackEmpty check array is empty or not -func stackEmpty() bool { +func stackEmpty() bool { return len(stackArray) == 0 } @@ -36,4 +36,4 @@ func stackPop() interface{} { pop := stackArray[0] stackArray = stackArray[1:] return pop -} \ No newline at end of file +} diff --git a/data_structures/stack/stacklinkedlist.go b/data_structures/stack/stacklinkedlist.go index 42a9c611d..9148cc7ad 100644 --- a/data_structures/stack/stacklinkedlist.go +++ b/data_structures/stack/stacklinkedlist.go @@ -50,7 +50,6 @@ func (ll *Stack) isEmpty() bool { return ll.length == 0 } - // len use to return length of our stack func (ll *Stack) len() int { return ll.length diff --git a/data_structures/stack/stacklinkedlistwithlist.go b/data_structures/stack/stacklinkedlistwithlist.go index 599b02bf9..6afb778f8 100644 --- a/data_structures/stack/stacklinkedlistwithlist.go +++ b/data_structures/stack/stacklinkedlistwithlist.go @@ -20,7 +20,7 @@ type SList struct { } // Push add a value into our stack -func (sl *SList) Push(val interface{}) { +func (sl *SList) Push(val interface{}) { sl.stack.PushFront(val) } @@ -57,4 +57,4 @@ func (sl *SList) Empty() bool { // check our stack is empty or not // if is 0 it means our stack is empty otherwise is not empty return sl.stack.Len() == 0 -} \ No newline at end of file +} diff --git a/genetic_algorithm/geneticalgorithm.go b/genetic_algorithm/geneticalgorithm.go index 908483e49..ece11ff26 100644 --- a/genetic_algorithm/geneticalgorithm.go +++ b/genetic_algorithm/geneticalgorithm.go @@ -42,7 +42,7 @@ func geneticString(target string, charmap []rune) (int, int, string) { // Verify if 'populationNum' s bigger than 'selectionNum' if populationNum < selectionNum { - fmt.Println(errors.New("PopulationNum must be bigger tha selectionNum ")) + fmt.Println(errors.New("populationNum must be bigger than selectionNum")) os.Exit(1) } // Verify that the target contains no genes besides the ones inside genes variable. @@ -56,7 +56,7 @@ func geneticString(target string, charmap []rune) (int, int, string) { return false } if !find() { - fmt.Println(errors.New("Character not aviable in charmap"), position, "\"", string(r), "\"") + fmt.Println(errors.New("character not aviable in charmap"), position, "\"", string(r), "\"") os.Exit(1) } } diff --git a/math/gcd/extended.go b/math/gcd/extended.go new file mode 100644 index 000000000..eea32e9e9 --- /dev/null +++ b/math/gcd/extended.go @@ -0,0 +1,18 @@ +// extended.go +// description: Implementation of Extended GCD Algorithm +// details: +// A simple implementation of Extended GCD algorithm, that returns GCD, a and b +// which solves ax + by = gcd(a, b) +// author(s) [Taj](https://github.com/tjgurwara99) +// see extended_test.go + +package gcd + +// Extended simple extended gcd +func Extended(a, b int64) (int64, int64, int64) { + if a == 0 { + return b, 0, 1 + } + gcd, xPrime, yPrime := Extended(b%a, a) + return gcd, yPrime - (b/a)*xPrime, xPrime +} diff --git a/math/gcd/extended_test.go b/math/gcd/extended_test.go new file mode 100644 index 000000000..b87e927ae --- /dev/null +++ b/math/gcd/extended_test.go @@ -0,0 +1,29 @@ +// extended_test.go +// description: Test for Extended GCD algorithm in extended.go +// author(s) [Taj](https://github.com/tjgurwara99) +// see extended.go + +package gcd + +import "testing" + +func TestExtended(t *testing.T) { + var testCasesExtended = []struct { + name string + a int64 + b int64 + gcd int64 + x int64 + y int64 + }{ + {"gcd of 30 and 50", 30, 50, 10, 2, -1}, + } + for _, tc := range testCasesExtended { + t.Run(tc.name, func(t *testing.T) { + gcd, x, y := Extended(tc.a, tc.b) + if gcd != tc.gcd && x != tc.x && y != tc.y { + t.Fatalf("Expected values:\n\tGCD: Expected %v Returned %v,\n\tx: Expected %v Returned %v\n\ty: Expected %v Returned %v", tc.gcd, gcd, tc.x, x, tc.y, y) + } + }) + } +} diff --git a/math/gcd/extendedgcd_test.go b/math/gcd/extendedgcd_test.go index d967ad57c..f8fc2b820 100644 --- a/math/gcd/extendedgcd_test.go +++ b/math/gcd/extendedgcd_test.go @@ -4,20 +4,19 @@ import "testing" type testExtendedFunction func(int64, int64) (int64, int64, int64) -var testCasesExtended = []struct { - name string - a int64 - b int64 - gcd int64 - x int64 - y int64 -}{ - {"gcd of 10 and 0", 10, 0, 10, 1, 0}, - {"gcd of 98 and 56", 98, 56, 14, -1, 2}, - {"gcd of 0 and 10", 0, 10, 10, 0, 1}, -} - func TemplateTestExtendedGCD(t *testing.T, f testExtendedFunction) { + var testCasesExtended = []struct { + name string + a int64 + b int64 + gcd int64 + x int64 + y int64 + }{ + {"gcd of 10 and 0", 10, 0, 10, 1, 0}, + {"gcd of 98 and 56", 98, 56, 14, -1, 2}, + {"gcd of 0 and 10", 0, 10, 10, 0, 1}, + } for _, tc := range testCasesExtended { t.Run(tc.name, func(t *testing.T) { actualGcd, actualX, actualY := f(tc.a, tc.b) diff --git a/math/modular_arithmetic/modularexponentiation.go b/math/modular/exponentiation.go similarity index 59% rename from math/modular_arithmetic/modularexponentiation.go rename to math/modular/exponentiation.go index 3b374f6d4..f71a8d3ff 100644 --- a/math/modular_arithmetic/modularexponentiation.go +++ b/math/modular/exponentiation.go @@ -1,4 +1,11 @@ -package modular_arithmetic +// exponentiation.go +// description: Implementation of Modular Exponentiation Algorithm +// details: +// A simple implementation of Modular Exponentiation - [Modular Exponenetation wiki](https://en.wikipedia.org/wiki/Modular_exponentiation) +// author(s) [Taj](https://github.com/tjgurwara99) +// see exponentiation_test.go + +package modular import ( "errors" @@ -6,13 +13,13 @@ import ( ) // ErrorIntOverflow For asserting that the values do not overflow in Int64 -var ErrorIntOverflow = errors.New("Integer Overflow") +var ErrorIntOverflow = errors.New("integer overflow") // ErrorNegativeExponent for asserting that the exponent we receive is positive -var ErrorNegativeExponent = errors.New("Negative Exponent Provided") +var ErrorNegativeExponent = errors.New("negative Exponent provided") -// ModularExponentiation returns base^exponent % mod -func ModularExponentiation(base, exponent, mod int64) (int64, error) { +// Exponentiation returns base^exponent % mod +func Exponentiation(base, exponent, mod int64) (int64, error) { if mod == 1 { return 0, nil } diff --git a/math/modular_arithmetic/modularexponentiation_test.go b/math/modular/exponentiation_test.go similarity index 82% rename from math/modular_arithmetic/modularexponentiation_test.go rename to math/modular/exponentiation_test.go index 1726a3bfb..b5c8d4eb9 100644 --- a/math/modular_arithmetic/modularexponentiation_test.go +++ b/math/modular/exponentiation_test.go @@ -1,4 +1,9 @@ -package modular_arithmetic +// exponentiation_test.go +// description: Test for ModularExponentation +// author(s) [Taj](https://github.com/tjgurwara99) +// see exponentiation.go + +package modular import "testing" @@ -60,10 +65,10 @@ var testCases = []cases{ }, } -func TestModularExponentiation(t *testing.T) { +func TestExponentiation(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - result, err := ModularExponentiation(test.base, test.exponent, test.mod) + result, err := Exponentiation(test.base, test.exponent, test.mod) if err != test.expectedError { t.Logf("Test Failed for %s", test.name) t.Logf("Unexpected error occurred") @@ -77,8 +82,8 @@ func TestModularExponentiation(t *testing.T) { } } -func BenchmarkModularExponentiation(b *testing.B) { +func BenchmarkExponentiation(b *testing.B) { for i := 0; i < b.N; i++ { - _, _ = ModularExponentiation(17, 60, 23) + _, _ = Exponentiation(17, 60, 23) } } diff --git a/math/modular/inverse.go b/math/modular/inverse.go new file mode 100644 index 000000000..e0aa73b1a --- /dev/null +++ b/math/modular/inverse.go @@ -0,0 +1,27 @@ +// inverse.go +// description: Implementation of Modular Inverse Algorithm +// details: +// A simple implementation of Modular Inverse - [Modular Inverse wiki](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse) +// author(s) [Taj](https://github.com/tjgurwara99) +// see inverse_test.go + +package modular + +import ( + "errors" + + "github.com/TheAlgorithms/Go/math/gcd" +) + +// ErrorIntOverflow For asserting that the values do not overflow in Int64 +var ErrorInverse = errors.New("no Modular Inverse exists") + +// Inverse Modular function +func Inverse(a, b int64) (int64, error) { + gcd, x, _ := gcd.Extended(a, b) + if gcd != 1 { + return 0, ErrorInverse + } + + return ((b + (x % b)) % b), nil // this is necessary because of Go's use of architecture specific instruction for the % operator. +} diff --git a/math/modular/inverse_test.go b/math/modular/inverse_test.go new file mode 100644 index 000000000..e27166dbc --- /dev/null +++ b/math/modular/inverse_test.go @@ -0,0 +1,29 @@ +// inverse_test.go +// description: Test for Modular Inverse +// author(s) [Taj](https://github.com/tjgurwara99) +// see inverse.go + +package modular + +import "testing" + +func TestInverse(t *testing.T) { + t.Run("Testing a = 3 and m = 11: ", func(t *testing.T) { + inv, err := Inverse(3, 11) + if err != nil { + t.Fatalf("Error was raised when it shouldn't: %v", err) + } + if inv != 4 { + t.Fatalf("Test failed:\n\tExpected values: %v\n\tReturned value: %v", 4, inv) + } + }) + t.Run("Testing a = 10 and m = 17: ", func(t *testing.T) { + inv, err := Inverse(10, 17) + if err != nil { + t.Fatalf("Error was raised when it shouldn't: %v", err) + } + if inv != 12 { + t.Fatalf("Test failed:\n\tExpected values: %v\n\tReturned value: %v", 12, inv) + } + }) +} diff --git a/math/prime/millerrabinprimalitytest.go b/math/prime/millerrabinprimalitytest.go index 37ba9f48e..2b358774d 100644 --- a/math/prime/millerrabinprimalitytest.go +++ b/math/prime/millerrabinprimalitytest.go @@ -1,9 +1,17 @@ +// millerrabinprimalitytest.go +// description: An implementation of Miller-Rabin primality test +// details: +// A simple implementation of Miller-Rabin Primality Test +// [Miller-Rabin primality test Wiki](https://en.wikipedia.org/wiki/Miller–Rabin_primality_test) +// author(s) [Taj](https://github.com/tjgurwara99) +// see millerrabinprimalitytest_test.go + package prime import ( "math/rand" - "github.com/TheAlgorithms/Go/math/modular_arithmetic" + "github.com/TheAlgorithms/Go/math/modular" ) // findD accepts a number and returns the @@ -24,7 +32,7 @@ func findRD(num int64) (int64, int64) { func MillerTest(d, num int64) (bool, error) { random := rand.Int63n(num-1) + 2 - res, err := modular_arithmetic.ModularExponentiation(random, d, num) + res, err := modular.Exponentiation(random, d, num) if err != nil { return false, err diff --git a/math/prime/millerrabinprimalitytest_test.go b/math/prime/millerrabinprimalitytest_test.go new file mode 100644 index 000000000..0773b1149 --- /dev/null +++ b/math/prime/millerrabinprimalitytest_test.go @@ -0,0 +1,41 @@ +// millerrabinprimality_test.go +// description: Test for Miller-Rabin Primality Test +// author(s) [Taj](https://github.com/tjgurwara99) +// see millerrabinprimalitytest.go + +package prime + +import "testing" + +func TestMillerRabinTest(t *testing.T) { + var tests = []struct { + name string + input int64 + expected bool + rounds int64 + err error + }{ + {"smallest prime", 2, true, 5, nil}, + {"random prime", 3, true, 5, nil}, + {"neither prime nor composite", 1, false, 5, nil}, + {"random non-prime", 10, false, 5, nil}, + {"another random prime", 23, true, 5, nil}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + output, err := MillerRabinTest(test.input, test.rounds) + if err != test.err { + t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err) + } + if output != test.expected { + t.Errorf("For input: %d, expected: %v", test.input, output) + } + }) + } +} + +func BenchmarkMillerRabinPrimalityTest(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = MillerRabinTest(23, 5) + } +} diff --git a/math/prime/primecheck_test.go b/math/prime/primecheck_test.go index a8b835f5e..0cbe310f7 100644 --- a/math/prime/primecheck_test.go +++ b/math/prime/primecheck_test.go @@ -49,33 +49,6 @@ func TestTablePairApproach(t *testing.T) { } -func TestMillerRabinTest(t *testing.T) { - var tests = []struct { - name string - input int64 - expected bool - rounds int64 - err error - }{ - {"smallest prime", 2, true, 5, nil}, - {"random prime", 3, true, 5, nil}, - {"neither prime nor composite", 1, false, 5, nil}, - {"random non-prime", 10, false, 5, nil}, - {"another random prime", 23, true, 5, nil}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - output, err := MillerRabinTest(test.input, test.rounds) - if err != test.err { - t.Errorf("For input: %d, unexpected error: %v, expected error: %v", test.input, err, test.err) - } - if output != test.expected { - t.Errorf("For input: %d, expected: %v", test.input, output) - } - }) - } -} - func BenchmarkNaiveApproach(b *testing.B) { for i := 0; i < b.N; i++ { NaiveApproach(23) diff --git a/math/sieve/sieve.go b/math/sieve/sieve.go index 4e4b7facf..506c64216 100644 --- a/math/sieve/sieve.go +++ b/math/sieve/sieve.go @@ -1,3 +1,8 @@ +// sieve.go +// description: Algorithms for generating prime numbers efficiently +// author(s) [Taj](https://github.com/tjgurwara99) +// see sieve_test.go + package sieve // Generate generates the sequence of integers starting at 2 and sends it to the channel `ch` @@ -16,3 +21,20 @@ func Sieve(in <-chan int, out chan<- int, prime int) { } } } + +// GeneratePrimes returns a int slice of prime numbers up to the limit +func GeneratePrimes(limit int) []int { + var primes []int + + ch := make(chan int) + go Generate(ch) + + for i := 0; i < limit; i++ { + primes = append(primes, <-ch) + ch1 := make(chan int) + go Sieve(ch, ch1, primes[i]) + ch = ch1 + } + + return primes +} diff --git a/math/sieve/sieve_test.go b/math/sieve/sieve_test.go index 5e6664dab..e96f442b6 100644 --- a/math/sieve/sieve_test.go +++ b/math/sieve/sieve_test.go @@ -1,6 +1,12 @@ +// sieve_test.go +// description: Testing all the algorithms related to the generation of prime numbers in sieve.go +// author(s) [Taj](https://github.com/tjgurwara99) +// see sieve.go + package sieve import ( + "reflect" "testing" ) @@ -26,3 +32,15 @@ func TestSieve(t *testing.T) { }) } + +func TestGeneratePrimes(t *testing.T) { + firstTenPrimes := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} + + t.Run("Testing GeneratePrimes Function", func(t *testing.T) { + testPrimes := GeneratePrimes(10) + + if !reflect.DeepEqual(firstTenPrimes, testPrimes) { + t.Fatal("GeneratePrimes function failed") + } + }) +} diff --git a/other/nested_brackets/nestedbrackets.go b/other/nested_brackets/nestedbrackets.go index 5ec4e7cc1..b70ab2aa2 100644 --- a/other/nested_brackets/nestedbrackets.go +++ b/other/nested_brackets/nestedbrackets.go @@ -1,4 +1,4 @@ -// Package nested_brackets provides functions for testing +// Package nested_brackets provides functions for testing // strings propper brackets nesting. package nested_brackets diff --git a/sorts/bubblesort.go b/sort/bubblesort.go similarity index 96% rename from sorts/bubblesort.go rename to sort/bubblesort.go index 2a0244908..83242e5c5 100644 --- a/sorts/bubblesort.go +++ b/sort/bubblesort.go @@ -1,7 +1,7 @@ // Implementation of basic bubble sort algorithm // Reference: https://en.wikipedia.org/wiki/Bubble_sort -package sorts +package sort func bubbleSort(arr []int) []int { swapped := true diff --git a/sort/doc.go b/sort/doc.go new file mode 100644 index 000000000..aef1ff300 --- /dev/null +++ b/sort/doc.go @@ -0,0 +1,2 @@ +// Package sort a package for demonstrating sorting algorithms in Go +package sort diff --git a/sorts/heapsort.go b/sort/heapsort.go similarity index 92% rename from sorts/heapsort.go rename to sort/heapsort.go index e5ccadbca..698c7610f 100644 --- a/sorts/heapsort.go +++ b/sort/heapsort.go @@ -1,5 +1,4 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts +package sort type maxHeap struct { slice []int diff --git a/sorts/insertionsort.go b/sort/insertionsort.go similarity index 79% rename from sorts/insertionsort.go rename to sort/insertionsort.go index b036fc751..11f0cd922 100644 --- a/sorts/insertionsort.go +++ b/sort/insertionsort.go @@ -1,5 +1,4 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts +package sort func InsertionSort(arr []int) []int { for currentIndex := 1; currentIndex < len(arr); currentIndex++ { diff --git a/sorts/mergesort.go b/sort/mergesort.go similarity index 87% rename from sorts/mergesort.go rename to sort/mergesort.go index ef52e557a..a5b4e2a36 100644 --- a/sorts/mergesort.go +++ b/sort/mergesort.go @@ -1,5 +1,4 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts +package sort func merge(a []int, b []int) []int { diff --git a/sort/quicksort.go b/sort/quicksort.go new file mode 100644 index 000000000..9db6c23bd --- /dev/null +++ b/sort/quicksort.go @@ -0,0 +1,33 @@ +// quicksort.go +// description: Implementation of in-place quicksort algorithm +// details: +// A simple in-place quicksort algorithm implementation. [Wikipedia](https://en.wikipedia.org/wiki/Quicksort) +// author(s) [Taj](https://github.com/tjgurwara99) +// see sort_test.go for a test implementation, test function TestQuickSort. + +package sort + +func partition(arr []int, low, high int) int { + index := low - 1 + pivotElement := arr[high] + for i := low; i < high; i++ { + if arr[i] <= pivotElement { + index += 1 + arr[index], arr[i] = arr[i], arr[index] + } + } + arr[index+1], arr[high] = arr[high], arr[index+1] + return index + 1 +} + +func QuickSort(arr []int, low, high int) { + if len(arr) <= 1 { + return + } + + if low < high { + pivot := partition(arr, low, high) + QuickSort(arr, low, pivot-1) + QuickSort(arr, pivot+1, high) + } +} diff --git a/sorts/radixsort.go b/sort/radixsort.go similarity index 96% rename from sorts/radixsort.go rename to sort/radixsort.go index 163678218..c499d1a76 100644 --- a/sorts/radixsort.go +++ b/sort/radixsort.go @@ -1,4 +1,4 @@ -package sorts +package sort func max(arr []int) int { max := arr[0] @@ -41,6 +41,9 @@ func unsignedRadixSort(arr []int) []int { } func RadixSort(arr []int) []int { + if len(arr) < 1 { + return arr + } var negatives, nonNegatives []int for _, item := range arr { diff --git a/sorts/selectionsort.go b/sort/selectionsort.go similarity index 73% rename from sorts/selectionsort.go rename to sort/selectionsort.go index 997f3b6cb..95fd4ffa1 100644 --- a/sorts/selectionsort.go +++ b/sort/selectionsort.go @@ -1,5 +1,4 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts +package sort func SelectionSort(arr []int) []int { diff --git a/sorts/shellsort.go b/sort/shellsort.go similarity index 73% rename from sorts/shellsort.go rename to sort/shellsort.go index 81e16b911..28f76dcae 100644 --- a/sorts/shellsort.go +++ b/sort/shellsort.go @@ -1,5 +1,4 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts +package sort func ShellSort(arr []int) []int { for d := int(len(arr) / 2); d > 0; d /= 2 { diff --git a/sort/sorts_test.go b/sort/sorts_test.go new file mode 100644 index 000000000..ba55bf5f7 --- /dev/null +++ b/sort/sorts_test.go @@ -0,0 +1,296 @@ +package sort + +import ( + "reflect" + "testing" +) + +func testFramework(t *testing.T, sortingFunction func([]int) []int) { + sortTests := []struct { + input []int + expected []int + name string + }{ + //Sorted slice + { + input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Sorted Unsigned", + }, + //Reversed slice + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Unsigned", + }, + + //Sorted slice + { + input: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Sorted Signed", + }, + + //Reversed slice + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Signed", + }, + + //Reversed slice, even length + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Signed #2", + }, + + //Random order with repetitions + { + input: []int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, + name: "Random order Signed", + }, + //Single-entry slice + { + input: []int{1}, + expected: []int{1}, + name: "Singleton", + }, + { + input: []int{}, + expected: []int{}, + name: "Empty Slice", + }, + } + for _, test := range sortTests { + t.Run(test.name, func(t *testing.T) { + actual := sortingFunction(test.input) + sorted := reflect.DeepEqual(actual, test.expected) + if !sorted { + t.Errorf("test %s failed", test.name) + t.Errorf("actual %v expected %v", actual, test.expected) + } + }) + } +} + +//BEGIN TESTS + +func TestBubble(t *testing.T) { + testFramework(t, bubbleSort) +} + +func TestInsertion(t *testing.T) { + testFramework(t, InsertionSort) +} + +func TestMerge(t *testing.T) { + testFramework(t, Mergesort) +} + +func TestHeap(t *testing.T) { + testFramework(t, HeapSort) +} + +func TestQuick(t *testing.T) { + testCases := []struct { + input []int + expected []int + name string + }{ + //Sorted slice + { + input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Sorted Unsigned", + }, + //Reversed slice + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Unsigned", + }, + + //Sorted slice + { + input: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Sorted Signed", + }, + + //Reversed slice + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Signed", + }, + + //Reversed slice, even length + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Signed #2", + }, + + //Random order with repetitions + { + input: []int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, + name: "Random order Signed", + }, + //Single-entry slice + { + input: []int{1}, + expected: []int{1}, + name: "Singleton", + }, + { + input: []int{}, + expected: []int{}, + name: "Empty Slice", + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + QuickSort(test.input, 0, len(test.input)-1) + if !reflect.DeepEqual(test.input, test.expected) { + t.Errorf("test %s failed", test.name) + t.Errorf("actual %v expected %v", test.input, test.expected) + } + }) + } + +} + +func TestShell(t *testing.T) { + testFramework(t, ShellSort) +} + +func TestRadix(t *testing.T) { + testFramework(t, RadixSort) +} + +// Very slow, consider commenting +// func TestSelection(t *testing.T) { +// testFramework(t, SelectionSort) +// } + +/* func TestTopological(t *testing.T) { +testFramework(t, topologicalSort) +} */ + +//END TESTS + +func benchmarkFramework(b *testing.B, f func(arr []int) []int) { + var sortTests = []struct { + input []int + expected []int + name string + }{ + //Sorted slice + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, + //Reversed slice + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, + + //Sorted slice + {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, + + //Reversed slice + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, + + //Reversed slice, even length + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, + + //Random order with repetitions + {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, + + //Empty slice + {[]int{}, []int{}, "Empty"}, + //Single-entry slice + {[]int{1}, []int{1}, "Singleton"}, + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, test := range sortTests { + f(test.input) + } + } +} +func BenchmarkBubble(b *testing.B) { + benchmarkFramework(b, bubbleSort) +} + +func BenchmarkInsertion(b *testing.B) { + benchmarkFramework(b, InsertionSort) +} + +func BenchmarkMerge(b *testing.B) { + benchmarkFramework(b, Mergesort) +} + +func BenchmarkHeap(b *testing.B) { + benchmarkFramework(b, HeapSort) +} + +func BenchmarkQuick(b *testing.B) { + var sortTests = []struct { + input []int + expected []int + name string + }{ + //Sorted slice + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, + //Reversed slice + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, + + //Sorted slice + {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, + + //Reversed slice + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, + + //Reversed slice, even length + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, + + //Random order with repetitions + {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, + + //Empty slice + {[]int{}, []int{}, "Empty"}, + //Single-entry slice + {[]int{1}, []int{1}, "Singleton"}, + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, test := range sortTests { + QuickSort(test.input, 0, len(test.input)-1) + } + } +} + +func BenchmarkShell(b *testing.B) { + benchmarkFramework(b, ShellSort) +} + +func BenchmarkRadix(b *testing.B) { + benchmarkFramework(b, RadixSort) +} + +// Very Slow, consider commenting +func BenchmarkSelection(b *testing.B) { + benchmarkFramework(b, SelectionSort) +} diff --git a/sorts/quicksort.go b/sorts/quicksort.go deleted file mode 100644 index 6cb73e5b5..000000000 --- a/sorts/quicksort.go +++ /dev/null @@ -1,26 +0,0 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts - -func QuickSort(array []int) []int { - if len(array) <= 1 { - return array - } - q := partition(array) - QuickSort(array[:q]) - QuickSort(array[q+1:]) - return array -} - -func partition(array []int) int { - r := len(array) - 1 - x := array[r] // last element of slice - i := -1 - for j := 0; j < r; j++ { - if array[j] <= x { - i++ - array[i], array[j] = array[j], array[i] - } - } - array[i+1], array[r] = array[r], array[i+1] - return i + 1 -} diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go deleted file mode 100644 index f93949132..000000000 --- a/sorts/sorts_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package sorts - -import ( - "testing" -) - -func testFramework(t *testing.T, sortingFunction func([]int) []int) { - for _, test := range sortTests { - t.Run(test.name, func(t *testing.T) { - actual := sortingFunction(test.input) - pos, sorted := compareSlices(actual, test.expected) - if !sorted { - if pos == -1 { - t.Errorf("test %s failed due to slice length changing", test.name) - } - t.Errorf("test %s failed at index %d", test.name, pos) - } - }) - } -} - -//BEGIN TESTS - -func TestBubble(t *testing.T) { - testFramework(t, bubbleSort) -} - -func TestInsertion(t *testing.T) { - testFramework(t, InsertionSort) -} - -func TestMerge(t *testing.T) { - testFramework(t, Mergesort) -} - -func TestHeap(t *testing.T) { - testFramework(t, HeapSort) -} - -func TestQuick(t *testing.T) { - testFramework(t, QuickSort) -} - -func TestShell(t *testing.T) { - testFramework(t, ShellSort) -} - -func TestRadix(t *testing.T) { - testFramework(t, RadixSort) -} - -// Very slow, consider commenting -// func TestSelection(t *testing.T) { -// testFramework(t, SelectionSort) -// } - -/* func TestTopological(t *testing.T) { - testFramework(t, topologicalSort) -} */ - -//END TESTS - -func BenchmarkBubble(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - bubbleSort(test.input) - } - } -} - -func BenchmarkInsertion(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - InsertionSort(test.input) - } - } -} - -func BenchmarkMerge(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - Mergesort(test.input) - } - } -} - -func BenchmarkHeap(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - HeapSort(test.input) - } - } -} - -func BenchmarkQuick(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - QuickSort(test.input) - } - } -} - -func BenchmarkShell(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - ShellSort(test.input) - } - } -} - -func BenchmarkRadix(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - RadixSort(test.input) - } - } -} - -// Very Slow, consider commenting -func BenchmarkSelection(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - SelectionSort(test.input) - } - } -} - -func compareSlices(a []int, b []int) (int, bool) { - if len(a) != len(b) { - return -1, false - } - for pos := range a { - if a[pos] != b[pos] { - return pos, false - } - } - return -1, true -} diff --git a/sorts/sorts_testcases.go b/sorts/sorts_testcases.go deleted file mode 100644 index 56550cee9..000000000 --- a/sorts/sorts_testcases.go +++ /dev/null @@ -1,75 +0,0 @@ -//Package sorts a package for demonstrating sorting algorithms in Go -package sorts - -import ( - "crypto/rand" - "math/big" - "sort" -) - -type sortTest struct { - input []int - expected []int - name string -} - -var uarr []int = makeRandomUnsignedSlice(500_000) -var arr []int = makeRandomSignedSlice(500_000) - -var sortTests = []sortTest{ - //Sorted slice - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, - //Reversed slice - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, - //500k unsigned int values sort - {uarr, getSortedVersion(uarr), "Large Random Unsigned"}, - - //Sorted slice - {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, - - //Reversed slice - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, - - //Reversed slice, even length - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, - - //Random order with repetitions - {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, - - //500k int values sort - {arr, getSortedVersion(arr), "Large Random Signed"}, - - //Empty slice - {[]int{}, []int{}, "Empty"}, - //Single-entry slice - {[]int{1}, []int{1}, "Singleton"}, -} - -func makeRandomUnsignedSlice(size int) []int { - vals := make([]int, size) - for i := 0; i < size; i++ { - temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size))) - vals[i] = int(temp.Int64()) - } - return vals -} - -func makeRandomSignedSlice(size int) []int { - vals := make([]int, size) - for i := 0; i < size; i++ { - temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size))) - vals[i] = int(temp.Int64()) - 250_000 - } - return vals -} - -func getSortedVersion(a []int) []int { - sort.Slice(a, func(i, j int) bool { return a[i] < a[j] }) - return a -} From 69bca29f463de2eb4d54c9677e32f391619949f0 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 4 Sep 2021 11:07:48 +0200 Subject: [PATCH 218/488] golang_lint_and_test.yml: Remove out-of-date comments (#332) --- .github/workflows/golang_lint_and_test.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index f34210f85..5ad79ff72 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -12,9 +12,6 @@ jobs: - run: go version - uses: golangci/golangci-lint-action@v2 with: - # Required: the version of golangci-lint is required and must be - # specified without patch version: we always use the latest patch version. - # https://github.com/golangci/golangci-lint/releases version: latest args: -E gofmt - run: go test ./... From f37786a95af51365f010af5a4beb28a26fb7d839 Mon Sep 17 00:00:00 2001 From: liyl <30368453+yaolin-Li@users.noreply.github.com> Date: Sun, 5 Sep 2021 17:20:46 +0800 Subject: [PATCH 219/488] Update some functions in the btree directory (#334) Co-authored-by: Yaolin_Li <1586505611@qq.com> Co-authored-by: Andrii Siriak Co-authored-by: Rak Laptudirm --- .../binary_tree/binarysearchtree.go | 53 +++++++++---------- data_structures/binary_tree/binarytree.go | 40 +++++++++----- data_structures/binary_tree/btree.go | 29 ++++++++++ 3 files changed, 81 insertions(+), 41 deletions(-) diff --git a/data_structures/binary_tree/binarysearchtree.go b/data_structures/binary_tree/binarysearchtree.go index f43893657..dde09d99d 100644 --- a/data_structures/binary_tree/binarysearchtree.go +++ b/data_structures/binary_tree/binarysearchtree.go @@ -8,31 +8,30 @@ package binarytree // ) // func main() { -// t := &BTree{nil} -// InOrder(t.root) -// t.root = Insert(t.root, 30) - -// t.root = Insert(t.root, 20) -// t.root = Insert(t.root, 15) -// t.root = Insert(t.root, 10) -// t.root = Insert(t.root, 12) -// t.root = Insert(t.root, 9) -// t.root = Insert(t.root, 11) -// t.root = Insert(t.root, 17) -// fmt.Print(t.depth(), "\n") -// InOrder(t.root) -// fmt.Print("\n") -// t.root = BstDelete(t.root, 10) -// InOrder(t.root) -// fmt.Print("\n") -// t.root = BstDelete(t.root, 30) -// InOrder(t.root) -// fmt.Print("\n") -// t.root = BstDelete(t.root, 15) -// InOrder(t.root) -// fmt.Print("\n") -// t.root = BstDelete(t.root, 20) -// InOrder(t.root) -// fmt.Print("\n") -// fmt.Print(t.depth(), "\n") +//t := &BTree{nil} +//InOrder(t.Root) +//t.Root = Insert(t.Root, 30) +//t.Root = Insert(t.Root, 20) +//t.Root = Insert(t.Root, 15) +//t.Root = Insert(t.Root, 10) +//t.Root = Insert(t.Root, 12) +//t.Root = Insert(t.Root, 9) +//t.Root = Insert(t.Root, 11) +//t.Root = Insert(t.Root, 17) +//fmt.Print(t.Depth(), "\n") +//InOrder(t.Root) +//fmt.Print("\n") +//t.Root = BstDelete(t.Root, 10) +//InOrder(t.Root) +//fmt.Print("\n") +//t.Root = BstDelete(t.Root, 30) +//InOrder(t.Root) +//fmt.Print("\n") +//t.Root = BstDelete(t.Root, 15) +//InOrder(t.Root) +//fmt.Print("\n") +//t.Root = BstDelete(t.Root, 20) +//InOrder(t.Root) +//fmt.Print("\n") +//fmt.Print(t.Depth(), "\n") // } diff --git a/data_structures/binary_tree/binarytree.go b/data_structures/binary_tree/binarytree.go index 003b89ba7..4eeca8da9 100644 --- a/data_structures/binary_tree/binarytree.go +++ b/data_structures/binary_tree/binarytree.go @@ -3,24 +3,36 @@ package binarytree /* func main() { - t := btree{nil} - t.root = newNode(0) - t.root.left = newNode(1) - t.root.right = newNode(2) - t.root.left.left = newNode(3) - t.root.left.right = newNode(4) - t.root.right.left = newNode(5) - t.root.right.right = newNode(6) - t.root.right.right.right = newNode(10) + t := BTree{nil} + t.Root = NewNode(0) + t.Root.left = NewNode(1) + t.Root.right = NewNode(2) + t.Root.left.left = NewNode(3) + t.Root.left.right = NewNode(4) + t.Root.right.left = NewNode(5) + t.Root.right.right = NewNode(6) + t.Root.right.right.right = NewNode(10) - inorder(t.root) + InOrder(t.Root) fmt.Print("\n") - preorder(t.root) + PreOrder(t.Root) fmt.Print("\n") - postorder(t.root) + PostOrder(t.Root) fmt.Print("\n") - levelorder(t.root) + LevelOrder(t.Root) fmt.Print("\n") - fmt.Print(t.depth(), "\n") + fmt.Print(t.Depth(), "\n") + var list = AccessNodesByLayer(t.Root) + fmt.Println("{") + for i, v := range list { + for _, v2 := range v { + fmt.Print(" [", v2, "]") + } + if i != len(list)-1 { + fmt.Print(",") + } + fmt.Println() + } + fmt.Println("}") } */ diff --git a/data_structures/binary_tree/btree.go b/data_structures/binary_tree/btree.go index 51c2aec5e..7345814ef 100644 --- a/data_structures/binary_tree/btree.go +++ b/data_structures/binary_tree/btree.go @@ -116,6 +116,35 @@ func LevelOrder(root *Node) { } } +// AccessNodesByLayer Function that access nodes layer by layer instead of printing the results as one line. +func AccessNodesByLayer(root *Node) [][]int { + var res [][]int + if root == nil { + return res + } + var q []*Node + var n *Node + var idx = 0 + q = append(q, root) + + for len(q) != 0 { + res = append(res, []int{}) + qLen := len(q) + for i := 0; i < qLen; i++ { + n, q = q[0], q[1:] + res[idx] = append(res[idx], n.val) + if n.left != nil { + q = append(q, n.left) + } + if n.right != nil { + q = append(q, n.right) + } + } + idx++ + } + return res +} + // Max Function that returns max of two numbers - possibly already declared. func Max(a, b int) int { if a > b { From c3de81ff3da882f35d7dd4570be8a44aa9896b81 Mon Sep 17 00:00:00 2001 From: Vitaly Tikhoplav <62797411+tikhoplav@users.noreply.github.com> Date: Mon, 6 Sep 2021 08:34:16 +0300 Subject: [PATCH 220/488] doc, test: genetic algorithm (#338) --- genetic_algorithm/geneticalgorithm.go | 148 +++++++++++++-------- genetic_algorithm/geneticalgorithm_test.go | 25 ++++ 2 files changed, 119 insertions(+), 54 deletions(-) create mode 100644 genetic_algorithm/geneticalgorithm_test.go diff --git a/genetic_algorithm/geneticalgorithm.go b/genetic_algorithm/geneticalgorithm.go index ece11ff26..0651f4318 100644 --- a/genetic_algorithm/geneticalgorithm.go +++ b/genetic_algorithm/geneticalgorithm.go @@ -1,75 +1,122 @@ -/* -Simple multithreaded algorithm to show how the 4 phases of a genetic -algorithm works (Evaluation, Selection, Crossover and Mutation) -https://en.wikipedia.org/wiki/Genetic_algorithm - -Link to the same algorithm implemented in python: -https://github.com/TheAlgorithms/Python/blob/master/genetic_algorithm/basic_string.py - -Author: D4rkia -*/ - -package main +// package geneticalgorithm provides functions to work with strings +// using genetic algorithm. https://en.wikipedia.org/wiki/Genetic_algorithm +// +// Author: D4rkia +package geneticalgorithm import ( "errors" "fmt" "math/rand" - "os" "sort" "strconv" "time" "unicode/utf8" ) -type populationItem struct { +// Population item represent a single step in the evolution process. +// One can think of ppopulation item as a single species. +// Key stands for the actual data entity of the species, which is a string +// in current implementation. Key can be interpreted as species DNA. +// Value shows how close this species to the desired target, where 1 means, +// that species DNA equals to the targeted one, 0 for no mathings in the DNA. +// +// **Note** In the current implementation species DNA lenght is suppose to be +// equal to the target length for algorithm to work. +type PopulationItem struct { Key string Value float64 } -func geneticString(target string, charmap []rune) (int, int, string) { - // Define parameters - // Maximum size of the population. bigger could be faster but is more memory expensive - populationNum := 200 - // Number of elements selected in every generation for evolution the selection takes - // place from the best to the worst of that generation must be smaller than N_POPULATION - selectionNum := 50 - // Probability that an element of a generation can mutate changing one of its genes this - // guarantees that all genes will be used during evolution - mutationProb := .4 - // Just a seed to improve randomness required by the algorithm - rand.Seed(time.Now().UnixNano()) +// Conf stands for cofigurations set provided to GeneticString function. +type Conf struct { + // Maximum size of the population. + // Bigger could be faster but more memory expensive. + PopulationNum int + + // Number of elements selected in every generation for evolution + // the selection takes. Place from the best to the worst of that + // generation must be smaller than PopulationNum. + SelectionNum int + + // Probability that an element of a generation can mutate changing one of + // its genes this guarantees that all genes will be used during evolution. + MutationProb float64 + + // Enables debugging output to the console. + Debug bool +} + +// Result structure contains generation process statistics, as well as the +// best resulted population item. +type Result struct { + // Number of generations steps performed. + Generation int + + // Number of generated population items. + Analyzed int + + // Result of generation with the best Value. + Best PopulationItem +} + +// GenerateString generates PopultaionItem based on the imputed target +// string, and a set of possible runes to build a string with. In order +// to optimise string generation additional configurations can be provided +// with Conf instance. Empty instance of Conf (&Conf{}) can be provided, +// then default values would be set. +// +// Link to the same algorithm implemented in python: +// https://github.com/TheAlgorithms/Python/blob/master/genetic_algorithm/basic_string.py +func GeneticString(target string, charmap []rune, conf *Conf) (*Result, error) { + populationNum := conf.PopulationNum + if populationNum == 0 { + populationNum = 200 + } + + selectionNum := conf.SelectionNum + if selectionNum == 0 { + selectionNum = 50 + } // Verify if 'populationNum' s bigger than 'selectionNum' if populationNum < selectionNum { - fmt.Println(errors.New("populationNum must be bigger than selectionNum")) - os.Exit(1) + return nil, errors.New("populationNum must be bigger than selectionNum") } + + mutationProb := conf.MutationProb + if mutationProb == .0 { + mutationProb = .4 + } + + debug := conf.Debug + + // Just a seed to improve randomness required by the algorithm + rand.Seed(time.Now().UnixNano()) + // Verify that the target contains no genes besides the ones inside genes variable. - for position, r := range []rune(target) { - find := func() bool { - for _, n := range charmap { - if n == r { - return true - } + for position, r := range target { + invalid := true + for _, n := range charmap { + if n == r { + invalid = false } - return false } - if !find() { - fmt.Println(errors.New("character not aviable in charmap"), position, "\"", string(r), "\"") - os.Exit(1) + if invalid { + message := fmt.Sprintf("character not aviable in charmap at position: %v", position) + return nil, errors.New(message) } } // Generate random starting population - pop := make([]populationItem, populationNum) + pop := make([]PopulationItem, populationNum) for i := 0; i < populationNum; i++ { key := "" for x := 0; x < utf8.RuneCountInString(target); x++ { choice := rand.Intn(len(charmap)) key += string(charmap[choice]) } - pop[i] = populationItem{key, 0} + pop[i] = PopulationItem{key, 0} } // Just some logs to know what the algorithms is doing @@ -97,15 +144,16 @@ func geneticString(target string, charmap []rune) (int, int, string) { if pop[0].Key == target { break } + // Print the best resultPrint the Best result every 10 generations // just to know that the algorithm is working - if gen%10 == 0 { + if debug && gen%10 == 0 { fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", pop[0]) } // Generate a new population vector keeping some of the best evolutions // Keeping this avoid regression of evolution - var popChildren []populationItem + var popChildren []PopulationItem popChildren = append(popChildren, pop[0:int(selectionNum/3)]...) // This is Selection @@ -122,7 +170,7 @@ func geneticString(target string, charmap []rune) (int, int, string) { split := rand.Intn(utf8.RuneCountInString(target)) child1 := append([]rune(parent1.Key)[:split], []rune(parent2.Key)[split:]...) child2 := append([]rune(parent2.Key)[:split], []rune(parent1.Key)[split:]...) - //Clean fitness value + // Clean fitness value // Mutate if rand.Float64() < mutationProb { child1[rand.Intn(len(child1))] = charmap[rand.Intn(len(charmap))] @@ -131,8 +179,8 @@ func geneticString(target string, charmap []rune) (int, int, string) { child2[rand.Intn(len(child2))] = charmap[rand.Intn(len(charmap))] } // Push into 'popChildren' - popChildren = append(popChildren, populationItem{string(child1), 0}) - popChildren = append(popChildren, populationItem{string(child2), 0}) + popChildren = append(popChildren, PopulationItem{string(child1), 0}) + popChildren = append(popChildren, PopulationItem{string(child2), 0}) // Check if the population has already reached the maximum value and if so, // break the cycle. If this check is disabled the algorithm will take @@ -145,13 +193,5 @@ func geneticString(target string, charmap []rune) (int, int, string) { } pop = popChildren } - return gen, generatedPop, pop[0].Key -} - -func main() { - // Define parameters - target := string("This is a genetic algorithm to evaluate, combine, evolve and mutate a string!") - charmap := []rune(" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,;!?+-*#@^'èéòà€ù=)(&%$£/\\") - gen, generatedPop, best := geneticString(target, charmap) - fmt.Println("Generation:", strconv.Itoa(gen), "Analyzed:", generatedPop, "Best:", best) + return &Result{gen, generatedPop, pop[0]}, nil } diff --git a/genetic_algorithm/geneticalgorithm_test.go b/genetic_algorithm/geneticalgorithm_test.go new file mode 100644 index 000000000..a57463963 --- /dev/null +++ b/genetic_algorithm/geneticalgorithm_test.go @@ -0,0 +1,25 @@ +package geneticalgorithm + +import ( + "testing" +) + +func TestSimple(t *testing.T) { + target := "This is a genetic algorithm to evaluate, combine, evolve and mutate a string!" + charmap := []rune(" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,;!?+-*#@^'èéòà€ù=)(&%$£/\\") + + res, err := GeneticString(target, charmap, &Conf{}) + if err != nil { + t.Errorf("Unexpected error: %v\n", err) + } + + got := res.Best + + if got.Value != float64(1.0) { + t.Errorf("Target value not reached\nwant: %f\n, got: %f\n", float64(1.0), got.Value) + } + + if got.Key != target { + t.Errorf("Target string not reached\nwant: %s\n, got: %s\n", target, got.Key) + } +} From e498a6961aab59a3f2bc091c06779cde84e41830 Mon Sep 17 00:00:00 2001 From: Pritam Singh <43764373+Zzocker@users.noreply.github.com> Date: Mon, 6 Sep 2021 15:35:18 +0530 Subject: [PATCH 221/488] chore: add AVL tree (#297) * adding AVL tree Signed-off-by: Zzocker * updating go.mod with assert pkg Signed-off-by: Zzocker * removed assert pkg dep Signed-off-by: Zzocker * exported delete function Signed-off-by: Zzocker * ds: add AVL tree Signed-off-by: Pritam Singh Co-authored-by: Andrii Siriak --- data_structures/avl/avl.go | 220 +++++++++++++++++++++++++ data_structures/avl/avl_test.go | 277 ++++++++++++++++++++++++++++++++ 2 files changed, 497 insertions(+) create mode 100644 data_structures/avl/avl.go create mode 100644 data_structures/avl/avl_test.go diff --git a/data_structures/avl/avl.go b/data_structures/avl/avl.go new file mode 100644 index 000000000..bdb17c81f --- /dev/null +++ b/data_structures/avl/avl.go @@ -0,0 +1,220 @@ +// Package avl is a Adelson-Velskii and Landis tree implemnation +// avl is self-balancing tree, i.e for all node in a tree, height difference +// between its left and right child will not exceed 1 +// more information : https://en.wikipedia.org/wiki/AVL_tree +package avl + +// Node of a tree +type Node struct { + Key int + Height int + Left, Right *Node +} + +// NewTree create a new AVL tree +func NewTree() *Node { + return nil +} + +// Get : return node with given key +func Get(root *Node, key int) *Node { + if root == nil { + return nil + } + if root.Key == key { + return root + } else if root.Key < key { + root = root.Right + } else { + root = root.Left + } + return Get(root, key) +} + +// Insert a new item +func Insert(root **Node, key int) { + if *root == nil { + *root = &Node{ + Key: key, + Height: 1, + } + return + } + if (*root).Key < key { + Insert(&(*root).Right, key) + } else if (*root).Key > key { + Insert(&(*root).Left, key) + } + + // update height + (*root).Height = height(*root) + + bFactor := balanceFactor(*root) + + if bFactor == 2 { // L + bFactor = balanceFactor((*root).Left) + if bFactor == 1 { // LL + llRotation(root) + } else if bFactor == -1 { // LR + lrRotation(root) + } + } else if bFactor == -2 { // R + bFactor = balanceFactor((*root).Right) + if bFactor == 1 { // RL + rlRotation(root) + } else if bFactor == -1 { // RR + rrRotation(root) + } + } +} + +// Delete : remove given key from the tree +func Delete(root **Node, key int) { + if root == nil { + return + } + if (*root).Key < key { + Delete(&(*root).Right, key) + } else if (*root).Key > key { + Delete(&(*root).Left, key) + } else { + // 3 cases + // 1. No Child + // 2. With One Child + // 3. With Two Child + if (*root).Left == nil && (*root).Right == nil { + *root = nil + } else if (*root).Left == nil { + *root = (*root).Right + } else if (*root).Right == nil { + *root = (*root).Left + } else { + minVal := min((*root).Right) + (*root).Key = minVal + Delete(root, minVal) + } + return + } + + // update height + (*root).Height = height(*root) + + bFactor := balanceFactor(*root) + + if bFactor == 2 { // L + switch balanceFactor((*root).Left) { + case 1: // LL + llRotation(root) + case -1: // LR + lrRotation(root) + case 0: // LL OR LR + llRotation(root) + } + } else if bFactor == -2 { // L + switch balanceFactor((*root).Right) { + case 1: // RL + rlRotation(root) + case -1: // RR + rrRotation(root) + case 0: // RL OR RR + rrRotation(root) + } + } +} + +// rotations +// 1. LL +// 2. LR +// 3. RR +// 4. RL +func llRotation(root **Node) { + b := (*root).Left + br := b.Right + b.Right = *root + (*root).Left = br + (*root).Height = height(*root) + b.Height = height(b) + *root = b +} +func lrRotation(root **Node) { + c := (*root).Left.Right + cl := c.Left + cr := c.Right + + c.Left = (*root).Left + c.Right = (*root) + c.Left.Right = cl + + (*root).Left = cr + + (*root).Height = height(*root) + c.Left.Height = height(c.Left) + c.Height = height(c) + + *root = c + +} +func rrRotation(root **Node) { + b := (*root).Right + bl := b.Left + b.Left = *root + + (*root).Right = bl + (*root).Height = height(*root) + b.Height = height(b) + *root = b + +} +func rlRotation(root **Node) { + c := (*root).Right.Left + cl := c.Left + cr := c.Right + + c.Right = (*root).Right + c.Right.Left = cr + c.Left = *root + (*root).Right = cl + + (*root).Height = height(*root) + c.Right.Height = height(c.Right) + c.Height = height(c) + *root = c +} + +// balanceFactor : -ve balance factor means subtree root is heavy toward left +// and +ve balance factor means subtree root is heavy toward right side +func balanceFactor(root *Node) int { + var leftHeight, rightHeight int + if root.Left != nil { + leftHeight = root.Left.Height + } + if root.Right != nil { + rightHeight = root.Right.Height + } + return leftHeight - rightHeight +} + +func height(root *Node) int { + if root == nil { + return 0 + } + var leftHeight, rightHeight int + if root.Left != nil { + leftHeight = root.Left.Height + } + if root.Right != nil { + rightHeight = root.Right.Height + } + max := leftHeight + if rightHeight > leftHeight { + max = rightHeight + } + return 1 + max +} + +func min(root *Node) int { + if root.Left == nil { + return root.Key + } + return min(root.Left) +} diff --git a/data_structures/avl/avl_test.go b/data_structures/avl/avl_test.go new file mode 100644 index 000000000..199d008e7 --- /dev/null +++ b/data_structures/avl/avl_test.go @@ -0,0 +1,277 @@ +package avl + +import ( + "testing" +) + +func TestInsert(t *testing.T) { + t.Run("LLRotaion-Test", func(t *testing.T) { + root := NewTree() + Insert(&root, 5) + Insert(&root, 4) + Insert(&root, 3) + + if root.Key != 4 { + t.Errorf("root should have value = 4") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + + }) + t.Run("LRRotaion-Test", func(t *testing.T) { + root := NewTree() + Insert(&root, 5) + Insert(&root, 3) + Insert(&root, 4) + + if root.Key != 4 { + t.Errorf("root should have value = 4") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + }) + + t.Run("RRRotaion-Test", func(t *testing.T) { + root := NewTree() + Insert(&root, 3) + Insert(&root, 4) + Insert(&root, 5) + + if root.Key != 4 { + t.Errorf("root should have value = 4") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + }) + t.Run("RLRotaion-Test", func(t *testing.T) { + root := NewTree() + Insert(&root, 3) + Insert(&root, 5) + Insert(&root, 4) + + if root.Key != 4 { + t.Errorf("root should have value = 4") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + }) +} + +func TestDelete(t *testing.T) { + t.Run("LLRotaion-Test", func(t *testing.T) { + root := NewTree() + + Insert(&root, 5) + Insert(&root, 4) + Insert(&root, 3) + Insert(&root, 2) + + Delete(&root, 5) + + if root.Key != 3 { + t.Errorf("root should have value = 3") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 2 { + t.Errorf("left child should have value = 2") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 4 { + t.Errorf("right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + }) + + t.Run("LRRotaion-Test", func(t *testing.T) { + root := NewTree() + + Insert(&root, 10) + Insert(&root, 8) + Insert(&root, 6) + Insert(&root, 7) + + Delete(&root, 10) + + if root.Key != 7 { + t.Errorf("root should have value = 7") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 6 { + t.Errorf("left child should have value = 6") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 8 { + t.Errorf("right child should have value = 8") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + + }) + + t.Run("RRRotaion-Test", func(t *testing.T) { + root := NewTree() + + Insert(&root, 2) + Insert(&root, 3) + Insert(&root, 4) + Insert(&root, 5) + + Delete(&root, 2) + + if root.Key != 4 { + t.Errorf("root should have value = 4") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 3 { + t.Errorf("left child should have value = 3") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 5 { + t.Errorf("right child should have value = 5") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + + }) + + t.Run("RLRotaion-Test", func(t *testing.T) { + root := NewTree() + + Insert(&root, 7) + Insert(&root, 6) + Insert(&root, 9) + Insert(&root, 8) + + Delete(&root, 6) + + if root.Key != 8 { + t.Errorf("root should have value = 8") + } + if root.Height != 2 { + t.Errorf("height of root should be = 2") + } + + if root.Left.Key != 7 { + t.Errorf("left child should have value = 7") + } + if root.Left.Height != 1 { + t.Errorf("height of left child should be 1") + } + + if root.Right.Key != 9 { + t.Errorf("right child should have value = 9") + } + if root.Right.Height != 1 { + t.Errorf("height of right should be 1") + } + + }) +} + +func TestGet(t *testing.T) { + + root := NewTree() + + if Get(root, 5) != nil { + t.Error("no item should exists in newly created AVL tree") + } + + Insert(&root, 5) + Insert(&root, 4) + Insert(&root, 3) + + n := Get(root, 4) + if n.Key != 4 { + t.Error("key should be 4") + } + if n.Right.Key != 5 { + t.Error("right child should have value 5") + } + + if n.Left.Key != 3 { + t.Error("left child should have value 3") + } + +} From 5ac0bd5719c60713ff73a5b1ef8c40b075a78d1a Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Tue, 7 Sep 2021 02:38:00 -0300 Subject: [PATCH 222/488] Correct types in caesar.go (#331) Co-authored-by: Andrii Siriak --- ciphers/caesar/caesar.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ciphers/caesar/caesar.go b/ciphers/caesar/caesar.go index 902f9c114..21da4f5a9 100644 --- a/ciphers/caesar/caesar.go +++ b/ciphers/caesar/caesar.go @@ -6,15 +6,16 @@ package caesar func Encrypt(input string, key int) string { // if key is negative value, // updates "key" the number which congruents to "key" modulo 26 - key = (key%26 + 26) % 26 + key8 := byte(key%26+26) % 26 - outputBuffer := []byte{} + var outputBuffer []byte + // r is a rune, which is the equivalent of uint32. for _, r := range input { newByte := byte(r) - if 'A' <= newByte && newByte <= 'Z' { - outputBuffer = append(outputBuffer, byte(int('A')+int(int(newByte-'A')+key)%26)) - } else if 'a' <= newByte && newByte <= 'z' { - outputBuffer = append(outputBuffer, byte(int('a')+int(int(newByte-'a')+key)%26)) + if 'A' <= r && r <= 'Z' { + outputBuffer = append(outputBuffer, 'A'+(newByte-'A'+key8)%26) + } else if 'a' <= r && r <= 'z' { + outputBuffer = append(outputBuffer, 'a'+(newByte-'a'+key8)%26) } else { outputBuffer = append(outputBuffer, newByte) } From 59b98b82a5ccc5682a949bfc2c15a13805db0568 Mon Sep 17 00:00:00 2001 From: Taj Date: Tue, 7 Sep 2021 11:44:53 +0100 Subject: [PATCH 223/488] fix: change directory structure to idiomatic go directory structure (#333) * fix: restructured directory structure * fix: minor name changes and updated README.md in linkedlist package * fix: cleanup of commented out code * fix: trying to fix alert caused by the password generator in 'other' directory * fix: golintci errors * fix: removed the montecarlopi algorithm which was implemented in a non testable way and was commented out * fix: restructured search math and strings subpackage * fix: removed commented out files Co-authored-by: Andrii Siriak --- .../diffiehellmankeyexchange.go | 4 +- .../diffiehellmankeyexchange_test.go | 2 +- ciphers/xor/xor.go | 4 +- ciphers/xor/xor_test.go | 2 +- .../{roman_to_integer => }/romantointeger.go | 0 .../romantointeger_test.go | 0 .../binary_tree/binarysearchtree.go | 37 -- data_structures/binary_tree/binarytree.go | 38 --- .../doubly_linkedlist/doublylinkedlist.go | 168 --------- .../singly_linkedlist/singly_linkedlist2.go | 104 ------ .../linkedlist/cyclicallylinkedlist/Readme.md | 12 - .../binomialcoefficient.go | 2 +- {dynamic_programming => dynamic}/fibonacci.go | 2 +- .../fibonacci_test.go | 2 +- {dynamic_programming => dynamic}/knapsack.go | 2 +- .../longestcommonsubsequence.go | 2 +- .../longestpalindromicsubsequence.go | 2 +- .../matrixmultiplication.go | 2 +- .../rodcutting.go | 2 +- .../geneticalgorithm.go => genetic/genetic.go | 6 +- .../geneticalgorithm_test.go | 2 +- .../breadthfirstsearch.go | 17 +- .../breadthfirstsearch_test.go | 2 +- .../depthfirstsearch.go | 4 +- .../floyd_warshall => graph}/floydwarshall.go | 2 +- math/{sieve => prime}/sieve.go | 10 +- math/{sieve => prime}/sieve_test.go | 6 +- .../maxsubarraysum.go | 2 +- other/monte_carlo_pi/montecarlopi.go | 50 --- other/monte_carlo_pi/montecarlopi_test.go | 16 - .../nestedbrackets.go | 2 +- .../nestedbrackets_test.go | 2 +- other/password/generator.go | 45 +++ other/password_generator/passwordgenerator.go | 53 --- .../binarysearch.go => search/binary.go | 14 +- search/binary_test.go | 23 ++ .../interpolation.go | 27 +- search/interpolation_test.go | 12 + search/linear.go | 11 + search/linear_test.go | 14 + .../testcases.go | 17 +- searches/binary_search/binarysearch_test.go | 42 --- .../interpolation_search_test.go | 31 -- searches/linear_search/linearsearch.go | 11 - strings/ahocorasick/advancedahocorasick.go | 82 +++++ .../advancedahocorasick_test.go} | 19 +- strings/ahocorasick/ahocorasick.go | 77 +++++ strings/ahocorasick/ahocorasick_test.go | 37 ++ .../patterns.txt | 0 strings/ahocorasick/shared.go | 139 ++++++++ .../text.txt | 0 .../{single_string_matching => }/bom/bom.go | 0 .../combination/combination.go | 8 +- .../horspool/horspool.go | 0 .../{single_string_matching => }/kmp/kmp.go | 0 .../kmp/kmp_test.go | 0 .../levenshteindistance.go | 6 +- .../levenshteindistance_test.go | 4 +- .../advancedahocorasick.go | 318 ------------------ .../advancedahocorasick_test.go | 83 ----- .../aho_corasick/ahocorasick.go | 303 ----------------- .../patternsearch.go} | 4 +- .../patternsearch_test.go} | 6 +- strings/single_string_matching/pattern.txt | 1 - strings/single_string_matching/text.txt | 1 - {data_structures => structure}/avl/avl.go | 0 .../avl/avl_test.go | 0 .../binarytree}/btree.go | 0 .../binarytree}/node.go | 0 .../dynamicarray}/dynamicarray.go | 63 ++-- .../dynamicarray}/dynamicarray_test.go | 2 - .../hashmap/hashmap.go | 0 .../hashmap/hashmap_test.go | 0 .../linkedlist}/Linked_Cyclic_List.jpg | Bin structure/linkedlist/Readme.md | 27 ++ .../linkedlist/cyclic.go | 87 ++--- .../linkedlist/cyclic_test.go | 28 +- structure/linkedlist/doc.go | 2 + structure/linkedlist/doubly.go | 142 ++++++++ .../linkedlist/doubly_test.go | 38 +-- structure/linkedlist/shared.go | 14 + .../linkedlist}/singlylinkedlist.go | 43 +-- .../linkedlist}/singlylinkedlist_test.go | 6 +- .../queue/queue_test.go | 0 .../queue/queuearray.go | 0 .../queue/queuelinkedlist.go | 0 .../queue/queuelinklistwithlist.go | 0 {data_structures => structure}/set/set.go | 0 .../stack/stack_test.go | 0 .../stack/stackarray.go | 0 .../stack/stacklinkedlist.go | 0 .../stack/stacklinkedlistwithlist.go | 0 {data_structures => structure}/trie/trie.go | 0 .../trie/trie_test.go | 0 94 files changed, 822 insertions(+), 1526 deletions(-) rename ciphers/{diffie_hellman_key_exchange => diffiehellman}/diffiehellmankeyexchange.go (89%) rename ciphers/{diffie_hellman_key_exchange => diffiehellman}/diffiehellmankeyexchange_test.go (97%) rename conversions/{roman_to_integer => }/romantointeger.go (100%) rename conversions/{roman_to_integer => }/romantointeger_test.go (100%) delete mode 100644 data_structures/binary_tree/binarysearchtree.go delete mode 100644 data_structures/binary_tree/binarytree.go delete mode 100644 data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go delete mode 100644 data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go delete mode 100644 datastructures/linkedlist/cyclicallylinkedlist/Readme.md rename {dynamic_programming => dynamic}/binomialcoefficient.go (96%) rename {dynamic_programming => dynamic}/fibonacci.go (92%) rename {dynamic_programming => dynamic}/fibonacci_test.go (96%) rename {dynamic_programming => dynamic}/knapsack.go (96%) rename {dynamic_programming => dynamic}/longestcommonsubsequence.go (97%) rename {dynamic_programming => dynamic}/longestpalindromicsubsequence.go (97%) rename {dynamic_programming => dynamic}/matrixmultiplication.go (97%) rename {dynamic_programming => dynamic}/rodcutting.go (97%) rename genetic_algorithm/geneticalgorithm.go => genetic/genetic.go (97%) rename {genetic_algorithm => genetic}/geneticalgorithm_test.go (96%) rename {graphs/breadth_first_search => graph}/breadthfirstsearch.go (53%) rename {graphs/breadth_first_search => graph}/breadthfirstsearch_test.go (98%) rename {graphs/depth_first_search => graph}/depthfirstsearch.go (93%) rename {graphs/floyd_warshall => graph}/floydwarshall.go (98%) rename math/{sieve => prime}/sieve.go (80%) rename math/{sieve => prime}/sieve_test.go (93%) rename other/{max_subarray_sum => maxsubarraysum}/maxsubarraysum.go (96%) delete mode 100644 other/monte_carlo_pi/montecarlopi.go delete mode 100644 other/monte_carlo_pi/montecarlopi_test.go rename other/{nested_brackets => nested}/nestedbrackets.go (98%) rename other/{nested_brackets => nested}/nestedbrackets_test.go (98%) create mode 100644 other/password/generator.go delete mode 100644 other/password_generator/passwordgenerator.go rename searches/binary_search/binarysearch.go => search/binary.go (60%) create mode 100644 search/binary_test.go rename searches/interpolation_search.go/interpolationsearch.go => search/interpolation.go (59%) create mode 100644 search/interpolation_test.go create mode 100644 search/linear.go create mode 100644 search/linear_test.go rename searches/linear_search/linearsearch_test.go => search/testcases.go (64%) delete mode 100644 searches/binary_search/binarysearch_test.go delete mode 100644 searches/interpolation_search.go/interpolation_search_test.go delete mode 100644 searches/linear_search/linearsearch.go create mode 100644 strings/ahocorasick/advancedahocorasick.go rename strings/{multiple_string_matching/aho_corasick/ahocorasick_test.go => ahocorasick/advancedahocorasick_test.go} (77%) create mode 100644 strings/ahocorasick/ahocorasick.go create mode 100644 strings/ahocorasick/ahocorasick_test.go rename strings/{multiple_string_matching => ahocorasick}/patterns.txt (100%) create mode 100644 strings/ahocorasick/shared.go rename strings/{multiple_string_matching => ahocorasick}/text.txt (100%) rename strings/{single_string_matching => }/bom/bom.go (100%) rename other/string_combinations/stringcombinations.go => strings/combination/combination.go (79%) rename strings/{single_string_matching => }/horspool/horspool.go (100%) rename strings/{single_string_matching => }/kmp/kmp.go (100%) rename strings/{single_string_matching => }/kmp/kmp_test.go (100%) rename strings/{levenshtein_distance => levenshtein}/levenshteindistance.go (82%) rename strings/{levenshtein_distance => levenshtein}/levenshteindistance_test.go (84%) delete mode 100644 strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go delete mode 100644 strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go delete mode 100644 strings/multiple_string_matching/aho_corasick/ahocorasick.go rename strings/{naive_string_search/naivestringsearch.go => search/patternsearch.go} (85%) rename strings/{naive_string_search/naivestringsearch_test.go => search/patternsearch_test.go} (85%) delete mode 100644 strings/single_string_matching/pattern.txt delete mode 100644 strings/single_string_matching/text.txt rename {data_structures => structure}/avl/avl.go (100%) rename {data_structures => structure}/avl/avl_test.go (100%) rename {data_structures/binary_tree => structure/binarytree}/btree.go (100%) rename {data_structures/binary_tree => structure/binarytree}/node.go (100%) rename {data_structures/dynamic_array => structure/dynamicarray}/dynamicarray.go (52%) rename {data_structures/dynamic_array => structure/dynamicarray}/dynamicarray_test.go (94%) rename {data_structures => structure}/hashmap/hashmap.go (100%) rename {data_structures => structure}/hashmap/hashmap_test.go (100%) rename {datastructures/linkedlist/cyclicallylinkedlist => structure/linkedlist}/Linked_Cyclic_List.jpg (100%) create mode 100644 structure/linkedlist/Readme.md rename datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go => structure/linkedlist/cyclic.go (56%) rename datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go => structure/linkedlist/cyclic_test.go (84%) create mode 100644 structure/linkedlist/doc.go create mode 100644 structure/linkedlist/doubly.go rename data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go => structure/linkedlist/doubly_test.go (65%) create mode 100644 structure/linkedlist/shared.go rename {data_structures/linkedlist/singly_linkedlist => structure/linkedlist}/singlylinkedlist.go (60%) rename {data_structures/linkedlist/singly_linkedlist => structure/linkedlist}/singlylinkedlist_test.go (93%) rename {data_structures => structure}/queue/queue_test.go (100%) rename {data_structures => structure}/queue/queuearray.go (100%) rename {data_structures => structure}/queue/queuelinkedlist.go (100%) rename {data_structures => structure}/queue/queuelinklistwithlist.go (100%) rename {data_structures => structure}/set/set.go (100%) rename {data_structures => structure}/stack/stack_test.go (100%) rename {data_structures => structure}/stack/stackarray.go (100%) rename {data_structures => structure}/stack/stacklinkedlist.go (100%) rename {data_structures => structure}/stack/stacklinkedlistwithlist.go (100%) rename {data_structures => structure}/trie/trie.go (100%) rename {data_structures => structure}/trie/trie_test.go (100%) diff --git a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go b/ciphers/diffiehellman/diffiehellmankeyexchange.go similarity index 89% rename from ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go rename to ciphers/diffiehellman/diffiehellmankeyexchange.go index 8d82b100f..ae26b1f09 100644 --- a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go +++ b/ciphers/diffiehellman/diffiehellmankeyexchange.go @@ -1,6 +1,6 @@ -// Package diffie_hellman_key_exchange implements Deffie Hellman Key Exchange Algorithm +// Package diffiehellman implements Deffie Hellman Key Exchange Algorithm // for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI -package diffie_hellman_key_exchange +package diffiehellman const ( generator = 3 diff --git a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go b/ciphers/diffiehellman/diffiehellmankeyexchange_test.go similarity index 97% rename from ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go rename to ciphers/diffiehellman/diffiehellmankeyexchange_test.go index 6865f6c63..7fe5ca7b9 100644 --- a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go +++ b/ciphers/diffiehellman/diffiehellmankeyexchange_test.go @@ -1,4 +1,4 @@ -package diffie_hellman_key_exchange +package diffiehellman import ( "crypto/rand" diff --git a/ciphers/xor/xor.go b/ciphers/xor/xor.go index 26a3c0225..0296c97ce 100644 --- a/ciphers/xor/xor.go +++ b/ciphers/xor/xor.go @@ -1,6 +1,6 @@ -// Package xor_cipher is an encryption algorithm that operates the exclusive disjunction(XOR) +// Package xor is an encryption algorithm that operates the exclusive disjunction(XOR) // ref: https://en.wikipedia.org/wiki/XOR_cipher -package xor_cipher +package xor // Encrypt encrypts with Xor encryption after converting each character to byte // The returned value might not be readable because there is no guarantee diff --git a/ciphers/xor/xor_test.go b/ciphers/xor/xor_test.go index 48b266390..999755188 100644 --- a/ciphers/xor/xor_test.go +++ b/ciphers/xor/xor_test.go @@ -1,4 +1,4 @@ -package xor_cipher +package xor import ( "fmt" diff --git a/conversions/roman_to_integer/romantointeger.go b/conversions/romantointeger.go similarity index 100% rename from conversions/roman_to_integer/romantointeger.go rename to conversions/romantointeger.go diff --git a/conversions/roman_to_integer/romantointeger_test.go b/conversions/romantointeger_test.go similarity index 100% rename from conversions/roman_to_integer/romantointeger_test.go rename to conversions/romantointeger_test.go diff --git a/data_structures/binary_tree/binarysearchtree.go b/data_structures/binary_tree/binarysearchtree.go deleted file mode 100644 index dde09d99d..000000000 --- a/data_structures/binary_tree/binarysearchtree.go +++ /dev/null @@ -1,37 +0,0 @@ -// Binary search tree -// https://en.wikipedia.org/wiki/Binary_search_tree - -package binarytree - -// import ( -// "fmt" -// ) - -// func main() { -//t := &BTree{nil} -//InOrder(t.Root) -//t.Root = Insert(t.Root, 30) -//t.Root = Insert(t.Root, 20) -//t.Root = Insert(t.Root, 15) -//t.Root = Insert(t.Root, 10) -//t.Root = Insert(t.Root, 12) -//t.Root = Insert(t.Root, 9) -//t.Root = Insert(t.Root, 11) -//t.Root = Insert(t.Root, 17) -//fmt.Print(t.Depth(), "\n") -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 10) -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 30) -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 15) -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 20) -//InOrder(t.Root) -//fmt.Print("\n") -//fmt.Print(t.Depth(), "\n") -// } diff --git a/data_structures/binary_tree/binarytree.go b/data_structures/binary_tree/binarytree.go deleted file mode 100644 index 4eeca8da9..000000000 --- a/data_structures/binary_tree/binarytree.go +++ /dev/null @@ -1,38 +0,0 @@ -// Package binarytree basic binary tree and related operations -package binarytree - -/* -func main() { - t := BTree{nil} - t.Root = NewNode(0) - t.Root.left = NewNode(1) - t.Root.right = NewNode(2) - t.Root.left.left = NewNode(3) - t.Root.left.right = NewNode(4) - t.Root.right.left = NewNode(5) - t.Root.right.right = NewNode(6) - t.Root.right.right.right = NewNode(10) - - InOrder(t.Root) - fmt.Print("\n") - PreOrder(t.Root) - fmt.Print("\n") - PostOrder(t.Root) - fmt.Print("\n") - LevelOrder(t.Root) - fmt.Print("\n") - fmt.Print(t.Depth(), "\n") - var list = AccessNodesByLayer(t.Root) - fmt.Println("{") - for i, v := range list { - for _, v2 := range v { - fmt.Print(" [", v2, "]") - } - if i != len(list)-1 { - fmt.Print(",") - } - fmt.Println() - } - fmt.Println("}") -} -*/ diff --git a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go b/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go deleted file mode 100644 index 7df7abcef..000000000 --- a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go +++ /dev/null @@ -1,168 +0,0 @@ -// Package doubly_linkedlist demonstration of doubly linked list in golang -package doubly_linkedlist - -import "fmt" - -// Node structure for a Node in the linkedlist -type Node struct { - val int - next *Node - prev *Node -} - -// DoubleLinkedList structure with just the head Node -type DoubleLinkedList struct { - head *Node -} - -// NewNode to avoid mistakes when using pointer vs struct for new Node creation -func NewNode(val int) *Node { - n := &Node{} - n.val = val - n.next = nil - n.prev = nil - return n -} - -// AddAtBeg Add a node to the beginning of the linkedlist -func (ll *DoubleLinkedList) AddAtBeg(val int) { - n := NewNode(val) - n.next = ll.head - - if ll.head != nil { - ll.head.prev = n - } - - ll.head = n - -} - -// AddAtEnd Add a node at the end of the linkedlist -func (ll *DoubleLinkedList) AddAtEnd(val int) { - n := NewNode(val) - - if ll.head == nil { - ll.head = n - return - } - - cur := ll.head - for ; cur.next != nil; cur = cur.next { - } - cur.next = n - n.prev = cur -} - -// DelAtBeg Delete the node at the beginning of the linkedlist -func (ll *DoubleLinkedList) DelAtBeg() int { - if ll.head == nil { - return -1 - } - - cur := ll.head - ll.head = cur.next - - if ll.head != nil { - ll.head.prev = nil - } - return cur.val -} - -// DetAtEnd Delete a node at the end of the linkedlist -func (ll *DoubleLinkedList) DelAtEnd() int { - // no item - if ll.head == nil { - return -1 - } - - // only one item - if ll.head.next == nil { - return ll.DelAtBeg() - } - - // more than one, go to second last - cur := ll.head - for ; cur.next.next != nil; cur = cur.next { - } - - retval := cur.next.val - cur.next = nil - return retval -} - -// Count Number of nodes in the linkedlist -func (ll *DoubleLinkedList) Count() int { - var ctr int = 0 - - for cur := ll.head; cur != nil; cur = cur.next { - ctr += 1 - } - - return ctr -} - -// Reverse Reverse the order of the linkedlist -func (ll *DoubleLinkedList) Reverse() { - var prev, next *Node - cur := ll.head - - for cur != nil { - next = cur.next - cur.next = prev - cur.prev = next - prev = cur - cur = next - } - - ll.head = prev -} - -// Display diplay the linked list -func (ll *DoubleLinkedList) Display() { - for cur := ll.head; cur != nil; cur = cur.next { - fmt.Print(cur.val, " ") - } - - fmt.Print("\n") -} - -// DisplayReverse Display the linkedlist in reverse order -func (ll *DoubleLinkedList) DisplayReverse() { - if ll.head == nil { - return - } - var cur *Node - for cur = ll.head; cur.next != nil; cur = cur.next { - } - - for ; cur != nil; cur = cur.prev { - fmt.Print(cur.val, " ") - } - - fmt.Print("\n") -} - -/* -func main() { - ll := DoubleLinkedList{} - - ll.addAtBeg(10) - ll.addAtEnd(20) - ll.display() - ll.addAtBeg(30) - ll.display() - - ll.reverse() - ll.display() - ll.displayReverse() - - fmt.Print(ll.delAtBeg(), "\n") - fmt.Print(ll.delAtEnd(), "\n") - fmt.Print("Display") - ll.display() - fmt.Print(ll.delAtBeg(), "\n") - ll.display() - fmt.Print(ll.delAtBeg(), "\n") - ll.display() -} -*/ diff --git a/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go deleted file mode 100644 index fb14fa7b8..000000000 --- a/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go +++ /dev/null @@ -1,104 +0,0 @@ -package singly_linkedlist - -// TODO not needed because there is already an implementation of SingleLinkedList - -// import "fmt" - -// /* v is the value of node; next is the pointer to next node */ -// type node struct { -// v int -// next *node -// } - -// /* first node, called head. It points from first node to last node */ -// var head *node = nil - -// func (l *node) pushFront(val int) *node { -// /* if there's no nodes, head points to l (first node) */ -// if head == nil { -// l.v = val -// l.next = nil -// head = l -// return l -// } else { -// /* create a new node equals to head */ -// nnode := new(node) -// nnode = head -// /* create a second node with new value and `next -> nnode` -// * is this way, nnode2 is before nnode -// */ -// nnode2 := &node{ -// v: val, -// next: nnode, -// } -// /* now head is equals nnode2 */ -// head = nnode2 -// return head -// } -// } - -// func (l *node) pushBack(val int) *node { -// /* if there's no nodes, head points to l (first node) */ -// if head == nil { -// l.v = val -// l.next = nil -// head = l -// return l -// } else { -// /* read all list to last node */ -// for l.next != nil { -// l = l.next -// } -// /* allocate a new portion of memory */ -// l.next = new(node) -// l.next.v = val -// l.next.next = nil -// return l -// } -// } - -// func (l *node) popFront() *node { -// if head == nil { -// return head -// } -// /* create a new node equals to first node pointed by head */ -// cpnode := new(node) -// cpnode = head.next - -// /* now head is equals cpnode (second node) */ -// head = cpnode - -// return head -// } - -// func (l *node) popBack() *node { -// if head == nil { -// return head -// } -// /* create a new node equals to head */ -// cpnode := new(node) -// cpnode = head - -// /* read list to the penultimate node */ -// for cpnode.next.next != nil { -// cpnode = cpnode.next -// } -// /* the penultimate node points to null. In this way the last node is deleted */ -// cpnode.next = nil -// return head -// } - -// func main() { -// lista := new(node) -// lista.pushBack(25).pushBack(24).pushBack(32) /* lista: 25 24 32 */ -// lista.pushBack(56) /* lista: 25 24 32 56 */ -// lista.pushFront(36) /* lista: 36 25 24 32 56 */ -// lista.popFront() /* lista: 25 24 32 56 */ -// lista.popBack() /* lista: 25 24 32 */ - -// /* read the list until head is not nil */ -// for head != nil { -// fmt.Printf("%d ", head.v) -// head = head.next /*head points to next node */ -// } -// } diff --git a/datastructures/linkedlist/cyclicallylinkedlist/Readme.md b/datastructures/linkedlist/cyclicallylinkedlist/Readme.md deleted file mode 100644 index f42b63377..000000000 --- a/datastructures/linkedlist/cyclicallylinkedlist/Readme.md +++ /dev/null @@ -1,12 +0,0 @@ -# Linked Cyclic List -*** -## What is it? -*** -Loop lists are single or doubly-linked lists that chase their own tail: -A points to B, B points to C, C points to D, and D points to A. -They are better suited for cyclic data such as train schedules. -These lists are missing the first and last items. -Therefore, it is necessary to introduce the concept of the current position. - -This picture shows similar lists: -![Alt text](./Linked_Cyclic_List.jpg?raw=true) diff --git a/dynamic_programming/binomialcoefficient.go b/dynamic/binomialcoefficient.go similarity index 96% rename from dynamic_programming/binomialcoefficient.go rename to dynamic/binomialcoefficient.go index 56682eab6..57ac880c4 100644 --- a/dynamic_programming/binomialcoefficient.go +++ b/dynamic/binomialcoefficient.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic // func main() { // myArrayOfK := [4]int{5, 6, 7, 8} diff --git a/dynamic_programming/fibonacci.go b/dynamic/fibonacci.go similarity index 92% rename from dynamic_programming/fibonacci.go rename to dynamic/fibonacci.go index 73fb49878..288b82b1c 100644 --- a/dynamic_programming/fibonacci.go +++ b/dynamic/fibonacci.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic // https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/ diff --git a/dynamic_programming/fibonacci_test.go b/dynamic/fibonacci_test.go similarity index 96% rename from dynamic_programming/fibonacci_test.go rename to dynamic/fibonacci_test.go index 0d94b8edf..db8aebae6 100644 --- a/dynamic_programming/fibonacci_test.go +++ b/dynamic/fibonacci_test.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic import ( "fmt" diff --git a/dynamic_programming/knapsack.go b/dynamic/knapsack.go similarity index 96% rename from dynamic_programming/knapsack.go rename to dynamic/knapsack.go index 7ccd64b02..032b91e79 100644 --- a/dynamic_programming/knapsack.go +++ b/dynamic/knapsack.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic // Knapsack Problem // https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ diff --git a/dynamic_programming/longestcommonsubsequence.go b/dynamic/longestcommonsubsequence.go similarity index 97% rename from dynamic_programming/longestcommonsubsequence.go rename to dynamic/longestcommonsubsequence.go index e251b57ad..447af9f7f 100644 --- a/dynamic_programming/longestcommonsubsequence.go +++ b/dynamic/longestcommonsubsequence.go @@ -2,7 +2,7 @@ // DP - 4 // https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/ -package dynamic_programming +package dynamic // LongestCommonSubsequence function func LongestCommonSubsequence(a string, b string, m int, n int) int { diff --git a/dynamic_programming/longestpalindromicsubsequence.go b/dynamic/longestpalindromicsubsequence.go similarity index 97% rename from dynamic_programming/longestpalindromicsubsequence.go rename to dynamic/longestpalindromicsubsequence.go index da783d7f7..9ec9af31f 100644 --- a/dynamic_programming/longestpalindromicsubsequence.go +++ b/dynamic/longestpalindromicsubsequence.go @@ -1,7 +1,7 @@ // longest palindromic subsequence // http://www.geeksforgeeks.org/dynamic-programming-set-12-longest-palindromic-subsequence/ -package dynamic_programming +package dynamic // LpsRec function func LpsRec(word string, i, j int) int { diff --git a/dynamic_programming/matrixmultiplication.go b/dynamic/matrixmultiplication.go similarity index 97% rename from dynamic_programming/matrixmultiplication.go rename to dynamic/matrixmultiplication.go index ff73b1762..4449c411f 100644 --- a/dynamic_programming/matrixmultiplication.go +++ b/dynamic/matrixmultiplication.go @@ -3,7 +3,7 @@ // www.geeksforgeeks.org/dynamic_programming-set-8-matrix-chain-multiplication/ // Package dynamic_programming Package for dynamically run algorithms -package dynamic_programming +package dynamic // MatrixChainRec function func MatrixChainRec(D []int, i, j int) int { diff --git a/dynamic_programming/rodcutting.go b/dynamic/rodcutting.go similarity index 97% rename from dynamic_programming/rodcutting.go rename to dynamic/rodcutting.go index 733798a39..ce721e18b 100644 --- a/dynamic_programming/rodcutting.go +++ b/dynamic/rodcutting.go @@ -2,7 +2,7 @@ // https://en.wikipedia.org/wiki/Cutting_stock_problem // http://www.geeksforgeeks.org/dynamic-programming-set-13-cutting-a-rod/ -package dynamic_programming +package dynamic // CutRodRec solve the problem recursively: initial approach func CutRodRec(price []int, length int) int { diff --git a/genetic_algorithm/geneticalgorithm.go b/genetic/genetic.go similarity index 97% rename from genetic_algorithm/geneticalgorithm.go rename to genetic/genetic.go index 0651f4318..12afb7c2d 100644 --- a/genetic_algorithm/geneticalgorithm.go +++ b/genetic/genetic.go @@ -1,8 +1,8 @@ -// package geneticalgorithm provides functions to work with strings +// Package genetic provides functions to work with strings // using genetic algorithm. https://en.wikipedia.org/wiki/Genetic_algorithm // // Author: D4rkia -package geneticalgorithm +package genetic import ( "errors" @@ -60,7 +60,7 @@ type Result struct { Best PopulationItem } -// GenerateString generates PopultaionItem based on the imputed target +// GeneticString generates PopultaionItem based on the imputed target // string, and a set of possible runes to build a string with. In order // to optimise string generation additional configurations can be provided // with Conf instance. Empty instance of Conf (&Conf{}) can be provided, diff --git a/genetic_algorithm/geneticalgorithm_test.go b/genetic/geneticalgorithm_test.go similarity index 96% rename from genetic_algorithm/geneticalgorithm_test.go rename to genetic/geneticalgorithm_test.go index a57463963..0971331fd 100644 --- a/genetic_algorithm/geneticalgorithm_test.go +++ b/genetic/geneticalgorithm_test.go @@ -1,4 +1,4 @@ -package geneticalgorithm +package genetic import ( "testing" diff --git a/graphs/breadth_first_search/breadthfirstsearch.go b/graph/breadthfirstsearch.go similarity index 53% rename from graphs/breadth_first_search/breadthfirstsearch.go rename to graph/breadthfirstsearch.go index c80bf8209..620d96a3f 100644 --- a/graphs/breadth_first_search/breadthfirstsearch.go +++ b/graph/breadthfirstsearch.go @@ -1,14 +1,13 @@ -// Package search Graph search algorithms +// Package graph demonstates Graph search algorithms // reference: https://en.wikipedia.org/wiki/Tree_traversal -package breadth_first_search +package graph -/*BreadthFirstSearch is an algorithm for traversing and searching graph data structures. - It starts at an arbitrary node of a graph, and explores all of the neighbor nodes - at the present depth prior to moving on to the nodes at the next depth level. - Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) - Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) -reference: https://en.wikipedia.org/wiki/Breadth-first_search -*/ +// BreadthFirstSearch is an algorithm for traversing and searching graph data structures. +// It starts at an arbitrary node of a graph, and explores all of the neighbor nodes +// at the present depth prior to moving on to the nodes at the next depth level. +// Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) +// Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) +// reference: https://en.wikipedia.org/wiki/Breadth-first_search func BreadthFirstSearch(start, end, nodes int, edges [][]int) (isConnected bool, distance int) { queue := make([]int, 0) discovered := make([]int, nodes) diff --git a/graphs/breadth_first_search/breadthfirstsearch_test.go b/graph/breadthfirstsearch_test.go similarity index 98% rename from graphs/breadth_first_search/breadthfirstsearch_test.go rename to graph/breadthfirstsearch_test.go index d80d767f5..a01db4fc1 100644 --- a/graphs/breadth_first_search/breadthfirstsearch_test.go +++ b/graph/breadthfirstsearch_test.go @@ -1,4 +1,4 @@ -package breadth_first_search +package graph import ( "testing" diff --git a/graphs/depth_first_search/depthfirstsearch.go b/graph/depthfirstsearch.go similarity index 93% rename from graphs/depth_first_search/depthfirstsearch.go rename to graph/depthfirstsearch.go index 07648e17c..a4afb7647 100644 --- a/graphs/depth_first_search/depthfirstsearch.go +++ b/graph/depthfirstsearch.go @@ -1,4 +1,4 @@ -package depth_first_search +package graph func GetIdx(target int, nodes []int) int { for i := 0; i < len(nodes); i++ { @@ -18,7 +18,7 @@ func NotExist(target int, slice []int) bool { return true } -func Dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { +func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool) { var route []int var stack []int startIdx := GetIdx(start, nodes) diff --git a/graphs/floyd_warshall/floydwarshall.go b/graph/floydwarshall.go similarity index 98% rename from graphs/floyd_warshall/floydwarshall.go rename to graph/floydwarshall.go index 0a9f7e7a4..a04b60ef8 100644 --- a/graphs/floyd_warshall/floydwarshall.go +++ b/graph/floydwarshall.go @@ -1,7 +1,7 @@ // Floyd-Warshall algorithm // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm -package floyd_warshall +package graph // Matrix Defining matrix to use 2d array easier type Matrix [][]float64 diff --git a/math/sieve/sieve.go b/math/prime/sieve.go similarity index 80% rename from math/sieve/sieve.go rename to math/prime/sieve.go index 506c64216..e6b216a68 100644 --- a/math/sieve/sieve.go +++ b/math/prime/sieve.go @@ -3,10 +3,10 @@ // author(s) [Taj](https://github.com/tjgurwara99) // see sieve_test.go -package sieve +package prime // Generate generates the sequence of integers starting at 2 and sends it to the channel `ch` -func Generate(ch chan<- int) { +func GenerateChannel(ch chan<- int) { for i := 2; ; i++ { ch <- i } @@ -22,12 +22,12 @@ func Sieve(in <-chan int, out chan<- int, prime int) { } } -// GeneratePrimes returns a int slice of prime numbers up to the limit -func GeneratePrimes(limit int) []int { +// Generate returns a int slice of prime numbers up to the limit +func Generate(limit int) []int { var primes []int ch := make(chan int) - go Generate(ch) + go GenerateChannel(ch) for i := 0; i < limit; i++ { primes = append(primes, <-ch) diff --git a/math/sieve/sieve_test.go b/math/prime/sieve_test.go similarity index 93% rename from math/sieve/sieve_test.go rename to math/prime/sieve_test.go index e96f442b6..82cc63017 100644 --- a/math/sieve/sieve_test.go +++ b/math/prime/sieve_test.go @@ -3,7 +3,7 @@ // author(s) [Taj](https://github.com/tjgurwara99) // see sieve.go -package sieve +package prime import ( "reflect" @@ -17,7 +17,7 @@ func TestSieve(t *testing.T) { var testTenPrimes [10]int ch := make(chan int) - go Generate(ch) + go GenerateChannel(ch) for i := 0; i < 10; i++ { testTenPrimes[i] = <-ch @@ -37,7 +37,7 @@ func TestGeneratePrimes(t *testing.T) { firstTenPrimes := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} t.Run("Testing GeneratePrimes Function", func(t *testing.T) { - testPrimes := GeneratePrimes(10) + testPrimes := Generate(10) if !reflect.DeepEqual(firstTenPrimes, testPrimes) { t.Fatal("GeneratePrimes function failed") diff --git a/other/max_subarray_sum/maxsubarraysum.go b/other/maxsubarraysum/maxsubarraysum.go similarity index 96% rename from other/max_subarray_sum/maxsubarraysum.go rename to other/maxsubarraysum/maxsubarraysum.go index 9101c4e6e..e50453b3b 100644 --- a/other/max_subarray_sum/maxsubarraysum.go +++ b/other/maxsubarraysum/maxsubarraysum.go @@ -1,7 +1,7 @@ /* O(n) solution, for calculating maximum contiguous sum in the given array. */ -package max_subarray_sum +package maxsubarraysum // Max - already defined somewhere in this repository TODO: remove this definition and add the import path func Max(x int, y int) int { diff --git a/other/monte_carlo_pi/montecarlopi.go b/other/monte_carlo_pi/montecarlopi.go deleted file mode 100644 index 2506af346..000000000 --- a/other/monte_carlo_pi/montecarlopi.go +++ /dev/null @@ -1,50 +0,0 @@ -package montecarlopi - -// import ( -// "fmt" -// "math" -// "math/rand" -// "runtime" -// "sync" -// "time" -// ) - -// func main() { -// cpus := runtime.NumCPU() -// monteCarlo := func(iterations, cpus int) float64{ -// start := time.Now() -// flow := make(chan int, int(math.Floor(float64(cpus)/2))) -// var wg sync.WaitGroup -// var total int -// miniFunc := func(iters int, flow chan int) { -// defer wg.Done() -// var inside int -// for i := 0; i < iters; i++ { -// x := rand.Float64() -// y := rand.Float64() -// if math.Hypot(x, y) <= 1 { -// inside++ -// } -// } -// flow <- inside -// } //end of minifunc -// fuxc := func(flow chan int) { -// defer wg.Done() -// for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { -// total += <-flow -// } -// } //end of fuxc -// wg.Add(int(math.Floor(float64(cpus) / 2))) -// //spawn goroutines for half the logical processors -// // This leaves free cpus for swapping -// for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { -// go miniFunc(int(math.Ceil(float64(iterations/int(math.Floor(float64(cpus)/2))))), flow) -// } -// wg.Add(1) -// go fuxc(flow) -// wg.Wait() -// fmt.Printf("took %v \n",time.Since(start)) -// return 4 * float64(total) / float64(iterations) -// }//end of monteCarlo -// fmt.Println(monteCarlo(2<<18, cpus)) -// } diff --git a/other/monte_carlo_pi/montecarlopi_test.go b/other/monte_carlo_pi/montecarlopi_test.go deleted file mode 100644 index 899fd5c46..000000000 --- a/other/monte_carlo_pi/montecarlopi_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package montecarlopi - -// import ( -// "math" -// "testing" -// ) - -// func TestMonteCarloPi(t *testing.T) { -// delta := 0.0001 - -// pi := MonteCarloPi(100000000) - -// if math.Abs(pi-math.Pi) > delta { -// t.Errorf("Given: %.4f, expected: %.4f", pi, math.Pi) -// } -// } diff --git a/other/nested_brackets/nestedbrackets.go b/other/nested/nestedbrackets.go similarity index 98% rename from other/nested_brackets/nestedbrackets.go rename to other/nested/nestedbrackets.go index b70ab2aa2..c0afd9571 100644 --- a/other/nested_brackets/nestedbrackets.go +++ b/other/nested/nestedbrackets.go @@ -1,6 +1,6 @@ // Package nested_brackets provides functions for testing // strings propper brackets nesting. -package nested_brackets +package nested // IsBalanced returns true if provided input string is properly nested. // diff --git a/other/nested_brackets/nestedbrackets_test.go b/other/nested/nestedbrackets_test.go similarity index 98% rename from other/nested_brackets/nestedbrackets_test.go rename to other/nested/nestedbrackets_test.go index 658cc4837..52fc41cfb 100644 --- a/other/nested_brackets/nestedbrackets_test.go +++ b/other/nested/nestedbrackets_test.go @@ -1,4 +1,4 @@ -package nested_brackets +package nested import ( "testing" diff --git a/other/password/generator.go b/other/password/generator.go new file mode 100644 index 000000000..b25f2f48b --- /dev/null +++ b/other/password/generator.go @@ -0,0 +1,45 @@ +// This program generates a password from a list of possible chars +// You must provide a minimum length and a maximum length +// This length is not fixed if you generate multiple passwords for the same range + +package password_generator + +import ( + "crypto/rand" + "io" + "math/big" +) + +// Generate returns a newly generated password +func Generate(minLength int, maxLength int) string { + var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~") + + length, err := rand.Int(rand.Reader, big.NewInt(int64(maxLength-minLength))) + if err != nil { + panic(err) // handle this gracefully + } + length.Add(length, big.NewInt(int64(minLength))) + + intLength := int(length.Int64()) + + newPassword := make([]byte, intLength) + randomData := make([]byte, intLength+intLength/4) + clen := byte(len(chars)) + maxrb := byte(256 - (256 % len(chars))) + i := 0 + for { + if _, err := io.ReadFull(rand.Reader, randomData); err != nil { + panic(err) + } + for _, c := range randomData { + if c >= maxrb { + continue + } + newPassword[i] = chars[c%clen] + i++ + if i == intLength { + return string(newPassword) + } + } + } +} diff --git a/other/password_generator/passwordgenerator.go b/other/password_generator/passwordgenerator.go deleted file mode 100644 index f795c16a1..000000000 --- a/other/password_generator/passwordgenerator.go +++ /dev/null @@ -1,53 +0,0 @@ -// This program generates a password from a list of possible chars -// You must provide a minimum length and a maximum length -// This length is not fixed if you generate multiple passwords for the same range - -package password_generator - -import ( - crand "crypto/rand" - "io" - "math/rand" -) - -// GeneratePassword returns a newly generated password -func GeneratePassword(minLength int, maxLength int) string { - var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~") - - var length = rand.Intn(maxLength-minLength) + minLength - - newPassword := make([]byte, length) - randomData := make([]byte, length+(length/4)) - clen := byte(len(chars)) - maxrb := byte(256 - (256 % len(chars))) - i := 0 - for { - if _, err := io.ReadFull(crand.Reader, randomData); err != nil { - panic(err) - } - for _, c := range randomData { - if c >= maxrb { - continue - } - newPassword[i] = chars[c%clen] - i++ - if i == length { - return string(newPassword) - } - } - } -} - -// func main() { -// rand.Seed(time.Now().Unix()) - -// fmt.Print("Please specify a minimum length: ") -// var minLength int -// fmt.Scanf("%d", &minLength) - -// fmt.Print("Please specify a maximum length: ") -// var maxLength int -// fmt.Scanf("%d", &maxLength) - -// fmt.Printf("Your generated password is %v\n", generatePassword(minLength, maxLength)) -// } diff --git a/searches/binary_search/binarysearch.go b/search/binary.go similarity index 60% rename from searches/binary_search/binarysearch.go rename to search/binary.go index f3c9b7840..e72e3e9d2 100644 --- a/searches/binary_search/binarysearch.go +++ b/search/binary.go @@ -1,22 +1,22 @@ -package binarysearch +package search -// BinarySearch Binary Search -func BinarySearch(array []int, target int, lowIndex int, highIndex int) int { +// Binary Binary Search +func Binary(array []int, target int, lowIndex int, highIndex int) int { if highIndex < lowIndex || len(array) == 0 { return -1 } mid := (highIndex + lowIndex) / 2 if array[mid] > target { - return BinarySearch(array, target, lowIndex, mid-1) + return Binary(array, target, lowIndex, mid-1) } else if array[mid] < target { - return BinarySearch(array, target, mid+1, highIndex) + return Binary(array, target, mid+1, highIndex) } else { return mid } } -// IterBinarySearch Iter Binary Search -func IterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { +// BinaryIterative Iterative Binary Search +func BinaryIterative(array []int, target int, lowIndex int, highIndex int) int { startIndex := lowIndex endIndex := highIndex var mid int diff --git a/search/binary_test.go b/search/binary_test.go new file mode 100644 index 000000000..70f4a7bcb --- /dev/null +++ b/search/binary_test.go @@ -0,0 +1,23 @@ +package search + +import ( + "testing" +) + +func TestBinarySearch(t *testing.T) { + for _, test := range searchTests { + actual := Binary(test.data, test.key, 0, len(test.data)-1) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} + +func TestIterBinarySearch(t *testing.T) { + for _, test := range searchTests { + actual := BinaryIterative(test.data, test.key, 0, len(test.data)-1) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/searches/interpolation_search.go/interpolationsearch.go b/search/interpolation.go similarity index 59% rename from searches/interpolation_search.go/interpolationsearch.go rename to search/interpolation.go index 7e4de0277..4bd277877 100644 --- a/searches/interpolation_search.go/interpolationsearch.go +++ b/search/interpolation.go @@ -1,18 +1,15 @@ -package interpolationsearch - -/* -InterpolationSearch searches for the entity in the given sortedData. -if the entity is present, it will return the index of the entity, if not -1 will be returned. -see: https://en.wikipedia.org/wiki/Interpolation_search -Complexity - Worst: O(N) - Average: O(log(log(N)) if the elements are uniformly distributed - Best: O(1) - -Example - fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) -*/ -func InterpolationSearch(sortedData []int, guess int) int { +package search + +// Interpolation searches for the entity in the given sortedData. +// if the entity is present, it will return the index of the entity, if not -1 will be returned. +// see: https://en.wikipedia.org/wiki/Interpolation_search +// Complexity +// Worst: O(N) +// Average: O(log(log(N)) if the elements are uniformly distributed +// Best: O(1) +// Example +// fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) +func Interpolation(sortedData []int, guess int) int { if len(sortedData) == 0 { return -1 } diff --git a/search/interpolation_test.go b/search/interpolation_test.go new file mode 100644 index 000000000..848ddf0aa --- /dev/null +++ b/search/interpolation_test.go @@ -0,0 +1,12 @@ +package search + +import "testing" + +func TestInterpolation(t *testing.T) { + for _, test := range searchTests { + actual := Interpolation(test.data, test.key) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/search/linear.go b/search/linear.go new file mode 100644 index 000000000..c442630c6 --- /dev/null +++ b/search/linear.go @@ -0,0 +1,11 @@ +package search + +// Linear Simple linear search algorithm that iterates over all elements of an array in the worst case scenario +func Linear(array []int, query int) int { + for i, item := range array { + if item == query { + return i + } + } + return -1 +} diff --git a/search/linear_test.go b/search/linear_test.go new file mode 100644 index 000000000..6f02db8cf --- /dev/null +++ b/search/linear_test.go @@ -0,0 +1,14 @@ +package search + +import ( + "testing" +) + +func TestLinear(t *testing.T) { + for _, test := range searchTests { + actual := Linear(test.data, test.key) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/searches/linear_search/linearsearch_test.go b/search/testcases.go similarity index 64% rename from searches/linear_search/linearsearch_test.go rename to search/testcases.go index 121dcd4a6..65e9bbd06 100644 --- a/searches/linear_search/linearsearch_test.go +++ b/search/testcases.go @@ -1,8 +1,4 @@ -package linear_search - -import ( - "testing" -) +package search type searchTest struct { data []int @@ -11,6 +7,8 @@ type searchTest struct { name string } +// Note that these are immutable therefore they are shared among all the search tests. +// If your algorithm is mutating these then it is advisable to create separate test cases. var searchTests = []searchTest{ //Sanity {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, @@ -22,12 +20,3 @@ var searchTests = []searchTest{ //Empty slice {[]int{}, 2, -1, "Empty"}, } - -func TestLinearSearch(t *testing.T) { - for _, test := range searchTests { - actual := LinearSearch(test.data, test.key) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} diff --git a/searches/binary_search/binarysearch_test.go b/searches/binary_search/binarysearch_test.go deleted file mode 100644 index 82909e99c..000000000 --- a/searches/binary_search/binarysearch_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package binarysearch - -import ( - "testing" -) - -type searchTest struct { - data []int - key int - expected int - name string -} - -var searchTests = []searchTest{ - //Sanity - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, - //Absent - {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, - {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, - //Empty slice - {[]int{}, 2, -1, "Empty"}, -} - -func TestBinarySearch(t *testing.T) { - for _, test := range searchTests { - actual := BinarySearch(test.data, test.key, 0, len(test.data)-1) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} - -func TestIterBinarySearch(t *testing.T) { - for _, test := range searchTests { - actual := IterBinarySearch(test.data, test.key, 0, len(test.data)-1) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} diff --git a/searches/interpolation_search.go/interpolation_search_test.go b/searches/interpolation_search.go/interpolation_search_test.go deleted file mode 100644 index 0ca829f14..000000000 --- a/searches/interpolation_search.go/interpolation_search_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package interpolationsearch - -import "testing" - -type searchTest struct { - data []int - key int - expected int - name string -} - -var searchTests = []searchTest{ - //Sanity - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, - //Absent - {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, - {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, - //Empty slice - {[]int{}, 2, -1, "Empty"}, -} - -func TestInterpolationSearch(t *testing.T) { - for _, test := range searchTests { - actual := InterpolationSearch(test.data, test.key) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} diff --git a/searches/linear_search/linearsearch.go b/searches/linear_search/linearsearch.go deleted file mode 100644 index 89be4fd8b..000000000 --- a/searches/linear_search/linearsearch.go +++ /dev/null @@ -1,11 +0,0 @@ -package linear_search - -// LinearSearch Simple linear search algorithm that iterates over all elements of an array in the worst case scenario -func LinearSearch(array []int, query int) int { - for i, item := range array { - if item == query { - return i - } - } - return -1 -} diff --git a/strings/ahocorasick/advancedahocorasick.go b/strings/ahocorasick/advancedahocorasick.go new file mode 100644 index 000000000..e465903a9 --- /dev/null +++ b/strings/ahocorasick/advancedahocorasick.go @@ -0,0 +1,82 @@ +package ahocorasick + +import ( + "fmt" + "time" +) + +// Advanced Function performing the Advanced Aho-Corasick alghoritm. +// Finds and prints occurrences of each pattern. +func Advanced(t string, p []string) Result { + startTime := time.Now() + occurrences := make(map[int][]int) + ac, f := BuildExtendedAc(p) + current := 0 + for pos := 0; pos < len(t); pos++ { + if GetTransition(current, t[pos], ac) != -1 { + current = GetTransition(current, t[pos], ac) + } else { + current = 0 + } + _, ok := f[current] + if ok { + for i := range f[current] { + if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match + newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurrences + occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 + } + } + } + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + + var resultOccurrences = make(map[string][]int) + for key, value := range occurrences { + resultOccurrences[p[key]] = value + } + + return Result{ + resultOccurrences, + } +} + +// BuildExtendedAc Functions that builds extended Aho Corasick automaton. +func BuildExtendedAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int) { + acTrie, stateIsTerminal, f := ConstructTrie(p) + s := make([]int, len(stateIsTerminal)) //supply function + i := 0 //root of acTrie + acToReturn = acTrie + s[i] = -1 + for current := 1; current < len(stateIsTerminal); current++ { + o, parent := GetParent(current, acTrie) + down := s[parent] + for StateExists(down, acToReturn) && GetTransition(down, o, acToReturn) == -1 { + down = s[down] + } + if StateExists(down, acToReturn) { + s[current] = GetTransition(down, o, acToReturn) + if stateIsTerminal[s[current]] { + stateIsTerminal[current] = true + f[current] = ArrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) + } + } else { + s[current] = i //initial state? + } + } + a := ComputeAlphabet(p) // concat of all patterns in p + for j := range a { + if GetTransition(i, a[j], acToReturn) == -1 { + CreateTransition(i, a[j], i, acToReturn) + } + } + for current := 1; current < len(stateIsTerminal); current++ { + for j := range a { + if GetTransition(current, a[j], acToReturn) == -1 { + CreateTransition(current, a[j], GetTransition(s[current], a[j], acToReturn), acToReturn) + } + } + } + return acToReturn, f +} diff --git a/strings/multiple_string_matching/aho_corasick/ahocorasick_test.go b/strings/ahocorasick/advancedahocorasick_test.go similarity index 77% rename from strings/multiple_string_matching/aho_corasick/ahocorasick_test.go rename to strings/ahocorasick/advancedahocorasick_test.go index 2f3241702..996651457 100644 --- a/strings/multiple_string_matching/aho_corasick/ahocorasick_test.go +++ b/strings/ahocorasick/advancedahocorasick_test.go @@ -1,9 +1,7 @@ package ahocorasick import ( - "fmt" "reflect" - "strings" "testing" ) @@ -50,7 +48,7 @@ var testCases = []struct { }, } -func TestAhoCorasick(t *testing.T) { +func TestAdvanced(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { actual := AhoCorasick(tc.text, tc.words) @@ -63,18 +61,3 @@ func TestAhoCorasick(t *testing.T) { }) } } - -func convertToString(res Result) string { - var r strings.Builder - for key, val := range res.occurrences { - r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) - for i := range val { - r.WriteString(fmt.Sprintf("%d", val[i])) - if i != len(val)-1 { - r.WriteString(", ") - } - } - r.WriteString(". ") - } - return r.String() -} diff --git a/strings/ahocorasick/ahocorasick.go b/strings/ahocorasick/ahocorasick.go new file mode 100644 index 000000000..e052e7905 --- /dev/null +++ b/strings/ahocorasick/ahocorasick.go @@ -0,0 +1,77 @@ +package ahocorasick + +import ( + "fmt" + "time" +) + +// Result structure to hold occurrences +type Result struct { + occurrences map[string][]int +} + +// AhoCorasick Function performing the Basic Aho-Corasick algorithm. +// Finds and prints occurrences of each pattern. +func AhoCorasick(t string, p []string) Result { + startTime := time.Now() + occurrences := make(map[int][]int) + ac, f, s := BuildAc(p) + current := 0 + for pos := 0; pos < len(t); pos++ { + for GetTransition(current, t[pos], ac) == -1 && s[current] != -1 { + current = s[current] + } + if GetTransition(current, t[pos], ac) != -1 { + current = GetTransition(current, t[pos], ac) + fmt.Printf(" (Continue) \n") + } else { + current = 0 + } + _, ok := f[current] + if ok { + for i := range f[current] { + if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match + newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurrences + occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 + } + } + } + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + var resultOccurrences = make(map[string][]int) + for key, value := range occurrences { + resultOccurrences[p[key]] = value + } + + return Result{ + resultOccurrences, + } +} + +// Functions that builds Aho Corasick automaton. +func BuildAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int, s []int) { + acTrie, stateIsTerminal, f := ConstructTrie(p) + s = make([]int, len(stateIsTerminal)) //supply function + i := 0 //root of acTrie + acToReturn = acTrie + s[i] = -1 + for current := 1; current < len(stateIsTerminal); current++ { + o, parent := GetParent(current, acTrie) + down := s[parent] + for StateExists(down, acToReturn) && GetTransition(down, o, acToReturn) == -1 { + down = s[down] + } + if StateExists(down, acToReturn) { + s[current] = GetTransition(down, o, acToReturn) + if stateIsTerminal[s[current]] { + stateIsTerminal[current] = true + f[current] = ArrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) + } + } else { + s[current] = i //initial state? + } + } + return acToReturn, f, s +} diff --git a/strings/ahocorasick/ahocorasick_test.go b/strings/ahocorasick/ahocorasick_test.go new file mode 100644 index 000000000..366410fa1 --- /dev/null +++ b/strings/ahocorasick/ahocorasick_test.go @@ -0,0 +1,37 @@ +package ahocorasick + +import ( + "fmt" + "reflect" + "strings" + "testing" +) + +func TestAhoCorasick(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := AhoCorasick(tc.text, tc.words) + if !reflect.DeepEqual(actual, tc.expected) { + actualString := convertToString(actual) + expectedString := convertToString(tc.expected) + t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", + tc.words, tc.text, actualString, expectedString) + } + }) + } +} + +func convertToString(res Result) string { + var r strings.Builder + for key, val := range res.occurrences { + r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) + for i := range val { + r.WriteString(fmt.Sprintf("%d", val[i])) + if i != len(val)-1 { + r.WriteString(", ") + } + } + r.WriteString(". ") + } + return r.String() +} diff --git a/strings/multiple_string_matching/patterns.txt b/strings/ahocorasick/patterns.txt similarity index 100% rename from strings/multiple_string_matching/patterns.txt rename to strings/ahocorasick/patterns.txt diff --git a/strings/ahocorasick/shared.go b/strings/ahocorasick/shared.go new file mode 100644 index 000000000..eee95c1b7 --- /dev/null +++ b/strings/ahocorasick/shared.go @@ -0,0 +1,139 @@ +package ahocorasick + +// ConstructTrie Function that constructs Trie as an automaton for a set of reversed & trimmed strings. +func ConstructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { + trie = make(map[int]map[uint8]int) + stateIsTerminal = make([]bool, 1) + f = make(map[int][]int) + state := 1 + CreateNewState(0, trie) + for i := 0; i < len(p); i++ { + current := 0 + j := 0 + for j < len(p[i]) && GetTransition(current, p[i][j], trie) != -1 { + current = GetTransition(current, p[i][j], trie) + j++ + } + for j < len(p[i]) { + stateIsTerminal = BoolArrayCapUp(stateIsTerminal) + CreateNewState(state, trie) + stateIsTerminal[state] = false + CreateTransition(current, p[i][j], state, trie) + current = state + j++ + state++ + } + if stateIsTerminal[current] { + newArray := IntArrayCapUp(f[current]) + newArray[len(newArray)-1] = i + f[current] = newArray // F(Current) <- F(Current) union {i} + } else { + stateIsTerminal[current] = true + f[current] = []int{i} // F(Current) <- {i} + } + } + return trie, stateIsTerminal, f +} + +// Contains Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. +func Contains(s []int, e int) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} + +// GetWord Function that returns word found in text 't' at position range 'begin' to 'end'. +func GetWord(begin, end int, t string) string { + for end >= len(t) { + return "" + } + d := make([]uint8, end-begin+1) + for j, i := 0, begin; i <= end; i, j = i+1, j+1 { + d[j] = t[i] + } + return string(d) +} + +// ComputeAlphabet Function that returns string of all the possible characters in given patterns. +func ComputeAlphabet(p []string) (s string) { + s = p[0] + for i := 1; i < len(p); i++ { + s = s + p[i] + } + return s +} + +// IntArrayCapUp Dynamically increases an array size of int's by 1. +func IntArrayCapUp(old []int) (new []int) { + new = make([]int, cap(old)+1) + copy(new, old) //copy(dst,src) + // old = new + return new +} + +// BoolArrayCapUp Dynamically increases an array size of bool's by 1. +func BoolArrayCapUp(old []bool) (new []bool) { + new = make([]bool, cap(old)+1) + copy(new, old) + // old = new + return new +} + +// ArrayUnion Concats two arrays of int's into one. +func ArrayUnion(to, from []int) (concat []int) { + concat = to + for i := range from { + if !Contains(concat, from[i]) { + concat = IntArrayCapUp(concat) + concat[len(concat)-1] = from[i] + } + } + return concat +} + +// GetParent Function that finds the first previous state of a state and returns it. +// Used for trie where there is only one parent. +func GetParent(state int, at map[int]map[uint8]int) (uint8, int) { + for beginState, transitions := range at { + for c, endState := range transitions { + if endState == state { + return c, beginState + } + } + } + return 0, 0 //unreachable +} + +// CreateNewState Automaton function for creating a new state 'state'. +func CreateNewState(state int, at map[int]map[uint8]int) { + at[state] = make(map[uint8]int) +} + +// CreateTransition Creates a transition for function σ(state,letter) = end. +func CreateTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { + at[fromState][overChar] = toState +} + +// GetTransition Returns ending state for transition σ(fromState,overChar), '-1' if there is none. +func GetTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { + if !StateExists(fromState, at) { + return -1 + } + toState, ok := at[fromState][overChar] + if !ok { + return -1 + } + return toState +} + +// StateExists Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. +func StateExists(state int, at map[int]map[uint8]int) bool { + _, ok := at[state] + if !ok || state == -1 || at[state] == nil { + return false + } + return true +} diff --git a/strings/multiple_string_matching/text.txt b/strings/ahocorasick/text.txt similarity index 100% rename from strings/multiple_string_matching/text.txt rename to strings/ahocorasick/text.txt diff --git a/strings/single_string_matching/bom/bom.go b/strings/bom/bom.go similarity index 100% rename from strings/single_string_matching/bom/bom.go rename to strings/bom/bom.go diff --git a/other/string_combinations/stringcombinations.go b/strings/combination/combination.go similarity index 79% rename from other/string_combinations/stringcombinations.go rename to strings/combination/combination.go index dc0f92fed..42bbdee8b 100644 --- a/other/string_combinations/stringcombinations.go +++ b/strings/combination/combination.go @@ -1,5 +1,5 @@ -// Package string_combinations ... -package string_combinations +// Package combination ... +package combination import "fmt" @@ -9,8 +9,8 @@ type Combinations struct { in []rune } -// StartCombinations ... -func StartCombinations(input string) { +// Start ... +func Start(input string) { c := &Combinations{ in: []rune(input), } diff --git a/strings/single_string_matching/horspool/horspool.go b/strings/horspool/horspool.go similarity index 100% rename from strings/single_string_matching/horspool/horspool.go rename to strings/horspool/horspool.go diff --git a/strings/single_string_matching/kmp/kmp.go b/strings/kmp/kmp.go similarity index 100% rename from strings/single_string_matching/kmp/kmp.go rename to strings/kmp/kmp.go diff --git a/strings/single_string_matching/kmp/kmp_test.go b/strings/kmp/kmp_test.go similarity index 100% rename from strings/single_string_matching/kmp/kmp_test.go rename to strings/kmp/kmp_test.go diff --git a/strings/levenshtein_distance/levenshteindistance.go b/strings/levenshtein/levenshteindistance.go similarity index 82% rename from strings/levenshtein_distance/levenshteindistance.go rename to strings/levenshtein/levenshteindistance.go index c718b1e5a..b5cdec547 100644 --- a/strings/levenshtein_distance/levenshteindistance.go +++ b/strings/levenshtein/levenshteindistance.go @@ -4,10 +4,10 @@ Parameters: two strings to compare and weights of insertion, substitution and de Output: distance between both strings */ -package levenshtein_distance +package levenshtein -// LevenshteinDistance Function that gives Levenshtein Distance -func LevenshteinDistance(str1, str2 string, icost, scost, dcost int) int { +// Distance Function that gives Levenshtein Distance +func Distance(str1, str2 string, icost, scost, dcost int) int { row1 := make([]int, len(str2)+1) row2 := make([]int, len(str2)+1) diff --git a/strings/levenshtein_distance/levenshteindistance_test.go b/strings/levenshtein/levenshteindistance_test.go similarity index 84% rename from strings/levenshtein_distance/levenshteindistance_test.go rename to strings/levenshtein/levenshteindistance_test.go index 25537dc98..8e15cd94e 100644 --- a/strings/levenshtein_distance/levenshteindistance_test.go +++ b/strings/levenshtein/levenshteindistance_test.go @@ -1,4 +1,4 @@ -package levenshtein_distance +package levenshtein import "testing" @@ -43,7 +43,7 @@ var testCases = []struct { func TestLevenshteinDistance(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := LevenshteinDistance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost) + actual := Distance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost) if actual != tc.expected { t.Errorf("Expected Levenshtein distance between strings: '%s' and '%s' is %v, but got: %v", tc.string1, tc.string2, tc.expected, actual) } diff --git a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go b/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go deleted file mode 100644 index dfbb6ae67..000000000 --- a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go +++ /dev/null @@ -1,318 +0,0 @@ -package advancedahocorasick - -import ( - "fmt" - "time" -) - -// User defined. -// Set to true to print various extra stuff out (slows down the execution) -// Set to false for quick and quiet execution. -// const debugMode bool = true // TODO: very convoluted algorithm need time to read through it properly - -// Result structure -type Result struct { - occurrences map[string][]int -} - -// Implementation of Advanced Aho-Corasick algorithm (Prefix based). -// Searches for a set of strings (patterns.txt) in text.txt. -// func main() { -// patFile, err := ioutil.ReadFile("../patterns.txt") -// if err != nil { -// log.Fatal(err) -// } -// textFile, err := ioutil.ReadFile("../text.txt") -// if err != nil { -// log.Fatal(err) -// } -// patterns := strings.Split(string(patFile), " ") -// fmt.Printf("\nRunning: Advanced Aho-Corasick algorithm.\n\n") -// if debugMode == true { -// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) -// } -// for i := 0; i < len(patterns); i++ { -// if len(patterns[i]) > len(textFile) { -// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) -// } -// if debugMode == true { -// fmt.Printf("%q ", patterns[i]) -// } -// } -// if debugMode == true { -// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) -// } -// r := ahoCorasick(string(textFile), patterns) -// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) -// for i := range value { -// fmt.Printf("%d", value[i]) -// if i != len(value)-1 { -// fmt.Printf(", ") -// } -// } -// fmt.Printf(".") -// } -// return -// } - -// AhoCorasick Function performing the Advanced Aho-Corasick alghoritm. -// Finds and prints occurrences of each pattern. -func AhoCorasick(t string, p []string) Result { - startTime := time.Now() - occurrences := make(map[int][]int) - ac, f := BuildExtendedAc(p) - // if debugMode == true { - // fmt.Printf("\n\nAC:\n\n") - // } - current := 0 - for pos := 0; pos < len(t); pos++ { - if GetTransition(current, t[pos], ac) != -1 { - current = GetTransition(current, t[pos], ac) - } else { - current = 0 - } - _, ok := f[current] - if ok { - for i := range f[current] { - if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match - // if debugMode == true { - // fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) - // } - newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) - occurrences[f[current][i]] = newOccurrences - occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 - } - } - } - } - elapsed := time.Since(startTime) - fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - - var resultOccurrences = make(map[string][]int) - for key, value := range occurrences { - resultOccurrences[p[key]] = value - } - - return Result{ - resultOccurrences, - } -} - -// BuildExtendedAc Functions that builds extended Aho Corasick automaton. -func BuildExtendedAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int) { - acTrie, stateIsTerminal, f := ConstructTrie(p) - s := make([]int, len(stateIsTerminal)) //supply function - i := 0 //root of acTrie - acToReturn = acTrie - s[i] = -1 - // if debugMode == true { - // fmt.Printf("\n\nAC construction: \n") - // } - for current := 1; current < len(stateIsTerminal); current++ { - o, parent := GetParent(current, acTrie) - down := s[parent] - for StateExists(down, acToReturn) && GetTransition(down, o, acToReturn) == -1 { - down = s[down] - } - if StateExists(down, acToReturn) { - s[current] = GetTransition(down, o, acToReturn) - if stateIsTerminal[s[current]] { - stateIsTerminal[current] = true - f[current] = ArrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) - // if debugMode == true { - // fmt.Printf(" f[%d] set to: ", current) - // for i := range f[current] { - // fmt.Printf("%d\n", f[current][i]) - // } - // } - } - } else { - s[current] = i //initial state? - } - } - // if debugMode == true { - // fmt.Printf("\nsupply function: \n") - // for i := range s { - // fmt.Printf("\ns[%d]=%d", i, s[i]) - // } - // fmt.Printf("\n\n") - // for i, j := range f { - // fmt.Printf("f[%d]=", i) - // for k := range j { - // fmt.Printf("%d\n", j[k]) - // } - // } - // } - // if debugMode == true { - // fmt.Printf("\n\nAdAC completion: \n") - // } - // advanced Aho-Corasick part - a := ComputeAlphabet(p) // concat of all patterns in p - for j := range a { - if GetTransition(i, a[j], acToReturn) == -1 { - CreateTransition(i, a[j], i, acToReturn) - } - } - for current := 1; current < len(stateIsTerminal); current++ { - for j := range a { - if GetTransition(current, a[j], acToReturn) == -1 { - CreateTransition(current, a[j], GetTransition(s[current], a[j], acToReturn), acToReturn) - } - } - } - return acToReturn, f -} - -// ConstructTrie Function that constructs Trie as an automaton for a set of reversed & trimmed strings. -func ConstructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { - trie = make(map[int]map[uint8]int) - stateIsTerminal = make([]bool, 1) - f = make(map[int][]int) - state := 1 - // if debugMode == true { - // fmt.Printf("\n\nTrie construction: \n") - // } - CreateNewState(0, trie) - for i := 0; i < len(p); i++ { - current := 0 - j := 0 - for j < len(p[i]) && GetTransition(current, p[i][j], trie) != -1 { - current = GetTransition(current, p[i][j], trie) - j++ - } - for j < len(p[i]) { - stateIsTerminal = BoolArrayCapUp(stateIsTerminal) - CreateNewState(state, trie) - stateIsTerminal[state] = false - CreateTransition(current, p[i][j], state, trie) - current = state - j++ - state++ - } - if stateIsTerminal[current] { - newArray := IntArrayCapUp(f[current]) - newArray[len(newArray)-1] = i - f[current] = newArray // F(Current) <- F(Current) union {i} - // if debugMode == true { - // fmt.Printf(" and %d", i) - // } - } else { - stateIsTerminal[current] = true - f[current] = []int{i} // F(Current) <- {i} - // if debugMode == true { - // fmt.Printf("\n%d is terminal for word number %d", current, i) - // } - } - } - return trie, stateIsTerminal, f -} - -// Contains Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. -func Contains(s []int, e int) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - -// GetWord Function that returns word found in text 't' at position range 'begin' to 'end'. -func GetWord(begin, end int, t string) string { - for end >= len(t) { - return "" - } - d := make([]uint8, end-begin+1) - for j, i := 0, begin; i <= end; i, j = i+1, j+1 { - d[j] = t[i] - } - return string(d) -} - -// ComputeAlphabet Function that returns string of all the possible characters in given patterns. -func ComputeAlphabet(p []string) (s string) { - s = p[0] - for i := 1; i < len(p); i++ { - s = s + p[i] - } - return s -} - -// IntArrayCapUp Dynamically increases an array size of int's by 1. -func IntArrayCapUp(old []int) (new []int) { - new = make([]int, cap(old)+1) - copy(new, old) //copy(dst,src) - // old = new - return new -} - -// BoolArrayCapUp Dynamically increases an array size of bool's by 1. -func BoolArrayCapUp(old []bool) (new []bool) { - new = make([]bool, cap(old)+1) - copy(new, old) - // old = new - return new -} - -// ArrayUnion Concats two arrays of int's into one. -func ArrayUnion(to, from []int) (concat []int) { - concat = to - for i := range from { - if !Contains(concat, from[i]) { - concat = IntArrayCapUp(concat) - concat[len(concat)-1] = from[i] - } - } - return concat -} - -// GetParent Function that finds the first previous state of a state and returns it. -// Used for trie where there is only one parent. -func GetParent(state int, at map[int]map[uint8]int) (uint8, int) { - for beginState, transitions := range at { - for c, endState := range transitions { - if endState == state { - return c, beginState - } - } - } - return 0, 0 //unreachable -} - -// CreateNewState Automaton function for creating a new state 'state'. -func CreateNewState(state int, at map[int]map[uint8]int) { - at[state] = make(map[uint8]int) - // if debugMode == true { - // fmt.Printf("\ncreated state %d", state) - // } -} - -// CreateTransition Creates a transition for function σ(state,letter) = end. -func CreateTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { - at[fromState][overChar] = toState - // if debugMode == true { - // fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - // } -} - -// GetTransition Returns ending state for transition σ(fromState,overChar), '-1' if there is none. -func GetTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { - if !StateExists(fromState, at) { - return -1 - } - toState, ok := at[fromState][overChar] - if !ok { - return -1 - } - return toState -} - -// StateExists Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. -func StateExists(state int, at map[int]map[uint8]int) bool { - _, ok := at[state] - if !ok || state == -1 || at[state] == nil { - return false - } - return true -} diff --git a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go b/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go deleted file mode 100644 index a7861858b..000000000 --- a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package advancedahocorasick - -import ( - "fmt" - "reflect" - "strings" - "testing" -) - -var testCases = []struct { - name string - words []string - text string - expected Result -}{ - - { - "String comparison on all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conferenceannounce_announce_annually_announce", - Result{ - map[string][]int{ - "annual": {4, 39}, - "announce": {21, 30, 48}, - "annually": {39}, - }, - }, - }, - { - "String comparison on not all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conference_announce", - Result{ - map[string][]int{ - "annual": {4}, - "announce": {22}, - }, - }, - }, - { - "String comparison on not all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conference_announce", - Result{ - map[string][]int{ - "annual": {4}, - "announce": {22}, - }, - }, - }, -} - -func TestAhoCorasick(t *testing.T) { - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - actual := AhoCorasick(tc.text, tc.words) - if !reflect.DeepEqual(actual, tc.expected) { - actualString := convertToString(actual) - expectedString := convertToString(tc.expected) - t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", - tc.words, tc.text, actualString, expectedString) - } - }) - } -} - -func convertToString(res Result) string { - // var r string - var r strings.Builder - for key, val := range res.occurrences { - r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) - for i := range val { - r.WriteString(fmt.Sprintf("%d", val[i])) - if i != len(val)-1 { - // r = r + fmt.Sprintf(", ") - r.WriteString(", ") - } - } - // r = r + fmt.Sprintf(". ") - r.WriteString(". ") - } - return r.String() -} diff --git a/strings/multiple_string_matching/aho_corasick/ahocorasick.go b/strings/multiple_string_matching/aho_corasick/ahocorasick.go deleted file mode 100644 index 903f693fc..000000000 --- a/strings/multiple_string_matching/aho_corasick/ahocorasick.go +++ /dev/null @@ -1,303 +0,0 @@ -package ahocorasick - -import ( - "fmt" - "time" -) - -// User defined. -// Set to true to print various extra stuff out (slows down the execution) -// Set to false for quick and quiet execution. -// const debugMode bool = true - -type Result struct { - occurrences map[string][]int -} - -// Implementation of Basic Aho-Corasick algorithm (Prefix based). -// Searches for a set of strings (patterns.txt) in text.txt. -// func main() { -// patFile, err := ioutil.ReadFile("../patterns.txt") -// if err != nil { -// log.Fatal(err) -// } -// textFile, err := ioutil.ReadFile("../text.txt") -// if err != nil { -// log.Fatal(err) -// } -// patterns := strings.Split(string(patFile), " ") -// fmt.Printf("\nRunning: Basic Aho-Corasick algorithm.\n\n") -// if debugMode == true { -// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) -// } -// for i := 0; i < len(patterns); i++ { -// if len(patterns[i]) > len(textFile) { -// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) -// } -// if debugMode == true { -// fmt.Printf("%q ", patterns[i]) -// } -// } -// if debugMode == true { -// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) -// } -// r := ahoCorasick(string(textFile), patterns) -// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) -// for i := range value { -// fmt.Printf("%d", value[i]) -// if i != len(value)-1 { -// fmt.Printf(", ") -// } -// } -// fmt.Printf(".") -// } -// } - -// AhoCorasick Function performing the Basic Aho-Corasick algorithm. -// Finds and prints occurrences of each pattern. -func AhoCorasick(t string, p []string) Result { - startTime := time.Now() - occurrences := make(map[int][]int) - ac, f, s := buildAc(p) - // if debugMode == true { - // fmt.Printf("\n\nAC:\n\n") - // } - current := 0 - for pos := 0; pos < len(t); pos++ { - // if debugMode == true { - // fmt.Printf("Position: %d, we read: %c", pos, t[pos]) - // } - for getTransition(current, t[pos], ac) == -1 && s[current] != -1 { - current = s[current] - } - if getTransition(current, t[pos], ac) != -1 { - current = getTransition(current, t[pos], ac) - fmt.Printf(" (Continue) \n") - } else { - current = 0 - // if debugMode == true { - // fmt.Printf(" (FAIL) \n") - // } - } - _, ok := f[current] - if ok { - for i := range f[current] { - if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match - // if debugMode == true { - // fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) - // } - newOccurrences := intArrayCapUp(occurrences[f[current][i]]) - occurrences[f[current][i]] = newOccurrences - occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 - } - } - } - } - elapsed := time.Since(startTime) - fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - var resultOccurrences = make(map[string][]int) - for key, value := range occurrences { - resultOccurrences[p[key]] = value - } - - return Result{ - resultOccurrences, - } -} - -// Functions that builds Aho Corasick automaton. -func buildAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int, s []int) { - acTrie, stateIsTerminal, f := constructTrie(p) - s = make([]int, len(stateIsTerminal)) //supply function - i := 0 //root of acTrie - acToReturn = acTrie - s[i] = -1 - // if debugMode == true { - // fmt.Printf("\n\nAC construction: \n") - // } - for current := 1; current < len(stateIsTerminal); current++ { - o, parent := getParent(current, acTrie) - down := s[parent] - for stateExists(down, acToReturn) && getTransition(down, o, acToReturn) == -1 { - down = s[down] - } - if stateExists(down, acToReturn) { - s[current] = getTransition(down, o, acToReturn) - if stateIsTerminal[s[current]] { - stateIsTerminal[current] = true - f[current] = arrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) - // if debugMode == true { - // fmt.Printf(" f[%d] set to: ", current) - // for i := range f[current] { - // fmt.Printf("%d\n", f[current][i]) - // } - // } - } - } else { - s[current] = i //initial state? - } - } - // if debugMode == true { - // fmt.Printf("\nsupply function: \n") - // for i := range s { - // fmt.Printf("\ns[%d]=%d", i, s[i]) - // } - // fmt.Printf("\n\n") - // for i, j := range f { - // fmt.Printf("f[%d]=", i) - // for k := range j { - // fmt.Printf("%d\n", j[k]) - // } - // } - // } - return acToReturn, f, s -} - -// Function that constructs Trie as an automaton for a set of reversed & trimmed strings. -func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { - trie = make(map[int]map[uint8]int) - stateIsTerminal = make([]bool, 1) - f = make(map[int][]int) - state := 1 - // if debugMode == true { - // fmt.Printf("\n\nTrie construction: \n") - // } - createNewState(0, trie) - for i := 0; i < len(p); i++ { - current := 0 - j := 0 - for j < len(p[i]) && getTransition(current, p[i][j], trie) != -1 { - current = getTransition(current, p[i][j], trie) - j++ - } - for j < len(p[i]) { - stateIsTerminal = boolArrayCapUp(stateIsTerminal) - createNewState(state, trie) - stateIsTerminal[state] = false - createTransition(current, p[i][j], state, trie) - current = state - j++ - state++ - } - if stateIsTerminal[current] { - newArray := intArrayCapUp(f[current]) - newArray[len(newArray)-1] = i - f[current] = newArray //F(Current) <- F(Current) union {i} - // if debugMode == true { - // fmt.Printf(" and %d", i) - // } - } else { - stateIsTerminal[current] = true - f[current] = []int{i} //F(Current) <- {i} - // if debugMode == true { - // fmt.Printf("\n%d is terminal for word number %d", current, i) - // } - } - } - return trie, stateIsTerminal, f -} - -/** -Returns 'true' if array of int's 's' contains int 'e', 'false' otherwise. - -@author Mostafa http://stackoverflow.com/a/10485970 -*/ -func contains(s []int, e int) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - -// Function that returns word found in text 't' at position range 'begin' to 'end'. -func getWord(begin, end int, t string) string { - for end >= len(t) { - return "" - } - d := make([]uint8, end-begin+1) - for j, i := 0, begin; i <= end; i, j = i+1, j+1 { - d[j] = t[i] - } - return string(d) -} - -// Dynamically increases an array size of int's by 1. -func intArrayCapUp(old []int) (new []int) { - new = make([]int, cap(old)+1) - copy(new, old) //copy(dst,src) - // old = new - return new -} - -// Dynamically increases an array size of bool's by 1. -func boolArrayCapUp(old []bool) (new []bool) { - new = make([]bool, cap(old)+1) - copy(new, old) - // old = new - return new -} - -// Concats two arrays of int's into one. -func arrayUnion(to, from []int) (concat []int) { - concat = to - for i := range from { - if !contains(concat, from[i]) { - concat = intArrayCapUp(concat) - concat[len(concat)-1] = from[i] - } - } - return concat -} - -// Function that finds the first previous state of a state and returns it. -// Used for trie where there is only one parent. -func getParent(state int, at map[int]map[uint8]int) (uint8, int) { - for beginState, transitions := range at { - for c, endState := range transitions { - if endState == state { - return c, beginState - } - } - } - return 0, 0 //unreachable -} - -// Automaton function for creating a new state 'state'. -func createNewState(state int, at map[int]map[uint8]int) { - at[state] = make(map[uint8]int) - // if debugMode == true { - // fmt.Printf("\ncreated state %d", state) - // } -} - -// Creates a transition for function σ(state,letter) = end. -func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { - at[fromState][overChar] = toState - // if debugMode == true { - // fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - // } -} - -// Returns ending state for transition σ(fromState,overChar), '-1' if there is none. -func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { - if !stateExists(fromState, at) { - return -1 - } - toState, ok := at[fromState][overChar] - if !ok { - return -1 - } - return toState -} - -// Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. -func stateExists(state int, at map[int]map[uint8]int) bool { - _, ok := at[state] - if !ok || state == -1 || at[state] == nil { - return false - } - return true -} diff --git a/strings/naive_string_search/naivestringsearch.go b/strings/search/patternsearch.go similarity index 85% rename from strings/naive_string_search/naivestringsearch.go rename to strings/search/patternsearch.go index 3aa9692a6..ca75129a4 100644 --- a/strings/naive_string_search/naivestringsearch.go +++ b/strings/search/patternsearch.go @@ -8,9 +8,9 @@ Time Complexity : O(n*m) m = length of pattern */ -package naive_string_search +package search -func naivePatternSearch(text string, pattern string) []int { +func Naive(text string, pattern string) []int { var positions []int for i := 0; i <= len(text)-len(pattern); i++ { var match bool = true diff --git a/strings/naive_string_search/naivestringsearch_test.go b/strings/search/patternsearch_test.go similarity index 85% rename from strings/naive_string_search/naivestringsearch_test.go rename to strings/search/patternsearch_test.go index 89db92958..2df0b842c 100644 --- a/strings/naive_string_search/naivestringsearch_test.go +++ b/strings/search/patternsearch_test.go @@ -1,4 +1,4 @@ -package naive_string_search +package search import ( "reflect" @@ -37,10 +37,10 @@ var testCases = []struct { }, } -func TestNaivePatternSearch(t *testing.T) { +func TestNaive(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := naivePatternSearch(tc.input, tc.pattern) + actual := Naive(tc.input, tc.pattern) if !reflect.DeepEqual(actual, tc.expected) { t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v, but actual matches are: %v", tc.pattern, tc.input, tc.expected, actual) } diff --git a/strings/single_string_matching/pattern.txt b/strings/single_string_matching/pattern.txt deleted file mode 100644 index 487161401..000000000 --- a/strings/single_string_matching/pattern.txt +++ /dev/null @@ -1 +0,0 @@ -announce \ No newline at end of file diff --git a/strings/single_string_matching/text.txt b/strings/single_string_matching/text.txt deleted file mode 100644 index e98cf5c73..000000000 --- a/strings/single_string_matching/text.txt +++ /dev/null @@ -1 +0,0 @@ -CPM_annual_conference_announce \ No newline at end of file diff --git a/data_structures/avl/avl.go b/structure/avl/avl.go similarity index 100% rename from data_structures/avl/avl.go rename to structure/avl/avl.go diff --git a/data_structures/avl/avl_test.go b/structure/avl/avl_test.go similarity index 100% rename from data_structures/avl/avl_test.go rename to structure/avl/avl_test.go diff --git a/data_structures/binary_tree/btree.go b/structure/binarytree/btree.go similarity index 100% rename from data_structures/binary_tree/btree.go rename to structure/binarytree/btree.go diff --git a/data_structures/binary_tree/node.go b/structure/binarytree/node.go similarity index 100% rename from data_structures/binary_tree/node.go rename to structure/binarytree/node.go diff --git a/data_structures/dynamic_array/dynamicarray.go b/structure/dynamicarray/dynamicarray.go similarity index 52% rename from data_structures/dynamic_array/dynamicarray.go rename to structure/dynamicarray/dynamicarray.go index 0d09bb8a3..66822be70 100644 --- a/data_structures/dynamic_array/dynamicarray.go +++ b/structure/dynamicarray/dynamicarray.go @@ -1,16 +1,16 @@ -// Dynamic Array -// description: A dynamic array is quite similar to a regular array, but its size is modifiable during program runtime. -// details: for more details check out those links below here: -// geeks for geeks article : https://www.geeksforgeeks.org/how-do-dynamic-arrays-work/ -// We can mention that Dynamic Array is like Slice for more detail about `Go` Slices check those articles : -// https://blog.golang.org/slices-intro -// https://blog.golang.org/slices +// Package dynamicarray +// A dynamic array is quite similar to a regular array, but its Size is modifiable during program runtime, +// very similar to how a slice in Go works. The implementation is for educational purposes and explains +// how one might go about implementing their own version of slices. +// +// For more details check out those links below here: +// GeeksForGeeks article : https://www.geeksforgeeks.org/how-do-dynamic-arrays-work/ +// Go blog: https://blog.golang.org/slices-intro +// Go blog: https://blog.golang.org/slices // authors [Wesllhey Holanda](https://github.com/wesllhey), [Milad](https://github.com/miraddo) // see dynamicarray.go, dynamicarray_test.go - package dynamicarray -// errors: used to handle CheckRangeFromIndex function with a reasonable error value import ( "errors" ) @@ -18,13 +18,10 @@ import ( var defaultCapacity = 10 // DynamicArray structure -// size: length of array -// capacity: the maximum length of the segment -// elementData: an array of any type of data with interface type DynamicArray struct { - size int - capacity int - elementData []interface{} + Size int + Capacity int + ElementData []interface{} } // Put function is change/update the value in array with the index and new value @@ -35,19 +32,19 @@ func (da *DynamicArray) Put(index int, element interface{}) error { return err } - da.elementData[index] = element + da.ElementData[index] = element return nil } // Add function is add new element to our array func (da *DynamicArray) Add(element interface{}) { - if da.size == da.capacity { + if da.Size == da.Capacity { da.NewCapacity() } - da.elementData[da.size] = element - da.size++ + da.ElementData[da.Size] = element + da.Size++ } // Remove function is remove an element with the index @@ -58,10 +55,10 @@ func (da *DynamicArray) Remove(index int) error { return err } - copy(da.elementData[index:], da.elementData[index+1:da.size]) - da.elementData[da.size-1] = nil + copy(da.ElementData[index:], da.ElementData[index+1:da.Size]) + da.ElementData[da.Size-1] = nil - da.size-- + da.Size-- return nil } @@ -74,38 +71,38 @@ func (da *DynamicArray) Get(index int) (interface{}, error) { return nil, err } - return da.elementData[index], nil + return da.ElementData[index], nil } // IsEmpty function is check that the array has value or not func (da *DynamicArray) IsEmpty() bool { - return da.size == 0 + return da.Size == 0 } // GetData function return all value of array func (da *DynamicArray) GetData() []interface{} { - return da.elementData[:da.size] + return da.ElementData[:da.Size] } // CheckRangeFromIndex function it will check the range from the index func (da *DynamicArray) CheckRangeFromIndex(index int) error { - if index >= da.size || index < 0 { + if index >= da.Size || index < 0 { return errors.New("index out of range") } return nil } -// NewCapacity function increase the capacity +// NewCapacity function increase the Capacity func (da *DynamicArray) NewCapacity() { - if da.capacity == 0 { - da.capacity = defaultCapacity + if da.Capacity == 0 { + da.Capacity = defaultCapacity } else { - da.capacity = da.capacity << 1 + da.Capacity = da.Capacity << 1 } - newDataElement := make([]interface{}, da.capacity) + newDataElement := make([]interface{}, da.Capacity) - copy(newDataElement, da.elementData) + copy(newDataElement, da.ElementData) - da.elementData = newDataElement + da.ElementData = newDataElement } diff --git a/data_structures/dynamic_array/dynamicarray_test.go b/structure/dynamicarray/dynamicarray_test.go similarity index 94% rename from data_structures/dynamic_array/dynamicarray_test.go rename to structure/dynamicarray/dynamicarray_test.go index adb1cd81a..976370ba8 100644 --- a/data_structures/dynamic_array/dynamicarray_test.go +++ b/structure/dynamicarray/dynamicarray_test.go @@ -1,12 +1,10 @@ package dynamicarray -// reflect: used for check equal values import ( "reflect" "testing" ) -// TestDynamicArray some test for dynamic array to make sure everything is ok, and we got the right result func TestDynamicArray(t *testing.T) { numbers := DynamicArray{} diff --git a/data_structures/hashmap/hashmap.go b/structure/hashmap/hashmap.go similarity index 100% rename from data_structures/hashmap/hashmap.go rename to structure/hashmap/hashmap.go diff --git a/data_structures/hashmap/hashmap_test.go b/structure/hashmap/hashmap_test.go similarity index 100% rename from data_structures/hashmap/hashmap_test.go rename to structure/hashmap/hashmap_test.go diff --git a/datastructures/linkedlist/cyclicallylinkedlist/Linked_Cyclic_List.jpg b/structure/linkedlist/Linked_Cyclic_List.jpg similarity index 100% rename from datastructures/linkedlist/cyclicallylinkedlist/Linked_Cyclic_List.jpg rename to structure/linkedlist/Linked_Cyclic_List.jpg diff --git a/structure/linkedlist/Readme.md b/structure/linkedlist/Readme.md new file mode 100644 index 000000000..32f784c96 --- /dev/null +++ b/structure/linkedlist/Readme.md @@ -0,0 +1,27 @@ +# Linked List +*** +## What is it? +*** +Linked list is a data structure that is a linear chain of data elements whose order is not given by their phyisical placement in memory. This structure is built up of nodes which point to the element ahead or behind this particular node (depending on the type of Linked List). + +# Types of Linked List implemented within this repository + +## Singly Linked List +Singly Linked List is a linked list in which a node only points to the next element. +Some of the main applications of Singly Linked List are in the construction +of fundamental data structures such as Stacks and Queues. + +## Doubly Linked List +Doubly Linked List is a linked list in which a node points to both the element ahead and behind the node. +Any application which requires us to keep track of forward and backward information uses doubly linked list. +For example, the feature of undo and redo are implemented using these doubly linked lists. + +## Cyclic Linked List AKA Looped Linked List +Looped Linked Lists are singly or doubly-linked that chase their own tail: +A points to B, B points to C, C points to D, and D points to A. +They are better suited for cyclic data such as train schedules. +These lists are missing the first and last items. +Therefore, it is necessary to introduce the concept of the current position. + +This picture shows similar lists: +![Alt text](./Linked_Cyclic_List.jpg?raw=true) diff --git a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go b/structure/linkedlist/cyclic.go similarity index 56% rename from datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go rename to structure/linkedlist/cyclic.go index 454088c86..cf0ab22df 100644 --- a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go +++ b/structure/linkedlist/cyclic.go @@ -1,49 +1,34 @@ -// Package cyclicallylinkedlist demonstration of Linked List Cycle in golang - -package cyclicallylinkedlist +package linkedlist import "fmt" -// Node of List. -type ClNode struct { - Val interface{} - prev *ClNode - next *ClNode -} - -// The Cycling list in this implementation is addressed -// by means of the element located at the current position. -type ClList struct { - Size int - CurrentItem *ClNode +// Cyclic Struct which cycles the linked list in this implementation. +type Cyclic struct { + Size int + Head *Node } // Create new list. -func NewList() *ClList { - return &ClList{0, nil} -} - -// Create new node. -func NewNode(val interface{}) *ClNode { - return &ClNode{val, nil, nil} +func NewCyclic() *Cyclic { + return &Cyclic{0, nil} } // Inserting the first node is a special case. It will // point to itself. For other cases, the node will be added -// to the end of the list. End of the list is prev field of +// to the end of the list. End of the list is Prev field of // current item. Complexity O(1). -func (cl *ClList) Add(val interface{}) { +func (cl *Cyclic) Add(val interface{}) { n := NewNode(val) cl.Size++ - if cl.CurrentItem == nil { - n.prev = n - n.next = n - cl.CurrentItem = n + if cl.Head == nil { + n.Prev = n + n.Next = n + cl.Head = n } else { - n.prev = cl.CurrentItem.prev - n.next = cl.CurrentItem - cl.CurrentItem.prev.next = n - cl.CurrentItem.prev = n + n.Prev = cl.Head.Prev + n.Next = cl.Head + cl.Head.Prev.Next = n + cl.Head.Prev = n } } @@ -61,7 +46,7 @@ func (cl *ClList) Add(val interface{}) { // places is the same as moving N - P places back. // Therefore, if P > N / 2, you can turn the list by N-P places back. // Complexity O(n). -func (cl *ClList) Rotate(places int) { +func (cl *Cyclic) Rotate(places int) { if cl.Size > 0 { if places < 0 { multiple := cl.Size - 1 - places/cl.Size @@ -72,13 +57,13 @@ func (cl *ClList) Rotate(places int) { if places > cl.Size/2 { places = cl.Size - places for i := 0; i < places; i++ { - cl.CurrentItem = cl.CurrentItem.prev + cl.Head = cl.Head.Prev } } else if places == 0 { return } else { for i := 0; i < places; i++ { - cl.CurrentItem = cl.CurrentItem.next + cl.Head = cl.Head.Next } } @@ -86,25 +71,25 @@ func (cl *ClList) Rotate(places int) { } // Delete the current item. -func (cl *ClList) Delete() bool { +func (cl *Cyclic) Delete() bool { var deleted bool - var prevItem, thisItem, nextItem *ClNode + var prevItem, thisItem, nextItem *Node if cl.Size == 0 { return deleted } deleted = true - thisItem = cl.CurrentItem - nextItem = thisItem.next - prevItem = thisItem.prev + thisItem = cl.Head + nextItem = thisItem.Next + prevItem = thisItem.Prev if cl.Size == 1 { - cl.CurrentItem = nil + cl.Head = nil } else { - cl.CurrentItem = nextItem - nextItem.prev = prevItem - prevItem.next = nextItem + cl.Head = nextItem + nextItem.Prev = prevItem + prevItem.Next = nextItem } cl.Size-- @@ -112,33 +97,33 @@ func (cl *ClList) Delete() bool { } // Destroy all items in the list. -func (cl *ClList) Destroy() { +func (cl *Cyclic) Destroy() { for cl.Delete() { continue } } // Show list body. -func (cl *ClList) Walk() *ClNode { - var start *ClNode - start = cl.CurrentItem +func (cl *Cyclic) Walk() *Node { + var start *Node + start = cl.Head for i := 0; i < cl.Size; i++ { fmt.Printf("%v \n", start.Val) - start = start.next + start = start.Next } return start } // https://en.wikipedia.org/wiki/Josephus_problem // This is a struct-based solution for Josephus problem. -func JosephusProblem(cl *ClList, k int) int { +func JosephusProblem(cl *Cyclic, k int) int { for cl.Size > 1 { cl.Rotate(k) cl.Delete() cl.Rotate(-1) } - retval := cl.CurrentItem.Val.(int) + retval := cl.Head.Val.(int) cl.Destroy() return retval } diff --git a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go b/structure/linkedlist/cyclic_test.go similarity index 84% rename from datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go rename to structure/linkedlist/cyclic_test.go index 10eb1f88c..162f9d0a1 100644 --- a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go +++ b/structure/linkedlist/cyclic_test.go @@ -1,28 +1,28 @@ -package cyclicallylinkedlist +package linkedlist import ( "reflect" "testing" ) -func fillList(list *ClList, n int) { +func fillList(list *Cyclic, n int) { for i := 1; i <= n; i++ { list.Add(i) } } func TestAdd(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) want := []interface{}{1, 2, 3} var got []interface{} - var start *ClNode - start = list.CurrentItem + var start *Node + start = list.Head for i := 0; i < list.Size; i++ { got = append(got, start.Val) - start = start.next + start = start.Next } if !reflect.DeepEqual(got, want) { t.Errorf("got: %v, want: %v", got, want) @@ -30,7 +30,7 @@ func TestAdd(t *testing.T) { } func TestWalk(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) want := 1 @@ -46,7 +46,7 @@ func TestRotate(t *testing.T) { param int wantToReturn int } - list := NewList() + list := NewCyclic() fillList(list, 3) testCases := []testCase{ @@ -61,7 +61,7 @@ func TestRotate(t *testing.T) { } for idx, tCase := range testCases { list.Rotate(tCase.param) - got := list.CurrentItem.Val + got := list.Head.Val if got != tCase.wantToReturn { t.Errorf("got: %v, want: %v for test id %v", got, tCase.wantToReturn, idx) } @@ -69,13 +69,13 @@ func TestRotate(t *testing.T) { } func TestDelete(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) want := 2 wantSize := 2 list.Delete() - got := list.CurrentItem.Val + got := list.Head.Val if want != got { t.Errorf("got: %v, want: %v", got, want) } @@ -85,12 +85,12 @@ func TestDelete(t *testing.T) { } func TestDestroy(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) wantSize := 0 list.Destroy() - got := list.CurrentItem + got := list.Head if got != nil { t.Errorf("got: %v, want: nil", got) @@ -119,7 +119,7 @@ func TestJosephusProblem(t *testing.T) { } for _, tCase := range testCases { - list := NewList() + list := NewCyclic() fillList(list, tCase.listCount) got := JosephusProblem(list, tCase.param) if got != tCase.wantToReturn { diff --git a/structure/linkedlist/doc.go b/structure/linkedlist/doc.go new file mode 100644 index 000000000..580adf068 --- /dev/null +++ b/structure/linkedlist/doc.go @@ -0,0 +1,2 @@ +// Package linkedlist demonstates different implementations on linkedlists. +package linkedlist diff --git a/structure/linkedlist/doubly.go b/structure/linkedlist/doubly.go new file mode 100644 index 000000000..b0c1970f3 --- /dev/null +++ b/structure/linkedlist/doubly.go @@ -0,0 +1,142 @@ +package linkedlist + +import "fmt" + +// Doubly structure with just the Head Node +// We call it `Doubly` to make it easier to +// understand when calling this in peoples +// own local code to understand and experiment +// with this easily. +// For example, we can use gotools `go get` command to get +// this repository cloned inside the +// $GOPATH/src/github.com/TheAlgorithms/Go (you can do this +// manually as well) and use the import statement as follows: +// +// `import "github.com/TheAlgorithms/Go/structure/linkedlist"` +// +// and call linkedlist.Doubly to create a new doubly linked list. +type Doubly struct { + Head *Node +} + +func NewDoubly() *Doubly { + return &Doubly{nil} +} + +// AddAtBeg Add a node to the beginning of the linkedlist +func (ll *Doubly) AddAtBeg(val interface{}) { + n := NewNode(val) + n.Next = ll.Head + + if ll.Head != nil { + ll.Head.Prev = n + } + + ll.Head = n + +} + +// AddAtEnd Add a node at the end of the linkedlist +func (ll *Doubly) AddAtEnd(val interface{}) { + n := NewNode(val) + + if ll.Head == nil { + ll.Head = n + return + } + + cur := ll.Head + for ; cur.Next != nil; cur = cur.Next { + } + cur.Next = n + n.Prev = cur +} + +// DelAtBeg Delete the node at the beginning of the linkedlist +func (ll *Doubly) DelAtBeg() interface{} { + if ll.Head == nil { + return -1 + } + + cur := ll.Head + ll.Head = cur.Next + + if ll.Head != nil { + ll.Head.Prev = nil + } + return cur.Val +} + +// DetAtEnd Delete a node at the end of the linkedlist +func (ll *Doubly) DelAtEnd() interface{} { + // no item + if ll.Head == nil { + return -1 + } + + // only one item + if ll.Head.Next == nil { + return ll.DelAtBeg() + } + + // more than one, go to second last + cur := ll.Head + for ; cur.Next.Next != nil; cur = cur.Next { + } + + retval := cur.Next.Val + cur.Next = nil + return retval +} + +// Count Number of nodes in the linkedlist +func (ll *Doubly) Count() interface{} { + var ctr int = 0 + + for cur := ll.Head; cur != nil; cur = cur.Next { + ctr += 1 + } + + return ctr +} + +// Reverse Reverse the order of the linkedlist +func (ll *Doubly) Reverse() { + var Prev, Next *Node + cur := ll.Head + + for cur != nil { + Next = cur.Next + cur.Next = Prev + cur.Prev = Next + Prev = cur + cur = Next + } + + ll.Head = Prev +} + +// Display diplay the linked list +func (ll *Doubly) Display() { + for cur := ll.Head; cur != nil; cur = cur.Next { + fmt.Print(cur.Val, " ") + } + + fmt.Print("\n") +} + +// DisplayReverse Display the linkedlist in reverse order +func (ll *Doubly) DisplayReverse() { + if ll.Head == nil { + return + } + var cur *Node + for cur = ll.Head; cur.Next != nil; cur = cur.Next { + } + + for ; cur != nil; cur = cur.Prev { + fmt.Print(cur.Val, " ") + } + + fmt.Print("\n") +} diff --git a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go b/structure/linkedlist/doubly_test.go similarity index 65% rename from data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go rename to structure/linkedlist/doubly_test.go index eeac97e87..b46474d48 100644 --- a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go +++ b/structure/linkedlist/doubly_test.go @@ -1,12 +1,12 @@ -package doubly_linkedlist +package linkedlist import ( "reflect" "testing" ) -func TestDoubleLinkedList(t *testing.T) { - newList := DoubleLinkedList{} +func TestDoubly(t *testing.T) { + newList := NewDoubly() newList.AddAtBeg(1) newList.AddAtBeg(2) @@ -17,27 +17,27 @@ func TestDoubleLinkedList(t *testing.T) { wantPrev := []int{1, 2, 3} got := []int{} - // check from next address - current := newList.head + // check from Next address + current := newList.Head - got = append(got, current.val) + got = append(got, current.Val.(int)) - for current.next != nil { - current = current.next - got = append(got, current.val) + for current.Next != nil { + current = current.Next + got = append(got, current.Val.(int)) } if !reflect.DeepEqual(got, wantNext) { t.Errorf("got: %v, want: %v", got, wantNext) } - // check from prev address + // check from Prev address got = []int{} - got = append(got, current.val) + got = append(got, current.Val.(int)) - for current.prev != nil { - current = current.prev - got = append(got, current.val) + for current.Prev != nil { + current = current.Prev + got = append(got, current.Val.(int)) } if !reflect.DeepEqual(got, wantPrev) { @@ -50,11 +50,11 @@ func TestDoubleLinkedList(t *testing.T) { t.Run("Test AddAtEnd", func(t *testing.T) { want := []int{3, 2, 1, 4} got := []int{} - current := newList.head - got = append(got, current.val) - for current.next != nil { - current = current.next - got = append(got, current.val) + current := newList.Head + got = append(got, current.Val.(int)) + for current.Next != nil { + current = current.Next + got = append(got, current.Val.(int)) } if !reflect.DeepEqual(got, want) { t.Errorf("got: %v, want: %v", got, want) diff --git a/structure/linkedlist/shared.go b/structure/linkedlist/shared.go new file mode 100644 index 000000000..b9d228f6f --- /dev/null +++ b/structure/linkedlist/shared.go @@ -0,0 +1,14 @@ +package linkedlist + +// Node Structure representing the linkedlist node. +// This node is shared accross different implementations. +type Node struct { + Val interface{} + Prev *Node + Next *Node +} + +// Create new node. +func NewNode(val interface{}) *Node { + return &Node{val, nil, nil} +} diff --git a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go similarity index 60% rename from data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go rename to structure/linkedlist/singlylinkedlist.go index 11267a9a6..cf69056a1 100644 --- a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -1,33 +1,24 @@ -// Package singlelinkedlist Single Linked List -package singly_linkedlist +package linkedlist // demonstration of singly linked list in golang import "fmt" -// TODO: This is not how it should be done but I don't see a way out of this -type snode struct { - Val interface{} - Next *snode -} - -// SingleLinkedList structure with length of the list and its head -type SingleLinkedList struct { +// Singly structure with length of the list and its head +type Singly struct { length int - Head *snode -} -// CreateList returns a new instance of a linked list -func CreateList() *SingleLinkedList { - return &SingleLinkedList{} + // Note that Node here holds both Next and Prev Node + // however only the Next node is used in Singly methods. + Head *Node } -// to avoid mistakes when using pointer vs struct for new snode creation -func NewNode(val interface{}) *snode { - return &snode{val, nil} +// NewSingly returns a new instance of a linked list +func NewSingly() *Singly { + return &Singly{} } // AddAtBeg adds a new snode with given value at the beginning of the list. -func (ll *SingleLinkedList) AddAtBeg(val interface{}) { +func (ll *Singly) AddAtBeg(val interface{}) { n := NewNode(val) n.Next = ll.Head ll.Head = n @@ -35,7 +26,7 @@ func (ll *SingleLinkedList) AddAtBeg(val interface{}) { } // AddAtEnd adds a new snode with given value at the end of the list. -func (ll *SingleLinkedList) AddAtEnd(val int) { +func (ll *Singly) AddAtEnd(val int) { n := NewNode(val) if ll.Head == nil { @@ -52,7 +43,7 @@ func (ll *SingleLinkedList) AddAtEnd(val int) { } // DelAtBeg deletes the snode at the head(beginning) of the list and returns its value. Returns -1 if the list is empty. -func (ll *SingleLinkedList) DelAtBeg() interface{} { +func (ll *Singly) DelAtBeg() interface{} { if ll.Head == nil { return -1 } @@ -65,7 +56,7 @@ func (ll *SingleLinkedList) DelAtBeg() interface{} { } // DelAtEnd deletes the snode at the tail(end) of the list and returns its value. Returns -1 if the list is empty. -func (ll *SingleLinkedList) DelAtEnd() interface{} { +func (ll *Singly) DelAtEnd() interface{} { if ll.Head == nil { return -1 } @@ -87,13 +78,13 @@ func (ll *SingleLinkedList) DelAtEnd() interface{} { } // Count returns the current size of the list. -func (ll *SingleLinkedList) Count() int { +func (ll *Singly) Count() int { return ll.length } // Reverse reverses the list. -func (ll *SingleLinkedList) Reverse() { - var prev, Next *snode +func (ll *Singly) Reverse() { + var prev, Next *Node cur := ll.Head for cur != nil { @@ -107,7 +98,7 @@ func (ll *SingleLinkedList) Reverse() { } // Display prints out the elements of the list. -func (ll *SingleLinkedList) Display() { +func (ll *Singly) Display() { for cur := ll.Head; cur != nil; cur = cur.Next { fmt.Print(cur.Val, " ") } diff --git a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go b/structure/linkedlist/singlylinkedlist_test.go similarity index 93% rename from data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go rename to structure/linkedlist/singlylinkedlist_test.go index 7cd713fd4..0da92cadf 100644 --- a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go +++ b/structure/linkedlist/singlylinkedlist_test.go @@ -1,12 +1,12 @@ -package singly_linkedlist +package linkedlist import ( "reflect" "testing" ) -func TestLinkedList(t *testing.T) { - list := CreateList() +func TestSingly(t *testing.T) { + list := NewSingly() list.AddAtBeg(1) list.AddAtBeg(2) list.AddAtBeg(3) diff --git a/data_structures/queue/queue_test.go b/structure/queue/queue_test.go similarity index 100% rename from data_structures/queue/queue_test.go rename to structure/queue/queue_test.go diff --git a/data_structures/queue/queuearray.go b/structure/queue/queuearray.go similarity index 100% rename from data_structures/queue/queuearray.go rename to structure/queue/queuearray.go diff --git a/data_structures/queue/queuelinkedlist.go b/structure/queue/queuelinkedlist.go similarity index 100% rename from data_structures/queue/queuelinkedlist.go rename to structure/queue/queuelinkedlist.go diff --git a/data_structures/queue/queuelinklistwithlist.go b/structure/queue/queuelinklistwithlist.go similarity index 100% rename from data_structures/queue/queuelinklistwithlist.go rename to structure/queue/queuelinklistwithlist.go diff --git a/data_structures/set/set.go b/structure/set/set.go similarity index 100% rename from data_structures/set/set.go rename to structure/set/set.go diff --git a/data_structures/stack/stack_test.go b/structure/stack/stack_test.go similarity index 100% rename from data_structures/stack/stack_test.go rename to structure/stack/stack_test.go diff --git a/data_structures/stack/stackarray.go b/structure/stack/stackarray.go similarity index 100% rename from data_structures/stack/stackarray.go rename to structure/stack/stackarray.go diff --git a/data_structures/stack/stacklinkedlist.go b/structure/stack/stacklinkedlist.go similarity index 100% rename from data_structures/stack/stacklinkedlist.go rename to structure/stack/stacklinkedlist.go diff --git a/data_structures/stack/stacklinkedlistwithlist.go b/structure/stack/stacklinkedlistwithlist.go similarity index 100% rename from data_structures/stack/stacklinkedlistwithlist.go rename to structure/stack/stacklinkedlistwithlist.go diff --git a/data_structures/trie/trie.go b/structure/trie/trie.go similarity index 100% rename from data_structures/trie/trie.go rename to structure/trie/trie.go diff --git a/data_structures/trie/trie_test.go b/structure/trie/trie_test.go similarity index 100% rename from data_structures/trie/trie_test.go rename to structure/trie/trie_test.go From 8cfdb2f00c17e5a8776b42218446149d6733c9e1 Mon Sep 17 00:00:00 2001 From: Taj Date: Wed, 8 Sep 2021 06:17:49 +0100 Subject: [PATCH 224/488] doc: fix: Added documentations that works with the autogenerated documentation (#339) * doc: fix: Add documentation that works with the autogenerated documentation * Update go.mod to accept go version 1.17 * test: add a few tests for one of the issues --- {ciphers => cipher}/caesar/caesar.go | 0 {ciphers => cipher}/caesar/caesar_test.go | 0 .../diffiehellman/diffiehellmankeyexchange.go | 0 .../diffiehellmankeyexchange_test.go | 0 cipher/doc.go | 2 + {ciphers => cipher}/polybius/polybius.go | 0 {ciphers => cipher}/polybius/polybius_test.go | 0 {ciphers => cipher}/rot13/rot13.go | 2 +- {ciphers => cipher}/rot13/rot13_test.go | 0 {ciphers => cipher}/rsa/rsa.go | 0 {ciphers => cipher}/rsa/rsa_test.go | 0 {ciphers => cipher}/xor/xor.go | 0 {ciphers => cipher}/xor/xor_test.go | 0 conversion/doc.go | 2 + {conversions => conversion}/romantointeger.go | 15 ++++--- .../romantointeger_test.go | 2 +- dynamic/doc.go | 2 + dynamic/matrixmultiplication.go | 1 - go.mod | 2 +- graph/breadthfirstsearch.go | 2 - graph/doc.go | 3 ++ math/doc.go | 2 + math/doc_test.go | 3 ++ math/max/max.go | 10 +++++ math/max/max_test.go | 35 ++++++++++++++++ other/doc.go | 3 ++ other/maxsubarraysum/maxsubarraysum.go | 29 ++++++------- other/maxsubarraysum/maxsubarraysum_test.go | 41 +++++++++++++++++++ other/nested/nestedbrackets.go | 2 +- other/password/generator.go | 3 +- search/doc.go | 2 + strings/doc.go | 3 ++ {genetic => strings/genetic}/genetic.go | 0 .../genetic}/geneticalgorithm_test.go | 0 structure/doc.go | 4 ++ 35 files changed, 138 insertions(+), 32 deletions(-) rename {ciphers => cipher}/caesar/caesar.go (100%) rename {ciphers => cipher}/caesar/caesar_test.go (100%) rename {ciphers => cipher}/diffiehellman/diffiehellmankeyexchange.go (100%) rename {ciphers => cipher}/diffiehellman/diffiehellmankeyexchange_test.go (100%) create mode 100644 cipher/doc.go rename {ciphers => cipher}/polybius/polybius.go (100%) rename {ciphers => cipher}/polybius/polybius_test.go (100%) rename {ciphers => cipher}/rot13/rot13.go (88%) rename {ciphers => cipher}/rot13/rot13_test.go (100%) rename {ciphers => cipher}/rsa/rsa.go (100%) rename {ciphers => cipher}/rsa/rsa_test.go (100%) rename {ciphers => cipher}/xor/xor.go (100%) rename {ciphers => cipher}/xor/xor_test.go (100%) create mode 100644 conversion/doc.go rename {conversions => conversion}/romantointeger.go (60%) rename {conversions => conversion}/romantointeger_test.go (97%) create mode 100644 dynamic/doc.go create mode 100644 graph/doc.go create mode 100644 math/doc.go create mode 100644 math/doc_test.go create mode 100644 math/max/max.go create mode 100644 math/max/max_test.go create mode 100644 other/doc.go create mode 100644 other/maxsubarraysum/maxsubarraysum_test.go create mode 100644 search/doc.go create mode 100644 strings/doc.go rename {genetic => strings/genetic}/genetic.go (100%) rename {genetic => strings/genetic}/geneticalgorithm_test.go (100%) create mode 100644 structure/doc.go diff --git a/ciphers/caesar/caesar.go b/cipher/caesar/caesar.go similarity index 100% rename from ciphers/caesar/caesar.go rename to cipher/caesar/caesar.go diff --git a/ciphers/caesar/caesar_test.go b/cipher/caesar/caesar_test.go similarity index 100% rename from ciphers/caesar/caesar_test.go rename to cipher/caesar/caesar_test.go diff --git a/ciphers/diffiehellman/diffiehellmankeyexchange.go b/cipher/diffiehellman/diffiehellmankeyexchange.go similarity index 100% rename from ciphers/diffiehellman/diffiehellmankeyexchange.go rename to cipher/diffiehellman/diffiehellmankeyexchange.go diff --git a/ciphers/diffiehellman/diffiehellmankeyexchange_test.go b/cipher/diffiehellman/diffiehellmankeyexchange_test.go similarity index 100% rename from ciphers/diffiehellman/diffiehellmankeyexchange_test.go rename to cipher/diffiehellman/diffiehellmankeyexchange_test.go diff --git a/cipher/doc.go b/cipher/doc.go new file mode 100644 index 000000000..0b1ebfb19 --- /dev/null +++ b/cipher/doc.go @@ -0,0 +1,2 @@ +// Package cipher is a package containing different implementations of certain ciphers +package cipher diff --git a/ciphers/polybius/polybius.go b/cipher/polybius/polybius.go similarity index 100% rename from ciphers/polybius/polybius.go rename to cipher/polybius/polybius.go diff --git a/ciphers/polybius/polybius_test.go b/cipher/polybius/polybius_test.go similarity index 100% rename from ciphers/polybius/polybius_test.go rename to cipher/polybius/polybius_test.go diff --git a/ciphers/rot13/rot13.go b/cipher/rot13/rot13.go similarity index 88% rename from ciphers/rot13/rot13.go rename to cipher/rot13/rot13.go index 83090129c..9b822332b 100644 --- a/ciphers/rot13/rot13.go +++ b/cipher/rot13/rot13.go @@ -3,7 +3,7 @@ package rot13 import ( - "github.com/TheAlgorithms/Go/ciphers/caesar" + "github.com/TheAlgorithms/Go/cipher/caesar" ) // rot13 is a special case, which is fixed the shift of 13, of the Caesar cipher diff --git a/ciphers/rot13/rot13_test.go b/cipher/rot13/rot13_test.go similarity index 100% rename from ciphers/rot13/rot13_test.go rename to cipher/rot13/rot13_test.go diff --git a/ciphers/rsa/rsa.go b/cipher/rsa/rsa.go similarity index 100% rename from ciphers/rsa/rsa.go rename to cipher/rsa/rsa.go diff --git a/ciphers/rsa/rsa_test.go b/cipher/rsa/rsa_test.go similarity index 100% rename from ciphers/rsa/rsa_test.go rename to cipher/rsa/rsa_test.go diff --git a/ciphers/xor/xor.go b/cipher/xor/xor.go similarity index 100% rename from ciphers/xor/xor.go rename to cipher/xor/xor.go diff --git a/ciphers/xor/xor_test.go b/cipher/xor/xor_test.go similarity index 100% rename from ciphers/xor/xor_test.go rename to cipher/xor/xor_test.go diff --git a/conversion/doc.go b/conversion/doc.go new file mode 100644 index 000000000..f5cc05779 --- /dev/null +++ b/conversion/doc.go @@ -0,0 +1,2 @@ +// Package conversion is a package of implementations which converts one data structure to another. +package conversion diff --git a/conversions/romantointeger.go b/conversion/romantointeger.go similarity index 60% rename from conversions/romantointeger.go rename to conversion/romantointeger.go index b0e250bc2..45e386a78 100644 --- a/conversions/romantointeger.go +++ b/conversion/romantointeger.go @@ -1,11 +1,10 @@ -/* -This algorithm will convert a standard roman number to an integer -https://en.wikipedia.org/wiki/Roman_numerals -Function receives a string as a roman number and outputs an integer -Maximum output will be 3999 -Only standard form is supported -*/ -package conversions +// This algorithm will convert a standard roman number to an integer +// https://en.wikipedia.org/wiki/Roman_numerals +// Function receives a string as a roman number and outputs an integer +// Maximum output will be 3999 +// Only standard form is supported + +package conversion var romans = map[string]int{"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} diff --git a/conversions/romantointeger_test.go b/conversion/romantointeger_test.go similarity index 97% rename from conversions/romantointeger_test.go rename to conversion/romantointeger_test.go index 9923e596a..59c175c19 100644 --- a/conversions/romantointeger_test.go +++ b/conversion/romantointeger_test.go @@ -1,4 +1,4 @@ -package conversions +package conversion import "testing" diff --git a/dynamic/doc.go b/dynamic/doc.go new file mode 100644 index 000000000..c6ff7e596 --- /dev/null +++ b/dynamic/doc.go @@ -0,0 +1,2 @@ +// Package dynamic is a package of certain implementations of dynamically run algorithms. +package dynamic diff --git a/dynamic/matrixmultiplication.go b/dynamic/matrixmultiplication.go index 4449c411f..dc4164f99 100644 --- a/dynamic/matrixmultiplication.go +++ b/dynamic/matrixmultiplication.go @@ -2,7 +2,6 @@ // https://en.wikipedia.org/wiki/Matrix_chain_multiplication // www.geeksforgeeks.org/dynamic_programming-set-8-matrix-chain-multiplication/ -// Package dynamic_programming Package for dynamically run algorithms package dynamic // MatrixChainRec function diff --git a/go.mod b/go.mod index d2d3ee496..e7de82f0c 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/TheAlgorithms/Go -go 1.15 +go 1.17 diff --git a/graph/breadthfirstsearch.go b/graph/breadthfirstsearch.go index 620d96a3f..93d29f9e4 100644 --- a/graph/breadthfirstsearch.go +++ b/graph/breadthfirstsearch.go @@ -1,5 +1,3 @@ -// Package graph demonstates Graph search algorithms -// reference: https://en.wikipedia.org/wiki/Tree_traversal package graph // BreadthFirstSearch is an algorithm for traversing and searching graph data structures. diff --git a/graph/doc.go b/graph/doc.go new file mode 100644 index 000000000..32a55f68b --- /dev/null +++ b/graph/doc.go @@ -0,0 +1,3 @@ +// Package graph demonstates Graph search algorithms +// reference: https://en.wikipedia.org/wiki/Tree_traversal +package graph diff --git a/math/doc.go b/math/doc.go new file mode 100644 index 000000000..d44df9e6d --- /dev/null +++ b/math/doc.go @@ -0,0 +1,2 @@ +// Package math is a package that contains mathematical algorithms and its different implementations. +package math diff --git a/math/doc_test.go b/math/doc_test.go new file mode 100644 index 000000000..943c734ca --- /dev/null +++ b/math/doc_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package math diff --git a/math/max/max.go b/math/max/max.go new file mode 100644 index 000000000..bb070a6c8 --- /dev/null +++ b/math/max/max.go @@ -0,0 +1,10 @@ +package max + +// Int gives max of two integers +// defining it here to be used in other subpackages of the repo. +func Int(x int, y int) int { + if x < y { + return y + } + return x +} diff --git a/math/max/max_test.go b/math/max/max_test.go new file mode 100644 index 000000000..dbd1ce8dc --- /dev/null +++ b/math/max/max_test.go @@ -0,0 +1,35 @@ +package max + +import "testing" + +func TestMax(t *testing.T) { + testCases := []struct { + name string + left int + right int + max int + }{ + { + name: "Left is max", + left: 10, + right: 9, + max: 10, + }, + { + name: "right is max", + left: 1, + right: 10, + max: 10, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + returnedMax := Int(test.left, test.right) + if returnedMax != test.max { + t.Errorf("Failed test %s\n\tleft: %v, right: %v, max: %v but received: %v", + test.name, test.left, test.right, test.max, returnedMax) + } + }) + } +} diff --git a/other/doc.go b/other/doc.go new file mode 100644 index 000000000..dbe11e339 --- /dev/null +++ b/other/doc.go @@ -0,0 +1,3 @@ +// Package other is dedicated to algorithms that +// do not quite fit into any of the other subpackages in this repository. +package other diff --git a/other/maxsubarraysum/maxsubarraysum.go b/other/maxsubarraysum/maxsubarraysum.go index e50453b3b..81c5042f7 100644 --- a/other/maxsubarraysum/maxsubarraysum.go +++ b/other/maxsubarraysum/maxsubarraysum.go @@ -1,28 +1,25 @@ /* O(n) solution, for calculating maximum contiguous sum in the given array. */ +// Package maxsubarraysum is a package containing a solution to a common +// problem of finding max contigious sum within a array of ints. package maxsubarraysum -// Max - already defined somewhere in this repository TODO: remove this definition and add the import path -func Max(x int, y int) int { - if x < y { - return y - } - return x -} +import ( + "github.com/TheAlgorithms/Go/math/max" +) // MaxSubarraySum returns the maximum subarray sum func MaxSubarraySum(array []int) int { - var currentMax int = 0 - var maxTillNow int = 0 + var currentMax int + var maxTillNow int + if len(array) != 0 { + currentMax = array[0] + maxTillNow = array[0] + } for _, v := range array { - currentMax = Max(v, currentMax+v) - maxTillNow = Max(maxTillNow, currentMax) + currentMax = max.Int(v, currentMax+v) + maxTillNow = max.Int(maxTillNow, currentMax) } return maxTillNow } - -// func main() { -// array := []int{-2, -5, 6, 0, -2, 0, -3, 1, 0, 5, -6} -// fmt.Println("Maximum contiguous sum: ", maxSubarraySum(array)) -// } diff --git a/other/maxsubarraysum/maxsubarraysum_test.go b/other/maxsubarraysum/maxsubarraysum_test.go new file mode 100644 index 000000000..013ba1d88 --- /dev/null +++ b/other/maxsubarraysum/maxsubarraysum_test.go @@ -0,0 +1,41 @@ +package maxsubarraysum + +import ( + "testing" +) + +func TestMaxSubarraySum(t *testing.T) { + testCases := []struct { + name string + slice []int + expected int + }{ + { + name: "Empty slice", + slice: []int{}, + expected: 0, + }, + { + name: "Max is 0", + slice: []int{0, -1, -2, -4, -5}, + expected: 0, + }, + { + name: "Max is -1", + slice: []int{-1, -3, -2, -5, -7}, + expected: -1, + }, + { + name: "Max is 7", + slice: []int{-2, -5, 6, 0, -2, 0, -3, 1, 0, 5, -6}, + expected: 7, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + if result := MaxSubarraySum(test.slice); result != test.expected { + t.Fatalf("%s\n\tslice: %v, expected: %v, returned: %v", test.name, test.slice, test.expected, result) + } + }) + } +} diff --git a/other/nested/nestedbrackets.go b/other/nested/nestedbrackets.go index c0afd9571..330f78fbb 100644 --- a/other/nested/nestedbrackets.go +++ b/other/nested/nestedbrackets.go @@ -1,4 +1,4 @@ -// Package nested_brackets provides functions for testing +// Package nested provides functions for testing // strings propper brackets nesting. package nested diff --git a/other/password/generator.go b/other/password/generator.go index b25f2f48b..0a8023c26 100644 --- a/other/password/generator.go +++ b/other/password/generator.go @@ -2,7 +2,8 @@ // You must provide a minimum length and a maximum length // This length is not fixed if you generate multiple passwords for the same range -package password_generator +// Package password contains functions to help generate random passwords +package password import ( "crypto/rand" diff --git a/search/doc.go b/search/doc.go new file mode 100644 index 000000000..4c71e36b4 --- /dev/null +++ b/search/doc.go @@ -0,0 +1,2 @@ +// Package search is a subpackage dedicated to all searching algorithms related to slices/arrays. +package search diff --git a/strings/doc.go b/strings/doc.go new file mode 100644 index 000000000..786876fec --- /dev/null +++ b/strings/doc.go @@ -0,0 +1,3 @@ +// Package strings is a package that contains all algorithms +// that are used to analyse and manipulate strings. +package strings diff --git a/genetic/genetic.go b/strings/genetic/genetic.go similarity index 100% rename from genetic/genetic.go rename to strings/genetic/genetic.go diff --git a/genetic/geneticalgorithm_test.go b/strings/genetic/geneticalgorithm_test.go similarity index 100% rename from genetic/geneticalgorithm_test.go rename to strings/genetic/geneticalgorithm_test.go diff --git a/structure/doc.go b/structure/doc.go new file mode 100644 index 000000000..fc157dcfd --- /dev/null +++ b/structure/doc.go @@ -0,0 +1,4 @@ +// Package structure is a subpackage that is dedicated to +// different implementations of data structures in the +// domain of computer science. +package structure From 1f2df3307b8f17e777aa8d524a998b0a8f81a2cc Mon Sep 17 00:00:00 2001 From: Taj Date: Thu, 9 Sep 2021 19:20:21 +0100 Subject: [PATCH 225/488] doc: fix: Add empty test files for packages that don't need test (#342) --- cipher/cipher_test.go | 3 +++ conversion/conversion_test.go | 3 +++ dynamic/dynamic_test.go | 3 +++ graph/graph_test.go | 3 +++ math/{doc_test.go => math_test.go} | 0 other/other_test.go | 3 +++ strings/strings_test.go | 3 +++ structure/structure_test.go | 3 +++ 8 files changed, 21 insertions(+) create mode 100644 cipher/cipher_test.go create mode 100644 conversion/conversion_test.go create mode 100644 dynamic/dynamic_test.go create mode 100644 graph/graph_test.go rename math/{doc_test.go => math_test.go} (100%) create mode 100644 other/other_test.go create mode 100644 strings/strings_test.go create mode 100644 structure/structure_test.go diff --git a/cipher/cipher_test.go b/cipher/cipher_test.go new file mode 100644 index 000000000..5a56f3ae3 --- /dev/null +++ b/cipher/cipher_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package cipher diff --git a/conversion/conversion_test.go b/conversion/conversion_test.go new file mode 100644 index 000000000..34eec8f96 --- /dev/null +++ b/conversion/conversion_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package conversion diff --git a/dynamic/dynamic_test.go b/dynamic/dynamic_test.go new file mode 100644 index 000000000..965718118 --- /dev/null +++ b/dynamic/dynamic_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package dynamic diff --git a/graph/graph_test.go b/graph/graph_test.go new file mode 100644 index 000000000..db9fd54ce --- /dev/null +++ b/graph/graph_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package graph diff --git a/math/doc_test.go b/math/math_test.go similarity index 100% rename from math/doc_test.go rename to math/math_test.go diff --git a/other/other_test.go b/other/other_test.go new file mode 100644 index 000000000..35aa59143 --- /dev/null +++ b/other/other_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package other diff --git a/strings/strings_test.go b/strings/strings_test.go new file mode 100644 index 000000000..aebadd648 --- /dev/null +++ b/strings/strings_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package strings diff --git a/structure/structure_test.go b/structure/structure_test.go new file mode 100644 index 000000000..29990a834 --- /dev/null +++ b/structure/structure_test.go @@ -0,0 +1,3 @@ +// Empty test file to keep track of all the tests for the algorithms. + +package structure From b2e79af22e2bc072024de9b2036e06282378c252 Mon Sep 17 00:00:00 2001 From: liyl <30368453+yaolin-Li@users.noreply.github.com> Date: Fri, 10 Sep 2021 02:39:48 +0800 Subject: [PATCH 226/488] Add some functions in the linkedlist directory (#341) * Add AccessNodesByLayer Function, which is used to access nodes layer by layer instead of printing the results as one line * Update the case of the function name in the main function so that it can run normally * Add ReversePartition() Function, which is used to reverse the linked list from the ath to the bth node * Add test program for function Reverse() in doublylinkedlist_test.go Co-authored-by: Yaolin_Li <1586505611@qq.com> Co-authored-by: Andrii Siriak Co-authored-by: Rak Laptudirm --- structure/linkedlist/doubly_test.go | 18 ++++++++ structure/linkedlist/singlylinkedlist.go | 38 ++++++++++++++++- structure/linkedlist/singlylinkedlist_test.go | 42 +++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/structure/linkedlist/doubly_test.go b/structure/linkedlist/doubly_test.go index b46474d48..b48eda812 100644 --- a/structure/linkedlist/doubly_test.go +++ b/structure/linkedlist/doubly_test.go @@ -85,4 +85,22 @@ func TestDoubly(t *testing.T) { } }) + newList2 := NewDoubly() + newList2.AddAtBeg(1) + newList2.AddAtBeg(2) + newList2.AddAtBeg(3) + t.Run("Test Reverse", func(t *testing.T) { + want := []int{1, 2, 3} + got := []int{} + newList2.Reverse() + current := newList2.Head + got = append(got, current.Val.(int)) + for current.Next != nil { + current = current.Next + got = append(got, current.Val.(int)) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got: %v, want: %v", got, want) + } + }) } diff --git a/structure/linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go index cf69056a1..5dd92e335 100644 --- a/structure/linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -1,7 +1,10 @@ package linkedlist // demonstration of singly linked list in golang -import "fmt" +import ( + "errors" + "fmt" +) // Singly structure with length of the list and its head type Singly struct { @@ -97,6 +100,39 @@ func (ll *Singly) Reverse() { ll.Head = prev } +// ReversePartition Reverse the linked list from the ath to the bth node +func (ll *Singly) ReversePartition(left, right int) error { + err := ll.CheckRangeFromIndex(left, right) + if err != nil { + return err + } + tmpNode := NewNode(-1) + tmpNode.Next = ll.Head + pre := tmpNode + for i := 0; i < left-1; i++ { + pre = pre.Next + } + cur := pre.Next + for i := 0; i < right-left; i++ { + next := cur.Next + cur.Next = next.Next + next.Next = pre.Next + pre.Next = next + } + ll.Head = tmpNode.Next + return nil +} +func (ll *Singly) CheckRangeFromIndex(left, right int) error { + if left > right { + return errors.New("left boundary must smaller than right") + } else if left < 1 { + return errors.New("left boundary starts from the first node") + } else if right > ll.length { + return errors.New("right boundary cannot be greater than the length of the linked list") + } + return nil +} + // Display prints out the elements of the list. func (ll *Singly) Display() { for cur := ll.Head; cur != nil; cur = cur.Next { diff --git a/structure/linkedlist/singlylinkedlist_test.go b/structure/linkedlist/singlylinkedlist_test.go index 0da92cadf..b5c615403 100644 --- a/structure/linkedlist/singlylinkedlist_test.go +++ b/structure/linkedlist/singlylinkedlist_test.go @@ -64,4 +64,46 @@ func TestSingly(t *testing.T) { t.Errorf("got: %v, want: %v", got, want) } }) + + list2 := Singly{} + list2.AddAtBeg(1) + list2.AddAtBeg(2) + list2.AddAtBeg(3) + list2.AddAtBeg(4) + list2.AddAtBeg(5) + list2.AddAtBeg(6) + + t.Run("Test Reverse()", func(t *testing.T) { + want := []interface{}{1, 2, 3, 4, 5, 6} + got := []interface{}{} + list2.Reverse() + current := list2.Head + got = append(got, current.Val) + for current.Next != nil { + current = current.Next + got = append(got, current.Val) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got: %v, want: %v", got, want) + } + }) + + t.Run("Test ReversePartition()", func(t *testing.T) { + want := []interface{}{1, 5, 4, 3, 2, 6} + got := []interface{}{} + err := list2.ReversePartition(2, 5) + + if err != nil { + t.Errorf("Incorrect boundary conditions entered%v", err) + } + current := list2.Head + got = append(got, current.Val) + for current.Next != nil { + current = current.Next + got = append(got, current.Val) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got: %v, want: %v", got, want) + } + }) } From d2f12849df76203d80762ceca5105531d3424384 Mon Sep 17 00:00:00 2001 From: William Chang <48861800+WilliamChang80@users.noreply.github.com> Date: Fri, 10 Sep 2021 01:56:09 +0700 Subject: [PATCH 227/488] Add tests on DepthFirstSearch (#299) Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Andrii Siriak --- graph/depthfirstsearch_test.go | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 graph/depthfirstsearch_test.go diff --git a/graph/depthfirstsearch_test.go b/graph/depthfirstsearch_test.go new file mode 100644 index 000000000..d63573ca1 --- /dev/null +++ b/graph/depthfirstsearch_test.go @@ -0,0 +1,64 @@ +package graph + +import ( + "reflect" + "testing" +) + +func TestDfsWhenPathIsFound(t *testing.T) { + nodes := []int{ + 1, 2, 3, 4, 5, 6, + } + + //Adjacency Matrix for connected nodes + edges := [][]bool{ + {false, true, true, false, false, false}, + {true, false, false, true, false, false}, + {true, false, false, true, false, false}, + {false, true, true, false, true, false}, + {false, false, false, true, false, true}, + {false, false, false, false, true, false}, + } + + start := 1 + end := 6 + + actual, actualIsFound := DepthFirstSearch(start, end, nodes, edges) + expected := []int{1, 3, 4, 5, 6} + expectedIsFound := true + t.Run("Test Dfs", func(t *testing.T) { + if !reflect.DeepEqual(expected, actual) || !reflect.DeepEqual(actualIsFound, expectedIsFound) { + t.Errorf("got route: %v, want route: %v", actual, expected) + t.Errorf("got isFound: %v, want isFound: %v", actualIsFound, expectedIsFound) + } + }) +} + +func TestDfsWhenPathIsNotFound(t *testing.T) { + nodes := []int{ + 1, 2, 3, 4, 5, 6, + } + + //Adjacency Matrix for connected nodes + edges := [][]bool{ + {false, true, true, false, false, false}, + {true, false, false, true, false, false}, + {true, false, false, true, false, false}, + {false, true, true, false, true, false}, + {false, false, false, true, false, true}, + {false, false, false, false, true, false}, + } + + start := 1 + end := 7 + + actual, actualIsFound := DepthFirstSearch(start, end, nodes, edges) + var expected []int + expectedIsFound := false + t.Run("Test Dfs", func(t *testing.T) { + if !reflect.DeepEqual(expected, actual) || !reflect.DeepEqual(actualIsFound, expectedIsFound) { + t.Errorf("got route: %v, want route: %v", actual, expected) + t.Errorf("got isFound: %v, want isFound: %v", actualIsFound, expectedIsFound) + } + }) +} From 4d732334b018c4186f090c8917876965cc3daade Mon Sep 17 00:00:00 2001 From: Oskar Wojciski Date: Sat, 11 Sep 2021 13:23:59 +0200 Subject: [PATCH 228/488] doc: fix: Fix links in README.md (#345) Co-authored-by: Taj --- README.md | 184 +++++++++++++++++++++++++++--------------------------- 1 file changed, 93 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 64f387fe2..f9ff81a69 100644 --- a/README.md +++ b/README.md @@ -13,98 +13,100 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ## List of Algorithms - -## Ciphers -* [Caesar](./ciphers/caesar/) -* [Diffie Hellman Key Exchange](./ciphers/diffie_hellman_key_exchange/) -* [Polybius](./ciphers/polybius/) -* [Rot13](./ciphers/rot13/) -* [Rsa](./ciphers/rsa/) -* [Xor](./ciphers/xor/) - -## Conversions -* [Roman To Integer](./conversions/roman_to_integer/) - -## Data Structures -* [Binary Tree](./data_structures/binary_tree/) -* [Dynamic Array](./data_structures/dynamic_array/) -* [Hashmap](./data_structures/hashmap/) +### Ciphers +* [Caesar](./cipher/caesar/caesar.go) +* [Diffie Hellman Key Exchange](./cipher/diffiehellman/diffiehellmankeyexchange.go) +* [Polybius](./cipher/polybius/polybius.go) +* [Rot13](./cipher/rot13/rot13.go) +* [Rsa](./cipher/rsa/rsa.go) +* [Xor](./cipher/xor/xor.go) + +### Conversions +* [Roman To Integer](./conversion/romantointeger.go) + +### Data Structures +* [AVL Tree](./structure/avl/avl.go) +* [Binary Tree](./structure/binarytree/btree.go) +* [Dynamic Array](./structure/dynamicarray/dynamicarray.go) +* [Hashmap](./structure/hashmap/hashmap.go) * Linked-List - * [Doubly Linked-list](./data_structures/linkedlist/doubly_linkedlist/) - * [Singly Linked-list](./data_structures/linkedlist/singly_linkedlist/) -* [Queue](./data_structures/queue/) | Array, Linked-List, STL(Container/List), Test -* [Stack](./data_structures/stack/) | Array, Linked-List, STL(Container/List), Test -* [Set](./data_structures/set/) -* [Trie](./data_structures/trie/) - -## Design Patterns -* [Abstract Factory](./design_patterns/abstract_factory/) -* [Builder](./design_patterns/builder/) -* [Factory Method](./design_patterns/factory_method/) -* [Prototype](./design_patterns/prototype/) - - -## Dynamic Programming -* [Binomial Coefficient](./dynamic_programming/binomialcoefficient.go) -* [Fibonacci](./dynamic_programming/fibonacci.go) | [Test](./dynamic_programming/fibonacci_test.go) -* [Knapsack](./dynamic_programming/knapsack.go) -* [Longest Common Subsequence](./dynamic_programming/longestcommonsubsequence.go) -* [Longest Palindromic Subsequence](./dynamic_programming/longestpalindromicsubsequence.go) -* [Matrix Multiplication](./dynamic_programming/matrixmultiplication.go) -* [Cutting a Rod](./dynamic_programming/rodcutting.go) - -## Genetic Algorithm -* [Genetic Algorithm](./genetic_algorithm/geneticalgorithm.go) - -## Graphs -* [Breadth First Search](./graphs/breadth_first_search/) -* [Depth First Search](./graphs/depth_first_search/) -* [Floyd Warshall](./graphs/floyd_warshall/) + * [Doubly Linked List](./structure/linkedlist/doubly.go) + * [Singly Linked List](./structure/linkedlist/singlylinkedlist.go) + * [Cyclic Linked List AKA Looped Linked List](./structure/linkedlist/cyclic.go) +* [Queue](./structure/queue) + * [Array Based](./structure/queue/queuearray.go) + * [Custom Linked List Based](./structure/queue/queuelinkedlist.go) + * [Standard Library Container/List Based](./structure/queue/queuelinkedlist.go) +* [Set](./structure/set/set.go) +* [Stack](./structure/stack) + * [Array Based](./structure/stack/stackarray.go) + * [Custom Linked List](./structure/stack/stacklinkedlist.go) + * [Standard Library Container/List Based](structure/stack/stacklinkedlistwithlist.go) +* [Trie](./structure/trie/trie.go) + +### Dynamic Programming +* [Binomial Coefficient](./dynamic/binomialcoefficient.go) +* [Fibonacci](./dynamic/fibonacci.go) +* [Knapsack](./dynamic/knapsack.go) +* [Longest Common Subsequence](./dynamic/longestcommonsubsequence.go) +* [Longest Palindromic Subsequence](./dynamic/longestpalindromicsubsequence.go) +* [Matrix Multiplication](./dynamic/matrixmultiplication.go) +* [Cutting a Rod](./dynamic/rodcutting.go) + +### Graphs +* [Breadth First Search](./graph/breadthfirstsearch.go) +* [Depth First Search](./graph/depthfirstsearch.go) +* [Floyd Warshall](./graph/floydwarshall.go) -## Math -* [Gcd](./math/gcd/) -* [Lcm](./math/lcm/) -* [Modular](./math/modular/) -* [Permutation](./math/permutation/) -* [Power](./math/power/) -* [Prime](./math/prime/) -* [Pythagoras](./math/pythagoras/) -* [Sieve](./math/sieve/) - - -## Other -* [Max Subarray Sum](./other/max_subarray_sum/) -* [Monte Carlo Pi](./other/monte_carlo_pi/) -* [Nested Brackets](./other/nested_brackets/) -* [Password Generator](./other/password_generator/) -* [String Combinations](./other/string_combinations/) - -## Searches -* [Binary Search](./searches/binary_search/) -* [Linear Search](./searches/linear_search/) - -## Sorts -* [Bubble Sort](./sorts/bubblesort.go) -* [Heap Sort](./sorts/heapsort.go) -* [Insertion Sort](./sorts/insertionsort.go) -* [Merge Sort](./sorts/mergesort.go) -* [Quick Sort](./sorts/quicksort.go) -* [Radix Sort](./sorts/radixsort.go) -* [Selection Sort](./sorts/selectionsort.go) -* [Shell Sort](./sorts/shellsort.go) - - -* Sorts Test - * [Sorts Test](./sorts/sorts_test.go) - * [Sorts Testcases](./sorts/sorts_testcases.go) - -## Strings -* [Levenshtein Distance](./strings/levenshtein_distance/) +### Math +* [Gcd](./math/gcd) + * [Extended](./math/gcd/extended.go) + * [Recursive](./math/gcd/gcd.go) + * [Iterative](./math/gcd/gcditerative.go) +* [Lcm](./math/lcm/lcm.go) +* [Max](./math/max/max.go) +* [Modular](./math/modular) + * [Exponentiation](./math/max/max.go) + * [Inverse](./math/modular/inverse.go) +* [Moser-de Bruijn sequence](./math/moserdebruijnsequence/sequence.go) +* [Permutation](./math/permutation/heaps.go) +* [Power](./math/power/fastexponent.go) +* [Prime](./math/prime) + * [Miller Rabin Primality Test](./math/prime/millerrabinprimalitytest.go) + * [Naive and Pair Approach](./math/prime/primecheck.go) + * [Sieve](./math/prime/sieve.go) +* [Pythagoras](./math/pythagoras/pythagoras.go) +* [Sieve](./math/prime/sieve.go) + +### Other +* [Max Subarray Sum](./other/maxsubarraysum/maxsubarraysum.go) +* [Nested Brackets](./other/nested/nestedbrackets.go) +* [Password Generator](./other/password/generator.go) + +### Searches +* [Binary Search](./search/binary.go) +* [Linear Search](./search/linear.go) +* [Interpolation Search](./search/interpolation.go) + +### Sorts +* [Bubble Sort](./sort/bubblesort.go) +* [Heap Sort](./sort/heapsort.go) +* [Insertion Sort](./sort/insertionsort.go) +* [Merge Sort](./sort/mergesort.go) +* [Quick Sort](./sort/quicksort.go) +* [Radix Sort](./sort/radixsort.go) +* [Selection Sort](./sort/selectionsort.go) +* [Shell Sort](./sort/shellsort.go) + + +* [Sorts Test](./sort/sorts_test.go) + +### Strings +* [Levenshtein Distance](./strings/levenshtein/levenshteindistance.go) * Multiple String Matching - * [Advanced Aho Corasick](./strings/multiple_string_matching/advanced_aho_corasick/) - * [Aho Corasick](./strings/multiple_string_matching/aho_corasick/) -* [Naive String Search](./strings/naive_string_search/) + * [Advanced Aho Corasick](./strings/ahocorasick/advancedahocorasick.go) + * [Aho Corasick](./strings/ahocorasick/ahocorasick.go) * Single String Matching - * [Bom](./strings/single_string_matching/bom/) - * [Horspool](./strings/single_string_matching/horspool/) - * [Kmp](./strings/single_string_matching/kmp/) + * [Bom](./strings/bom/bom.go) + * [Horspool](./strings/horspool/horspool.go) + * [Kmp](./strings/kmp/kmp.go) From e7b0fe7e804211c732c5801acf19234c2c21b836 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Sun, 12 Sep 2021 08:53:39 +0300 Subject: [PATCH 229/488] Update stale.yml --- .github/stale.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index 009887105..e92cb9610 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -24,10 +24,10 @@ exemptMilestones: false exemptAssignees: false # Label to use when marking as stale -staleLabel: abandoned +staleLabel: stale # Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 1 +limitPerRun: 5 # Comment to post when removing the stale label. # unmarkComment: > @@ -45,8 +45,8 @@ pulls: closeComment: > Please ping one of the maintainers once you commit the changes requested or make improvements on the code. If this is not the case and you need - some help, feel free to ask for help in our [Gitter](https://gitter.im/TheAlgorithms) - channel. Thank you for your contributions! + some help, feel free to ask for help on our [Discord](https://discord.gg/c7MnfGFGa6) + server. Thank you for your contributions! issues: # Comment to post when marking as stale. Set to `false` to disable @@ -59,4 +59,4 @@ issues: closeComment: > Please ping one of the maintainers once you add more information and updates here. If this is not the case and you need some help, feel free to ask for help - in our [Gitter](https://gitter.im/TheAlgorithms) channel. Thank you for your contributions! + on our [Discord](https://discord.gg/c7MnfGFGa6) server. Thank you for your contributions! From 0250a579bd319642f85bce52e9fec931379f7037 Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Mon, 13 Sep 2021 21:24:48 +0300 Subject: [PATCH 230/488] Add working workflow for stale items (#346) --- .github/stale.yml | 62 ------------------------------------- .github/workflows/stale.yml | 19 ++++++++++++ 2 files changed, 19 insertions(+), 62 deletions(-) delete mode 100644 .github/stale.yml create mode 100644 .github/workflows/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index e92cb9610..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,62 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 30 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 7 - -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: [] - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: - - "dont-close" - -# Set to true to ignore issues in a project (defaults to false) -exemptProjects: false - -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: false - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: false - -# Label to use when marking as stale -staleLabel: stale - -# Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 5 - -# Comment to post when removing the stale label. -# unmarkComment: > -# Your comment here. - -# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': -pulls: - # Comment to post when marking as stale. Set to `false` to disable - markComment: > - This pull request has been automatically marked as abandoned because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. - - # Comment to post when closing a stale Pull Request. - closeComment: > - Please ping one of the maintainers once you commit the changes requested - or make improvements on the code. If this is not the case and you need - some help, feel free to ask for help on our [Discord](https://discord.gg/c7MnfGFGa6) - server. Thank you for your contributions! - -issues: - # Comment to post when marking as stale. Set to `false` to disable - markComment: > - This issue has been automatically marked as abandoned because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. - - # Comment to post when closing a stale Issue. - closeComment: > - Please ping one of the maintainers once you add more information and updates here. - If this is not the case and you need some help, feel free to ask for help - on our [Discord](https://discord.gg/c7MnfGFGa6) server. Thank you for your contributions! diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..0b4234c4a --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,19 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '0 0 * * *' +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v4 + with: + stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' + close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' + stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' + close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.' + exempt-issue-labels: 'dont-close' + exempt-pr-labels: 'dont-close' + days-before-stale: 30 + days-before-close: 7 + operations-per-run: 5 From 63400d5c7e93f6b9657d8782392a1f3c6fbb1efa Mon Sep 17 00:00:00 2001 From: Andrii Siriak Date: Tue, 14 Sep 2021 15:43:42 +0300 Subject: [PATCH 231/488] Unleash full power of the stale workflow --- .github/workflows/stale.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 0b4234c4a..126bd7ad4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,4 +16,3 @@ jobs: exempt-pr-labels: 'dont-close' days-before-stale: 30 days-before-close: 7 - operations-per-run: 5 From bcb29db7032062f708626a85b8ea8ddeab1572a2 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Fri, 17 Sep 2021 14:13:49 +0300 Subject: [PATCH 232/488] feat: add bitwise max (#347) * feat: add an algorithm for finding the maximum number without using conditional operators --- math/max/bitwiseMax.go | 14 +++++++ math/max/bitwiseMax_test.go | 77 +++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 math/max/bitwiseMax.go create mode 100644 math/max/bitwiseMax_test.go diff --git a/math/max/bitwiseMax.go b/math/max/bitwiseMax.go new file mode 100644 index 000000000..ece9c4dbe --- /dev/null +++ b/math/max/bitwiseMax.go @@ -0,0 +1,14 @@ +// bitwiseMax.go +// description: Gives max of two integers +// details: +// implementation of finding the maximum of two numbers using only binary operations without using conditions +// author(s) [red_byte](https://github.com/i-redbyte) +// see bitwiseMax_test.go + +package max + +func BitwiseMax(a int, b int, base int) int { + z := a - b + i := (z >> base) & 1 + return a - (i * z) +} diff --git a/math/max/bitwiseMax_test.go b/math/max/bitwiseMax_test.go new file mode 100644 index 000000000..addf45733 --- /dev/null +++ b/math/max/bitwiseMax_test.go @@ -0,0 +1,77 @@ +// bitwiseMax_test.go +// description: Test for BitwiseMax +// author(s) [red_byte](https://github.com/i-redbyte) +// see bitwiseMax.go + +package max + +import "testing" + +func TestBitwiseMax(t *testing.T) { + base32 := 31 + + t.Run("Testing(32bit) a = 32 and m = 64: ", func(t *testing.T) { + max := BitwiseMax(32, 64, base32) + if max != 64 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + t.Run("Testing(32bit) a = 1024 and m = -9: ", func(t *testing.T) { + max := BitwiseMax(1024, -9, base32) + if max != 1024 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + t.Run("Testing(32bit) a = -6 and m = -6: ", func(t *testing.T) { + max := BitwiseMax(-6, -6, base32) + if max != -6 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + t.Run("Testing(32bit) a = -72 and m = -73: ", func(t *testing.T) { + max := BitwiseMax(-72, -73, base32) + if max != -72 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + base64 := 63 + t.Run("Testing(64bit) a = 32 and m = 9223372036854775807: ", func(t *testing.T) { + max := BitwiseMax(32, 9223372036854775807, base64) + if max != 9223372036854775807 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + t.Run("Testing(64bit) a = 1024 and m = -9223372036854770001: ", func(t *testing.T) { + max := BitwiseMax(1024, -9223372036854770001, base64) + if max != 1024 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + t.Run("Testing(64bit) a = -6 and m = -6: ", func(t *testing.T) { + max := BitwiseMax(-6, -6, base64) + if max != -6 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + t.Run("Testing(64bit) a = -4223372036854775809 and m = -4223372036854775808: ", func(t *testing.T) { + max := BitwiseMax(-4223372036854775809, -4223372036854775808, base64) + if max != -4223372036854775808 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) + + base8 := 7 + t.Run("Testing(8bit) a = 257 and m = 256: ", func(t *testing.T) { + max := BitwiseMax(8, 16, base8) + if max != 16 { + t.Fatalf("Error: BitwiseMax returned bad value") + } + }) +} From 4edb8021663157bf4bba8e67ae766134aa347d6b Mon Sep 17 00:00:00 2001 From: Shivam Rathore Date: Mon, 20 Sep 2021 12:52:44 +0530 Subject: [PATCH 233/488] chore: merge "feat: add Graph Coloring algorithms (#349)" * feat: add Graph Coloring algorithms * chore(graph): styling & naming changes --- CONTRIBUTING.md | 2 +- README.md | 6 +- graph/coloring/backtracking.go | 50 +++++++++ graph/coloring/backtracking_test.go | 24 +++++ graph/coloring/bfs.go | 56 ++++++++++ graph/coloring/bfs_test.go | 24 +++++ graph/coloring/doc.go | 5 + graph/coloring/graph.go | 57 +++++++++++ graph/coloring/graph_test.go | 153 ++++++++++++++++++++++++++++ graph/coloring/greedy.go | 52 ++++++++++ graph/coloring/greedy_test.go | 24 +++++ graph/doc.go | 2 +- graph/graph.go | 37 +++++++ 13 files changed, 489 insertions(+), 3 deletions(-) create mode 100644 graph/coloring/backtracking.go create mode 100644 graph/coloring/backtracking_test.go create mode 100644 graph/coloring/bfs.go create mode 100644 graph/coloring/bfs_test.go create mode 100644 graph/coloring/doc.go create mode 100644 graph/coloring/graph.go create mode 100644 graph/coloring/graph_test.go create mode 100644 graph/coloring/greedy.go create mode 100644 graph/coloring/greedy_test.go create mode 100644 graph/graph.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index feaaeb162..c3abb3977 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Being a contributor at The Algorithms, we request you to follow the points menti - You did your own work. - No plagiarism is allowed. Any plagiarized work will not be merged. -- Your work will be distributed under the [MIT License](https://github.com/TheAlgoritms/Go/blob/master/LICENSE) once your pull request has been merged. +- Your work will be distributed under the [MIT License](https://github.com/TheAlgorithms/Go/blob/master/LICENSE) once your pull request has been merged. - Please follow the repository guidelines and standards mentioned below. **New implementation** New implementations are welcome! diff --git a/README.md b/README.md index f9ff81a69..e71ab36d9 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,11 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Breadth First Search](./graph/breadthfirstsearch.go) * [Depth First Search](./graph/depthfirstsearch.go) * [Floyd Warshall](./graph/floydwarshall.go) - +* [Coloring Algorithms](./graph/coloring) + * [Using BFS](./graph/coloring/bfs.go) + * [Using Backtracking](./graph/coloring/backtracking.go) + * [Using Greedy Approach](./graph/coloring/greedy.go) + ### Math * [Gcd](./math/gcd) * [Extended](./math/gcd/extended.go) diff --git a/graph/coloring/backtracking.go b/graph/coloring/backtracking.go new file mode 100644 index 000000000..1ae657d45 --- /dev/null +++ b/graph/coloring/backtracking.go @@ -0,0 +1,50 @@ +// This file contains the graph coloring implementation using backtracking +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring + +// ColorUsingBacktracking will return the Color of each vertex and the +// total number of different colors used, using backtracking +func (g *Graph) ColorUsingBacktracking() (map[int]Color, int) { + vertexColors := make(map[int]Color, g.vertices) + g.colorVertex(0, vertexColors) + + colorsUsed := 0 + for _, cr := range vertexColors { + if colorsUsed < int(cr) { + colorsUsed = int(cr) + } + } + return vertexColors, colorsUsed +} + +// colorVertex will try to color provided vertex, v +func (g *Graph) colorVertex(v int, color map[int]Color) bool { + // If all vertices are colored, the colors store will be completely filled. + if len(color) == g.vertices { + return true + } + + // As the upper bound of no. of colors is the no. of vertices in graph, + // try assigning each color to the vertex v + for cr := Color(1); cr <= Color(g.vertices); cr++ { + // Use the color, cr for vertex, v if it is safe to use, by + // checking its neighbours + safe := true + for nb := range g.edges[v] { + // cr, color is not safe if color of nb, crnb is not equal to cr + if crnb, ok := color[nb]; ok && crnb == cr { + safe = false + break + } + } + if safe { + color[v] = cr + if g.colorVertex(v+1, color) { + return true + } + delete(color, v) + } + } + return false +} diff --git a/graph/coloring/backtracking_test.go b/graph/coloring/backtracking_test.go new file mode 100644 index 000000000..6bc735cca --- /dev/null +++ b/graph/coloring/backtracking_test.go @@ -0,0 +1,24 @@ +// This file provides tests for coloring using backtracking. +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring_test + +import ( + "strconv" + "testing" +) + +func TestGraphColorUsingBacktracking(t *testing.T) { + for i, tt := range getTestGraphs() { + t.Run(strconv.Itoa(i), func(t *testing.T) { + colorsOfVertices, colors := tt.Graph.ColorUsingBacktracking() + if colors != tt.ColorsUsed { + t.Errorf("ColorUsingBacktracking() return more number of colors: %v, want %v colors", colors, tt.ColorsUsed) + } + // check colors + if err := tt.Graph.ValidateColorsOfVertex(colorsOfVertices); err != nil { + t.Errorf("ColorUsingBacktracking() assigned colors are wrong, error = %v", err) + } + }) + } +} diff --git a/graph/coloring/bfs.go b/graph/coloring/bfs.go new file mode 100644 index 000000000..d73b0ed31 --- /dev/null +++ b/graph/coloring/bfs.go @@ -0,0 +1,56 @@ +// This file contains the graph coloring implementation using BFS +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring + +import "container/list" + +// ColorUsingBFS will return the Color of each vertex and the +// total number of different colors used, using BFS +func (g *Graph) ColorUsingBFS() (map[int]Color, int) { + // Initially all vertices will have same color + vertexColors := make(map[int]Color, g.vertices) + for i := 0; i < g.vertices; i++ { + vertexColors[i] = 1 + } + + visited := make(map[int]struct{}) + // Run BFS from each non-visited vertex + for i := 0; i < g.vertices; i++ { + if _, ok := visited[i]; ok { + continue + } + visited[i] = struct{}{} + + queue := list.New() + queue.PushBack(i) + + for queue.Len() != 0 { + // front vertex in the queue + frontNode := queue.Front() + front := frontNode.Value.(int) + queue.Remove(frontNode) + + // Now, check all neighbours of front vertex, if they have same + // color as that of front, change their color + for nb := range g.edges[front] { + if vertexColors[nb] == vertexColors[front] { + vertexColors[nb]++ + } + // if the neighbour is not already visited, add it to the queue + if _, ok := visited[nb]; !ok { + visited[nb] = struct{}{} + queue.PushBack(nb) + } + } + } + } + + colorsUsed := 0 + for _, cr := range vertexColors { + if colorsUsed < int(cr) { + colorsUsed = int(cr) + } + } + return vertexColors, colorsUsed +} diff --git a/graph/coloring/bfs_test.go b/graph/coloring/bfs_test.go new file mode 100644 index 000000000..adfc502ce --- /dev/null +++ b/graph/coloring/bfs_test.go @@ -0,0 +1,24 @@ +// This file provides tests for coloring using BFS. +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring_test + +import ( + "strconv" + "testing" +) + +func TestGraphColorUsingBFS(t *testing.T) { + for i, tt := range getTestGraphs() { + t.Run(strconv.Itoa(i), func(t *testing.T) { + colorsOfVertices, colors := tt.Graph.ColorUsingBFS() + if colors != tt.ColorsUsed { + t.Errorf("ColorUsingBFS() return more number of colors: %v, want %v colors", colors, tt.ColorsUsed) + } + // check colors + if err := tt.Graph.ValidateColorsOfVertex(colorsOfVertices); err != nil { + t.Errorf("ColorUsingBFS() assigned colors are wrong, error = %v", err) + } + }) + } +} diff --git a/graph/coloring/doc.go b/graph/coloring/doc.go new file mode 100644 index 000000000..849144dcc --- /dev/null +++ b/graph/coloring/doc.go @@ -0,0 +1,5 @@ +// Package coloring provides implementation of different graph coloring +// algorithms, e.g. coloring using BFS, using Backtracking, using greedy +// approach. +// Author(s): [Shivam](https://github.com/Shivam010) +package coloring diff --git a/graph/coloring/graph.go b/graph/coloring/graph.go new file mode 100644 index 000000000..d8065cb10 --- /dev/null +++ b/graph/coloring/graph.go @@ -0,0 +1,57 @@ +// This file contains the simple structural implementation of undirected +// graph, used in coloring algorithms. +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring + +import "errors" + +// Color provides a type for vertex color +type Color int + +// Graph provides a structure to store an undirected graph. +// It is safe to use its empty object. +type Graph struct { + vertices int + edges map[int]map[int]struct{} +} + +// AddVertex will add a new vertex in the graph, if the vertex already +// exist it will do nothing +func (g *Graph) AddVertex(v int) { + if g.edges == nil { + g.edges = make(map[int]map[int]struct{}) + } + + // Check if vertex is present or not + if _, ok := g.edges[v]; !ok { + g.vertices++ + g.edges[v] = make(map[int]struct{}) + } +} + +// AddEdge will add a new edge between the provided vertices in the graph +func (g *Graph) AddEdge(one, two int) { + // Add vertices: one and two to the graph if they are not present + g.AddVertex(one) + g.AddVertex(two) + + // and finally add the edges: one->two and two->one for undirected graph + g.edges[one][two] = struct{}{} + g.edges[two][one] = struct{}{} +} + +func (g *Graph) ValidateColorsOfVertex(colors map[int]Color) error { + if g.vertices != len(colors) { + return errors.New("coloring: not all vertices of graph are colored") + } + // check colors + for vertex, neighbours := range g.edges { + for nb := range neighbours { + if colors[vertex] == colors[nb] { + return errors.New("coloring: same colors of neighbouring vertex") + } + } + } + return nil +} diff --git a/graph/coloring/graph_test.go b/graph/coloring/graph_test.go new file mode 100644 index 000000000..839d9f261 --- /dev/null +++ b/graph/coloring/graph_test.go @@ -0,0 +1,153 @@ +// This file provides tests for graph coloring validations. +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring_test + +import ( + "github.com/TheAlgorithms/Go/graph/coloring" + "strconv" + "testing" +) + +type testGraph struct { + Graph *coloring.Graph + ColorsUsed int + VertexColors map[int]coloring.Color +} + +func getTestGraphs() (list []*testGraph) { + // Graph 0th: + // 1---2 + // | / \ + // 4---3 0 + // Min number of colors required = 3 + g0 := &testGraph{ + Graph: &coloring.Graph{}, + ColorsUsed: 3, + VertexColors: map[int]coloring.Color{ + 1: 1, 4: 1, 0: 1, + 2: 2, + 3: 3, + }, + } + list = append(list, g0) + g0.Graph.AddEdge(4, 3) + g0.Graph.AddEdge(3, 1) + g0.Graph.AddEdge(3, 2) + g0.Graph.AddEdge(1, 2) + g0.Graph.AddEdge(2, 0) + + // Graph 1st: + // 1---2 + // | / | + // 4---3---0 + // Min number of colors required = 3 + g1 := &testGraph{ + Graph: &coloring.Graph{}, + ColorsUsed: 3, + VertexColors: map[int]coloring.Color{ + 1: 1, 4: 1, 0: 1, + 2: 2, + 3: 3, + }, + } + list = append(list, g1) + g1.Graph.AddEdge(4, 3) + g1.Graph.AddEdge(3, 1) + g1.Graph.AddEdge(3, 2) + g1.Graph.AddEdge(1, 2) + g1.Graph.AddEdge(2, 0) + g1.Graph.AddEdge(3, 0) + + // Graph 2nd: + // 1---2 + // | + // 4---3 0 + // Min number of colors required = 2 + g2 := &testGraph{ + Graph: &coloring.Graph{}, + ColorsUsed: 2, + VertexColors: map[int]coloring.Color{ + 1: 1, 4: 1, 0: 1, + 2: 2, 3: 2, + }, + } + list = append(list, g2) + g2.Graph.AddVertex(0) + g2.Graph.AddEdge(4, 3) + g2.Graph.AddEdge(3, 1) + g2.Graph.AddEdge(1, 2) + + // Graph 3rd: + // 1---2 4 + // | | | + // 0---3 5 + // Min number of colors required = 2 + g3 := &testGraph{ + Graph: &coloring.Graph{}, + ColorsUsed: 2, + VertexColors: map[int]coloring.Color{ + 1: 1, 3: 1, 4: 1, + 0: 2, 2: 2, 5: 2, + }, + } + list = append(list, g3) + g3.Graph.AddEdge(0, 3) + g3.Graph.AddEdge(1, 2) + g3.Graph.AddEdge(1, 0) + g3.Graph.AddEdge(3, 2) + g3.Graph.AddEdge(4, 5) + + // Graph 4th: + // Completely Connected graph of vertex 4 + // Min number of colors required = 2 + g4 := &testGraph{ + Graph: &coloring.Graph{}, + ColorsUsed: 4, + VertexColors: map[int]coloring.Color{ + 0: 1, 1: 2, 2: 3, 4: 4, + }, + } + list = append(list, g4) + for i := 0; i < 4; i++ { + for j := i + 1; j < 4; j++ { + g4.Graph.AddEdge(i, j) + } + } + + return +} + +func TestGraph_ValidateColorsOfVertex(t *testing.T) { + for i, tt := range getTestGraphs() { + t.Run(strconv.Itoa(i), func(t *testing.T) { + if err := tt.Graph.ValidateColorsOfVertex(tt.VertexColors); err != nil { + t.Errorf("ValidateColorsOfVertex() error = %v, wantErr nil", err) + } + }) + } +} + +func getTestGraphsForNegativeTests() (list []*testGraph) { + list = getTestGraphs() + list[0].VertexColors = nil + list[1].VertexColors = map[int]coloring.Color{} + for v := range list[2].VertexColors { + in := len(list[2].VertexColors) - v - 1 + list[2].VertexColors[v] = list[2].VertexColors[in] + } + for v := range list[3].VertexColors { + list[3].VertexColors[v] = 1 + } + return list[:4] +} + +func TestGraphValidateColorsOfVertex_Negative(t *testing.T) { + for i, tt := range getTestGraphsForNegativeTests() { + t.Run(strconv.Itoa(i), func(t *testing.T) { + if err := tt.Graph.ValidateColorsOfVertex(tt.VertexColors); err == nil { + t.Errorf("ValidateColorsOfVertex() error = nil, want some err") + } + }) + } +} diff --git a/graph/coloring/greedy.go b/graph/coloring/greedy.go new file mode 100644 index 000000000..907395d96 --- /dev/null +++ b/graph/coloring/greedy.go @@ -0,0 +1,52 @@ +// This file contains the graph coloring implementation using Greedy Approach. +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring + +import "sort" + +// ColorUsingGreedyApproach will return the Color of each vertex and the +// total number of different colors used, using a greedy approach, based on +// the number of edges (or degree) from any vertex. +func (g *Graph) ColorUsingGreedyApproach() (map[int]Color, int) { + degreeOfVertex := make([]struct{ degree, vertex int }, 0, g.vertices) + for v, neighbours := range g.edges { + degreeOfVertex = append(degreeOfVertex, + struct{ degree, vertex int }{ + vertex: v, + degree: len(neighbours), + }, + ) + } + // sort the degreeOfVertex in decreasing order of degrees + sort.Slice(degreeOfVertex, func(i, j int) bool { + return degreeOfVertex[i].degree > degreeOfVertex[j].degree + }) + + vertexColors := make(map[int]Color, g.vertices) + // Start with a color and assign the color to all possible vertices in the degreeOfVertex slice + // and then, re-iterate with new color for all those which are left + for color := 1; color <= g.vertices; color++ { + vertexLoop: + for _, val := range degreeOfVertex { + // skip, if already assigned + if _, ok := vertexColors[val.vertex]; ok { + continue vertexLoop + } + // Check its neighbours + for ng := range g.edges[val.vertex] { + if vertexColors[ng] == Color(color) { + // not possible to use this color for val.vertex + continue vertexLoop + } + } + // Assign color to the vertex + vertexColors[val.vertex] = Color(color) + } + // continue till all the vertices are colored + if len(vertexColors) == g.vertices { + return vertexColors, color + } + } + return vertexColors, g.vertices +} diff --git a/graph/coloring/greedy_test.go b/graph/coloring/greedy_test.go new file mode 100644 index 000000000..cd55d7d38 --- /dev/null +++ b/graph/coloring/greedy_test.go @@ -0,0 +1,24 @@ +// This file provides tests for coloring using Greedy approach. +// Author(s): [Shivam](https://github.com/Shivam010) + +package coloring_test + +import ( + "strconv" + "testing" +) + +func TestGraphColorUsingGreedyApproach(t *testing.T) { + for i, tt := range getTestGraphs() { + t.Run(strconv.Itoa(i), func(t *testing.T) { + colorsOfVertices, colors := tt.Graph.ColorUsingGreedyApproach() + if colors != tt.ColorsUsed { + t.Errorf("ColorUsingGreedyApproach() return more number of colors: %v, want %v colors", colors, tt.ColorsUsed) + } + // check colors + if err := tt.Graph.ValidateColorsOfVertex(colorsOfVertices); err != nil { + t.Errorf("ColorUsingGreedyApproach() assigned colors are wrong, error = %v", err) + } + }) + } +} diff --git a/graph/doc.go b/graph/doc.go index 32a55f68b..ec3d4c5ce 100644 --- a/graph/doc.go +++ b/graph/doc.go @@ -1,3 +1,3 @@ -// Package graph demonstates Graph search algorithms +// Package graph demonstrates Graph search algorithms // reference: https://en.wikipedia.org/wiki/Tree_traversal package graph diff --git a/graph/graph.go b/graph/graph.go new file mode 100644 index 000000000..6d00d1661 --- /dev/null +++ b/graph/graph.go @@ -0,0 +1,37 @@ +// This file contains the simple structural implementation of undirected +// graph. Used in coloring algorithms [here](./coloring) +// Author(s): [Shivam](https://github.com/Shivam010) + +package graph + +// UndirectedGraph provides a structure to store an undirected graph. +// It is safe to use its empty object. +type UndirectedGraph struct { + vertices int + edges map[int]map[int]struct{} +} + +// AddVertex will add a new vertex in the graph, if the vertex already +// exist it will do nothing +func (g *UndirectedGraph) AddVertex(v int) { + if g.edges == nil { + g.edges = make(map[int]map[int]struct{}) + } + + // Check if vertex is present or not + if _, ok := g.edges[v]; !ok { + g.vertices++ + g.edges[v] = make(map[int]struct{}) + } +} + +// AddEdge will add a new edge between the provided vertices in the graph +func (g *UndirectedGraph) AddEdge(one, two int) { + // Add vertices: one and two to the graph if they are not present + g.AddVertex(one) + g.AddVertex(two) + + // and finally add the edges: one->two and two->one for undirected graph + g.edges[one][two] = struct{}{} + g.edges[two][one] = struct{}{} +} From 1fb424c8588d24f1e94e536ba9ad6091e8ee5b52 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 23 Sep 2021 08:11:28 +0300 Subject: [PATCH 234/488] Add powers in terms of logarithms (#348) --- math/pi/spigotpi.go | 59 ++++++++++++++++++++++++++++++ math/pi/spigotpi_test.go | 50 +++++++++++++++++++++++++ math/power/powvialogarithm.go | 24 ++++++++++++ math/power/powvialogarithm_test.go | 44 ++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 math/pi/spigotpi.go create mode 100644 math/pi/spigotpi_test.go create mode 100644 math/power/powvialogarithm.go create mode 100644 math/power/powvialogarithm_test.go diff --git a/math/pi/spigotpi.go b/math/pi/spigotpi.go new file mode 100644 index 000000000..6274176e4 --- /dev/null +++ b/math/pi/spigotpi.go @@ -0,0 +1,59 @@ +// spigotpi.go +// description: A Spigot Algorithm for the Digits of Pi +// details: +// implementation of Spigot Algorithm for the Digits of Pi - [Spigot algorithm](https://en.wikipedia.org/wiki/Spigot_algorithm) +// author(s) [red_byte](https://github.com/i-redbyte) +// see spigotpi_test.go + +package pi + +import "strconv" + +func Spigot(n int) string { + pi := "" + boxes := n * 10 / 3 + remainders := make([]int, boxes) + for i := 0; i < boxes; i++ { + remainders[i] = 2 + } + digitsHeld := 0 + for i := 0; i < n; i++ { + carriedOver := 0 + sum := 0 + for j := boxes - 1; j >= 0; j-- { + remainders[j] *= 10 + sum = remainders[j] + carriedOver + quotient := sum / (j*2 + 1) + remainders[j] = sum % (j*2 + 1) + carriedOver = quotient * j + } + remainders[0] = sum % 10 + q := sum / 10 + switch q { + case 9: + digitsHeld++ + case 10: + q = 0 + for k := 1; k <= digitsHeld; k++ { + replaced, _ := strconv.Atoi(pi[i-k : i-k+1]) + if replaced == 9 { + replaced = 0 + } else { + replaced++ + } + pi = delChar(pi, i-k) + pi = pi[:i-k] + strconv.Itoa(replaced) + pi[i-k:] + } + digitsHeld = 1 + default: + digitsHeld = 1 + } + pi += strconv.Itoa(q) + } + return pi +} + +func delChar(s string, index int) string { + tmp := []rune(s) + return string(append(tmp[0:index], tmp[index+1:]...)) +} diff --git a/math/pi/spigotpi_test.go b/math/pi/spigotpi_test.go new file mode 100644 index 000000000..ad845da15 --- /dev/null +++ b/math/pi/spigotpi_test.go @@ -0,0 +1,50 @@ +// spigotpi_test.go +// description: Test for Spigot Algorithm for the Digits of Pi +// author(s) [red_byte](https://github.com/i-redbyte) +// see spigotpi.go +package pi + +import ( + "strconv" + "testing" +) + +func TestSpigot(t *testing.T) { + var tests = []struct { + result string + n int + }{ + {"314159", 6}, + {"31415926535", 11}, + {"314159265358", 12}, + {"314159265358979323846", 21}, + {"314", 3}, + {"31415", 5}, + } + for _, tv := range tests { + t.Run(strconv.Itoa(tv.n)+":"+tv.result, func(t *testing.T) { + result := Spigot(tv.n) + if result != tv.result { + t.Errorf("Bad result %d:%s", tv.n, tv.result) + } + }) + } +} + +func BenchmarkPiSpigotN10(b *testing.B) { + for i := 0; i < b.N; i++ { + Spigot(10) + } +} + +func BenchmarkPiSpigotN100(b *testing.B) { + for i := 0; i < b.N; i++ { + Spigot(100) + } +} + +func BenchmarkPiSpigotN1000(b *testing.B) { + for i := 0; i < b.N; i++ { + Spigot(1000) + } +} diff --git a/math/power/powvialogarithm.go b/math/power/powvialogarithm.go new file mode 100644 index 000000000..df1de157f --- /dev/null +++ b/math/power/powvialogarithm.go @@ -0,0 +1,24 @@ +// powvialogarithm.go +// description: Powers in terms of logarithms +// details: +// implementation of exponentiation using exponent and logarithm, without using loops - [Powers via logarithms wiki](https://en.wikipedia.org/wiki/Exponentiation#Powers_via_logarithms) +// author(s) [red_byte](https://github.com/i-redbyte) +// see powvialogarithm_test.go + +package power + +import ( + "math" +) + +func UsingLog(a float64, b float64) float64 { + var p float64 + p = 1 + if a < 0 && int(b)&1 != 0 { + p = -1 + } + log := math.Log(math.Abs(a)) + exp := math.Exp(b * log) + result := exp * p + return math.Round(result) +} diff --git a/math/power/powvialogarithm_test.go b/math/power/powvialogarithm_test.go new file mode 100644 index 000000000..e38046c9c --- /dev/null +++ b/math/power/powvialogarithm_test.go @@ -0,0 +1,44 @@ +// powvialogarithm_test.go +// description: Test for UsingLog +// author(s) [red_byte](https://github.com/i-redbyte) +// see powvialogarithm.go + +package power + +import "testing" + +func TestUsingLog(t *testing.T) { + var tests = []struct { + name string + base float64 + power float64 + expected float64 + }{ + {"0^0", 99, 1, 99}, + {"-3^9", -3, 9, -19683}, + {"0^2", 0, 2, 0}, + {"2^0", 2, 0, 1}, + {"2^3", 2, 3, 8}, + {"8^3", 8, 3, 512}, + {"11^11", 11, 11, 285311670611}, + {"5^5", 5, 5, 3125}, + {"-7^2", -7, 2, 49}, + {"-6^3", -6, 3, -216}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result := UsingLog(tc.base, tc.power) + t.Log(result) + if result != tc.expected { + t.Errorf("Expected %.2f to the power of %.2f to be: %.2f, but got: %.2f", tc.base, tc.power, tc.expected, result) + } + }) + } +} + +func BenchmarkUsingLog(b *testing.B) { + for i := 0; i < b.N; i++ { + UsingLog(10, 5) + } +} From 012bdbc614d8acac3a1df8aa0ad49c207f83b5b2 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 23 Sep 2021 14:46:56 +0300 Subject: [PATCH 235/488] Find a missing number in a sequence (#350) --- math/binarymath/xorsearch.go | 17 ++++++++++++++ math/binarymath/xorsearch_test.go | 38 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 math/binarymath/xorsearch.go create mode 100644 math/binarymath/xorsearch_test.go diff --git a/math/binarymath/xorsearch.go b/math/binarymath/xorsearch.go new file mode 100644 index 000000000..1d706e8ad --- /dev/null +++ b/math/binarymath/xorsearch.go @@ -0,0 +1,17 @@ +// xorsearch.go +// description: Find a missing number in a sequence +// details: +// Given an array A containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. - [xor](https://en.wikipedia.org/wiki/Exclusive_or) +// author(s) [red_byte](https://github.com/i-redbyte) +// see xorsearch_test.go + +package binarymath + +func XorSearchMissingNumber(a []int) int { + n := len(a) + result := len(a) + for i := 0; i < n; i++ { + result ^= i ^ a[i] + } + return result +} diff --git a/math/binarymath/xorsearch_test.go b/math/binarymath/xorsearch_test.go new file mode 100644 index 000000000..73e5489d9 --- /dev/null +++ b/math/binarymath/xorsearch_test.go @@ -0,0 +1,38 @@ +// xorsearch_test.go +// description: Test for Find a missing number in a sequence +// author(s) [red_byte](https://github.com/i-redbyte) +// see xorsearch.go +package binarymath + +import ( + "testing" +) + +func TestXorSearchMissingNumber(t *testing.T) { + var tests = []struct { + name string + a []int + missing int + }{ + {"[3, 0, 1]/2", []int{3, 0, 1}, 2}, + {"[0, 1, 3, 4, 5, 6, 7]/2", []int{0, 1, 3, 4, 5, 6, 7}, 2}, + {"[0, 2, 3, 4, 5, 6, 7, 8, 9]/1", []int{0, 2, 3, 4, 5, 6, 7, 8, 9}, 1}, + {"[0, 10, 9, 7, 2, 1, 4, 3, 5, 6]/8", []int{0, 10, 9, 7, 2, 1, 4, 3, 5, 6}, 8}, + } + + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := XorSearchMissingNumber(tv.a) + if result != tv.missing { + t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.missing, result) + } + }) + } + +} + +func BenchmarkTestXorSearchMissingNumber(b *testing.B) { + for i := 0; i < b.N; i++ { + XorSearchMissingNumber([]int{0, 10, 9, 7, 2, 1, 4, 3, 5, 6}) + } +} From d700f6ae8d53e8d74d43974f3cdf999e019e718d Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 23 Sep 2021 20:52:10 +0300 Subject: [PATCH 236/488] chore: merge "Feat: arithmetic mean (#351)" * feat: add an algorithm for finding the maximum number without using conditional operators * fix: rename to bitwiseMax * feat: Powers via logarithms * fix: change types and add benchmark * feat: A Spigot Algorithm for the Digits of Pi * feat: add benchmark * fix: change after review * fix: change after review(two version) * fix: rename heldDigits to digitsHeld * feat: arithmetic mean (binary realization) * fix: change after review --- math/binarymath/arithmeticmean.go | 17 +++++++ math/binarymath/arithmeticmean_test.go | 65 ++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 math/binarymath/arithmeticmean.go create mode 100644 math/binarymath/arithmeticmean_test.go diff --git a/math/binarymath/arithmeticmean.go b/math/binarymath/arithmeticmean.go new file mode 100644 index 000000000..46f72a405 --- /dev/null +++ b/math/binarymath/arithmeticmean.go @@ -0,0 +1,17 @@ +// arithmeticmean.go +// description: Arithmetic mean +// details: +// The most common type of average is the arithmetic mean. If n numbers are given, each number denoted by ai (where i = 1,2, ..., n), the arithmetic mean is the sum of the as divided by n or - [Arithmetic mean](https://en.wikipedia.org/wiki/Average#Arithmetic_mean) +// author(s) [red_byte](https://github.com/i-redbyte) +// see arithmeticmean_test.go + +// Package binarymath describes algorithms that use binary operations for different calculations. +package binarymath + +func MeanUsingAndXor(a int, b int) int { + return ((a ^ b) >> 1) + (a & b) +} + +func MeanUsingRightShift(a int, b int) int { + return (a + b) >> 1 +} diff --git a/math/binarymath/arithmeticmean_test.go b/math/binarymath/arithmeticmean_test.go new file mode 100644 index 000000000..0b06aa50f --- /dev/null +++ b/math/binarymath/arithmeticmean_test.go @@ -0,0 +1,65 @@ +// arithmeticmean_test.go +// description: Test for Arithmetic mean +// author(s) [red_byte](https://github.com/i-redbyte) +// see arithmeticmean.go + +package binarymath + +import "testing" + +func TestMeanUsingAndXor(t *testing.T) { + tests := getTests() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := MeanUsingAndXor(tv.a, tv.b) + if result != tv.result { + t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) + } + }) + } + +} + +func TestMeanUsingRightShift(t *testing.T) { + tests := getTests() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := MeanUsingRightShift(tv.a, tv.b) + if result != tv.result { + t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) + } + }) + } + +} +func getTests() []struct { + name string + a int + b int + result int +} { + var tests = []struct { + name string + a int + b int + result int + }{ + {"Average of 2 and 4", 2, 4, 3}, + {"Average of 5 and 5", 5, 5, 5}, + {"Average of 1000 and 1002", 1000, 1002, 1001}, + {"Average of 80 and 40", 80, 40, 60}, + {"Average of 7 and 4", 7, 4, 5}, + } + return tests +} +func BenchmarkMeanUsingAndXor(b *testing.B) { + for i := 0; i < b.N; i++ { + MeanUsingAndXor(222, 888) + } +} + +func BenchmarkMeanUsingRightShift(b *testing.B) { + for i := 0; i < b.N; i++ { + MeanUsingRightShift(222, 888) + } +} From 1fce86c0269c820a04a59e509970016df335a913 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Fri, 24 Sep 2021 08:04:25 +0300 Subject: [PATCH 237/488] Add calculating factorial (#352) --- math/factorial/factorial.go | 52 ++++++++++++++++++++ math/factorial/factorial_test.go | 81 ++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 math/factorial/factorial.go create mode 100644 math/factorial/factorial_test.go diff --git a/math/factorial/factorial.go b/math/factorial/factorial.go new file mode 100644 index 000000000..2d376a87b --- /dev/null +++ b/math/factorial/factorial.go @@ -0,0 +1,52 @@ +// factorial.go +// description: Calculating factorial +// details: +// The factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n - [Factorial](https://en.wikipedia.org/wiki/Factorial) +// author(s) [red_byte](https://github.com/i-redbyte) +// see factorial_test.go + +// Package factorial describes algorithms Factorials calculations. +package factorial + +func BruteForceFactorial(n int) int { + result := 1 + for i := 2; i <= n; i++ { + result *= i + } + return result +} + +func RecursiveFactorial(n int) int { + if n == 1 { + return 1 + } else { + return n * RecursiveFactorial(n-1) + } +} + +func CalculateFactorialUseTree(n int) int { + if n < 0 { + return 0 + } + if n == 0 { + return 1 + } + if n == 1 || n == 2 { + return n + } + return prodTree(2, n) +} + +func prodTree(l int, r int) int { + if l > r { + return 1 + } + if l == r { + return l + } + if r-l == 1 { + return l * r + } + m := (l + r) / 2 + return prodTree(l, m) * prodTree(m+1, r) +} diff --git a/math/factorial/factorial_test.go b/math/factorial/factorial_test.go new file mode 100644 index 000000000..9a083441d --- /dev/null +++ b/math/factorial/factorial_test.go @@ -0,0 +1,81 @@ +// factorial_test.go +// description: Test for calculating factorial +// author(s) [red_byte](https://github.com/i-redbyte) +// see factorial.go + +package factorial + +import "testing" + +func getTests() []struct { + name string + n int + result int +} { + var tests = []struct { + name string + n int + result int + }{ + {"5!", 5, 120}, + {"3!", 3, 6}, + {"6!", 6, 720}, + {"12!", 12, 479001600}, + {"1!", 1, 1}, + } + return tests +} + +func TestBruteForceFactorial(t *testing.T) { + tests := getTests() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := BruteForceFactorial(tv.n) + if result != tv.result { + t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) + } + }) + } +} + +func TestRecursiveFactorial(t *testing.T) { + tests := getTests() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := RecursiveFactorial(tv.n) + if result != tv.result { + t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) + } + }) + } +} + +func TestCalculateFactorialUseTree(t *testing.T) { + tests := getTests() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := CalculateFactorialUseTree(tv.n) + if result != tv.result { + t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) + } + }) + } +} + +func BenchmarkBruteForceFactorial(b *testing.B) { + for i := 0; i < b.N; i++ { + BruteForceFactorial(10) + } +} + +func BenchmarkRecursiveFactorial(b *testing.B) { + for i := 0; i < b.N; i++ { + RecursiveFactorial(10) + } +} + +func BenchmarkCalculateFactorialUseTree(b *testing.B) { + for i := 0; i < b.N; i++ { + RecursiveFactorial(10) + } +} From f2ca9030c07da0db864827846abcbd919c379dec Mon Sep 17 00:00:00 2001 From: Branden <37084158+brandenc40@users.noreply.github.com> Date: Fri, 24 Sep 2021 00:15:30 -0500 Subject: [PATCH 238/488] Optimize roman to int and adde int to roman (#353) Co-authored-by: Andrii Siriak --- conversion/integertoroman.go | 36 ++++++++++++++++++ conversion/integertoroman_test.go | 30 +++++++++++++++ conversion/romantointeger.go | 55 ++++++++++++++++++++++----- conversion/romantointeger_test.go | 62 +++++++++++++++++++++---------- 4 files changed, 154 insertions(+), 29 deletions(-) create mode 100644 conversion/integertoroman.go create mode 100644 conversion/integertoroman_test.go diff --git a/conversion/integertoroman.go b/conversion/integertoroman.go new file mode 100644 index 000000000..c1764db1f --- /dev/null +++ b/conversion/integertoroman.go @@ -0,0 +1,36 @@ +package conversion + +import ( + "errors" +) + +var ( + // lookup arrays used for converting from an int to a roman numeral extremely quickly. + r0 = []string{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"} // 1 - 9 + r1 = []string{"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"} // 10 - 90 + r2 = []string{"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"} // 100 - 900 + r3 = []string{"", "M", "MM", "MMM"} // 1,000 - 3,000 +) + +// IntToRoman converts an integer value to a roman numeral string. An error is +// returned if the integer is not between 1 and 3999. +func IntToRoman(n int) (string, error) { + if n < 1 || n > 3999 { + return "", errors.New("integer must be between 1 and 3999") + } + // Concatenate strings for each of 4 lookup array categories. + // + // Key behavior to note here is how math with integers is handled. Values are floored to the + // nearest int, not rounded up. For example, 26/10 = 2 even though the actual result is 2.6. + // + // For example, lets use an input value of 126: + // `r3[n%1e4/1e3]` --> 126 % 10_000 = 126 --> 126 / 1_000 = 0.126 (0 as int) --> r3[0] = "" + // `r2[n%1e3/1e2]` --> 126 % 1_000 = 126 --> 126 / 100 = 1.26 (1 as int) --> r2[1] = "C" + // `r1[n%100/10]` --> 126 % 100 = 26 --> 26 / 10 = 2.6 (2 as int) --> r1[2] = "XX" + // `r0[n%10]` --> 126 % 10 = 6 --> r0[6] = "VI" + // FINAL --> "" + "C" + "XX" + "VI" = "CXXVI" + // + // This is efficient in Go. The 4 operands are evaluated, + // then a single allocation is made of the exact size needed for the result. + return r3[n%1e4/1e3] + r2[n%1e3/1e2] + r1[n%100/10] + r0[n%10], nil +} diff --git a/conversion/integertoroman_test.go b/conversion/integertoroman_test.go new file mode 100644 index 000000000..20bb24999 --- /dev/null +++ b/conversion/integertoroman_test.go @@ -0,0 +1,30 @@ +package conversion + +import "testing" + +func TestIntToRoman(t *testing.T) { + for expected, input := range romanTestCases { + out, err := IntToRoman(input) + if err != nil { + t.Errorf("IntToRoman(%d) returned an error %s", input, err.Error()) + } + if out != expected { + t.Errorf("IntToRoman(%d) = %s; want %s", input, out, expected) + } + } + _, err := IntToRoman(100000) + if err == nil { + t.Errorf("IntToRoman(%d) expected an error", 100000) + } + _, err = IntToRoman(0) + if err == nil { + t.Errorf("IntToRoman(%d) expected an error", 0) + } +} + +func BenchmarkIntToRoman(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = IntToRoman(3999) + } +} diff --git a/conversion/romantointeger.go b/conversion/romantointeger.go index 45e386a78..8281e2f0c 100644 --- a/conversion/romantointeger.go +++ b/conversion/romantointeger.go @@ -6,17 +6,52 @@ package conversion -var romans = map[string]int{"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} +import ( + "errors" + "strings" +) -func RomanToInteger(roman string) int { - total := 0 - romanLen := len(roman) - for holder := range roman { - if holder+1 < romanLen && romans[string(roman[holder])] < romans[string(roman[holder+1])] { - total -= romans[string(roman[holder])] - } else { - total += romans[string(roman[holder])] +// numeral describes the value and symbol of a single roman numeral +type numeral struct { + val int + sym string +} + +// lookup array for numeral values sorted by largest to smallest +var nums = []numeral{ + {1000, "M"}, + {900, "CM"}, + {500, "D"}, + {400, "CD"}, + {100, "C"}, + {90, "XC"}, + {50, "L"}, + {40, "XL"}, + {10, "X"}, + {9, "IX"}, + {5, "V"}, + {4, "IV"}, + {1, "I"}, +} + +// RomanToInteger converts a roman numeral string to an integer. Roman numerals for numbers +// outside the range 1 to 3,999 will return an error. Nil or empty string return 0 +// with no error thrown. +func RomanToInteger(input string) (int, error) { + if input == "" { + return 0, nil + } + var output int + for _, n := range nums { + for strings.HasPrefix(input, n.sym) { + output += n.val + input = input[len(n.sym):] } } - return total + // if we are still left with input string values then the + // input was invalid and the bool is returned as false + if len(input) > 0 { + return 0, errors.New("invalid roman numeral") + } + return output, nil } diff --git a/conversion/romantointeger_test.go b/conversion/romantointeger_test.go index 59c175c19..2916c1981 100644 --- a/conversion/romantointeger_test.go +++ b/conversion/romantointeger_test.go @@ -2,28 +2,52 @@ package conversion import "testing" -type romanToIntegerConversionTest struct { - input string - expected int - name string -} - -var romanToIntegerTests = []romanToIntegerConversionTest{ - {input: "DCCLXXXIX", expected: 789, name: "DCCLXXXIX-789"}, - {input: "MLXVI", expected: 1066, name: "MLXVI-1066"}, - {input: "MCMXVIII", expected: 1918, name: "MCMXVIII-1918"}, - {input: "V", expected: 5, name: "V-5"}, +var romanTestCases = map[string]int{ + "I": 1, "II": 2, "III": 3, "IV": 4, "V": 5, "VI": 6, + "VII": 7, "VIII": 8, "IX": 9, "X": 10, "XI": 11, "XII": 12, + "XIII": 13, "XIV": 14, "XV": 15, "XVI": 16, "XVII": 17, + "XVIII": 18, "XIX": 19, "XX": 20, "XXXI": 31, "XXXII": 32, + "XXXIII": 33, "XXXIV": 34, "XXXV": 35, "XXXVI": 36, "XXXVII": 37, + "XXXVIII": 38, "XXXIX": 39, "XL": 40, "XLI": 41, "XLII": 42, + "XLIII": 43, "XLIV": 44, "XLV": 45, "XLVI": 46, "XLVII": 47, + "XLVIII": 48, "XLIX": 49, "L": 50, "LXXXIX": 89, "XC": 90, + "XCI": 91, "XCII": 92, "XCIII": 93, "XCIV": 94, "XCV": 95, + "XCVI": 96, "XCVII": 97, "XCVIII": 98, "XCIX": 99, "C": 100, + "CI": 101, "CII": 102, "CIII": 103, "CIV": 104, "CV": 105, + "CVI": 106, "CVII": 107, "CVIII": 108, "CIX": 109, "CXLIX": 149, + "CCCXLIX": 349, "CDLVI": 456, "D": 500, "DCIV": 604, "DCCLXXXIX": 789, + "DCCCXLIX": 849, "CMIV": 904, "M": 1000, "MVII": 1007, "MLXVI": 1066, + "MCCXXXIV": 1234, "MDCCLXXVI": 1776, "MMXXI": 2021, "MMDCCCVI": 2806, + "MMCMXCIX": 2999, "MMM": 3000, "MMMCMLXXIX": 3979, "MMMCMXCIX": 3999, } func TestRomanToInteger(t *testing.T) { - - for _, test := range romanToIntegerTests { - convertedValue := RomanToInteger(test.input) - if convertedValue != test.expected { - t.Errorf( - "roman to integer test %s failed. expected '%d' but got '%d'", - test.name, test.expected, convertedValue, - ) + for input, expected := range romanTestCases { + out, err := RomanToInteger(input) + if err != nil { + t.Errorf("RomanToInteger(%s) returned an error %s", input, err.Error()) } + if out != expected { + t.Errorf("RomanToInteger(%s) = %d; want %d", input, out, expected) + } + } + _, err := RomanToInteger("IVCMXCIX") + if err == nil { + t.Error("RomanToInteger(IVCMXCIX) expected an error") + } + + val, err := RomanToInteger("") + if val != 0 { + t.Errorf("RomanToInteger(\"\") = %d; want 0", val) + } + if err != nil { + t.Errorf("RomanToInteger(\"\") returned an error %s", err.Error()) + } +} + +func BenchmarkRomanToInteger(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = RomanToInteger("MMMCMXCIX") } } From 40a975fa4943e9b1b352d3322eb5bce7f5fdaf68 Mon Sep 17 00:00:00 2001 From: Branden <37084158+brandenc40@users.noreply.github.com> Date: Sat, 25 Sep 2021 14:43:25 -0500 Subject: [PATCH 239/488] Updated README to include new int to roman function (#355) --- README.md | 3 ++- conversion/romantointeger.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e71ab36d9..3b596f14b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Xor](./cipher/xor/xor.go) ### Conversions -* [Roman To Integer](./conversion/romantointeger.go) +* [Roman Numeral To Integer](./conversion/romantointeger.go) +* [Integer To Roman Numeral](./conversion/integertoroman.go) ### Data Structures * [AVL Tree](./structure/avl/avl.go) diff --git a/conversion/romantointeger.go b/conversion/romantointeger.go index 8281e2f0c..e7a8eb594 100644 --- a/conversion/romantointeger.go +++ b/conversion/romantointeger.go @@ -49,7 +49,7 @@ func RomanToInteger(input string) (int, error) { } } // if we are still left with input string values then the - // input was invalid and the bool is returned as false + // input was invalid and an error is returned. if len(input) > 0 { return 0, errors.New("invalid roman numeral") } From 87f185cc1cb6f9a16188146471e7535685241de9 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Sat, 25 Sep 2021 22:48:53 +0300 Subject: [PATCH 240/488] Add monte carlo pi calculation (#354) --- math/pi/montecarlopi.go | 27 +++++++++++++++++++++++++++ math/pi/montecarlopi_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 math/pi/montecarlopi.go create mode 100644 math/pi/montecarlopi_test.go diff --git a/math/pi/montecarlopi.go b/math/pi/montecarlopi.go new file mode 100644 index 000000000..53f39d943 --- /dev/null +++ b/math/pi/montecarlopi.go @@ -0,0 +1,27 @@ +// montecarlopi.go +// description: Calculating pi by the Monte Carlo method +// details: +// implementation of Monte Carlo Algorithm for the calculating of Pi - [Monte Carlo method](https://en.wikipedia.org/wiki/Monte_Carlo_method) +// author(s) [red_byte](https://github.com/i-redbyte) +// see montecarlopi_test.go + +package pi + +import ( + "math/rand" + "time" +) + +func MonteCarloPi(randomPoints int) float64 { + rnd := rand.New(rand.NewSource(time.Now().UnixNano())) + inside := 0 + for i := 0; i < randomPoints; i++ { + x := rnd.Float64() + y := rnd.Float64() + if x*x+y*y <= 1 { + inside += 1 + } + } + pi := float64(inside) / float64(randomPoints) * float64(4) + return pi +} diff --git a/math/pi/montecarlopi_test.go b/math/pi/montecarlopi_test.go new file mode 100644 index 000000000..4c650899e --- /dev/null +++ b/math/pi/montecarlopi_test.go @@ -0,0 +1,27 @@ +// montecarlopi_test.go +// description: Test for calculating pi by the Monte Carlo method +// author(s) [red_byte](https://github.com/i-redbyte) +// see montecarlopi.go + +package pi + +import ( + "fmt" + "testing" +) + +func TestMonteCarloPi(t *testing.T) { + t.Run("Monte Carlo Pi", func(t *testing.T) { + result := fmt.Sprintf("%.2f", MonteCarloPi(100000000)) + t.Log(result) + if result != "3.14" { + t.Errorf("Wrong result! Expected:%f, returned:%s ", 3.1415, result) + } + }) +} + +func BenchmarkMonteCarloPi(b *testing.B) { + for i := 0; i < b.N; i++ { + MonteCarloPi(100000000) + } +} From 26b0e2d46dcfaab9068dd322b3ef018341a204cc Mon Sep 17 00:00:00 2001 From: Femi Novia Lina <77434812+FemiNoviaLina@users.noreply.github.com> Date: Sun, 26 Sep 2021 12:26:30 +0700 Subject: [PATCH 241/488] Add btree tests (#356) --- structure/binarytree/btree_test.go | 147 +++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 structure/binarytree/btree_test.go diff --git a/structure/binarytree/btree_test.go b/structure/binarytree/btree_test.go new file mode 100644 index 000000000..a2e8b7cdf --- /dev/null +++ b/structure/binarytree/btree_test.go @@ -0,0 +1,147 @@ +package binarytree + +import ( + "reflect" + "testing" +) + +func TestInsert(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + + if root.val != 90 { + t.Errorf("root should have value = 90") + } + + if root.left.val != 80 { + t.Errorf("left child should have value = 80") + } + + if root.right.val != 100 { + t.Errorf("right child should have value = 100") + } + + if BTree.Depth() != 2 { + t.Errorf("tree should have depth = 1") + } +} + +func TestDelete(t *testing.T) { + t.Run("Delete a node with no child", func(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + + BstDelete(root, 100) + + if root.val != 90 { + t.Errorf("root should have value = 90") + } + + if root.left.val != 80 { + t.Errorf("left child should have value = 80") + } + + if root.right != nil { + t.Errorf("right child should have value = nil") + } + + if BTree.Depth() != 2 { + t.Errorf("Depth should have value = 2") + } + }) + + t.Run("Delete a node with one child", func(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + Insert(root, 70) + + BstDelete(root, 80) + + if root.val != 90 { + t.Errorf("root should have value = 90") + } + + if root.right.val != 100 { + t.Errorf("right child should have value = 100") + } + + if root.left.val != 70 { + t.Errorf("left child should have value = 70") + } + + if BTree.Depth() != 2 { + t.Errorf("Depth should have value = 2") + } + }) + + t.Run("Delete a node with two children", func(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + Insert(root, 70) + Insert(root, 85) + + BstDelete(root, 80) + + if root.val != 90 { + t.Errorf("root should have value = 90") + } + + if root.left.val != 85 { + t.Errorf("left child should have value = 85") + } + + if root.right.val != 100 { + t.Errorf("right child should have value = 100") + } + + if BTree.Depth() != 3 { + t.Errorf("Depth should have value = 3") + } + }) +} + +func TestAccessNodesByLayer(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + Insert(root, 70) + Insert(root, 85) + Insert(root, 95) + Insert(root, 105) + + a := AccessNodesByLayer(root) + b := [][]int{{90}, {80, 100}, {70, 85, 95, 105}} + + if !reflect.DeepEqual(a, b) { + t.Errorf("Nodes should have value = [[90] [80 100] [70 85 95 105]]") + } +} From adc50ebcc4b9da26617d7adea986e6be93c5a1f5 Mon Sep 17 00:00:00 2001 From: FuXiang Shu <6470547+Crazy3lf@users.noreply.github.com> Date: Tue, 28 Sep 2021 00:21:21 +0800 Subject: [PATCH 242/488] Update iterBinarySearch and add tests (#247) Co-authored-by: Rak Laptudirm --- search/binary.go | 28 +++++++++++++------------- search/binary_test.go | 46 ++++++++++++++++++++++++++++++++++--------- search/errors.go | 6 ++++++ search/testcases.go | 28 ++++++++++++++++---------- 4 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 search/errors.go diff --git a/search/binary.go b/search/binary.go index e72e3e9d2..7692813d7 100644 --- a/search/binary.go +++ b/search/binary.go @@ -1,38 +1,38 @@ package search -// Binary Binary Search -func Binary(array []int, target int, lowIndex int, highIndex int) int { +// Binary search for target within a sorted array by repeatedly dividing the array in half and comparing the midpoint with the target. +// This function uses recursive call to itself. +// If a target is found, the index of the target is returned. Else the function return -1 and ErrNotFound. +func Binary(array []int, target int, lowIndex int, highIndex int) (int, error) { if highIndex < lowIndex || len(array) == 0 { - return -1 + return -1, ErrNotFound } - mid := (highIndex + lowIndex) / 2 + mid := int(lowIndex + (highIndex-lowIndex)/2) if array[mid] > target { return Binary(array, target, lowIndex, mid-1) } else if array[mid] < target { return Binary(array, target, mid+1, highIndex) } else { - return mid + return mid, nil } } -// BinaryIterative Iterative Binary Search -func BinaryIterative(array []int, target int, lowIndex int, highIndex int) int { +// BinaryIterative search for target within a sorted array by repeatedly dividing the array in half and comparing the midpoint with the target. +// Unlike Binary, this function uses iterative method and not recursive. +// If a target is found, the index of the target is returned. Else the function return -1 and ErrNotFound. +func BinaryIterative(array []int, target int, lowIndex int, highIndex int) (int, error) { startIndex := lowIndex endIndex := highIndex var mid int - size := len(array) - if size == 0 || highIndex > size || lowIndex < 0 { - return -1 - } for startIndex <= endIndex { - mid = (endIndex + startIndex) / 2 + mid = int(startIndex + (endIndex-startIndex)/2) if array[mid] > target { endIndex = mid - 1 } else if array[mid] < target { startIndex = mid + 1 } else { - return mid + return mid, nil } } - return -1 + return -1, ErrNotFound } diff --git a/search/binary_test.go b/search/binary_test.go index 70f4a7bcb..748544cf7 100644 --- a/search/binary_test.go +++ b/search/binary_test.go @@ -1,23 +1,51 @@ package search -import ( - "testing" -) +import "testing" func TestBinarySearch(t *testing.T) { for _, test := range searchTests { - actual := Binary(test.data, test.key, 0, len(test.data)-1) - if actual != test.expected { - t.Errorf("test %s failed", test.name) + actualValue, actualError := Binary(test.data, test.key, 0, len(test.data)-1) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) + } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) } } } func TestIterBinarySearch(t *testing.T) { for _, test := range searchTests { - actual := BinaryIterative(test.data, test.key, 0, len(test.data)-1) - if actual != test.expected { - t.Errorf("test %s failed", test.name) + actualValue, actualError := BinaryIterative(test.data, test.key, 0, len(test.data)-1) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) + } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) } } } + +func generateBenchmarkTestCase() []int { + var testCase []int + for i := 0; i < 100; i++ { + testCase = append(testCase, i) + } + return testCase +} + +func BenchmarkBinarySearch(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // this is important because the generateBenchmarkTestCase() is expensive + for i := 0; i < b.N; i++ { + _, _ = Binary(testCase, 10, 0, len(testCase)-1) + } +} + +func BenchmarkIterBinarySearch(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // this is important because the generateBenchmarkTestCase() is expensive + for i := 0; i < b.N; i++ { + _, _ = BinaryIterative(testCase, 10, 0, len(testCase)-1) + } +} diff --git a/search/errors.go b/search/errors.go new file mode 100644 index 000000000..831073599 --- /dev/null +++ b/search/errors.go @@ -0,0 +1,6 @@ +package search + +import "errors" + +// ErrNotFound is returned by search functions when target is not found +var ErrNotFound = errors.New("target not found in array") diff --git a/search/testcases.go b/search/testcases.go index 65e9bbd06..524bb3d3b 100644 --- a/search/testcases.go +++ b/search/testcases.go @@ -1,22 +1,30 @@ package search type searchTest struct { - data []int - key int - expected int - name string + data []int + key int + expected int + expectedError error + name string } // Note that these are immutable therefore they are shared among all the search tests. // If your algorithm is mutating these then it is advisable to create separate test cases. var searchTests = []searchTest{ //Sanity - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 9, 8, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 8, 7, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 7, 6, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 6, 5, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 4, 3, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 3, 2, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 2, 1, nil, "Sanity"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, nil, "Sanity"}, //Absent - {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, - {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, + {[]int{1, 4, 5, 6, 7, 10}, -25, -1, ErrNotFound, "Absent"}, + {[]int{1, 4, 5, 6, 7, 10}, 25, -1, ErrNotFound, "Absent"}, //Empty slice - {[]int{}, 2, -1, "Empty"}, + {[]int{}, 2, -1, ErrNotFound, "Empty"}, } From a91ef217470d5eaa5a674839c22c5a2cde2fbb66 Mon Sep 17 00:00:00 2001 From: Femi Novia Lina <77434812+FemiNoviaLina@users.noreply.github.com> Date: Fri, 1 Oct 2021 01:00:29 +0700 Subject: [PATCH 243/488] Change binary tree traversal implementation and add the test (#360) * add btree test file * change binary tree traversal implementation and add btree traversal test Co-authored-by: Rak Laptudirm --- structure/binarytree/btree.go | 64 +++++++++++++++------- structure/binarytree/btree_test.go | 88 ++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 21 deletions(-) diff --git a/structure/binarytree/btree.go b/structure/binarytree/btree.go index 7345814ef..e3d128dee 100644 --- a/structure/binarytree/btree.go +++ b/structure/binarytree/btree.go @@ -1,7 +1,5 @@ package binarytree -import "fmt" - // BTree Returns a binary tree structure which contains only a root Node type BTree struct { Root *Node @@ -33,15 +31,6 @@ func (t *BTree) Depth() int { return calculateDepth(t.Root, 0) } -// InOrder add's children to a node in order left first then right recursively -func InOrder(n *Node) { - if n != nil { - InOrder(n.left) - fmt.Print(n.val, " ") - InOrder(n.right) - } -} - // InOrderSuccessor Goes to the left func InOrderSuccessor(root *Node) *Node { cur := root @@ -77,28 +66,55 @@ func BstDelete(root *Node, val int) *Node { return root } +// InOrder add's children to a node in order left first then right recursively +func inOrderRecursive(n *Node, traversal *[]int) { + if n != nil { + inOrderRecursive(n.left, traversal) + *traversal = append(*traversal, n.val) + inOrderRecursive(n.right, traversal) + } +} + +func InOrder(root *Node) []int { + traversal := make([]int, 0) + inOrderRecursive(root, &traversal) + return traversal +} + // PreOrder Preorder -func PreOrder(n *Node) { +func preOrderRecursive(n *Node, traversal *[]int) { if n == nil { return } - fmt.Print(n.val, " ") - PreOrder(n.left) - PreOrder(n.right) + *traversal = append(*traversal, n.val) + preOrderRecursive(n.left, traversal) + preOrderRecursive(n.right, traversal) +} + +func PreOrder(root *Node) []int { + traversal := make([]int, 0) + preOrderRecursive(root, &traversal) + return traversal } // PostOrder PostOrder -func PostOrder(n *Node) { +func postOrderRecursive(n *Node, traversal *[]int) { if n == nil { return } - PostOrder(n.left) - PostOrder(n.right) - fmt.Print(n.val, " ") + postOrderRecursive(n.left, traversal) + postOrderRecursive(n.right, traversal) + *traversal = append(*traversal, n.val) +} + +func PostOrder(root *Node) []int { + traversal := make([]int, 0) + postOrderRecursive(root, &traversal) + return traversal } // LevelOrder LevelOrder -func LevelOrder(root *Node) { +func levelOrderRecursive(root *Node, traversal *[]int) { var q []*Node // queue var n *Node // temporary node @@ -106,7 +122,7 @@ func LevelOrder(root *Node) { for len(q) != 0 { n, q = q[0], q[1:] - fmt.Print(n.val, " ") + *traversal = append(*traversal, n.val) if n.left != nil { q = append(q, n.left) } @@ -116,6 +132,12 @@ func LevelOrder(root *Node) { } } +func LevelOrder(root *Node) []int { + traversal := make([]int, 0) + levelOrderRecursive(root, &traversal) + return traversal +} + // AccessNodesByLayer Function that access nodes layer by layer instead of printing the results as one line. func AccessNodesByLayer(root *Node) [][]int { var res [][]int diff --git a/structure/binarytree/btree_test.go b/structure/binarytree/btree_test.go index a2e8b7cdf..0a24850f0 100644 --- a/structure/binarytree/btree_test.go +++ b/structure/binarytree/btree_test.go @@ -124,6 +124,94 @@ func TestDelete(t *testing.T) { }) } +func TestInOrder(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + Insert(root, 70) + Insert(root, 85) + Insert(root, 95) + Insert(root, 105) + + a := InOrder(root) + b := []int{70, 80, 85, 90, 95, 100, 105} + + if !reflect.DeepEqual(a, b) { + t.Errorf("Nodes should have value = [70 80 85 90 95 100 105]") + } +} + +func TestPreOrder(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + Insert(root, 70) + Insert(root, 85) + Insert(root, 95) + Insert(root, 105) + + a := PreOrder(root) + b := []int{90, 80, 70, 85, 100, 95, 105} + + if !reflect.DeepEqual(a, b) { + t.Errorf("Nodes should have value = [90 80 70 85 100 95 105]") + } +} + +func TestPostOrder(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + Insert(root, 70) + Insert(root, 85) + Insert(root, 95) + Insert(root, 105) + + a := PostOrder(root) + b := []int{70, 85, 80, 95, 105, 100, 90} + + if !reflect.DeepEqual(a, b) { + t.Errorf("Nodes should have value = [70 85 80 95 105 100 90]") + } +} + +func TestLevelOrder(t *testing.T) { + BTree := BTree{ + Root: NewNode(90), + } + + root := BTree.Root + + Insert(root, 80) + Insert(root, 100) + Insert(root, 70) + Insert(root, 85) + Insert(root, 95) + Insert(root, 105) + + a := LevelOrder(root) + b := []int{90, 80, 100, 70, 85, 95, 105} + + if !reflect.DeepEqual(a, b) { + t.Errorf("Nodes should have value = [90 80 100 70 85 95 105]") + } +} + func TestAccessNodesByLayer(t *testing.T) { BTree := BTree{ Root: NewNode(90), From 420ddd6905c7492ff31b57b0565f9c2fee3f32cd Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 30 Sep 2021 21:07:30 +0300 Subject: [PATCH 244/488] Add is power of two (#358) * feat: is power of two algorithm * fix: add doc and rename files * fix: text for tests * fix: after review * fix: after review2 * fix: move IsPowerOfTwoUseLog method to math package * fix: rename IsPowerOfTwoUseLog * fix: create checkisnumberpoweroftwo_test Co-authored-by: Andrii Siriak --- math/{binarymath => binary}/arithmeticmean.go | 4 +- .../arithmeticmean_test.go | 2 +- math/binary/checkisnumberpoweroftwo.go | 36 +++++++ math/binary/checkisnumberpoweroftwo_test.go | 93 +++++++++++++++++++ math/{binarymath => binary}/xorsearch.go | 2 +- math/{binarymath => binary}/xorsearch_test.go | 2 +- math/checkisnumberpoweroftwo.go | 16 ++++ math/checkisnumberpoweroftwo_test.go | 54 +++++++++++ 8 files changed, 204 insertions(+), 5 deletions(-) rename math/{binarymath => binary}/arithmeticmean.go (82%) rename math/{binarymath => binary}/arithmeticmean_test.go (98%) create mode 100644 math/binary/checkisnumberpoweroftwo.go create mode 100644 math/binary/checkisnumberpoweroftwo_test.go rename math/{binarymath => binary}/xorsearch.go (96%) rename math/{binarymath => binary}/xorsearch_test.go (98%) create mode 100644 math/checkisnumberpoweroftwo.go create mode 100644 math/checkisnumberpoweroftwo_test.go diff --git a/math/binarymath/arithmeticmean.go b/math/binary/arithmeticmean.go similarity index 82% rename from math/binarymath/arithmeticmean.go rename to math/binary/arithmeticmean.go index 46f72a405..3fbce0631 100644 --- a/math/binarymath/arithmeticmean.go +++ b/math/binary/arithmeticmean.go @@ -5,8 +5,8 @@ // author(s) [red_byte](https://github.com/i-redbyte) // see arithmeticmean_test.go -// Package binarymath describes algorithms that use binary operations for different calculations. -package binarymath +// Package binary describes algorithms that use binary operations for different calculations. +package binary func MeanUsingAndXor(a int, b int) int { return ((a ^ b) >> 1) + (a & b) diff --git a/math/binarymath/arithmeticmean_test.go b/math/binary/arithmeticmean_test.go similarity index 98% rename from math/binarymath/arithmeticmean_test.go rename to math/binary/arithmeticmean_test.go index 0b06aa50f..fe030e859 100644 --- a/math/binarymath/arithmeticmean_test.go +++ b/math/binary/arithmeticmean_test.go @@ -3,7 +3,7 @@ // author(s) [red_byte](https://github.com/i-redbyte) // see arithmeticmean.go -package binarymath +package binary import "testing" diff --git a/math/binary/checkisnumberpoweroftwo.go b/math/binary/checkisnumberpoweroftwo.go new file mode 100644 index 000000000..46c459cf8 --- /dev/null +++ b/math/binary/checkisnumberpoweroftwo.go @@ -0,0 +1,36 @@ +// checkisnumberpoweroftwo.go +// description: Is the number a power of two +// details: +// Checks if a number is a power of two- [Power of two](https://en.wikipedia.org/wiki/Power_of_two) +// author(s) [red_byte](https://github.com/i-redbyte) +// see checkisnumberpoweroftwo_test.go + +package binary + +// IsPowerOfTwo This function uses the fact that powers of 2 are represented +// like 10...0 in binary, and numbers one less than the power of 2 +// are represented like 11...1. +// Therefore, using the and function: +// 10...0 +// & 01...1 +// 00...0 -> 0 +// This is also true for 0, which is not a power of 2, for which we +// have to add and extra condition. +func IsPowerOfTwo(x int) bool { + return x > 0 && (x&(x-1)) == 0 +} + +// IsPowerOfTwoLeftShift This function takes advantage of the fact that left shifting a number +// by 1 is equivalent to multiplying by 2. For example, binary 00000001 when shifted by 3 becomes 00001000, +// which in decimal system is 8 or = 2 * 2 * 2 +func IsPowerOfTwoLeftShift(number uint) bool { + if number == 0 { + return false + } + for p := uint(1); p > 0; p = p << 1 { + if number == p { + return true + } + } + return false +} diff --git a/math/binary/checkisnumberpoweroftwo_test.go b/math/binary/checkisnumberpoweroftwo_test.go new file mode 100644 index 000000000..83c0b0083 --- /dev/null +++ b/math/binary/checkisnumberpoweroftwo_test.go @@ -0,0 +1,93 @@ +// checkisnumberpoweroftwo_test.go +// description: Test for Is the number a power of two +// author(s) [red_byte](https://github.com/i-redbyte) +// see checkisnumberpoweroftwo.go + +package binary + +import ( + math2 "github.com/TheAlgorithms/Go/math" + "math" + "testing" +) + +func getTestsForPowerOfTwo() []struct { + name string + a int + missing bool +} { + var tests = []struct { + name string + a int + missing bool + }{ + {"Is 64 a power of 2? - YES", 64, true}, + {"Is 1 a power of 2? - YES", 1, true}, + {"Is 2 a power of 2? - YES", 2, true}, + {"Is 5 a power of 2? - NO", 5, false}, + {"Is 1023 a power of 2? - NO", 1023, false}, + {"Is 1024 a power of 2? - YES", 1024, true}, + {"Is 0 a power of 2? - NO", 0, false}, + {"Is 9223372036854775807 a power of 2? - NO", math.MaxInt64, false}, + {"Is 9223372036854775806 a power of 2? - NO", math.MaxInt64, false}, + {"Is 4611686018427387904 a power of 2? - YES", 4611686018427387904, true}, + } + return tests +} + +func TestIsPowerOfTwo(t *testing.T) { + tests := getTestsForPowerOfTwo() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := IsPowerOfTwo(tv.a) + t.Log(tv.a, " ", result) + if result != tv.missing { + t.Errorf("Wrong result! Expected:%v, returned:%v ", tv.missing, result) + } + }) + } +} + +func TestIsPowerOfTwoLeftShift(t *testing.T) { + tests := getTestsForPowerOfTwo() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := IsPowerOfTwoLeftShift(uint(tv.a)) + t.Log(tv.a, " ", result) + if result != tv.missing { + t.Errorf("Wrong result! Expected:%v, returned:%v ", tv.missing, result) + } + }) + } +} + +func TestIsPowOfTwoUseLog(t *testing.T) { + tests := getTestsForPowerOfTwo() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := math2.IsPowOfTwoUseLog(float64(tv.a)) + t.Log(tv.a, " ", result) + if result != tv.missing { + t.Errorf("Wrong result! Expected:%v, returned:%v ", tv.missing, result) + } + }) + } +} + +func BenchmarkIsPowerOfTwoBinaryMethod(b *testing.B) { + for i := 0; i < b.N; i++ { + IsPowerOfTwo(1024) + } +} + +func BenchmarkIsPowerOfTwoUseCycleAndLeftShift(b *testing.B) { + for i := 0; i < b.N; i++ { + IsPowerOfTwoLeftShift(1024) + } +} + +func BenchmarkIsPowerOfTwoUseLog(b *testing.B) { + for i := 0; i < b.N; i++ { + math2.IsPowOfTwoUseLog(1024) + } +} diff --git a/math/binarymath/xorsearch.go b/math/binary/xorsearch.go similarity index 96% rename from math/binarymath/xorsearch.go rename to math/binary/xorsearch.go index 1d706e8ad..cdd4e09c8 100644 --- a/math/binarymath/xorsearch.go +++ b/math/binary/xorsearch.go @@ -5,7 +5,7 @@ // author(s) [red_byte](https://github.com/i-redbyte) // see xorsearch_test.go -package binarymath +package binary func XorSearchMissingNumber(a []int) int { n := len(a) diff --git a/math/binarymath/xorsearch_test.go b/math/binary/xorsearch_test.go similarity index 98% rename from math/binarymath/xorsearch_test.go rename to math/binary/xorsearch_test.go index 73e5489d9..40bc8a8ef 100644 --- a/math/binarymath/xorsearch_test.go +++ b/math/binary/xorsearch_test.go @@ -2,7 +2,7 @@ // description: Test for Find a missing number in a sequence // author(s) [red_byte](https://github.com/i-redbyte) // see xorsearch.go -package binarymath +package binary import ( "testing" diff --git a/math/checkisnumberpoweroftwo.go b/math/checkisnumberpoweroftwo.go new file mode 100644 index 000000000..48f0fe84a --- /dev/null +++ b/math/checkisnumberpoweroftwo.go @@ -0,0 +1,16 @@ +package math + +import ( + "math" +) + +// IsPowOfTwoUseLog This function checks if a number is a power of two using the logarithm. +// The limiting degree can be from 0 to 63. +// See alternatives in the binary package. +func IsPowOfTwoUseLog(number float64) bool { + if number == 0 || math.Round(number) == math.MaxInt64 { + return false + } + log := math.Log2(number) + return log == math.Round(log) +} diff --git a/math/checkisnumberpoweroftwo_test.go b/math/checkisnumberpoweroftwo_test.go new file mode 100644 index 000000000..834b99d83 --- /dev/null +++ b/math/checkisnumberpoweroftwo_test.go @@ -0,0 +1,54 @@ +// checkisnumberpoweroftwo_test.go +// description: Test for Is the number a power of two +// author(s) [red_byte](https://github.com/i-redbyte) +// see checkisnumberpoweroftwo.go + +package math + +import ( + "math" + "testing" +) + +func getTestsForPowerOfTwo() []struct { + name string + a int + missing bool +} { + var tests = []struct { + name string + a int + missing bool + }{ + {"Is 64 a power of 2? - YES", 64, true}, + {"Is 1 a power of 2? - YES", 1, true}, + {"Is 2 a power of 2? - YES", 2, true}, + {"Is 5 a power of 2? - NO", 5, false}, + {"Is 1023 a power of 2? - NO", 1023, false}, + {"Is 1024 a power of 2? - YES", 1024, true}, + {"Is 0 a power of 2? - NO", 0, false}, + {"Is 9223372036854775807 a power of 2? - NO", math.MaxInt64, false}, + {"Is 9223372036854775806 a power of 2? - NO", math.MaxInt64, false}, + {"Is 4611686018427387904 a power of 2? - YES", 4611686018427387904, true}, + } + return tests +} + +func TestIsPowOfTwoUseLog(t *testing.T) { + tests := getTestsForPowerOfTwo() + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := IsPowOfTwoUseLog(float64(tv.a)) + t.Log(tv.a, " ", result) + if result != tv.missing { + t.Errorf("Wrong result! Expected:%v, returned:%v ", tv.missing, result) + } + }) + } +} + +func BenchmarkIsPowerOfTwoUseLog(b *testing.B) { + for i := 0; i < b.N; i++ { + IsPowOfTwoUseLog(1024) + } +} From 28ede291de091587b1e87975d07b7c35c41835db Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Fri, 1 Oct 2021 07:25:57 +0300 Subject: [PATCH 245/488] feat: generate parentheses (#361) --- .../generateparentheses.go | 34 +++++++++++++++++++ .../generateparentheses_test.go | 21 ++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 strings/generateparentheses/generateparentheses.go create mode 100644 strings/generateparentheses/generateparentheses_test.go diff --git a/strings/generateparentheses/generateparentheses.go b/strings/generateparentheses/generateparentheses.go new file mode 100644 index 000000000..3d466761b --- /dev/null +++ b/strings/generateparentheses/generateparentheses.go @@ -0,0 +1,34 @@ +// generateparenthesesgo +// description: Generate Parentheses +// details: +// Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. +// author(s) [red_byte](https://github.com/i-redbyte) +// see generateparentheses_test.go + +package generateparentheses + +import "strings" + +func GenerateParenthesis(n int) []string { + result := make([]string, 0) + maxLen := 2 * n + var recursiveComputation func(s []string, left int, right int) + recursiveComputation = func(s []string, left int, right int) { + if len(s) == maxLen { + result = append(result, strings.Join(s, "")) + return + } + if left < n { + s = append(s, "(") + recursiveComputation(s, left+1, right) + s = s[:len(s)-1] + } + if right < left { + s = append(s, ")") + recursiveComputation(s, left, right+1) + _ = s[:len(s)-1] + } + } + recursiveComputation(make([]string, 0), 0, 0) + return result +} diff --git a/strings/generateparentheses/generateparentheses_test.go b/strings/generateparentheses/generateparentheses_test.go new file mode 100644 index 000000000..0013b5ba6 --- /dev/null +++ b/strings/generateparentheses/generateparentheses_test.go @@ -0,0 +1,21 @@ +// generateparentheses_test.go +// description: Generate Parentheses +// author(s) [red_byte](https://github.com/i-redbyte) +// see generateparentheses.go + +package generateparentheses + +import "testing" + +func TestGenerateParenthesis(t *testing.T) { + t.Run("GenerateParenthesis", func(t *testing.T) { + result := GenerateParenthesis(3) + t.Log(result) + exp := []string{"((()))", "(()())", "(())()", "()(())", "()()()"} + for i, v := range result { + if v != exp[i] { + t.Errorf("Wrong result! Expected:%s, returned:%s ", result[i], exp[i]) + } + } + }) +} From c72db0460f1fcd181bc6fe6c5f5fdd0d5f1da577 Mon Sep 17 00:00:00 2001 From: FuXiang Shu <6470547+Crazy3lf@users.noreply.github.com> Date: Fri, 1 Oct 2021 12:46:39 +0800 Subject: [PATCH 246/488] Add error value to search and add related benchmark (#364) * feat: added error for when target not found * test: change tests name to match functions name * test: added benchmark tests * test: change benchmark target to variable to test for average performance Co-authored-by: Rak Laptudirm --- search/binary_test.go | 20 ++++++-------------- search/interpolation.go | 10 +++++----- search/interpolation_test.go | 17 ++++++++++++++--- search/linear.go | 6 +++--- search/linear_test.go | 17 ++++++++++++++--- search/testcases.go | 9 +++++++++ 6 files changed, 51 insertions(+), 28 deletions(-) diff --git a/search/binary_test.go b/search/binary_test.go index 748544cf7..ec3e563cc 100644 --- a/search/binary_test.go +++ b/search/binary_test.go @@ -2,7 +2,7 @@ package search import "testing" -func TestBinarySearch(t *testing.T) { +func TestBinary(t *testing.T) { for _, test := range searchTests { actualValue, actualError := Binary(test.data, test.key, 0, len(test.data)-1) if actualValue != test.expected { @@ -14,7 +14,7 @@ func TestBinarySearch(t *testing.T) { } } -func TestIterBinarySearch(t *testing.T) { +func TestBinaryIterative(t *testing.T) { for _, test := range searchTests { actualValue, actualError := BinaryIterative(test.data, test.key, 0, len(test.data)-1) if actualValue != test.expected { @@ -26,26 +26,18 @@ func TestIterBinarySearch(t *testing.T) { } } -func generateBenchmarkTestCase() []int { - var testCase []int - for i := 0; i < 100; i++ { - testCase = append(testCase, i) - } - return testCase -} - -func BenchmarkBinarySearch(b *testing.B) { +func BenchmarkBinary(b *testing.B) { testCase := generateBenchmarkTestCase() b.ResetTimer() // this is important because the generateBenchmarkTestCase() is expensive for i := 0; i < b.N; i++ { - _, _ = Binary(testCase, 10, 0, len(testCase)-1) + _, _ = Binary(testCase, i, 0, len(testCase)-1) } } -func BenchmarkIterBinarySearch(b *testing.B) { +func BenchmarkBinaryIterative(b *testing.B) { testCase := generateBenchmarkTestCase() b.ResetTimer() // this is important because the generateBenchmarkTestCase() is expensive for i := 0; i < b.N; i++ { - _, _ = BinaryIterative(testCase, 10, 0, len(testCase)-1) + _, _ = BinaryIterative(testCase, i, 0, len(testCase)-1) } } diff --git a/search/interpolation.go b/search/interpolation.go index 4bd277877..963e68000 100644 --- a/search/interpolation.go +++ b/search/interpolation.go @@ -9,9 +9,9 @@ package search // Best: O(1) // Example // fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) -func Interpolation(sortedData []int, guess int) int { +func Interpolation(sortedData []int, guess int) (int, error) { if len(sortedData) == 0 { - return -1 + return -1, ErrNotFound } var ( @@ -27,7 +27,7 @@ func Interpolation(sortedData []int, guess int) int { for mid > 0 && sortedData[mid-1] == guess { mid-- } - return mid + return mid, nil } @@ -42,7 +42,7 @@ func Interpolation(sortedData []int, guess int) int { } if guess == lowVal { - return low + return low, nil } - return -1 + return -1, ErrNotFound } diff --git a/search/interpolation_test.go b/search/interpolation_test.go index 848ddf0aa..b59cf1847 100644 --- a/search/interpolation_test.go +++ b/search/interpolation_test.go @@ -4,9 +4,20 @@ import "testing" func TestInterpolation(t *testing.T) { for _, test := range searchTests { - actual := Interpolation(test.data, test.key) - if actual != test.expected { - t.Errorf("test %s failed", test.name) + actualValue, actualError := Interpolation(test.data, test.key) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) + } + } +} + +func BenchmarkInterpolation(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // exclude time taken to generate test case + for i := 0; i < b.N; i++ { + _, _ = Interpolation(testCase, i) } } diff --git a/search/linear.go b/search/linear.go index c442630c6..4cc360793 100644 --- a/search/linear.go +++ b/search/linear.go @@ -1,11 +1,11 @@ package search // Linear Simple linear search algorithm that iterates over all elements of an array in the worst case scenario -func Linear(array []int, query int) int { +func Linear(array []int, query int) (int, error) { for i, item := range array { if item == query { - return i + return i, nil } } - return -1 + return -1, ErrNotFound } diff --git a/search/linear_test.go b/search/linear_test.go index 6f02db8cf..36c1f9b49 100644 --- a/search/linear_test.go +++ b/search/linear_test.go @@ -6,9 +6,20 @@ import ( func TestLinear(t *testing.T) { for _, test := range searchTests { - actual := Linear(test.data, test.key) - if actual != test.expected { - t.Errorf("test %s failed", test.name) + actualValue, actualError := Linear(test.data, test.key) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) + } + } +} + +func BenchmarkLinear(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // exclude time taken to generate test case + for i := 0; i < b.N; i++ { + _, _ = Linear(testCase, i) } } diff --git a/search/testcases.go b/search/testcases.go index 524bb3d3b..eacbaeb4f 100644 --- a/search/testcases.go +++ b/search/testcases.go @@ -28,3 +28,12 @@ var searchTests = []searchTest{ //Empty slice {[]int{}, 2, -1, ErrNotFound, "Empty"}, } + +// This function generate consistent testcase for benchmark test. +func generateBenchmarkTestCase() []int { + var testCase []int + for i := 0; i < 1000; i++ { + testCase = append(testCase, i) + } + return testCase +} From bb8c0b837b838a2d6a067173bd46b379aba67764 Mon Sep 17 00:00:00 2001 From: Vivek Nathani <52988856+viveknathani@users.noreply.github.com> Date: Sat, 2 Oct 2021 17:20:07 +0530 Subject: [PATCH 247/488] Add Edit Distance Problem (#363) Co-authored-by: Rak Laptudirm --- dynamic/editdistance.go | 82 ++++++++++++++++++++++++++++++++++++ dynamic/editdistance_test.go | 35 +++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 dynamic/editdistance.go create mode 100644 dynamic/editdistance_test.go diff --git a/dynamic/editdistance.go b/dynamic/editdistance.go new file mode 100644 index 000000000..fe129da54 --- /dev/null +++ b/dynamic/editdistance.go @@ -0,0 +1,82 @@ +// EDIT DISTANCE PROBLEM +// https://www.geeksforgeeks.org/edit-distance-dp-5/ +// https://leetcode.com/problems/edit-distance/ + +package dynamic + +// Utility function which does what you expect. +func minOfTwo(a int, b int) int { + + if a < b { + return a + } + return b +} + +// Utility function to compute minimum of three numbers using minOfTwo. +func minOfThree(a int, b int, c int) int { + + return minOfTwo(a, minOfTwo(b, c)) +} + +// EditDistanceRecursive is a naive implementation with exponential time complexity. +func EditDistanceRecursive(first string, second string, pointerFirst int, pointerSecond int) int { + + if pointerFirst == 0 { + return pointerSecond + } + + if pointerSecond == 0 { + return pointerFirst + } + + // Characters match, so we recur for the remaining portions + if first[pointerFirst-1] == second[pointerSecond-1] { + return EditDistanceRecursive(first, second, pointerFirst-1, pointerSecond-1) + } + + // We have three choices, all with cost of 1 unit + return 1 + minOfThree(EditDistanceRecursive(first, second, pointerFirst, pointerSecond-1), // Insert + EditDistanceRecursive(first, second, pointerFirst-1, pointerSecond), // Delete + EditDistanceRecursive(first, second, pointerFirst-1, pointerSecond-1)) // Replace +} + +// EditDistanceDP is an optimised implementation which builds on the ideas of the recursive implementation. +// We use dynamic programming to compute the DP table where dp[i][j] denotes the edit distance value +// of first[0..i-1] and second[0..j-1]. Time complexity is O(m * n) where m and n are lengths of the strings, +// first and second respectively. +func EditDistanceDP(first string, second string) int { + + m := len(first) + n := len(second) + + // Create the DP table + dp := make([][]int, m+1) + for i := 0; i <= m; i++ { + dp[i] = make([]int, n+1) + } + + for i := 0; i <= m; i++ { + for j := 0; j <= n; j++ { + + if i == 0 { + dp[i][j] = j + continue + } + + if j == 0 { + dp[i][j] = i + continue + } + + if first[i-1] == second[j-1] { + dp[i][j] = dp[i-1][j-1] + continue + } + + dp[i][j] = 1 + minOfThree(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + } + } + + return dp[m][n] +} diff --git a/dynamic/editdistance_test.go b/dynamic/editdistance_test.go new file mode 100644 index 000000000..188591413 --- /dev/null +++ b/dynamic/editdistance_test.go @@ -0,0 +1,35 @@ +package dynamic + +import ( + "fmt" + "testing" +) + +func Test_EditDistance(t *testing.T) { + + var testCases = []struct { + first string + second string + expected int + }{ + {"", "", 0}, + {"horse", "ros", 3}, + {"intention", "execution", 5}, + {"abcdxabcde", "abcdeabcdx", 2}, + {"sunday", "saturday", 3}, + {"food", "money", 4}, + {"voldemort", "dumbledore", 7}, + } + + for i := range testCases { + + t.Run(fmt.Sprintf("Word 1: %s, Word 2: %s", testCases[i].first, testCases[i].second), func(t *testing.T) { + + computed := EditDistanceDP(testCases[i].first, testCases[i].second) + + if computed != testCases[i].expected { + t.Errorf("Word 1: %s, Word 2: %s, Expected: %d, Computed: %d", testCases[i].first, testCases[i].second, testCases[i].expected, computed) + } + }) + } +} From 8ba0724373c17a80f23bd1b30430156d8f22809a Mon Sep 17 00:00:00 2001 From: Mercurio <32540679+SignorMercurio@users.noreply.github.com> Date: Tue, 5 Oct 2021 18:14:05 +0100 Subject: [PATCH 248/488] Adjust instructions in CONTRIBUTING.md (#369) --- CONTRIBUTING.md | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c3abb3977..ea44b249f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -157,27 +157,48 @@ Common prefixes: - docs: Documentation changes - test: Correct existing tests or add new ones -### Pull Requests +### For New Gophers -- Check out our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.md - ) +#### Installing Go -#### Building Locally +- Installation (only needs to be installed once.) + - Mac (using home-brew): `brew install go` + - Windows (MSYS2 64-bit): `choco install golang` [Chocolatey Package Manager](https://chocolatey.org/) + - Linux (Debian): `sudo apt-get install golang` + - Manual Installation: [Downloads - The Go Programming Language](https://golang.org/dl/) +- Running (all platforms): `go run filexyz.go` + +> Note: New packages should not be `main`, and never implement `main` functions for any package. + +#### Code formatter +To format your code, you can use the gofmt tool directly: + +```bash +gofmt -w filexyz.go +``` + +Or you can use the "go fmt" command: -Before submitting a pull request, -build the code locally or using the convenient [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/Go) service. +```bash +go fmt path/to/your/package +``` + +#### Building + +To build you code locally, simply run: ```bash go build . ``` -#### Code Formatter +### Pull Requests -- Installation (only needs to be installed once.) - - Mac (using home-brew): `brew install go` - - Windows (MSYS2 64-bit): `choco install golang` [Chocolatey Package Manager](https://chocolatey.org/) - - Linux (Debian): `sudo apt-get install golang` -- Running (all platforms): `go run main.go` or `go build main.go` +- Check out our [pull request template](https://github.com/TheAlgorithms/Go/blob/master/.github/PULL_REQUEST_TEMPLATE/pull_request.md + ) + +#### Building Locally + +Before submitting a pull request, [build the code locally](#building) or using the convenient [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/Go) service. #### GitHub Actions From 9d18802c042c0769b0b154c4aa18fefa00e2d117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Vald=C3=A9s?= Date: Tue, 5 Oct 2021 10:24:46 -0700 Subject: [PATCH 249/488] Add math improvements (#366) --- math/max/{bitwiseMax.go => bitwisemax.go} | 0 math/max/{bitwiseMax_test.go => bitwisemax_test.go} | 0 math/moserdebruijnsequence/sequence.go | 6 +----- math/pi/montecarlopi.go | 2 +- 4 files changed, 2 insertions(+), 6 deletions(-) rename math/max/{bitwiseMax.go => bitwisemax.go} (100%) rename math/max/{bitwiseMax_test.go => bitwisemax_test.go} (100%) diff --git a/math/max/bitwiseMax.go b/math/max/bitwisemax.go similarity index 100% rename from math/max/bitwiseMax.go rename to math/max/bitwisemax.go diff --git a/math/max/bitwiseMax_test.go b/math/max/bitwisemax_test.go similarity index 100% rename from math/max/bitwiseMax_test.go rename to math/max/bitwisemax_test.go diff --git a/math/moserdebruijnsequence/sequence.go b/math/moserdebruijnsequence/sequence.go index 1c02201b3..dd846b5a1 100644 --- a/math/moserdebruijnsequence/sequence.go +++ b/math/moserdebruijnsequence/sequence.go @@ -26,9 +26,5 @@ func generateNthTerm(num int) int { } //number is odd - if num%2 != 0 { - return 4*generateNthTerm(num/2) + 1 - } - - return 0 + return 4*generateNthTerm(num/2) + 1 } diff --git a/math/pi/montecarlopi.go b/math/pi/montecarlopi.go index 53f39d943..d31b20a45 100644 --- a/math/pi/montecarlopi.go +++ b/math/pi/montecarlopi.go @@ -22,6 +22,6 @@ func MonteCarloPi(randomPoints int) float64 { inside += 1 } } - pi := float64(inside) / float64(randomPoints) * float64(4) + pi := float64(inside) / float64(randomPoints) * 4 return pi } From 2655a05c10f8184beb3d8019427dbeb88c8c76de Mon Sep 17 00:00:00 2001 From: Vivek Nathani <52988856+viveknathani@users.noreply.github.com> Date: Tue, 5 Oct 2021 23:19:41 +0530 Subject: [PATCH 250/488] docs: fix invalid path to file (#372) Co-authored-by: Andrii Siriak --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b596f14b..d14ff4d37 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Lcm](./math/lcm/lcm.go) * [Max](./math/max/max.go) * [Modular](./math/modular) - * [Exponentiation](./math/max/max.go) + * [Exponentiation](./math/modular/exponentiation.go) * [Inverse](./math/modular/inverse.go) * [Moser-de Bruijn sequence](./math/moserdebruijnsequence/sequence.go) * [Permutation](./math/permutation/heaps.go) From 1e5c5286c7498dffb49024797e7d2346e387153a Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Wed, 6 Oct 2021 09:29:43 +0300 Subject: [PATCH 251/488] feat: reverse bits (#371) --- math/binary/reversebits.go | 23 ++++++++++++++++++++ math/binary/reversebits_test.go | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 math/binary/reversebits.go create mode 100644 math/binary/reversebits_test.go diff --git a/math/binary/reversebits.go b/math/binary/reversebits.go new file mode 100644 index 000000000..f4367cc94 --- /dev/null +++ b/math/binary/reversebits.go @@ -0,0 +1,23 @@ +// reversebits.go +// description: Reverse bits +// details: +// Reverse the bits of an integer number +// author(s) [red_byte](https://github.com/i-redbyte) +// see reversebits_test.go + +package binary + +// ReverseBits This function initialized the result by 0 (all bits 0) and process the given number starting +// from its least significant bit. If the current bit is 1, set the corresponding most significant bit in the result +// and finally move on to the next bit in the input number. +// Repeat this till all its bits are processed. +func ReverseBits(number uint) uint { + result := uint(0) + intSize := 31 + for number != 0 { + result += (number & 1) << intSize + number = number >> 1 + intSize -= 1 + } + return result +} diff --git a/math/binary/reversebits_test.go b/math/binary/reversebits_test.go new file mode 100644 index 000000000..c53d3600a --- /dev/null +++ b/math/binary/reversebits_test.go @@ -0,0 +1,37 @@ +// reversebits_test.go +// description: Reverse bits +// author(s) [red_byte](https://github.com/i-redbyte) +// see reversebits.go + +package binary + +import "testing" + +func TestReverseBits(t *testing.T) { + var tests = []struct { + name string + number uint + result uint + }{ + {"43261596 (00000010100101000001111010011100) to 964176192 (00111001011110000010100101000000)", 43261596, 964176192}, + {"3758096384 (11100000000000000000000000000000) to 7 (00000000000000000000000000000111)", 3758096384, 7}, + {"7 (00000000000000000000000000000111) to 3758096384 (11100000000000000000000000000000)", 7, 3758096384}, + {"2684354560 (10100000000000000000000000000000) to 5 (00000000000000000000000000000101)", 2684354560, 5}, + {"2684354561 (10100000000000000000000000000001) to 5 (10000000000000000000000000000101)", 2684354561, 2147483653}, + } + for _, tv := range tests { + t.Run(tv.name, func(t *testing.T) { + result := ReverseBits(tv.number) + t.Log(result) + if result != tv.result { + t.Errorf("Wrong result! Expected:%d, returned:%d ", tv.result, result) + } + }) + } +} + +func BenchmarkReverseBits(b *testing.B) { + for i := 0; i < b.N; i++ { + ReverseBits(2684354560) + } +} From e14ac15717b04ca80fa6c5fc400c3d69a75fb68c Mon Sep 17 00:00:00 2001 From: Shreyas Sable <43932047+KILLinefficiency@users.noreply.github.com> Date: Wed, 6 Oct 2021 15:15:10 +0530 Subject: [PATCH 252/488] chore: merge Added Straight Line Algorithms in the math directory. (#362) * added dir and tests for straight lines * added straight lines to README.md * formatted the straight lines code and tests with gofmt * changed the straight line code and file names * implemented the Line struct in code in ./math/straightlines directory and changed the test likewise * fixed the tests and changed the dir name in ./math/straightlines * exported the required stuff in ./math/straightlines/ * exported the functions in math/straightlines * renamed straightlines to geometry in the math directory * deleted previous straightlines files * updated README.md Co-authored-by: Rak Laptudirm --- README.md | 1 + math/geometry/straightlines.go | 54 ++++++++++++++++++++++ math/geometry/straightlines_test.go | 70 +++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 math/geometry/straightlines.go create mode 100644 math/geometry/straightlines_test.go diff --git a/README.md b/README.md index d14ff4d37..0f4749af0 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Sieve](./math/prime/sieve.go) * [Pythagoras](./math/pythagoras/pythagoras.go) * [Sieve](./math/prime/sieve.go) +* [Straight Lines](./math/geometry/straightlines.go) ### Other * [Max Subarray Sum](./other/maxsubarraysum/maxsubarraysum.go) diff --git a/math/geometry/straightlines.go b/math/geometry/straightlines.go new file mode 100644 index 000000000..5595069d4 --- /dev/null +++ b/math/geometry/straightlines.go @@ -0,0 +1,54 @@ +package geometry + +import ( + "math" +) + +// Defines a point with x and y coordinates. +type Point struct { + X, Y float64 +} + +type Line struct { + P1, P2 Point +} + +// Calculates the shortest distance between two points. +func Distance(a, b *Point) float64 { + return math.Sqrt(math.Pow(a.X-b.X, 2) + math.Pow(a.Y-b.Y, 2)) +} + +// Calcualtes the Point that divides a line in specific ratio. +// DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. +func Section(p1, p2 *Point, r float64) Point { + var point Point + point.X = (r*p2.X + p1.X) / (r + 1) + point.Y = (r*p2.Y + p1.Y) / (r + 1) + return point +} + +// Calculates the slope (gradient) of a line. +func Slope(l *Line) float64 { + return (l.P2.Y - l.P1.Y) / (l.P2.X - l.P1.X) +} + +// Calculates the Y-Intercept of a line from a specific Point. +func Intercept(p *Point, slope float64) float64 { + return p.Y - (slope * p.X) +} + +// Checks if two lines are parallel or not. +func IsParallel(l1, l2 *Line) bool { + return Slope(l1) == Slope(l2) +} + +// Checks if two lines are perpendicular or not. +func IsPerpendicular(l1, l2 *Line) bool { + return Slope(l1)*Slope(l2) == -1 +} + +// Calculates the distance of a given Point from a given line. +// The slice should contain the coefficiet of x, the coefficient of y and the constant in the respective order. +func PointDistance(p *Point, equation [3]float64) float64 { + return math.Abs(equation[0]*p.X+equation[1]*p.Y+equation[2]) / math.Sqrt(math.Pow(equation[0], 2)+math.Pow(equation[1], 2)) +} diff --git a/math/geometry/straightlines_test.go b/math/geometry/straightlines_test.go new file mode 100644 index 000000000..262bc3147 --- /dev/null +++ b/math/geometry/straightlines_test.go @@ -0,0 +1,70 @@ +package geometry + +import ( + "testing" +) + +func TestDistance(t *testing.T) { + p1 := Point{0, 0} + p2 := Point{3, 4} + var wantedDistance float64 = 5 + var calculatedDistance float64 = Distance(&p1, &p2) + if calculatedDistance != wantedDistance { + t.Fatalf("Failed to calculate Distance.") + } +} + +func TestSection(t *testing.T) { + p1 := Point{1, 0} + p2 := Point{5, 0} + wantedPoint := Point{3, 0} + calculatedPoint := Section(&p1, &p2, 1) + if calculatedPoint != wantedPoint { + t.Fatalf("Failed to calculate Section.") + } +} + +func TestSlope(t *testing.T) { + line := Line{P1: Point{1, 2}, P2: Point{2, 4}} + var wantedSlope float64 = 2 + var calculatedSlope float64 = Slope(&line) + if calculatedSlope != wantedSlope { + t.Fatalf("Failed to calculate Slope.") + } +} + +func TestIntercept(t *testing.T) { + p := Point{0, 3} + var slope float64 = -5 + var wantedIntercept float64 = 3 + var calculatedIntercept float64 = Intercept(&p, slope) + if calculatedIntercept != wantedIntercept { + t.Fatalf("Failed to calculate Intercept.") + } +} + +func TestIsParallel(t *testing.T) { + l1 := Line{P1: Point{1, 2}, P2: Point{2, 4}} + l2 := Line{P1: Point{25, 50}, P2: Point{50, 100}} + if !IsParallel(&l1, &l2) { + t.Fatalf("Failed to check if Parallel.") + } +} + +func TestIsPerpendicular(t *testing.T) { + l1 := Line{P1: Point{1, 2}, P2: Point{2, 4}} + l2 := Line{P1: Point{2, 2}, P2: Point{4, 1}} + if !IsPerpendicular(&l1, &l2) { + t.Fatalf("Failed to check if Perpendicular.") + } +} + +func TestPointDistance(t *testing.T) { + p := Point{1, 1} + equation := [3]float64{4, 3, 1} + var wantedDistance float64 = 1.6 + var calculatedDistance float64 = PointDistance(&p, equation) + if calculatedDistance != wantedDistance { + t.Fatalf("Failed to calculate Point Distance.") + } +} From ace84abac9b9561c2f7a7e62c55cee12ec81bc98 Mon Sep 17 00:00:00 2001 From: Calebe Oliveira <30943380+calebeof@users.noreply.github.com> Date: Thu, 7 Oct 2021 14:24:35 -0300 Subject: [PATCH 253/488] test: add TestFloydWarshall (#373) --- graph/floydwarshall.go | 50 ++++++++-------- graph/floydwarshall_test.go | 110 ++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 28 deletions(-) create mode 100644 graph/floydwarshall_test.go diff --git a/graph/floydwarshall.go b/graph/floydwarshall.go index a04b60ef8..33b97a2c1 100644 --- a/graph/floydwarshall.go +++ b/graph/floydwarshall.go @@ -3,35 +3,44 @@ package graph -// Matrix Defining matrix to use 2d array easier -type Matrix [][]float64 +import "math" + +// WeightedGraph defining matrix to use 2d array easier +type WeightedGraph [][]float64 // Defining maximum value. If two vertices share this value, it means they are not connected -// var maxValue = math.Inf(1) // This is not being used in the code?? +var Inf = math.Inf(1) // FloydWarshall Returns all pair's shortest path using Floyd Warshall algorithm -func FloydWarshall(graph Matrix) Matrix { - // If graph is empty or width != height, returns nil +func FloydWarshall(graph WeightedGraph) WeightedGraph { + // If graph is empty, returns nil if len(graph) == 0 || len(graph) != len(graph[0]) { return nil } - numVertecies := len(graph) + for i := 0; i < len(graph); i++ { + //If graph matrix width is different than the height, returns nil + if len(graph[i]) != len(graph) { + return nil + } + } + + numVertices := len(graph) // Initializing result matrix and filling it up with same values as given graph - result := make(Matrix, numVertecies) + result := make(WeightedGraph, numVertices) - for i := 0; i < numVertecies; i++ { - result[i] = make([]float64, numVertecies) - for j := 0; j < numVertecies; j++ { + for i := 0; i < numVertices; i++ { + result[i] = make([]float64, numVertices) + for j := 0; j < numVertices; j++ { result[i][j] = graph[i][j] } } // Running over the result matrix and following the algorithm - for k := 0; k < numVertecies; k++ { - for i := 0; i < numVertecies; i++ { - for j := 0; j < numVertecies; j++ { + for k := 0; k < numVertices; k++ { + for i := 0; i < numVertices; i++ { + for j := 0; j < numVertices; j++ { // If there is a less costly path from i to j node, remembering it if result[i][j] > result[i][k]+result[k][j] { result[i][j] = result[i][k] + result[k][j] @@ -42,18 +51,3 @@ func FloydWarshall(graph Matrix) Matrix { return result } - -// func main() { -// var graph Matrix -// graph = Matrix{{0, maxValue, -2, maxValue}, -// {4, 0, 3, maxValue}, -// {maxValue, maxValue, 0, 2}, -// {maxValue, -1, maxValue, 0}} - -// result := FloydWarshall(graph) - -// //Print result -// for i := 0; i < len(result); i++ { -// fmt.Printf("%4g\n", result[i]) -// } -// } diff --git a/graph/floydwarshall_test.go b/graph/floydwarshall_test.go new file mode 100644 index 000000000..17d82930e --- /dev/null +++ b/graph/floydwarshall_test.go @@ -0,0 +1,110 @@ +package graph + +import ( + "math" + "testing" +) + +const float64EqualityThreshold = 1e-9 + +//almostEqual subtracts two float64 variables and returns true if they differ less then float64EqualityThreshold +//reference: https://stackoverflow.com/a/47969546 +func almostEqual(a, b float64) bool { + return math.Abs(a-b) <= float64EqualityThreshold +} + +//IsAlmostEqualTo verifies if two WeightedGraphs can be considered almost equal +func (a *WeightedGraph) IsAlmostEqualTo(b WeightedGraph) bool { + if len(*a) != len(b) { + return false + } + + for i := range *a { + if len((*a)[i]) != len(b[i]) { + return false + } + + for j := range (*a)[i] { + if (*a)[i][j] == Inf && b[i][j] == Inf { + continue + } + + if !almostEqual((*a)[i][j], b[i][j]) { + return false + } + } + } + + return true +} + +func TestFloydWarshall(t *testing.T) { + var floydWarshallTestData = []struct { + description string + graph [][]float64 + expected [][]float64 + }{ + { + description: "test empty graph", + graph: nil, + expected: nil, + }, + { + description: "test graph with wrong dimensions", + graph: [][]float64{ + {1, 2}, + {Inf}, + }, + expected: nil, + }, + { + description: "test graph with no edges", + graph: [][]float64{ + {Inf, Inf}, + {Inf, Inf}, + }, + expected: [][]float64{ + {Inf, Inf}, + {Inf, Inf}, + }, + }, + { + description: "test graph with only negative edges", + graph: [][]float64{ + {-3, -2}, + {-3, -2}, + }, + expected: [][]float64{ + {-17, -25}, + {-26, -34}, + }, + }, + { + description: "test graph with 5 vertices and self-loops", + graph: [][]float64{ + {1, 2, Inf, Inf, Inf}, + {Inf, Inf, 3, -4, Inf}, + {Inf, Inf, Inf, Inf, 5}, + {1, Inf, Inf, Inf, Inf}, + {Inf, Inf, Inf, 2, Inf}, + }, + expected: [][]float64{ + {-1, 1, 4, -3, 8}, + {-3, -1, 2, -5, 6}, + {7, 9, 12, 5, 5}, + {0, 2, 5, -2, 9}, + {2, 4, 7, 0, 9}, + }, + }, + } + for _, test := range floydWarshallTestData { + t.Run(test.description, func(t *testing.T) { + result := FloydWarshall(test.graph) + + if !result.IsAlmostEqualTo(test.expected) { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expected result:%f\nFound: %f", test.expected, result) + } + }) + } +} From af4ca77d9fe09ceedf330bd8ca0703864a74a5cb Mon Sep 17 00:00:00 2001 From: Vivek Nathani <52988856+viveknathani@users.noreply.github.com> Date: Thu, 7 Oct 2021 23:24:01 +0530 Subject: [PATCH 254/488] feat: kruskal's algorithm using DSU (#374) --- graph/kruskal.go | 113 +++++++++++++++++++++++++++++ graph/kruskal_test.go | 162 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 graph/kruskal.go create mode 100644 graph/kruskal_test.go diff --git a/graph/kruskal.go b/graph/kruskal.go new file mode 100644 index 000000000..c6f094020 --- /dev/null +++ b/graph/kruskal.go @@ -0,0 +1,113 @@ +// KRUSKAL'S ALGORITHM +// https://cp-algorithms.com/data_structures/disjoint_set_union.html +// https://cp-algorithms.com/graph/mst_kruskal_with_dsu.html + +package graph + +import ( + "sort" +) + +type Vertex int + +// Edge describes the edge of a weighted graph +type Edge struct { + Start Vertex + End Vertex + Weight int +} + +// DisjointSetUnionElement describes what an element of DSU looks like +type DisjointSetUnionElement struct { + Parent Vertex + Rank int +} + +// DisjointSetUnion is a data structure that treats its elements as separate sets +// and provides fast operations for set creation, merging sets, and finding the parent +// of the given element of a set. +type DisjointSetUnion []DisjointSetUnionElement + +// NewDSU will return an initialised DSU using the value of n +// which will be treated as the number of elements out of which +// the DSU is being made +func NewDSU(n int) *DisjointSetUnion { + + dsu := DisjointSetUnion(make([]DisjointSetUnionElement, n)) + return &dsu +} + +// MakeSet will create a set in the DSU for the given node +func (dsu DisjointSetUnion) MakeSet(node Vertex) { + + dsu[node].Parent = node + dsu[node].Rank = 0 +} + +// FindSetRepresentative will return the parent element of the set the given node +// belongs to. Since every single element in the path from node to parent +// has the same parent, we store the parent value for each element in the +// path. This reduces consequent function calls and helps in going from O(n) +// to O(log n). This is known as path compression technique. +func (dsu DisjointSetUnion) FindSetRepresentative(node Vertex) Vertex { + + if node == dsu[node].Parent { + return node + } + + dsu[node].Parent = dsu.FindSetRepresentative(dsu[node].Parent) + return dsu[node].Parent +} + +// unionSets will merge two given sets. The naive implementation of this +// always combines the secondNode's tree with the firstNode's tree. This can lead +// to creation of trees of length O(n) so we optimize by attaching the node with +// smaller rank to the node with bigger rank. Rank represents the upper bound depth of the tree. +func (dsu DisjointSetUnion) UnionSets(firstNode Vertex, secondNode Vertex) { + + firstNode = dsu.FindSetRepresentative(firstNode) + secondNode = dsu.FindSetRepresentative(secondNode) + + if firstNode != secondNode { + + if dsu[firstNode].Rank < dsu[secondNode].Rank { + firstNode, secondNode = secondNode, firstNode + } + dsu[secondNode].Parent = firstNode + + if dsu[firstNode].Rank == dsu[secondNode].Rank { + dsu[firstNode].Rank++ + } + } +} + +// KruskalMST will return a minimum spanning tree along with its total cost +// to using Kruskal's algorithm. Time complexity is O(m * log (n)) where m is +// the number of edges in the graph and n is number of nodes in it. +func KruskalMST(n int, edges []Edge) ([]Edge, int) { + + var mst []Edge // The resultant minimum spanning tree + var cost int = 0 + + dsu := NewDSU(n) + + for i := 0; i < n; i++ { + dsu.MakeSet(Vertex(i)) + } + + sort.SliceStable(edges, func(i, j int) bool { + return edges[i].Weight < edges[j].Weight + }) + + for _, edge := range edges { + + if dsu.FindSetRepresentative(edge.Start) != dsu.FindSetRepresentative(edge.End) { + + mst = append(mst, edge) + cost += edge.Weight + dsu.UnionSets(edge.Start, edge.End) + } + } + + return mst, cost +} diff --git a/graph/kruskal_test.go b/graph/kruskal_test.go new file mode 100644 index 000000000..86f062d53 --- /dev/null +++ b/graph/kruskal_test.go @@ -0,0 +1,162 @@ +package graph + +import ( + "fmt" + "testing" +) + +func Test_KruskalMST(t *testing.T) { + + var testCases = []struct { + n int + graph []Edge + cost int + }{ + { + n: 5, + graph: []Edge{ + { + Start: 0, + End: 1, + Weight: 4, + }, + { + Start: 0, + End: 2, + Weight: 13, + }, + { + Start: 0, + End: 3, + Weight: 7, + }, + { + Start: 0, + End: 4, + Weight: 7, + }, + { + Start: 1, + End: 2, + Weight: 9, + }, + { + Start: 1, + End: 3, + Weight: 3, + }, + { + Start: 1, + End: 4, + Weight: 7, + }, + { + Start: 2, + End: 3, + Weight: 10, + }, + { + Start: 2, + End: 4, + Weight: 14, + }, + { + Start: 3, + End: 4, + Weight: 4, + }, + }, + cost: 20, + }, + { + n: 3, + graph: []Edge{ + { + Start: 0, + End: 1, + Weight: 12, + }, + { + Start: 0, + End: 2, + Weight: 18, + }, + { + Start: 1, + End: 2, + Weight: 6, + }, + }, + cost: 18, + }, + { + n: 4, + graph: []Edge{ + { + Start: 0, + End: 1, + Weight: 2, + }, + { + Start: 0, + End: 2, + Weight: 1, + }, + { + Start: 0, + End: 3, + Weight: 2, + }, + { + Start: 1, + End: 2, + Weight: 1, + }, + { + Start: 1, + End: 3, + Weight: 2, + }, + { + Start: 2, + End: 3, + Weight: 3, + }, + }, + cost: 4, + }, + { + n: 2, + graph: []Edge{ + { + Start: 0, + End: 1, + Weight: 4000000, + }, + }, + cost: 4000000, + }, + { + n: 1, + graph: []Edge{ + { + Start: 0, + End: 0, + Weight: 0, + }, + }, + cost: 0, + }, + } + + for i := range testCases { + + t.Run(fmt.Sprintf("Test Case %d", i), func(t *testing.T) { + + _, computed := KruskalMST(testCases[i].n, testCases[i].graph) + if computed != testCases[i].cost { + t.Errorf("Test Case %d, Expected: %d, Computed: %d", i, testCases[i].cost, computed) + } + }) + } +} From 5a6407aea4bfdea80313fb14111edff00e92eca2 Mon Sep 17 00:00:00 2001 From: Ayoub Chegraoui Date: Sun, 10 Oct 2021 18:35:39 +0100 Subject: [PATCH 255/488] chore: merge feat: add Euler Totient function Phi (#377) --- math/eulertotient.go | 23 ++++++++++++++++++++ math/eulertotient_test.go | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 math/eulertotient.go create mode 100644 math/eulertotient_test.go diff --git a/math/eulertotient.go b/math/eulertotient.go new file mode 100644 index 000000000..6e0d5d23b --- /dev/null +++ b/math/eulertotient.go @@ -0,0 +1,23 @@ +package math + +// Phi is the Euler totient function. +// This function computes the number of numbers less then n that are coprime with n. +func Phi(n int64) int64 { + result := n + for i := int64(2); i*i <= n; i += 1 { + if n%i == 0 { + for { + if n%i != 0 { + break + } + n /= i + } + result -= result / i + } + } + + if n > 1 { + result -= result / n + } + return result +} diff --git a/math/eulertotient_test.go b/math/eulertotient_test.go new file mode 100644 index 000000000..5a7d7e21b --- /dev/null +++ b/math/eulertotient_test.go @@ -0,0 +1,44 @@ +package math + +import ( + "testing" +) + +func getTestsForPhi() []struct { + n int64 + expected int64 +} { + var tests = []struct { + n int64 + expected int64 + }{ + {4, 2}, + {5, 4}, + {7, 6}, + {10, 4}, + {999, 648}, + {1000, 400}, + {1000000, 400000}, + {999999, 466560}, + {999999999999878, 473684210526240}, + } + return tests +} + +func TestPhi(t *testing.T) { + + tests := getTestsForPhi() + for _, test := range tests { + result := Phi(test.n) + t.Log(test.n, " ", result) + if result != test.expected { + t.Errorf("Wrong result! Expected:%v, returned:%v ", test.expected, result) + } + } +} + +func BenchmarkPhi(b *testing.B) { + for i := 0; i < b.N; i++ { + Phi(65536) + } +} From 9b064308cff7c79f9f7208d89044e59e066582ed Mon Sep 17 00:00:00 2001 From: Abel Date: Sun, 17 Oct 2021 02:19:19 +0800 Subject: [PATCH 256/488] Fix typos in strings/genetic/genetic.go (#382) --- strings/genetic/genetic.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/strings/genetic/genetic.go b/strings/genetic/genetic.go index 12afb7c2d..14aa8fa82 100644 --- a/strings/genetic/genetic.go +++ b/strings/genetic/genetic.go @@ -15,13 +15,13 @@ import ( ) // Population item represent a single step in the evolution process. -// One can think of ppopulation item as a single species. +// One can think of population item as a single species. // Key stands for the actual data entity of the species, which is a string // in current implementation. Key can be interpreted as species DNA. // Value shows how close this species to the desired target, where 1 means, -// that species DNA equals to the targeted one, 0 for no mathings in the DNA. +// that species DNA equals to the targeted one, 0 for no matchings in the DNA. // -// **Note** In the current implementation species DNA lenght is suppose to be +// **Note** In the current implementation species DNA length is suppose to be // equal to the target length for algorithm to work. type PopulationItem struct { Key string From 3e747fc12f102c9c87930ba82afb3272dc66b191 Mon Sep 17 00:00:00 2001 From: Ayoub Chegraoui Date: Sat, 16 Oct 2021 19:30:04 +0100 Subject: [PATCH 257/488] fix: rename binarytree to binarysearchtree (#385) --- .../btree.go => binarysearchtree/bstree.go} | 15 ++++--- .../bstree_test.go} | 44 +++++++++---------- .../{binarytree => binarysearchtree}/node.go | 0 3 files changed, 31 insertions(+), 28 deletions(-) rename structure/{binarytree/btree.go => binarysearchtree/bstree.go} (87%) rename structure/{binarytree/btree_test.go => binarysearchtree/bstree_test.go} (88%) rename structure/{binarytree => binarysearchtree}/node.go (100%) diff --git a/structure/binarytree/btree.go b/structure/binarysearchtree/bstree.go similarity index 87% rename from structure/binarytree/btree.go rename to structure/binarysearchtree/bstree.go index e3d128dee..0e0b511d9 100644 --- a/structure/binarytree/btree.go +++ b/structure/binarysearchtree/bstree.go @@ -1,11 +1,11 @@ package binarytree -// BTree Returns a binary tree structure which contains only a root Node -type BTree struct { +// BSTree Returns a binary search tree structure which contains only a root Node +type BSTree struct { Root *Node } -// calculateDepth helper function for BTree's depth() +// calculateDepth helper function for BSTree's depth() func calculateDepth(n *Node, depth int) int { if n == nil { return depth @@ -13,7 +13,7 @@ func calculateDepth(n *Node, depth int) int { return Max(calculateDepth(n.left, depth+1), calculateDepth(n.right, depth+1)) } -// Insert a value in the BTree +// Insert a value in the BSTree func Insert(root *Node, val int) *Node { if root == nil { return NewNode(val) @@ -26,8 +26,8 @@ func Insert(root *Node, val int) *Node { return root } -// Depth returns the calculated depth of a binary tree -func (t *BTree) Depth() int { +// Depth returns the calculated depth of a binary saerch tree +func (t *BSTree) Depth() int { return calculateDepth(t.Root, 0) } @@ -75,6 +75,7 @@ func inOrderRecursive(n *Node, traversal *[]int) { } } +// Travers the tree in the following order left --> root --> right func InOrder(root *Node) []int { traversal := make([]int, 0) inOrderRecursive(root, &traversal) @@ -91,6 +92,7 @@ func preOrderRecursive(n *Node, traversal *[]int) { preOrderRecursive(n.right, traversal) } +// Travers the tree in the following order root --> left --> right func PreOrder(root *Node) []int { traversal := make([]int, 0) preOrderRecursive(root, &traversal) @@ -107,6 +109,7 @@ func postOrderRecursive(n *Node, traversal *[]int) { *traversal = append(*traversal, n.val) } +// Travers the tree in the following order left --> right --> root func PostOrder(root *Node) []int { traversal := make([]int, 0) postOrderRecursive(root, &traversal) diff --git a/structure/binarytree/btree_test.go b/structure/binarysearchtree/bstree_test.go similarity index 88% rename from structure/binarytree/btree_test.go rename to structure/binarysearchtree/bstree_test.go index 0a24850f0..f813063c6 100644 --- a/structure/binarytree/btree_test.go +++ b/structure/binarysearchtree/bstree_test.go @@ -6,11 +6,11 @@ import ( ) func TestInsert(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -27,18 +27,18 @@ func TestInsert(t *testing.T) { t.Errorf("right child should have value = 100") } - if BTree.Depth() != 2 { + if BSTree.Depth() != 2 { t.Errorf("tree should have depth = 1") } } func TestDelete(t *testing.T) { t.Run("Delete a node with no child", func(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -57,17 +57,17 @@ func TestDelete(t *testing.T) { t.Errorf("right child should have value = nil") } - if BTree.Depth() != 2 { + if BSTree.Depth() != 2 { t.Errorf("Depth should have value = 2") } }) t.Run("Delete a node with one child", func(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -87,17 +87,17 @@ func TestDelete(t *testing.T) { t.Errorf("left child should have value = 70") } - if BTree.Depth() != 2 { + if BSTree.Depth() != 2 { t.Errorf("Depth should have value = 2") } }) t.Run("Delete a node with two children", func(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -118,18 +118,18 @@ func TestDelete(t *testing.T) { t.Errorf("right child should have value = 100") } - if BTree.Depth() != 3 { + if BSTree.Depth() != 3 { t.Errorf("Depth should have value = 3") } }) } func TestInOrder(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -147,11 +147,11 @@ func TestInOrder(t *testing.T) { } func TestPreOrder(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -169,11 +169,11 @@ func TestPreOrder(t *testing.T) { } func TestPostOrder(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -191,11 +191,11 @@ func TestPostOrder(t *testing.T) { } func TestLevelOrder(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) @@ -213,11 +213,11 @@ func TestLevelOrder(t *testing.T) { } func TestAccessNodesByLayer(t *testing.T) { - BTree := BTree{ + BSTree := BSTree{ Root: NewNode(90), } - root := BTree.Root + root := BSTree.Root Insert(root, 80) Insert(root, 100) diff --git a/structure/binarytree/node.go b/structure/binarysearchtree/node.go similarity index 100% rename from structure/binarytree/node.go rename to structure/binarysearchtree/node.go From 654fcb53be6dd68a6aea8d837cff8418870ff4d6 Mon Sep 17 00:00:00 2001 From: Metta Ong Date: Sun, 17 Oct 2021 02:35:50 +0800 Subject: [PATCH 258/488] add boyer moore string search (#388) --- strings/search/boyermoore.go | 57 +++++++++++++++++++ strings/search/{patternsearch.go => naive.go} | 12 +--- strings/search/patternsearch_test.go | 23 ++++++++ 3 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 strings/search/boyermoore.go rename strings/search/{patternsearch.go => naive.go} (59%) diff --git a/strings/search/boyermoore.go b/strings/search/boyermoore.go new file mode 100644 index 000000000..dd8bb6eb2 --- /dev/null +++ b/strings/search/boyermoore.go @@ -0,0 +1,57 @@ +package search + +// Implementation of boyer moore string search +// O(l) where l=len(text) +func BoyerMoore(text string, pattern string) []int { + var positions []int + + l := len(text) + n := len(pattern) + + // using booyer moore horspool modification + // O(n) space instead of O(n**2) + bcr := make(map[byte]int) + for i := 0; i < n-1; i++ { + bcr[pattern[i]] = n - i - 1 + } + + // Apostolico–Giancarlo modification + // allow to skip patterns that we know matches + // let us do O(l) instead of O(ln) + skips := make(map[int]int) + for _, s := range bcr { + i := 0 + for ; i < n-s; i++ { + if pattern[n-1-i] != pattern[n-1-s-i] { + break + } + } + skips[s] = i + } + + skip := 0 + jump := n + for i := 0; i < l-n+1; { + skip = skips[jump] + for k := n - 1; k > -1; k-- { + if text[i+k] != pattern[k] { + jump, ok := bcr[text[i+k]] + if !ok { + jump = n + } + i += jump + break + } + if k == n-jump { + k -= skip + } + if k == 0 { + positions = append(positions, i) + jump = 1 + i += jump + } + } + } + + return positions +} diff --git a/strings/search/patternsearch.go b/strings/search/naive.go similarity index 59% rename from strings/search/patternsearch.go rename to strings/search/naive.go index ca75129a4..51f47222f 100644 --- a/strings/search/patternsearch.go +++ b/strings/search/naive.go @@ -1,15 +1,7 @@ -/* -This algorithm tries to search the given pattern in the given text. -If pattern is found from index position i in the text, -it is added to positions. - -Time Complexity : O(n*m) - n = length of text - m = length of pattern -*/ - package search +// Implementation of naive string search +// O(n*m) where n=len(txt) and m=len(pattern) func Naive(text string, pattern string) []int { var positions []int for i := 0; i <= len(text)-len(pattern); i++ { diff --git a/strings/search/patternsearch_test.go b/strings/search/patternsearch_test.go index 2df0b842c..83dbf1e72 100644 --- a/strings/search/patternsearch_test.go +++ b/strings/search/patternsearch_test.go @@ -35,6 +35,18 @@ var testCases = []struct { "XYZ", []int(nil), }, + { + "worse case 1", + "AAAAAAAAAA", + "AAA", + []int{0, 1, 2, 3, 4, 5, 6, 7}, + }, + { + "worse case 2", + "NANANANANANANANANA", + "NANANA", + []int{0, 2, 4, 6, 8, 10, 12}, + }, } func TestNaive(t *testing.T) { @@ -47,3 +59,14 @@ func TestNaive(t *testing.T) { }) } } + +func TestBooyerMoore(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := BoyerMoore(tc.input, tc.pattern) + if !reflect.DeepEqual(actual, tc.expected) { + t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v, but actual matches are: %v", tc.pattern, tc.input, tc.expected, actual) + } + }) + } +} From 3a61b50dcb74c828179b26a4cda3c763820a22a3 Mon Sep 17 00:00:00 2001 From: Ayoub Chegraoui Date: Mon, 18 Oct 2021 17:39:01 +0100 Subject: [PATCH 259/488] feat: Add prime factorization (#384) --- math/prime/primefactorization.go | 22 ++++++++++++++++++ math/prime/primefactorization_test.go | 33 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 math/prime/primefactorization.go create mode 100644 math/prime/primefactorization_test.go diff --git a/math/prime/primefactorization.go b/math/prime/primefactorization.go new file mode 100644 index 000000000..c25522871 --- /dev/null +++ b/math/prime/primefactorization.go @@ -0,0 +1,22 @@ +package prime + +// Factorize is a function that computes the exponents +// of each prime in the prime factorization of n +func Factorize(n int64) map[int64]int64 { + result := make(map[int64]int64) + + for i := int64(2); i*i <= n; i += 1 { + for { + if n%i != 0 { + break + } + result[i] += 1 + n /= i + } + + } + if n > 1 { + result[n] += 1 + } + return result +} diff --git a/math/prime/primefactorization_test.go b/math/prime/primefactorization_test.go new file mode 100644 index 000000000..a5c900fe8 --- /dev/null +++ b/math/prime/primefactorization_test.go @@ -0,0 +1,33 @@ +package prime + +import ( + "reflect" + "testing" +) + +func TestFactorize(t *testing.T) { + var tests = []struct { + n int64 + expected map[int64]int64 + }{ + {4, map[int64]int64{2: 2}}, + {5, map[int64]int64{5: 1}}, + {7, map[int64]int64{7: 1}}, + {10, map[int64]int64{2: 1, 5: 1}}, + {999, map[int64]int64{3: 3, 37: 1}}, + {999999999999878, map[int64]int64{2: 1, 19: 1, 26315789473681: 1}}, + } + for _, test := range tests { + result := Factorize(test.n) + t.Log(test.n, " ", result) + if !reflect.DeepEqual(result, test.expected) { + t.Errorf("Wrong result! Expected:%v, returned:%v ", test.expected, result) + } + } +} + +func BenchmarkFactorize(b *testing.B) { + for i := 0; i < b.N; i++ { + Factorize(1000000007) + } +} From 11381400af0d325036c8a7f5eb8ded57abe3f462 Mon Sep 17 00:00:00 2001 From: Motasim <44056349+motasimmakki@users.noreply.github.com> Date: Mon, 18 Oct 2021 23:44:50 +0530 Subject: [PATCH 260/488] feat: Decimal to Binary Conversion (#391) --- README.md | 1 + conversion/decimaltobinary.go | 46 ++++++++++++++++++++++++++++++ conversion/decimaltobinary_test.go | 46 ++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 conversion/decimaltobinary.go create mode 100644 conversion/decimaltobinary_test.go diff --git a/README.md b/README.md index 0f4749af0..5817908d6 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ### Conversions * [Roman Numeral To Integer](./conversion/romantointeger.go) * [Integer To Roman Numeral](./conversion/integertoroman.go) +* [Decimal To Binary](./conversion/decimaltobinary.go) ### Data Structures * [AVL Tree](./structure/avl/avl.go) diff --git a/conversion/decimaltobinary.go b/conversion/decimaltobinary.go new file mode 100644 index 000000000..749c70c28 --- /dev/null +++ b/conversion/decimaltobinary.go @@ -0,0 +1,46 @@ +/* +Author: Motasim +GitHub: https://github.com/motasimmakki +Date: 14-Oct-2021 +*/ + +// This algorithm will convert any Decimal (+ve integer) number to Binary number. +// https://en.wikipedia.org/wiki/Binary_number +// Function receives a integer as a Decimal number and returns the Binary number. +// Suppoted integer value range is 0 to 2^(31 -1). + +// Package name. +package conversion + +// Importing necessary package. +import ( + "errors" + "strconv" +) + +// Inverse() function that will take string, +// and returns the inverse of that string. +func Inverse(str string) string { + rStr := []rune(str) + for i, j := 0, len(rStr)-1; i < len(rStr)/2; i, j = i+1, j-1 { + rStr[i], rStr[j] = rStr[j], rStr[i] + } + return string(rStr) +} + +// Convert() function that will take Decimal number as int, +// and return it's Binary equivalent as string. +func Convert(num int) (string, error) { + if num < 0 { + return "", errors.New("integer must have +ve value") + } + if num == 0 { + return "0", nil + } + var result string = "" + for num > 0 { + result += strconv.Itoa(num & 1) + num >>= 1 + } + return Inverse(result), nil +} diff --git a/conversion/decimaltobinary_test.go b/conversion/decimaltobinary_test.go new file mode 100644 index 000000000..9791da47c --- /dev/null +++ b/conversion/decimaltobinary_test.go @@ -0,0 +1,46 @@ +package conversion + +import "testing" + +var decimalTestCases = map[int]string{ + 0: "0", 1: "1", 2: "10", 3: "11", 4: "100", + 5: "101", 6: "110", 7: "111", 8: "1000", 9: "1001", + 10: "1010", 11: "1011", 12: "1100", 13: "1101", 14: "1110", + 15: "1111", 16: "10000", 17: "10001", 18: "10010", 19: "10011", + 20: "10100", 21: "10101", 22: "10110", 23: "10111", 24: "11000", + 25: "11001", 26: "11010", 27: "11011", 28: "11100", 29: "11101", + 30: "11110", 31: "11111", 32: "100000", 33: "100001", 34: "100010", + 35: "100011", 36: "100100", 37: "100101", 38: "100110", 39: "100111", + 40: "101000", 41: "101001", 42: "101010", 43: "101011", 44: "101100", + 45: "101101", 46: "101110", 47: "101111", 48: "110000", 49: "110001", + 50: "110010", 51: "110011", 52: "110100", 53: "110101", 54: "110110", + 55: "110111", 56: "111000", 57: "111001", 58: "111010", 59: "111011", + 60: "111100", 61: "111101", 62: "111110", 63: "111111", 64: "1000000", + 65: "1000001", 66: "1000010", 67: "1000011", 68: "1000100", 69: "1000101", + 70: "1000110", 71: "1000111", 72: "1001000", 73: "1001001", 74: "1001010", + 75: "1001011", 76: "1001100", 77: "1001101", 78: "1001110", 79: "1001111", + 80: "1010000", 81: "1010001", 82: "1010010", 83: "1010011", 84: "1010100", + 85: "1010101", 86: "1010110", 87: "1010111", 88: "1011000", 89: "1011001", + 90: "1011010", 91: "1011011", 92: "1011100", 93: "1011101", 94: "1011110", + 95: "1011111", 96: "1100000", 97: "1100001", 98: "1100010", 99: "1100011", + 100: "1100100", +} + +func TestConvert(t *testing.T) { + for input, expected := range decimalTestCases { + out, err := Convert(input) + if err != nil { + t.Errorf("Convert(%d) returned an error %s", input, err.Error()) + } + if out != expected { + t.Errorf("Convert(%d) = %s; want %s", input, out, expected) + } + } +} + +func BenchmarkConvert(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = Convert(100) + } +} From fefa8ca9a9ea5956c098638455f3ade32970a2a2 Mon Sep 17 00:00:00 2001 From: Erik Pellizzon Date: Mon, 18 Oct 2021 20:19:57 +0200 Subject: [PATCH 261/488] feat: add exchangesort (#394) --- sort/exchangesort.go | 16 ++++++++++++++++ sort/sorts_test.go | 8 ++++++++ 2 files changed, 24 insertions(+) create mode 100644 sort/exchangesort.go diff --git a/sort/exchangesort.go b/sort/exchangesort.go new file mode 100644 index 000000000..b901490cb --- /dev/null +++ b/sort/exchangesort.go @@ -0,0 +1,16 @@ +// Implementation of exchange sort algorithm, a variant of bubble sort +// Reference: https://en.wikipedia.org/wiki/Sorting_algorithm#Exchange_sort + +package sort + +func Exchange(arr []int) []int { + for i := 0; i < len(arr)-1; i++ { + for j := i + 1; j < len(arr); j++ { + if arr[i] > arr[j] { + arr[i], arr[j] = arr[j], arr[i] + } + } + } + + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index ba55bf5f7..ce838f056 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -81,6 +81,10 @@ func TestBubble(t *testing.T) { testFramework(t, bubbleSort) } +func TestExchange(t *testing.T) { + testFramework(t, Exchange) +} + func TestInsertion(t *testing.T) { testFramework(t, InsertionSort) } @@ -228,6 +232,10 @@ func BenchmarkBubble(b *testing.B) { benchmarkFramework(b, bubbleSort) } +func BenchmarkExchange(b *testing.B) { + benchmarkFramework(b, Exchange) +} + func BenchmarkInsertion(b *testing.B) { benchmarkFramework(b, InsertionSort) } From 9cdf346c4365bf2ddf0b35f0e199df2ef11c5a74 Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Tue, 19 Oct 2021 20:02:03 +0300 Subject: [PATCH 262/488] feat: Transposition cipher (#375) --- cipher/transposition/transposition.go | 106 +++++++++++++++++++++ cipher/transposition/transposition_test.go | 103 ++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 cipher/transposition/transposition.go create mode 100644 cipher/transposition/transposition_test.go diff --git a/cipher/transposition/transposition.go b/cipher/transposition/transposition.go new file mode 100644 index 000000000..e27020b43 --- /dev/null +++ b/cipher/transposition/transposition.go @@ -0,0 +1,106 @@ +// transposition.go +// description: Transposition cipher +// details: +// Implementation "Transposition cipher" is a method of encryption by which the positions held by units of plaintext (which are commonly characters or groups of characters) are shifted according to a regular system, so that the ciphertext constitutes a permutation of the plaintext [Transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher) +// author(s) [red_byte](https://github.com/i-redbyte) +// see transposition_test.go + +package transposition + +import ( + "sort" + "strings" +) + +type NoTextToEncryptError struct{} +type KeyMissingError struct{} + +func (n *NoTextToEncryptError) Error() string { + return "No text to encrypt" +} +func (n *KeyMissingError) Error() string { + return "Missing Key" +} + +func getKey(keyWord string) []int { + keyWord = strings.ToLower(keyWord) + word := []rune(keyWord) + var sortedWord = make([]rune, len(word)) + copy(sortedWord, word) + sort.Slice(sortedWord, func(i, j int) bool { return sortedWord[i] < sortedWord[j] }) + usedLettersMap := make(map[rune]int) + wordLength := len(word) + resultKey := make([]int, wordLength) + for i := 0; i < wordLength; i++ { + char := word[i] + numberOfUsage := usedLettersMap[char] + resultKey[i] = getIndex(sortedWord, char) + numberOfUsage + 1 //+1 -so that indexing does not start at 0 + numberOfUsage++ + usedLettersMap[char] = numberOfUsage + } + return resultKey +} + +func getIndex(wordSet []rune, subString rune) int { + n := len(wordSet) + for i := 0; i < n; i++ { + if wordSet[i] == subString { + return i + } + } + return 0 +} + +func Encrypt(text []rune, keyWord string) (string, error) { + key := getKey(keyWord) + space := ' ' + keyLength := len(key) + textLength := len(text) + if keyLength <= 0 { + return "", &KeyMissingError{} + } + if textLength <= 0 { + return "", &NoTextToEncryptError{} + } + n := textLength % keyLength + + for i := 0; i < keyLength-n; i++ { + text = append(text, space) + } + textLength = len(text) + result := "" + for i := 0; i < textLength; i += keyLength { + transposition := make([]rune, keyLength) + for j := 0; j < keyLength; j++ { + transposition[key[j]-1] = text[i+j] + } + result += string(transposition) + } + return result, nil +} + +func Decrypt(text []rune, keyWord string) (string, error) { + key := getKey(keyWord) + textLength := len(text) + if textLength <= 0 { + return "", &NoTextToEncryptError{} + } + keyLength := len(key) + if keyLength <= 0 { + return "", &KeyMissingError{} + } + space := ' ' + n := textLength % keyLength + for i := 0; i < keyLength-n; i++ { + text = append(text, space) + } + result := "" + for i := 0; i < textLength; i += keyLength { + transposition := make([]rune, keyLength) + for j := 0; j < keyLength; j++ { + transposition[j] = text[i+key[j]-1] + } + result += string(transposition) + } + return result, nil +} diff --git a/cipher/transposition/transposition_test.go b/cipher/transposition/transposition_test.go new file mode 100644 index 000000000..f2f155a15 --- /dev/null +++ b/cipher/transposition/transposition_test.go @@ -0,0 +1,103 @@ +// transposition_test.go +// description: Transposition cipher +// author(s) [red_byte](https://github.com/i-redbyte) +// see transposition.go + +package transposition + +import ( + "errors" + "math/rand" + "strings" + "testing" +) + +const enAlphabet = "abcdefghijklmnopqrstuvwxyz " + +func getTexts() []string { + return []string{ + "Ilya Sokolov", + "A slice literal is declared just like an array literal, except you leave out the element count", + "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.", + "Go’s treatment of errors as values has served us well over the last decade. Although the standard library’s support for errors has been minimal—just the errors.New and fmt.Errorf functions, which produce errors that contain only a message—the built-in error interface allows Go programmers to add whatever information they desire. All it requires is a type that implements an Error method:", + "А тут для примера русский текст", + } +} + +func getRandomString() string { + enRunes := []rune(enAlphabet) + b := make([]rune, rand.Intn(100)) + for i := range b { + b[i] = enRunes[rand.Intn(len(enRunes))] + } + return string(b) +} + +func TestEncrypt(t *testing.T) { + fn := func(text string, keyWord string) (bool, error) { + encrypt, err := Encrypt([]rune(text), keyWord) + if err != nil && !errors.Is(err, &NoTextToEncryptError{}) && !errors.Is(err, &KeyMissingError{}) { + t.Error("Unexpected error ", err) + } + return text == encrypt, err + } + for _, s := range getTexts() { + if check, err := fn(s, getRandomString()); check || err != nil { + t.Error("String ", s, " not encrypted") + } + } + if _, err := fn(getRandomString(), ""); err == nil { + t.Error("Error! empty string encryption") + } +} + +func TestDecrypt(t *testing.T) { + for _, s := range getTexts() { + keyWord := getRandomString() + encrypt, errEncrypt := Encrypt([]rune(s), keyWord) + if errEncrypt != nil && + !errors.Is(errEncrypt, &NoTextToEncryptError{}) && + !errors.Is(errEncrypt, &KeyMissingError{}) { + t.Error("Unexpected error ", errEncrypt) + } + if errEncrypt != nil { + t.Error(errEncrypt) + } + decrypt, errDecrypt := Decrypt([]rune(encrypt), keyWord) + if errDecrypt != nil && + !errors.Is(errDecrypt, &NoTextToEncryptError{}) && + !errors.Is(errDecrypt, &KeyMissingError{}) { + t.Error("Unexpected error ", errDecrypt) + } + if errDecrypt != nil { + t.Error(errDecrypt) + } + if encrypt == decrypt { + t.Error("String ", s, " not encrypted") + } + if encrypt == s { + t.Error("String ", s, " not encrypted") + } + } +} + +func TestEncryptDecrypt(t *testing.T) { + text := "Test text for checking the algorithm" + key1 := "testKey" + key2 := "Test Key2" + encrypt, errEncrypt := Encrypt([]rune(text), key1) + if errEncrypt != nil { + t.Error(errEncrypt) + } + decrypt, errDecrypt := Decrypt([]rune(encrypt), key1) + if errDecrypt != nil { + t.Error(errDecrypt) + } + if strings.Contains(decrypt, text) == false { + t.Error("The string was not decrypted correctly") + } + decrypt, _ = Decrypt([]rune(encrypt), key2) + if strings.Contains(decrypt, text) == true { + t.Error("The string was decrypted with a different key") + } +} From cfd0999f1ad533db72514358a028a882ed5b3fa0 Mon Sep 17 00:00:00 2001 From: FuXiang Shu <6470547+Crazy3lf@users.noreply.github.com> Date: Wed, 20 Oct 2021 15:53:08 +0800 Subject: [PATCH 263/488] feat: add implementation of simple sort (#395) --- sort/simplesort.go | 35 +++++++++++++++++++++++++++++++++++ sort/sorts_test.go | 16 ++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 sort/simplesort.go diff --git a/sort/simplesort.go b/sort/simplesort.go new file mode 100644 index 000000000..39f3a55f9 --- /dev/null +++ b/sort/simplesort.go @@ -0,0 +1,35 @@ +// simplesort.go +// description: Implementation of a simple sorting algorithm +// details: +// A simple sorting algorithm that look counter intuitive at first glance and very similar to Exchange Sort +// An improved version is included with slight changes to make the sort slightly more efficient +// reference: https://arxiv.org/abs/2110.01111v1 +// see sort_test.go for a test implementation, test function TestSimple and TestImprovedSimple + +package sort + +func SimpleSort(arr []int) []int { + for i := 0; i < len(arr); i++ { + for j := 0; j < len(arr); j++ { + if arr[i] < arr[j] { + // swap arr[i] and arr[j] + arr[i], arr[j] = arr[j], arr[i] + } + } + } + return arr +} + +// ImprovedSimpleSort is a improve SimpleSort by skipping an unnecessary comparison of the first and last. +// This improved version is more similar to implementation of insertion sort +func ImprovedSimpleSort(arr []int) []int { + for i := 1; i < len(arr); i++ { + for j := 0; j < len(arr)-1; j++ { + if arr[i] < arr[j] { + // swap arr[i] and arr[j] + arr[i], arr[j] = arr[j], arr[i] + } + } + } + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index ce838f056..3eaa72af2 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -176,6 +176,14 @@ func TestRadix(t *testing.T) { testFramework(t, RadixSort) } +func TestSimple(t *testing.T) { + testFramework(t, SimpleSort) +} + +func TestImprovedSimple(t *testing.T) { + testFramework(t, ImprovedSimpleSort) +} + // Very slow, consider commenting // func TestSelection(t *testing.T) { // testFramework(t, SelectionSort) @@ -298,6 +306,14 @@ func BenchmarkRadix(b *testing.B) { benchmarkFramework(b, RadixSort) } +func BenchmarkSimple(b *testing.B) { + benchmarkFramework(b, SimpleSort) +} + +func BenchmarkImprovedSimple(b *testing.B) { + benchmarkFramework(b, ImprovedSimpleSort) +} + // Very Slow, consider commenting func BenchmarkSelection(b *testing.B) { benchmarkFramework(b, SelectionSort) From 9e47ef47b939f14545e0014a7ca64141190ab309 Mon Sep 17 00:00:00 2001 From: xavier268 Date: Wed, 20 Oct 2021 20:40:07 +0200 Subject: [PATCH 264/488] Feat: Add word removal to the Go/struct/trie (#380) Co-authored-by: xavier --- structure/set/setexample_test.go | 24 +++++ structure/trie/trie.go | 75 +++++++++++-- structure/trie/trie_bench_test.go | 116 ++++++++++++++++++++ structure/trie/trie_test.go | 163 ++++++++++++++++++++++------- structure/trie/trieexample_test.go | 39 +++++++ 5 files changed, 372 insertions(+), 45 deletions(-) create mode 100644 structure/set/setexample_test.go create mode 100644 structure/trie/trie_bench_test.go create mode 100644 structure/trie/trieexample_test.go diff --git a/structure/set/setexample_test.go b/structure/set/setexample_test.go new file mode 100644 index 000000000..801298217 --- /dev/null +++ b/structure/set/setexample_test.go @@ -0,0 +1,24 @@ +// package set implements a Set using a golang map. +// This implies that only the types that are accepted as valid map keys can be used as set elements. +// For instance, do not try to Add a slice, or the program will panic. +// +package set + +import ( + "fmt" +) + +func ExampleSet() { + + set := New(1, 2, 3) + fmt.Println(set.Len()) // 3 + set.Add(3) + fmt.Println(set.Len()) // 3 + set.Add(4) + fmt.Println(set.Len()) // 4 + + // output: + // 3 + // 3 + // 4 +} diff --git a/structure/trie/trie.go b/structure/trie/trie.go index df3c87ae3..3665e2c3c 100644 --- a/structure/trie/trie.go +++ b/structure/trie/trie.go @@ -18,8 +18,8 @@ func NewNode() *Node { return n } -// Insert inserts words at a Trie node. -func (n *Node) Insert(s string) { +// insert a single word at a Trie node. +func (n *Node) insert(s string) { curr := n for _, c := range s { next, ok := curr.children[c] @@ -32,15 +32,76 @@ func (n *Node) Insert(s string) { curr.isLeaf = true } -// Find finds words at a Trie node. +// Insert zero, one or more words at a Trie node. +func (n *Node) Insert(s ...string) { + for _, ss := range s { + n.insert(ss) + } +} + +// Find words at a Trie node. func (n *Node) Find(s string) bool { - curr := n + next, ok := n, false for _, c := range s { - next, ok := curr.children[c] + next, ok = next.children[c] if !ok { return false } - curr = next } - return true + return next.isLeaf +} + +// Capacity returns the number of nodes in the Trie +func (n *Node) Capacity() int { + r := 0 + for _, c := range n.children { + r += c.Capacity() + } + return 1 + r +} + +// Size returns the number of words in the Trie +func (n *Node) Size() int { + r := 0 + for _, c := range n.children { + r += c.Size() + } + if n.isLeaf { + r++ + } + return r +} + +// remove lazily a word from the Trie node, no node is actually removed. +func (n *Node) remove(s string) { + if len(s) == 0 { + return + } + next, ok := n, false + for _, c := range s { + next, ok = next.children[c] + if !ok { + // word cannot be found - we're done ! + return + } + } + next.isLeaf = false +} + +// Remove zero, one or more words lazily from the Trie, no node is actually removed. +func (n *Node) Remove(s ...string) { + for _, ss := range s { + n.remove(ss) + } +} + +// Compact will remove unecessay nodes, reducing the capacity, returning true if node n itself should be removed. +func (n *Node) Compact() (remove bool) { + + for r, c := range n.children { + if c.Compact() { + delete(n.children, r) + } + } + return !n.isLeaf && len(n.children) == 0 } diff --git a/structure/trie/trie_bench_test.go b/structure/trie/trie_bench_test.go new file mode 100644 index 000000000..f3af3aaa1 --- /dev/null +++ b/structure/trie/trie_bench_test.go @@ -0,0 +1,116 @@ +package trie + +import ( + "fmt" + "math/rand" + "testing" +) + +// CAUTION : make sure to limit the benchamrks to 3000 iterations, +// or removal will mostly process an empty Trie, giving absurd results. + +// go test -v -bench=. -benchmem -benchtime=3000x + +// === RUN TestTrieInsert +// --- PASS: TestTrieInsert (0.00s) +// === RUN TestTrieRemove +// --- PASS: TestTrieRemove (0.00s) +// === RUN ExampleNode +// --- PASS: ExampleNode (0.00s) +// goos: linux +// goarch: amd64 +// pkg: github.com/TheAlgorithms/Go/structure/trie +// BenchmarkTrie_Insert +// BenchmarkTrie_Insert-8 3000 1559881 ns/op 1370334 B/op 25794 allocs/op +// BenchmarkTrie_Find_non_existant +// BenchmarkTrie_Find_non_existant-8 3000 59.1 ns/op 0 B/op 0 allocs/op +// BenchmarkTrie_Find_existant +// BenchmarkTrie_Find_existant-8 3000 238 ns/op 0 B/op 0 allocs/op +// BenchmarkTrie_Remove_lazy +// BenchmarkTrie_Remove_lazy-8 3000 126 ns/op 0 B/op 0 allocs/op +// BenchmarkTrie_Remove_and_Compact +// BenchmarkTrie_Remove_and_Compact-8 3000 213945 ns/op 0 B/op 0 allocs/op +// PASS +// ok github.com/TheAlgorithms/Go/structure/trie 5.355s + +func BenchmarkTrie_Insert(b *testing.B) { + + // prepare random words for insertion + insert := make([]string, 3000) + for i := 0; i < len(insert); i++ { + insert[i] = fmt.Sprintf("%f", rand.Float64()) + } + + // Reset timer and run benchmark for insertion + b.ResetTimer() + for i := 0; i < b.N; i++ { + n := NewNode() + n.Insert(insert...) + } +} + +func BenchmarkTrie_Find_non_existant(b *testing.B) { + + // prepare random words for insertion + insert := make([]string, 3000) + for i := 0; i < len(insert); i++ { + insert[i] = fmt.Sprintf("%f", rand.Float64()) + } + n := NewNode() + n.Insert(insert...) + + // Reset timer and run benchmark for finding non existing + b.ResetTimer() + for i := 0; i < b.N; i++ { + n.Find("0.3213213244346546546546565465465") // does not exists + } +} + +func BenchmarkTrie_Find_existant(b *testing.B) { + // prepare and insert random words + insert := make([]string, 3000) + for i := 0; i < len(insert); i++ { + insert[i] = fmt.Sprintf("%f", rand.Float64()) + } + n := NewNode() + n.Insert(insert...) + + // Reset timer and run benchmark for finding existing words + b.ResetTimer() + for i := 0; i < b.N; i++ { + n.Find(insert[i%3000]) // always exists ! + } +} + +func BenchmarkTrie_Remove_lazy(b *testing.B) { + // prepare and insert random words + insert := make([]string, 3000) + for i := 0; i < len(insert); i++ { + insert[i] = fmt.Sprintf("%f", rand.Float64()) + } + n := NewNode() + n.Insert(insert...) + + // Reset timer and run benchmark for lazily removing words + b.ResetTimer() + for i := 0; i < b.N; i++ { + n.Remove(insert[i%3000]) // exists, at least until removed ... + } +} + +func BenchmarkTrie_Remove_and_Compact(b *testing.B) { + // prepare and insert random words + insert := make([]string, 3000) + for i := 0; i < len(insert); i++ { + insert[i] = fmt.Sprintf("%f", rand.Float64()) + } + n := NewNode() + n.Insert(insert...) + + // Reset timer and run benchmark for removing words and immediately compacting + b.ResetTimer() + for i := 0; i < b.N; i++ { + n.Remove(insert[i%3000]) + n.Compact() + } +} diff --git a/structure/trie/trie_test.go b/structure/trie/trie_test.go index 1b73896e3..8747a0e1b 100644 --- a/structure/trie/trie_test.go +++ b/structure/trie/trie_test.go @@ -4,67 +4,154 @@ import ( "testing" ) -func TestTrie(t *testing.T) { +func TestTrieInsert(t *testing.T) { n := NewNode() - insertWords := [...]string{ + insertWords := []string{ "nikola", "tesla", } + checkWords := map[string]bool{ "thomas": false, "edison": false, "nikola": true, } - for _, w := range insertWords { - n.Insert(w) - t.Logf( - "added \"%s\" to the Trie.", - w, - ) + n.Insert(insertWords...) + n.verify(t, checkWords) + n.verifySizeCapa(t, 2, 12) + +} + +func TestTrieInsert_substrings(t *testing.T) { + n := NewNode() + + insertWords := []string{ + "aa", + "aaaa", + "aaaaa", + } + + checkWords := map[string]bool{ + "a": false, + "aa": true, + "aaa": false, + "aaaa": true, + "aaaaa": true, + "aaaaaa": false, + "aaaaaaa": false, + } + + n.Insert(insertWords...) + n.verify(t, checkWords) + n.verifySizeCapa(t, 3, 5+1) + + n.Remove("aaaa") + checkWords["aaaa"] = false + n.verify(t, checkWords) + n.verifySizeCapa(t, 2, 5+1) + + if n.Compact() { + t.Fatalf("it should not be possible to remove the node") } + n.verify(t, checkWords) + n.verifySizeCapa(t, 2, 5+1) +} +func TestTrieRemove(t *testing.T) { + n := NewNode() + + insertWords := []string{ + "nikola", + "tesla", + "albert", + "einstein", + } + + checkWords := map[string]bool{ + "thomas": false, + "edison": false, + "nikola": true, + "albert": true, + "einstein": true, + } + + n.Insert(insertWords...) + n.verify(t, checkWords) + size, capa := n.Size(), n.Capacity() // 4 words ... + + n.Remove("albert") + checkWords["albert"] = false + size-- // 3 words in size, but no change in capacity + n.verify(t, checkWords) + n.verifySizeCapa(t, size, capa) + + n.Remove("albert") // no effect since already removed + n.verify(t, checkWords) + n.verifySizeCapa(t, size, capa) + + n.Remove("marcel") // no effect since ,o, existant + n.verify(t, checkWords) + n.verifySizeCapa(t, size, capa) + + n.Remove("nikola", "tesla") // 1 word + checkWords["nikola"] = false + checkWords["tesla"] = false + size -= 2 // t1 word left, but still no change in capacity + n.verify(t, checkWords) + n.verifySizeCapa(t, size, capa) + + // compact the Tree + if n.Compact() { + t.Fatal("the Trie should not be completely removable after compaction") + } + if capa <= n.Capacity() { + t.Fatal("capacity should have reduced following compaction") + } + capa = n.Capacity() + n.verify(t, checkWords) + n.verifySizeCapa(t, size, capa) // still 1 word, reduced capacity + + n.Remove("einstein") + checkWords["einstein"] = false + size-- // No more words + n.verify(t, checkWords) + n.verifySizeCapa(t, size, capa) // no words, but still have some nodes left capacity + + if !n.Compact() { + t.Fatal("the root node of an empty Trie should be marked as removable after compaction") + } + n.verifySizeCapa(t, 0, 1) // no words, only the root node left +} + +// --------------- helper functions --------------------------- + +// verify if provided words are present +func (n *Node) verify(t *testing.T, checkWords map[string]bool) { for k, v := range checkWords { ok := n.Find(k) if ok != v { t.Fatalf( - "\"%s\" is supposed to be %sin the Trie.", + "%q is %s supposed to be in the Trie.", k, map[bool]string{true: "", false: "NOT "}[v], ) } - t.Logf( - "\"%s\" is %sin the Trie.", - k, - map[bool]string{true: "", false: "NOT "}[ok], - ) + // t.Logf( + // "\"%s\" is %sin the Trie.", + // k, + // map[bool]string{true: "", false: "NOT "}[ok], + // ) } } -func BenchmarkTrie(b *testing.B) { - for i := 0; i < b.N; i++ { - n := NewNode() - - n.Insert("nikola") - n.Insert("tesla") - - n.Find("thomas") - n.Find("edison") - n.Find("nikola") +// verify expected size and capacity +func (n *Node) verifySizeCapa(t *testing.T, expectedSize, expectedCapacity int) { + if got := n.Size(); got != expectedSize { + t.Fatalf("Expected Size was %d but got %d", expectedSize, got) + } + if got := n.Capacity(); got != expectedCapacity { + t.Fatalf("Expected Capacity was %d but got %d", expectedCapacity, got) } -} - -func ExampleNode() { - // creates a new node - node := NewNode() - - // adds words - node.Insert("nikola") - node.Insert("tesla") - - // finds words - node.Find("thomas") // false - node.Find("edison") // false - node.Find("nikola") // true } diff --git a/structure/trie/trieexample_test.go b/structure/trie/trieexample_test.go new file mode 100644 index 000000000..fb3f9bc0f --- /dev/null +++ b/structure/trie/trieexample_test.go @@ -0,0 +1,39 @@ +package trie + +import "fmt" + +func ExampleNode() { + // creates a new node + node := NewNode() + + // adds words + node.Insert("nikola") + node.Insert("tesla") + + // check size and capacity + fmt.Println(node.Size()) // 2 words + fmt.Println(node.Capacity()) // 12 nodes + + // finds words + fmt.Println(node.Find("thomas")) // false + fmt.Println(node.Find("edison")) // false + fmt.Println(node.Find("nikola")) // true + + // remove a word, and check it is gone + node.Remove("tesla") + fmt.Println(node.Find("tesla")) // false + + // size and capacity have changed + fmt.Println(node.Size()) // 1 word left + fmt.Println(node.Capacity()) // 12 nodes remaining + + // output: + // 2 + // 12 + // false + // false + // true + // false + // 1 + // 12 +} From 04663b5cb3023de5289dd4006180acce93efdd77 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Thu, 21 Oct 2021 06:47:47 +0200 Subject: [PATCH 265/488] test: add knapsack test and example (#390) Co-authored-by: Michele Caci --- dynamic/knapsack.go | 6 +++--- dynamic/knapsack_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 dynamic/knapsack_test.go diff --git a/dynamic/knapsack.go b/dynamic/knapsack.go index 032b91e79..b07bf6b40 100644 --- a/dynamic/knapsack.go +++ b/dynamic/knapsack.go @@ -12,9 +12,9 @@ func Max(a, b int) int { return int(math.Max(float64(a), float64(b))) } -// Solve knapsack problem +// Knapsack solves knapsack problem // return maxProfit -func Solve(maxWeight int, weights, values []int) int { +func Knapsack(maxWeight int, weights, values []int) int { n := len(weights) m := maxWeight // create dp data structure @@ -43,7 +43,7 @@ func main() { weights := []int{ 10, 20, 30, } - maxProfit := solve(maxWeight, weights, values) + maxProfit := Knapsack(maxWeight, weights, values) fmt.Println(maxProfit) } */ diff --git a/dynamic/knapsack_test.go b/dynamic/knapsack_test.go new file mode 100644 index 000000000..aaa7a579b --- /dev/null +++ b/dynamic/knapsack_test.go @@ -0,0 +1,38 @@ +package dynamic_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +func TestKnapsack(t *testing.T) { + td := []struct { + maxWeight int + weights []int + values []int + expected int + }{ + {0, []int{0}, []int{0}, 0}, + {10, []int{1, 2, 3}, []int{1, 1, 1}, 3}, // picks all + {10, []int{1, 2, 3, 4, 5, 6}, []int{1, 1, 1, 1, 1, 1}, 4}, // picks 1,2,3,4 + {10, []int{1, 2, 3, 4, 5, 6}, []int{1, 1, 1, 1, 1, 5}, 7}, // picks 1,3,6 + {10, []int{1, 2, 3, 4, 5, 6}, []int{-1, 10, -3, -4, 10, 1}, 20}, // picks 2,5 + {10, []int{1, 2, 3, 4, 5, 6}, []int{-10, -10, -10, -10, 10, 10}, 10}, // picks 5 or 6 + } + for _, tc := range td { + name := fmt.Sprintf("Knapsack problem with (maxWeight: %d, weights: %v, values: %v)", tc.maxWeight, tc.weights, tc.values) + t.Run(name, func(t *testing.T) { + actual := dynamic.Knapsack(tc.maxWeight, tc.weights, tc.values) + if actual != tc.expected { + t.Errorf("expecting knapsack with (maxWeight: %d, weights: %v, values: %v) to return %d but got %d", tc.maxWeight, tc.weights, tc.values, tc.expected, actual) + } + }) + } +} + +func ExampleKnapsack() { + fmt.Print(dynamic.Knapsack(10, []int{4, 5, 8}, []int{50, 15, 60})) + //Output:65 +} From 47e3e1c41b6bce4ad1885dded24be7e3f477c771 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Thu, 21 Oct 2021 07:08:54 +0200 Subject: [PATCH 266/488] add: binomial coefficient tests (#389) Co-authored-by: Michele Caci --- dynamic/binomialcoefficient.go | 12 ++--- dynamic/binomialcoefficient_test.go | 32 ++++++++++++ dynamic/editdistance.go | 19 ++----- dynamic/matrixmultiplication.go | 6 ++- math/min/min.go | 12 +++++ math/min/min_test.go | 81 +++++++++++++++++++++++++++++ 6 files changed, 135 insertions(+), 27 deletions(-) create mode 100644 dynamic/binomialcoefficient_test.go create mode 100644 math/min/min.go create mode 100644 math/min/min_test.go diff --git a/dynamic/binomialcoefficient.go b/dynamic/binomialcoefficient.go index 57ac880c4..b26dbcbbf 100644 --- a/dynamic/binomialcoefficient.go +++ b/dynamic/binomialcoefficient.go @@ -1,5 +1,7 @@ package dynamic +import "github.com/TheAlgorithms/Go/math/min" + // func main() { // myArrayOfK := [4]int{5, 6, 7, 8} // var x int @@ -24,7 +26,7 @@ func Bin2(n int, k int) int { } for i = 0; i <= n; i++ { - for j = 0; j <= Min(i, k); j++ { + for j = 0; j <= min.Int(i, k); j++ { if j == 0 || j == i { B[i][j] = 1 } else { @@ -34,11 +36,3 @@ func Bin2(n int, k int) int { } return B[n][k] } - -// Min function - possible duplicate -func Min(a, b int) int { - if a < b { - return a - } - return b -} diff --git a/dynamic/binomialcoefficient_test.go b/dynamic/binomialcoefficient_test.go new file mode 100644 index 000000000..109a5b955 --- /dev/null +++ b/dynamic/binomialcoefficient_test.go @@ -0,0 +1,32 @@ +package dynamic_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +func TestBin2(t *testing.T) { + td := []struct { + n, k, expected int + }{ + {0, 0, 1}, + {1, 1, 1}, + {2, 0, 1}, {2, 1, 2}, {2, 2, 1}, + {3, 0, 1}, {3, 1, 3}, {3, 2, 3}, {3, 3, 1}, + {4, 0, 1}, {4, 1, 4}, {4, 2, 6}, {4, 3, 4}, {4, 4, 1}, + {5, 0, 1}, {5, 1, 5}, {5, 2, 10}, {5, 3, 10}, {5, 4, 5}, {5, 5, 1}, + {10, 2, 45}, + {15, 10, 3003}, + } + for _, tc := range td { + name := fmt.Sprintf("binomial coefficient of (%d, %d)", tc.n, tc.k) + t.Run(name, func(t *testing.T) { + actual := dynamic.Bin2(tc.n, tc.k) + if actual != tc.expected { + t.Errorf("expecting binomial coefficient of (%d, %d) to be %d but got %d", tc.n, tc.k, tc.expected, actual) + } + }) + } +} diff --git a/dynamic/editdistance.go b/dynamic/editdistance.go index fe129da54..92abe9583 100644 --- a/dynamic/editdistance.go +++ b/dynamic/editdistance.go @@ -4,20 +4,7 @@ package dynamic -// Utility function which does what you expect. -func minOfTwo(a int, b int) int { - - if a < b { - return a - } - return b -} - -// Utility function to compute minimum of three numbers using minOfTwo. -func minOfThree(a int, b int, c int) int { - - return minOfTwo(a, minOfTwo(b, c)) -} +import "github.com/TheAlgorithms/Go/math/min" // EditDistanceRecursive is a naive implementation with exponential time complexity. func EditDistanceRecursive(first string, second string, pointerFirst int, pointerSecond int) int { @@ -36,7 +23,7 @@ func EditDistanceRecursive(first string, second string, pointerFirst int, pointe } // We have three choices, all with cost of 1 unit - return 1 + minOfThree(EditDistanceRecursive(first, second, pointerFirst, pointerSecond-1), // Insert + return 1 + min.Int(EditDistanceRecursive(first, second, pointerFirst, pointerSecond-1), // Insert EditDistanceRecursive(first, second, pointerFirst-1, pointerSecond), // Delete EditDistanceRecursive(first, second, pointerFirst-1, pointerSecond-1)) // Replace } @@ -74,7 +61,7 @@ func EditDistanceDP(first string, second string) int { continue } - dp[i][j] = 1 + minOfThree(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + dp[i][j] = 1 + min.Int(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) } } diff --git a/dynamic/matrixmultiplication.go b/dynamic/matrixmultiplication.go index dc4164f99..373936e62 100644 --- a/dynamic/matrixmultiplication.go +++ b/dynamic/matrixmultiplication.go @@ -4,6 +4,8 @@ package dynamic +import "github.com/TheAlgorithms/Go/math/min" + // MatrixChainRec function func MatrixChainRec(D []int, i, j int) int { // d[i-1] x d[i] : dimension of matrix i @@ -13,7 +15,7 @@ func MatrixChainRec(D []int, i, j int) int { q := 1 << 32 for k := i; k < j; k++ { prod := MatrixChainRec(D, i, k) + MatrixChainRec(D, k+1, j) + D[i-1]*D[k]*D[j] - q = Min(prod, q) + q = min.Int(prod, q) } return q } @@ -35,7 +37,7 @@ func MatrixChainDp(D []int) int { dp[i][j] = 1 << 31 for k := i; k < j; k++ { prod := dp[i][k] + dp[k+1][j] + D[i-1]*D[k]*D[j] - dp[i][j] = Min(prod, dp[i][j]) + dp[i][j] = min.Int(prod, dp[i][j]) } } } diff --git a/math/min/min.go b/math/min/min.go new file mode 100644 index 000000000..965018f1f --- /dev/null +++ b/math/min/min.go @@ -0,0 +1,12 @@ +package min + +// Int is a function which returns the minimum of two integers. +func Int(values ...int) int { + min := values[0] + for _, value := range values { + if value < min { + min = value + } + } + return min +} diff --git a/math/min/min_test.go b/math/min/min_test.go new file mode 100644 index 000000000..663f5b734 --- /dev/null +++ b/math/min/min_test.go @@ -0,0 +1,81 @@ +package min_test + +import ( + "testing" + + "github.com/TheAlgorithms/Go/math/min" +) + +func TestMin(t *testing.T) { + testCases := []struct { + name string + left int + right int + min int + }{ + { + name: "left is min", + left: 1, + right: 10, + min: 1, + }, + { + name: "right is min", + left: 10, + right: 9, + min: 9, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + actualMin := min.Int(test.left, test.right) + if actualMin != test.min { + t.Errorf("Failed test %s\n\tleft: %v, right: %v, min: %v but received: %v", + test.name, test.left, test.right, test.min, actualMin) + } + }) + } +} + +func TestMinOfThree(t *testing.T) { + testCases := []struct { + name string + left int + middle int + right int + min int + }{ + { + name: "left is min", + left: 1, + middle: 5, + right: 10, + min: 1, + }, + { + name: "middle is min", + left: 10, + middle: 5, + right: 9, + min: 5, + }, + { + name: "right is min", + left: 10, + middle: 8, + right: 6, + min: 6, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + actualMin := min.Int(test.left, test.middle, test.right) + if actualMin != test.min { + t.Errorf("Failed test %s\n\tleft: %v, middle: %v, right: %v, min: %v but received: %v", + test.name, test.left, test.middle, test.right, test.min, actualMin) + } + }) + } +} From 66bcc85148e2653c1617d93445e342ccb4f18fde Mon Sep 17 00:00:00 2001 From: Daniel <71837281+darmiel@users.noreply.github.com> Date: Thu, 21 Oct 2021 07:13:57 +0200 Subject: [PATCH 267/488] feat: rgb extract, combine (#396) --- conversion/rgbhex.go | 53 +++++++++++++++++++++++++++++++++++++++ conversion/rgbhex_test.go | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 conversion/rgbhex.go create mode 100644 conversion/rgbhex_test.go diff --git a/conversion/rgbhex.go b/conversion/rgbhex.go new file mode 100644 index 000000000..d050edc8d --- /dev/null +++ b/conversion/rgbhex.go @@ -0,0 +1,53 @@ +// rgbhex.go +// description: convert hex input to red, green and blue and vice versa +// author(s) [darmiel](https://github.com/darmiel) +// see rgbhex_test.go + +package conversion + +// HEXToRGB splits an RGB input (e.g. a color in hex format; 0x) +// into the individual components: red, green and blue +func HEXToRGB(hex uint) (red, green, blue byte) { + // A hex code is structured like this: + // #3498db (light blue) - converted to binary: + // 00110100 10011000 11011011 + // + + // To get the blue value we use the bit operation AND with the bit mask 0xFF (in binary: 11111111) + // 00110100 10011000 <11011011> & + // 00000000 00000000 11111111 = + // 00000000 00000000 <11011011> = + blue = byte(hex & 0xFF) + + // To get the green value, we first shift the value 8 bits to the right: + // 00110100 <10011000> 11011011 >> 8 = + // 00000000 00110100 <10011000> & + // 00000000 00000000 11111111 = + // 00000000 00000000 <10011000> = + green = byte((hex >> 8) & 0xFF) + + // Same as green value, only this time shift 16 to the right + // Alternatively, you can apply a bitmask first and then shift it. + // <00110100> 10011000 11011011 & + // 11111111 00000000 00000000 = + // <00110100> 00000000 00000000 >> 16 + // 00000000 00000000 <00110100> = + red = byte((hex >> 16) & 0xFF) + return +} + +// RGBToHEX does exactly the opposite of HEXToRGB: +// it combines the three components red, green and blue to an RGB value, which can be converted to e.g. Hex +func RGBToHEX(red, green, blue byte) (hex uint) { + // Sets the bits of blue in position 1-8, green in 9-16 and red in 17-24 + + // Red: 00110100 + // Green: 10011000 + // Blue: 11011011 + // RGB: + // R << 16: [00110100] 00000000 00000000 | + // G << 8 : 00000000 {10011000} 00000000 | + // B : 00000000 00000000 <11011011> = + // [00110100] {10011000} <11011011> + return (uint(red) << 16) | (uint(green) << 8) | uint(blue) +} diff --git a/conversion/rgbhex_test.go b/conversion/rgbhex_test.go new file mode 100644 index 000000000..7b56cbe4d --- /dev/null +++ b/conversion/rgbhex_test.go @@ -0,0 +1,51 @@ +package conversion + +import "testing" + +var HEX = []uint{ + 0x1abc9c, + 0x3498db, + 0x9b59b6, +} + +var RGB = [][]byte{ + {26, 188, 156}, + {52, 152, 219}, + {155, 89, 182}, +} + +func TestHEXToRGB(t *testing.T) { + for i := 0; i < len(HEX); i++ { + hex := HEX[i] + expected := RGB[i] + resultR, resultG, resultB := HEXToRGB(hex) + if resultR != expected[0] || resultG != expected[1] || resultB != expected[2] { + t.Errorf("HEXToRGB(%d) = %d,%d,%d; want %d,%d,%d", + hex, resultR, resultG, resultB, expected[0], expected[1], expected[2]) + } + } +} + +func BenchmarkHEXToRGB(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _, _ = HEXToRGB(0xdeadbe) + } +} + +func TestRGBToHEX(t *testing.T) { + for i := 0; i < len(RGB); i++ { + args := RGB[i] + expected := HEX[i] + result := RGBToHEX(args[0], args[1], args[2]) + if result != expected { + t.Errorf("RGBToHEX(%d,%d,%d) = %d; want %d", + args[0], args[1], args[2], result, expected) + } + } +} + +func BenchmarkRGBToHEX(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = RGBToHEX(222, 173, 190) + } +} From 6fd35401da22140437d2f4de34d6306234bb702e Mon Sep 17 00:00:00 2001 From: Eric Johnson Date: Thu, 21 Oct 2021 00:23:17 -0500 Subject: [PATCH 268/488] eliminate duplication of test cases for sort (#397) Co-authored-by: eric.johnson --- sort/quicksort.go | 13 +++-- sort/sorts_test.go | 126 ++++----------------------------------------- 2 files changed, 21 insertions(+), 118 deletions(-) diff --git a/sort/quicksort.go b/sort/quicksort.go index 9db6c23bd..6ecbac20e 100644 --- a/sort/quicksort.go +++ b/sort/quicksort.go @@ -20,14 +20,21 @@ func partition(arr []int, low, high int) int { return index + 1 } -func QuickSort(arr []int, low, high int) { +// QuickSortRange Sorts the specified range within the array +func QuickSortRange(arr []int, low, high int) { if len(arr) <= 1 { return } if low < high { pivot := partition(arr, low, high) - QuickSort(arr, low, pivot-1) - QuickSort(arr, pivot+1, high) + QuickSortRange(arr, low, pivot-1) + QuickSortRange(arr, pivot+1, high) } } + +// QuickSort Sorts the entire array +func QuickSort(arr []int) []int { + QuickSortRange(arr, 0, len(arr)-1) + return arr +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 3eaa72af2..3a015e687 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -57,6 +57,7 @@ func testFramework(t *testing.T, sortingFunction func([]int) []int) { expected: []int{1}, name: "Singleton", }, + // Empty slice { input: []int{}, expected: []int{}, @@ -98,74 +99,7 @@ func TestHeap(t *testing.T) { } func TestQuick(t *testing.T) { - testCases := []struct { - input []int - expected []int - name string - }{ - //Sorted slice - { - input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Sorted Unsigned", - }, - //Reversed slice - { - input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Reversed Unsigned", - }, - - //Sorted slice - { - input: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Sorted Signed", - }, - - //Reversed slice - { - input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Reversed Signed", - }, - - //Reversed slice, even length - { - input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Reversed Signed #2", - }, - - //Random order with repetitions - { - input: []int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, - name: "Random order Signed", - }, - //Single-entry slice - { - input: []int{1}, - expected: []int{1}, - name: "Singleton", - }, - { - input: []int{}, - expected: []int{}, - name: "Empty Slice", - }, - } - - for _, test := range testCases { - t.Run(test.name, func(t *testing.T) { - QuickSort(test.input, 0, len(test.input)-1) - if !reflect.DeepEqual(test.input, test.expected) { - t.Errorf("test %s failed", test.name) - t.Errorf("actual %v expected %v", test.input, test.expected) - } - }) - } - + testFramework(t, QuickSort) } func TestShell(t *testing.T) { @@ -184,14 +118,9 @@ func TestImprovedSimple(t *testing.T) { testFramework(t, ImprovedSimpleSort) } -// Very slow, consider commenting -// func TestSelection(t *testing.T) { -// testFramework(t, SelectionSort) -// } - -/* func TestTopological(t *testing.T) { -testFramework(t, topologicalSort) -} */ +func TestSelection(t *testing.T) { + testFramework(t, SelectionSort) +} //END TESTS @@ -236,6 +165,9 @@ func benchmarkFramework(b *testing.B, f func(arr []int) []int) { } } } + +//BEGIN BENCHMARKS + func BenchmarkBubble(b *testing.B) { benchmarkFramework(b, bubbleSort) } @@ -257,45 +189,7 @@ func BenchmarkHeap(b *testing.B) { } func BenchmarkQuick(b *testing.B) { - var sortTests = []struct { - input []int - expected []int - name string - }{ - //Sorted slice - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, - //Reversed slice - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, - - //Sorted slice - {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, - - //Reversed slice - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, - - //Reversed slice, even length - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, - - //Random order with repetitions - {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, - - //Empty slice - {[]int{}, []int{}, "Empty"}, - //Single-entry slice - {[]int{1}, []int{1}, "Singleton"}, - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - QuickSort(test.input, 0, len(test.input)-1) - } - } + benchmarkFramework(b, QuickSort) } func BenchmarkShell(b *testing.B) { @@ -318,3 +212,5 @@ func BenchmarkImprovedSimple(b *testing.B) { func BenchmarkSelection(b *testing.B) { benchmarkFramework(b, SelectionSort) } + +//END BENCHMARKS From 278c46a32347186e85b577f40f1af0a823695e3f Mon Sep 17 00:00:00 2001 From: Philip Schikora Date: Thu, 21 Oct 2021 17:26:48 +0200 Subject: [PATCH 269/488] add counting sort (#392) Co-authored-by: Administrator --- sort/countingsort.go | 25 ++++++++++ sort/sorts_test.go | 115 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 sort/countingsort.go diff --git a/sort/countingsort.go b/sort/countingsort.go new file mode 100644 index 000000000..9ac7fbdfc --- /dev/null +++ b/sort/countingsort.go @@ -0,0 +1,25 @@ +// countingsort.go +// description: Implementation of counting sort algorithm +// details: A simple counting sort algorithm implementation +// author [Phil](https://github.com/pschik) +// see sort_test.go for a test implementation, test function TestQuickSort + +// package sort provides primitives for sorting slices and user-defined collections +package sort + +func Count(data []int) []int { + var aMin, aMax = -1000, 1000 + count := make([]int, aMax-aMin+1) + for _, x := range data { + count[x-aMin]++ + } + z := 0 + for i, c := range count { + for c > 0 { + data[z] = i + aMin + z++ + c-- + } + } + return data +} diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 3a015e687..db7ea1241 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -23,28 +23,24 @@ func testFramework(t *testing.T, sortingFunction func([]int) []int) { expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, name: "Reversed Unsigned", }, - //Sorted slice { input: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, name: "Sorted Signed", }, - //Reversed slice { input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, name: "Reversed Signed", }, - //Reversed slice, even length { input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, name: "Reversed Signed #2", }, - //Random order with repetitions { input: []int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, @@ -98,8 +94,73 @@ func TestHeap(t *testing.T) { testFramework(t, HeapSort) } +func TestCount(t *testing.T) { + testFramework(t, Count) +} + func TestQuick(t *testing.T) { - testFramework(t, QuickSort) + testCases := []struct { + input []int + expected []int + name string + }{ + //Sorted slice + { + input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Sorted Unsigned", + }, + //Reversed slice + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Unsigned", + }, + //Sorted slice + { + input: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Sorted Signed", + }, + //Reversed slice + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Signed", + }, + //Reversed slice, even length + { + input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + name: "Reversed Signed #2", + }, + //Random order with repetitions + { + input: []int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, + expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, + name: "Random order Signed", + }, + //Single-entry slice + { + input: []int{1}, + expected: []int{1}, + name: "Singleton", + }, + { + input: []int{}, + expected: []int{}, + name: "Empty Slice", + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + QuickSort(test.input) + if !reflect.DeepEqual(test.input, test.expected) { + t.Errorf("test %s failed", test.name) + t.Errorf("actual %v expected %v", test.input, test.expected) + } + }) + } } func TestShell(t *testing.T) { @@ -136,23 +197,18 @@ func benchmarkFramework(b *testing.B, f func(arr []int) []int) { //Reversed slice {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, - //Sorted slice {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, - //Reversed slice {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, - //Reversed slice, even length {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, - //Random order with repetitions {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, - //Empty slice {[]int{}, []int{}, "Empty"}, //Single-entry slice @@ -188,8 +244,45 @@ func BenchmarkHeap(b *testing.B) { benchmarkFramework(b, HeapSort) } +func BenchmarkCount(b *testing.B) { + benchmarkFramework(b, Count) +} + func BenchmarkQuick(b *testing.B) { - benchmarkFramework(b, QuickSort) + var sortTests = []struct { + input []int + expected []int + name string + }{ + //Sorted slice + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, + //Reversed slice + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, + []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, + //Sorted slice + {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, + //Reversed slice + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, + //Reversed slice, even length + {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, + //Random order with repetitions + {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, + []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, + //Empty slice + {[]int{}, []int{}, "Empty"}, + //Single-entry slice + {[]int{1}, []int{1}, "Singleton"}, + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, test := range sortTests { + QuickSort(test.input) + } + } } func BenchmarkShell(b *testing.B) { From 2019e663d7b0e94b12384aa73432dbee1a0c0108 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Fri, 22 Oct 2021 16:13:00 +0530 Subject: [PATCH 270/488] feat: use test framework for quick-sort tests (#413) --- sort/sorts_test.go | 98 +--------------------------------------------- 1 file changed, 2 insertions(+), 96 deletions(-) diff --git a/sort/sorts_test.go b/sort/sorts_test.go index db7ea1241..21635514d 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -99,68 +99,7 @@ func TestCount(t *testing.T) { } func TestQuick(t *testing.T) { - testCases := []struct { - input []int - expected []int - name string - }{ - //Sorted slice - { - input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Sorted Unsigned", - }, - //Reversed slice - { - input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Reversed Unsigned", - }, - //Sorted slice - { - input: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Sorted Signed", - }, - //Reversed slice - { - input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Reversed Signed", - }, - //Reversed slice, even length - { - input: []int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - name: "Reversed Signed #2", - }, - //Random order with repetitions - { - input: []int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, - expected: []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, - name: "Random order Signed", - }, - //Single-entry slice - { - input: []int{1}, - expected: []int{1}, - name: "Singleton", - }, - { - input: []int{}, - expected: []int{}, - name: "Empty Slice", - }, - } - for _, test := range testCases { - t.Run(test.name, func(t *testing.T) { - QuickSort(test.input) - if !reflect.DeepEqual(test.input, test.expected) { - t.Errorf("test %s failed", test.name) - t.Errorf("actual %v expected %v", test.input, test.expected) - } - }) - } + testFramework(t, QuickSort) } func TestShell(t *testing.T) { @@ -249,40 +188,7 @@ func BenchmarkCount(b *testing.B) { } func BenchmarkQuick(b *testing.B) { - var sortTests = []struct { - input []int - expected []int - name string - }{ - //Sorted slice - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Unsigned"}, - //Reversed slice - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, - //Sorted slice - {[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted Signed"}, - //Reversed slice - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed"}, - //Reversed slice, even length - {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Signed #2"}, - //Random order with repetitions - {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, - []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, - //Empty slice - {[]int{}, []int{}, "Empty"}, - //Single-entry slice - {[]int{1}, []int{1}, "Singleton"}, - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - QuickSort(test.input) - } - } + benchmarkFramework(b, QuickSort) } func BenchmarkShell(b *testing.B) { From 004cc9d940c1724b8f19c1efa941deb808123f07 Mon Sep 17 00:00:00 2001 From: Fernanda Kawasaki <50497814+fernandakawasaki@users.noreply.github.com> Date: Sat, 23 Oct 2021 05:04:41 -0300 Subject: [PATCH 271/488] merge: feat: add palindrome checker (#386) * feat: add ispalindrome algorithm * test: add test for ispalindrome algorithm * fix: change package name to respect naming conventions * fix: add description and adapt to utf8 * Update strings/palindrome/ispalindrome.go Co-authored-by: Taj * fix: Update strings/palindrome/ispalindrome.go Co-authored-by: Rak Laptudirm Co-authored-by: Taj --- strings/palindrome/ispalindrome.go | 37 +++++++++++++++++ strings/palindrome/ispalindrome_test.go | 53 +++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 strings/palindrome/ispalindrome.go create mode 100644 strings/palindrome/ispalindrome_test.go diff --git a/strings/palindrome/ispalindrome.go b/strings/palindrome/ispalindrome.go new file mode 100644 index 000000000..65d525dd3 --- /dev/null +++ b/strings/palindrome/ispalindrome.go @@ -0,0 +1,37 @@ +// ispalindrome.go +// description: Checks if a given string is palindrome or not +// details: +// Palindromes are expressions that read the same way forwards and backwards. +// They can be words/phrases (like "racecar" and "Do geese see God?"), or even +// numbers (like "02/02/2020"). Usually punctuation signs, capitalization +// and spaces are ignored. A regular expression was used to achieve that. +// See more information on: https://en.wikipedia.org/wiki/Palindrome +// author(s) [Fernanda Kawasaki](https://github.com/fernandakawasaki) +// see ispalindrome_test.go + +package palindrome + +import ( + "regexp" + "strings" +) + +func cleanString(text string) string { + clean_text := strings.ToLower(text) + clean_text = strings.Join(strings.Fields(clean_text), "") // Remove spaces + regex, _ := regexp.Compile(`[^\p{L}\p{N} ]+`) // Regular expression for alphanumeric only characters + return regex.ReplaceAllString(clean_text, "") +} + +func IsPalindrome(text string) bool { + clean_text := cleanString(text) + var i, j int + rune := []rune(clean_text) + for i = 0; i < len(rune)/2; i++ { + j = len(rune) - 1 - i + if string(rune[i]) != string(rune[j]) { + return false + } + } + return true +} diff --git a/strings/palindrome/ispalindrome_test.go b/strings/palindrome/ispalindrome_test.go new file mode 100644 index 000000000..409e6bb8f --- /dev/null +++ b/strings/palindrome/ispalindrome_test.go @@ -0,0 +1,53 @@ +package palindrome + +import ( + "testing" +) + +var testCases = []struct { + name string // test description + input string // user input + expected bool // expected return +}{ + { + "non palindrome string", + "According to the laws of aviation bees can't flyã", + false, + }, + { + "non palindrome string", + "Alô?", + false, + }, + { + "palindrome string 1", + "Do geese see God?", + true, + }, + { + "palindrome string 2", + "ΝΙΨΟΝ ΑΝΟΜΗΜΑΤΑ ΜΗ ΜΟΝΑΝ ΟΨΙΝ", + true, + }, + { + "palindrome string 3", + "Was it a car or a cat I saw?", + true, + }, + { + "empty string", + "", + true, + }, +} + +func TestIsPalindrome(t *testing.T) { + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + func_result := IsPalindrome(test.input) + if test.expected != func_result { + t.Errorf("Expected answer '%t' for string '%s' but answer given was %t", test.expected, test.input, func_result) + } + }) + } +} From c722bdc56fe7d8f3f881019c5a1bbb13b378750b Mon Sep 17 00:00:00 2001 From: Calebe Oliveira <30943380+calebeof@users.noreply.github.com> Date: Sat, 23 Oct 2021 05:07:31 -0300 Subject: [PATCH 272/488] merge: feat: add Segment Tree (#376) * add Segment Tree algorithm and test * address comments * add lazy tree and range updates * add update comment * export Array, SegmentTree and LazyTree * adjust min and max Co-authored-by: Rak Laptudirm Co-authored-by: Andrii Siriak --- structure/segmenttree/segmenttree.go | 134 ++++++++++++++++++++++ structure/segmenttree/segmenttree_test.go | 83 ++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 structure/segmenttree/segmenttree.go create mode 100644 structure/segmenttree/segmenttree_test.go diff --git a/structure/segmenttree/segmenttree.go b/structure/segmenttree/segmenttree.go new file mode 100644 index 000000000..acdae7b35 --- /dev/null +++ b/structure/segmenttree/segmenttree.go @@ -0,0 +1,134 @@ +//Segment Tree Data Structure for Range Queries +//Build: O(n*log(n)) +//Query: O(log(n)) +//Update: O(log(n)) +//reference: https://cp-algorithms.com/data_structures/segment_tree.html + +package segmenttree + +import ( + "github.com/TheAlgorithms/Go/math/max" + "github.com/TheAlgorithms/Go/math/min" +) + +const emptyLazyNode = -1 + +//SegmentTree with original Array and the Segment Tree Array +type SegmentTree struct { + Array []int + SegmentTree []int + LazyTree []int +} + +//Propagate lazy tree node values +func (s *SegmentTree) Propagate(node int, leftNode int, rightNode int) { + if s.LazyTree[node] != emptyLazyNode { + //add lazy node value multiplied by (right-left+1), which represents all interval + //this is the same of adding a value on each node + s.SegmentTree[node] += (rightNode - leftNode + 1) * s.LazyTree[node] + + if leftNode == rightNode { + //leaf node + s.Array[leftNode] = s.LazyTree[node] + } else { + //propagate lazy node value for children nodes + s.LazyTree[2*node] = s.LazyTree[node] + s.LazyTree[2*node+1] = s.LazyTree[node] + } + + //clear lazy node + s.LazyTree[node] = emptyLazyNode + } +} + +//Query on interval [firstIndex, leftIndex] +//node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +func (s *SegmentTree) Query(node int, leftNode int, rightNode int, firstIndex int, lastIndex int) int { + if (firstIndex > lastIndex) || (leftNode > rightNode) { + //outside the interval + return 0 + } + + //propagate lazy tree + s.Propagate(node, leftNode, rightNode) + + if (leftNode >= firstIndex) && (rightNode <= lastIndex) { + //inside the interval + return s.SegmentTree[node] + } + + //get sum of left and right nodes + mid := (leftNode + rightNode) / 2 + + leftNodeSum := s.Query(2*node, leftNode, mid, firstIndex, min.Int(mid, lastIndex)) + rightNodeSum := s.Query(2*node+1, mid+1, rightNode, max.Int(firstIndex, mid+1), lastIndex) + + return leftNodeSum + rightNodeSum +} + +//Update Segment Tree +//node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +//index is the Array index that you want to update +//value is the value that you want to override +func (s *SegmentTree) Update(node int, leftNode int, rightNode int, firstIndex int, lastIndex int, value int) { + //propagate lazy tree + s.Propagate(node, leftNode, rightNode) + + if (firstIndex > lastIndex) || (leftNode > rightNode) { + //outside the interval + return + } + + if (leftNode >= firstIndex) && (rightNode <= lastIndex) { + //inside the interval + s.LazyTree[node] = value + s.Propagate(node, leftNode, rightNode) + } else { + //update left and right nodes + mid := (leftNode + rightNode) / 2 + + s.Update(2*node, leftNode, mid, firstIndex, min.Int(mid, lastIndex), value) + s.Update(2*node+1, mid+1, rightNode, max.Int(firstIndex, mid+1), lastIndex, value) + + s.SegmentTree[node] = s.SegmentTree[2*node] + s.SegmentTree[2*node+1] + } +} + +//Build Segment Tree +//node, leftNode and rightNode always should start with 1, 0 and len(Array)-1 +func (s *SegmentTree) Build(node int, left int, right int) { + if left == right { + //leaf node + s.SegmentTree[node] = s.Array[left] + } else { + //get sum of left and right nodes + mid := (left + right) / 2 + + s.Build(2*node, left, mid) + s.Build(2*node+1, mid+1, right) + + s.SegmentTree[node] = s.SegmentTree[2*node] + s.SegmentTree[2*node+1] + } +} + +func NewSegmentTree(Array []int) *SegmentTree { + if len(Array) == 0 { + return nil + } + + segTree := SegmentTree{ + Array: Array, + SegmentTree: make([]int, 4*len(Array)), + LazyTree: make([]int, 4*len(Array)), + } + + for i := range segTree.LazyTree { + //fill LazyTree with empty lazy nodes + segTree.LazyTree[i] = emptyLazyNode + } + + //starts with node 1 and interval [0, len(arr)-1] inclusive + segTree.Build(1, 0, len(Array)-1) + + return &segTree +} diff --git a/structure/segmenttree/segmenttree_test.go b/structure/segmenttree/segmenttree_test.go new file mode 100644 index 000000000..c8e2c9e45 --- /dev/null +++ b/structure/segmenttree/segmenttree_test.go @@ -0,0 +1,83 @@ +package segmenttree + +import ( + "testing" +) + +//Query interval +type query struct { + firstIndex int + lastIndex int +} + +type update struct { + firstIndex int + lastIndex int + value int +} + +func TestSegmentTree(t *testing.T) { + var segmentTreeTestData = []struct { + description string + array []int + updates []update + queries []query + expected []int + }{ + { + description: "test empty array", + array: []int{}, + queries: []query{{0, 0}}, + expected: []int{0}, + }, + { + description: "test array with size 5", + array: []int{1, 2, 3, 4, 5}, + queries: []query{{0, 5}, {0, 2}, {2, 4}}, + expected: []int{15, 6, 12}, + }, + { + description: "test array with size 5 and updates", + array: []int{1, 2, 3, 4, 5}, + updates: []update{{firstIndex: 1, lastIndex: 1, value: 2}, + {firstIndex: 2, lastIndex: 2, value: 3}}, + queries: []query{{0, 5}, {0, 2}, {2, 4}}, + expected: []int{20, 11, 15}, + }, + { + description: "test array with size 5 and single index updates", + array: []int{1, 2, 3, 4, 5}, + updates: []update{{firstIndex: 1, lastIndex: 1, value: 2}, + {firstIndex: 2, lastIndex: 2, value: 3}}, + queries: []query{{0, 5}, {0, 2}, {2, 4}}, + expected: []int{20, 11, 15}, + }, + { + description: "test array with size 5 and range updates", + array: []int{1, 2, 3, 4, 5}, + updates: []update{{firstIndex: 0, lastIndex: 4, value: 2}, + {firstIndex: 2, lastIndex: 4, value: 2}}, + queries: []query{{0, 5}, {0, 2}, {2, 4}}, + expected: []int{31, 14, 24}, + }, + } + for _, test := range segmentTreeTestData { + t.Run(test.description, func(t *testing.T) { + segmentTree := NewSegmentTree(test.array) + + for i := 0; i < len(test.updates); i++ { + segmentTree.Update(1, 0, len(test.array)-1, test.updates[i].firstIndex, test.updates[i].lastIndex, test.updates[i].value) + } + + for i := 0; i < len(test.queries); i++ { + result := segmentTree.Query(1, 0, len(test.array)-1, test.queries[i].firstIndex, test.queries[i].lastIndex) + + if result != test.expected[i] { + t.Logf("FAIL: %s", test.description) + t.Fatalf("Expected result: %d\nFound: %d\n", test.expected[i], result) + } + } + + }) + } +} From 5f9d41bca6c788aa214536ffa3d74dfd2f5ef623 Mon Sep 17 00:00:00 2001 From: Metta Ong Date: Sat, 23 Oct 2021 19:05:47 +0800 Subject: [PATCH 273/488] feat: bipartite checking implementation (#400) --- graph/coloring/bipartite.go | 49 ++++++++++++++++++++++++++++++++ graph/coloring/bipartite_test.go | 32 +++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 graph/coloring/bipartite.go create mode 100644 graph/coloring/bipartite_test.go diff --git a/graph/coloring/bipartite.go b/graph/coloring/bipartite.go new file mode 100644 index 000000000..f27c7dc54 --- /dev/null +++ b/graph/coloring/bipartite.go @@ -0,0 +1,49 @@ +package coloring + +func (g *Graph) TryBipartiteColoring() map[int]Color { + // 0 is uncolored, 1/2 is colors + colors := make(map[int]Color) + visited := make(map[int]bool) + + for i := range g.edges { + colors[i] = 0 + visited[i] = false + } + + var color_node func(int) + color_node = func(s int) { + visited[s] = true + coloring := []Color{0, 2, 1} + + for n := range g.edges[s] { + if colors[n] == 0 { + colors[n] = coloring[colors[s]] + } + if !visited[n] { + color_node(n) + } + } + } + + for i := range g.edges { + if colors[i] == 0 { + colors[i] = 1 + color_node(i) + } + } + + return colors +} + +// basically tries to color the graph in two colors if each edge +// connects 2 differently colored nodes the graph can be considered bipartite +func BipartiteCheck(N int, edges [][]int) bool { + var graph Graph + for i := 0; i < N; i++ { + graph.AddVertex(i) + } + for _, e := range edges { + graph.AddEdge(e[0], e[1]) + } + return graph.ValidateColorsOfVertex(graph.TryBipartiteColoring()) == nil +} diff --git a/graph/coloring/bipartite_test.go b/graph/coloring/bipartite_test.go new file mode 100644 index 000000000..0b60ae79b --- /dev/null +++ b/graph/coloring/bipartite_test.go @@ -0,0 +1,32 @@ +package coloring + +import ( + "testing" +) + +var testCases = []struct { + name string + N int + isBipartite bool + edges [][]int +}{ + { + "basic true", 2, true, + [][]int{{1, 0}}, + }, + { + "basic false", 3, false, + [][]int{{0, 1}, {1, 2}, {2, 0}}, + }, +} + +func TestBipartite(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := BipartiteCheck(tc.N, tc.edges) + if tc.isBipartite != actual { + t.Errorf("failed %s: %v", tc.name, tc.edges) + } + }) + } +} From 18451c60828d081cb42aa367a53e0713af120e2e Mon Sep 17 00:00:00 2001 From: Motasim <44056349+motasimmakki@users.noreply.github.com> Date: Sat, 23 Oct 2021 16:38:53 +0530 Subject: [PATCH 274/488] feat: Binary to Decimal Conversion (#398) --- README.md | 1 + conversion/binarytodecimal.go | 41 ++++++++++++++++++++++++++ conversion/binarytodecimal_test.go | 46 ++++++++++++++++++++++++++++++ conversion/decimaltobinary.go | 12 ++++---- conversion/decimaltobinary_test.go | 12 ++++---- 5 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 conversion/binarytodecimal.go create mode 100644 conversion/binarytodecimal_test.go diff --git a/README.md b/README.md index 5817908d6..c6932d69d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. * [Roman Numeral To Integer](./conversion/romantointeger.go) * [Integer To Roman Numeral](./conversion/integertoroman.go) * [Decimal To Binary](./conversion/decimaltobinary.go) +* [Binary To Decimal](./conversion/binarytodecimal.go) ### Data Structures * [AVL Tree](./structure/avl/avl.go) diff --git a/conversion/binarytodecimal.go b/conversion/binarytodecimal.go new file mode 100644 index 000000000..5cfada517 --- /dev/null +++ b/conversion/binarytodecimal.go @@ -0,0 +1,41 @@ +/* +Author: Motasim +GitHub: https://github.com/motasimmakki +Date: 19-Oct-2021 +*/ + +// This algorithm will convert any Binary number(0 or 1) to Decimal number(+ve number). +// https://en.wikipedia.org/wiki/Binary_number +// https://en.wikipedia.org/wiki/Decimal +// Function receives a Binary Number as string and returns the Decimal number as integer. +// Suppoted Binary number range is 0 to 2^(31-1). + +// Package name. +package conversion + +// Importing necessary package. +import ( + "errors" + "regexp" +) + +var isValid = regexp.MustCompile("^[0-1]{1,}$").MatchString + +// BinaryToDecimal() function that will take Binary number as string, +// and return it's Decimal equivalent as integer. +func BinaryToDecimal(binary string) (int, error) { + if !isValid(binary) { + return -1, errors.New("not a valid binary string") + } + if len(binary) > 32 { + return -1, errors.New("binary number must be in range 0 to 2^(31-1)") + } + var result, base int = 0, 1 + for i := len(binary) - 1; i >= 0; i-- { + if binary[i] == '1' { + result += base + } + base *= 2 + } + return result, nil +} diff --git a/conversion/binarytodecimal_test.go b/conversion/binarytodecimal_test.go new file mode 100644 index 000000000..3cbec8099 --- /dev/null +++ b/conversion/binarytodecimal_test.go @@ -0,0 +1,46 @@ +package conversion + +import "testing" + +var binaryTestCases = map[string]int{ + "0": 0, "1": 1, "10": 2, "11": 3, "100": 4, + "101": 5, "110": 6, "111": 7, "1000": 8, "1001": 9, + "1010": 10, "1011": 11, "1100": 12, "1101": 13, "1110": 14, + "1111": 15, "10000": 16, "10001": 17, "10010": 18, "10011": 19, + "10100": 20, "10101": 21, "10110": 22, "10111": 23, "11000": 24, + "11001": 25, "11010": 26, "11011": 27, "11100": 28, "11101": 29, + "11110": 30, "11111": 31, "100000": 32, "100001": 33, "100010": 34, + "100011": 35, "100100": 36, "100101": 37, "100110": 38, "100111": 39, + "101000": 40, "101001": 41, "101010": 42, "101011": 43, "101100": 44, + "101101": 45, "101110": 46, "101111": 47, "110000": 48, "110001": 49, + "110010": 50, "110011": 51, "110100": 52, "110101": 53, "110110": 54, + "110111": 55, "111000": 56, "111001": 57, "111010": 58, "111011": 59, + "111100": 60, "111101": 61, "111110": 62, "111111": 63, "1000000": 64, + "1000001": 65, "1000010": 66, "1000011": 67, "1000100": 68, "1000101": 69, + "1000110": 70, "1000111": 71, "1001000": 72, "1001001": 73, "1001010": 74, + "1001011": 75, "1001100": 76, "1001101": 77, "1001110": 78, "1001111": 79, + "1010000": 80, "1010001": 81, "1010010": 82, "1010011": 83, "1010100": 84, + "1010101": 85, "1010110": 86, "1010111": 87, "1011000": 88, "1011001": 89, + "1011010": 90, "1011011": 91, "1011100": 92, "1011101": 93, "1011110": 94, + "1011111": 95, "1100000": 96, "1100001": 97, "1100010": 98, "1100011": 99, + "1100100": 100, +} + +func TestBinaryToDecimal(t *testing.T) { + for input, expected := range binaryTestCases { + out, err := BinaryToDecimal(input) + if err != nil { + t.Errorf("BinaryToDecimal(%s) returned an error %s", input, err.Error()) + } + if out != expected { + t.Errorf("BinaryToDecimal(%s) = %d; want %d", input, out, expected) + } + } +} + +func BenchmarkBinaryToDecimal(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _ = BinaryToDecimal("1100100") + } +} diff --git a/conversion/decimaltobinary.go b/conversion/decimaltobinary.go index 749c70c28..6b78bb16c 100644 --- a/conversion/decimaltobinary.go +++ b/conversion/decimaltobinary.go @@ -18,9 +18,9 @@ import ( "strconv" ) -// Inverse() function that will take string, -// and returns the inverse of that string. -func Inverse(str string) string { +// Reverse() function that will take string, +// and returns the reverse of that string. +func Reverse(str string) string { rStr := []rune(str) for i, j := 0, len(rStr)-1; i < len(rStr)/2; i, j = i+1, j-1 { rStr[i], rStr[j] = rStr[j], rStr[i] @@ -28,9 +28,9 @@ func Inverse(str string) string { return string(rStr) } -// Convert() function that will take Decimal number as int, +// DecimalToBinary() function that will take Decimal number as int, // and return it's Binary equivalent as string. -func Convert(num int) (string, error) { +func DecimalToBinary(num int) (string, error) { if num < 0 { return "", errors.New("integer must have +ve value") } @@ -42,5 +42,5 @@ func Convert(num int) (string, error) { result += strconv.Itoa(num & 1) num >>= 1 } - return Inverse(result), nil + return Reverse(result), nil } diff --git a/conversion/decimaltobinary_test.go b/conversion/decimaltobinary_test.go index 9791da47c..d8ec05fca 100644 --- a/conversion/decimaltobinary_test.go +++ b/conversion/decimaltobinary_test.go @@ -26,21 +26,21 @@ var decimalTestCases = map[int]string{ 100: "1100100", } -func TestConvert(t *testing.T) { +func TestDecimalToBinary(t *testing.T) { for input, expected := range decimalTestCases { - out, err := Convert(input) + out, err := DecimalToBinary(input) if err != nil { - t.Errorf("Convert(%d) returned an error %s", input, err.Error()) + t.Errorf("DecimalToBinary(%d) returned an error %s", input, err.Error()) } if out != expected { - t.Errorf("Convert(%d) = %s; want %s", input, out, expected) + t.Errorf("DecimalToBinary(%d) = %s; want %s", input, out, expected) } } } -func BenchmarkConvert(b *testing.B) { +func BenchmarkDecimalToBinary(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - _, _ = Convert(100) + _, _ = DecimalToBinary(100) } } From a4ea2bb7b7485311e766962fc1fe26c427febe58 Mon Sep 17 00:00:00 2001 From: Metta Ong Date: Sun, 24 Oct 2021 14:24:51 +0800 Subject: [PATCH 275/488] feat: implementation of topological sort (#399) --- graph/depthfirstsearch.go | 13 +++++++-- graph/topological.go | 35 +++++++++++++++++++++++ graph/topological_test.go | 59 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 graph/topological.go create mode 100644 graph/topological_test.go diff --git a/graph/depthfirstsearch.go b/graph/depthfirstsearch.go index a4afb7647..c035c79f5 100644 --- a/graph/depthfirstsearch.go +++ b/graph/depthfirstsearch.go @@ -18,7 +18,7 @@ func NotExist(target int, slice []int) bool { return true } -func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool) { +func DepthFirstSearchHelper(start, end int, nodes []int, edges [][]bool, showroute bool) ([]int, bool) { var route []int var stack []int startIdx := GetIdx(start, nodes) @@ -42,7 +42,16 @@ func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool) return route, true } } - return nil, false + + if showroute { + return route, false + } else { + return nil, false + } +} + +func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool) { + return DepthFirstSearchHelper(start, end, nodes, edges, false) } // func main() { diff --git a/graph/topological.go b/graph/topological.go new file mode 100644 index 000000000..89fe46c42 --- /dev/null +++ b/graph/topological.go @@ -0,0 +1,35 @@ +package graph + +// Assumes that graph given is valid and possible to +// get a topo ordering. +// constraints are array of []int{a, b}, representing +// an edge going from a to b +func Topological(N int, constraints [][]int) []int { + dependencies := make([]int, N) + nodes := make([]int, N) + for i := range nodes { + nodes[i] = i + } + edges := make([][]bool, N) + for i := range edges { + edges[i] = make([]bool, N) + } + + for _, c := range constraints { + a := c[0] + b := c[1] + dependencies[b]++ + edges[a][b] = true + } + + ans := []int{} + for s := 0; s < N; s++ { + // Only start walking from top level nodes + if dependencies[s] == 0 { + route, _ := DepthFirstSearchHelper(s, N, nodes, edges, true) + ans = append(ans, route...) + } + } + + return ans +} diff --git a/graph/topological_test.go b/graph/topological_test.go new file mode 100644 index 000000000..2a914e0ae --- /dev/null +++ b/graph/topological_test.go @@ -0,0 +1,59 @@ +package graph + +import ( + "testing" +) + +var testCases = []struct { + name string + N int + constraints [][]int +}{ + { + "basic test", 2, + [][]int{{1, 0}}, + }, + { + "double path", 7, + [][]int{ + {0, 1}, {1, 3}, {3, 5}, + {0, 2}, {2, 4}, {4, 6}}, + }, + { + "star shape", 7, + [][]int{ + {0, 1}, {0, 3}, {0, 5}, + {0, 2}, {0, 4}, {0, 6}}, + }, + { + "tree shape", 7, + [][]int{ + {0, 1}, {1, 3}, {1, 5}, + {0, 2}, {2, 4}, {2, 6}}, + }, +} + +func TestTopological(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := Topological(tc.N, tc.constraints) + + visited := make([]bool, tc.N) + positions := make([]int, tc.N) + for i := 0; i < tc.N; i++ { + positions[actual[i]] = i + visited[actual[i]] = true + } + for _, v := range visited { + if !v { + t.Errorf("nodes not all visited, %v", visited) + } + } + for _, c := range tc.constraints { + if positions[c[0]] > positions[c[1]] { + t.Errorf("%v dun satisfy %v", actual, c) + } + } + }) + } +} From b9166e21f611a0cf9e1252b6ca534a045dff3cb5 Mon Sep 17 00:00:00 2001 From: FuXiang Shu <6470547+Crazy3lf@users.noreply.github.com> Date: Sun, 24 Oct 2021 17:07:12 +0800 Subject: [PATCH 276/488] merge: feat: implementation of jump search (#412) Co-authored-by: Rak Laptudirm --- search/jump.go | 55 +++++++++++++++++++++++++++++++++++++++++++++ search/jump_test.go | 23 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 search/jump.go create mode 100644 search/jump_test.go diff --git a/search/jump.go b/search/jump.go new file mode 100644 index 000000000..163dea55d --- /dev/null +++ b/search/jump.go @@ -0,0 +1,55 @@ +// jump.go +// description: Implementation of jump search +// details: +// A search algorithm for ordered list that jump through the list to narrow down the range +// before performing a linear search +// reference: https://en.wikipedia.org/wiki/Jump_search +// see jump_test.go for a test implementation, test function TestJump + +package search + +import "math" + +// Jump search works by jumping multiple steps ahead in sorted list until it find an item larger than target, +// then create a sublist of item from the last searched item up to the current item and perform a linear search. +func Jump(array []int, target int) (int, error) { + n := len(array) + if n == 0 { + return -1, ErrNotFound + } + + // the optimal value of step is square root of the length of list + step := int(math.Round(math.Sqrt(float64(n)))) + + prev := 0 // previous index + curr := step // current index + for array[curr-1] < target { + prev = curr + if prev >= len(array) { + return -1, ErrNotFound + } + + curr += step + + // prevent jumping over list range + if curr > n { + curr = n + } + } + + // perform linear search from index prev to index curr + for array[prev] < target { + prev++ + + // if reach end of range, indicate target not found + if prev == curr { + return -1, ErrNotFound + } + } + if array[prev] == target { + return prev, nil + } + + return -1, ErrNotFound + +} diff --git a/search/jump_test.go b/search/jump_test.go new file mode 100644 index 000000000..4c27df4f6 --- /dev/null +++ b/search/jump_test.go @@ -0,0 +1,23 @@ +package search + +import "testing" + +func TestJump(t *testing.T) { + for _, test := range searchTests { + actualValue, actualError := Jump(test.data, test.key) + if actualValue != test.expected { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected '%d', get '%d'", test.name, test.data, test.key, test.expected, actualValue) + } + if actualError != test.expectedError { + t.Errorf("test '%s' failed: input array '%v' with key '%d', expected error '%s', get error '%s'", test.name, test.data, test.key, test.expectedError, actualError) + } + } +} + +func BenchmarkJump(b *testing.B) { + testCase := generateBenchmarkTestCase() + b.ResetTimer() // exclude time taken to generate test case + for i := 0; i < b.N; i++ { + _, _ = Jump(testCase, i) + } +} From 31fa2d5384c5a90b5fc0fdcb2baba9812ec95a94 Mon Sep 17 00:00:00 2001 From: Calebe Oliveira <30943380+calebeof@users.noreply.github.com> Date: Sun, 24 Oct 2021 06:15:57 -0300 Subject: [PATCH 277/488] merge: feat: add Catalan Numbers (#405) * add Catalan Numbers * add complexity * add error * rename errCatalan Co-authored-by: Rak Laptudirm --- dynamic/catalan.go | 31 +++++++++++++++++++++++++++ dynamic/catalan_test.go | 46 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 dynamic/catalan.go create mode 100644 dynamic/catalan_test.go diff --git a/dynamic/catalan.go b/dynamic/catalan.go new file mode 100644 index 000000000..7e0076fba --- /dev/null +++ b/dynamic/catalan.go @@ -0,0 +1,31 @@ +//The Catalan numbers are a sequence of positive integers that appear in many counting +//problems in combinatorics. +//reference: https://brilliant.org/wiki/catalan-numbers/ + +package dynamic + +import "fmt" + +var errCatalan = fmt.Errorf("can't have a negative n-th catalan number") + +// NthCatalan returns the n-th Catalan Number +// Complexity: O(n²) +func NthCatalanNumber(n int) (int64, error) { + if n < 0 { + //doesn't accept negative number + return 0, errCatalan + } + + var catalanNumberList []int64 + catalanNumberList = append(catalanNumberList, 1) //first value is 1 + + for i := 1; i <= n; i++ { + catalanNumberList = append(catalanNumberList, 0) //append 0 and calculate + + for j := 0; j < i; j++ { + catalanNumberList[i] += catalanNumberList[j] * catalanNumberList[i-j-1] + } + } + + return catalanNumberList[n], nil +} diff --git a/dynamic/catalan_test.go b/dynamic/catalan_test.go new file mode 100644 index 000000000..4867053d8 --- /dev/null +++ b/dynamic/catalan_test.go @@ -0,0 +1,46 @@ +package dynamic + +import ( + "fmt" + "testing" +) + +func TestCatalanNumbers(t *testing.T) { + var testCatalanNumbersData = []struct { + nthCatalanNumber int + expectedCatalanNumber int64 + expectedError error + }{ + {nthCatalanNumber: -1000, expectedCatalanNumber: 0, expectedError: errCatalan}, + {nthCatalanNumber: -1, expectedCatalanNumber: 0, expectedError: errCatalan}, + {nthCatalanNumber: 0, expectedCatalanNumber: 1, expectedError: nil}, + {nthCatalanNumber: 1, expectedCatalanNumber: 1, expectedError: nil}, + {nthCatalanNumber: 2, expectedCatalanNumber: 2, expectedError: nil}, + {nthCatalanNumber: 3, expectedCatalanNumber: 5, expectedError: nil}, + {nthCatalanNumber: 4, expectedCatalanNumber: 14, expectedError: nil}, + {nthCatalanNumber: 5, expectedCatalanNumber: 42, expectedError: nil}, + {nthCatalanNumber: 6, expectedCatalanNumber: 132, expectedError: nil}, + {nthCatalanNumber: 7, expectedCatalanNumber: 429, expectedError: nil}, + {nthCatalanNumber: 8, expectedCatalanNumber: 1430, expectedError: nil}, + {nthCatalanNumber: 9, expectedCatalanNumber: 4862, expectedError: nil}, + {nthCatalanNumber: 10, expectedCatalanNumber: 16796, expectedError: nil}, + {nthCatalanNumber: 1000, expectedCatalanNumber: 4233371109654655040, expectedError: nil}, + } + + for i := range testCatalanNumbersData { + t.Run(fmt.Sprintf("the %dth Catalan Number", testCatalanNumbersData[i].nthCatalanNumber), func(t *testing.T) { + nthCatalanNumber := testCatalanNumbersData[i].nthCatalanNumber + result, err := NthCatalanNumber(nthCatalanNumber) + expectedCatalanNumber := testCatalanNumbersData[i].expectedCatalanNumber + expectedError := testCatalanNumbersData[i].expectedError + + if err != expectedError { + t.Errorf("Expected %dth Catalan Number error: %d\nFound: %d\n", nthCatalanNumber, expectedError, err) + } + + if result != expectedCatalanNumber { + t.Errorf("Expected %dth Catalan Number: %d\nFound: %d\n", nthCatalanNumber, expectedCatalanNumber, result) + } + }) + } +} From e9fe6d7392746180f4a9cd5f3b4ed62c74751fef Mon Sep 17 00:00:00 2001 From: Meet Valani <40715819+meetvalani@users.noreply.github.com> Date: Sun, 24 Oct 2021 16:21:27 +0530 Subject: [PATCH 278/488] merge: feat: added pigeonhole sorting (#403) * added pigeonhole sorting * Updated math.max package and reduced complexity * Update math/max/max.go Co-authored-by: Taj * Update math/min/min.go Co-authored-by: Taj * updated comments for better doc generation Co-authored-by: Taj --- math/max/max.go | 14 ++++++++------ math/max/max_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ math/min/min.go | 2 +- sort/pigeonholesort.go | 39 +++++++++++++++++++++++++++++++++++++++ sort/radixsort.go | 12 ++---------- sort/sorts_test.go | 8 +++++++- 6 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 sort/pigeonholesort.go diff --git a/math/max/max.go b/math/max/max.go index bb070a6c8..0449a2d6b 100644 --- a/math/max/max.go +++ b/math/max/max.go @@ -1,10 +1,12 @@ package max -// Int gives max of two integers -// defining it here to be used in other subpackages of the repo. -func Int(x int, y int) int { - if x < y { - return y +// Int is a function which returns the maximum of all the integers provided as arguments. +func Int(values ...int) int { + max := values[0] + for _, value := range values { + if value > max { + max = value + } } - return x + return max } diff --git a/math/max/max_test.go b/math/max/max_test.go index dbd1ce8dc..1c289917f 100644 --- a/math/max/max_test.go +++ b/math/max/max_test.go @@ -33,3 +33,45 @@ func TestMax(t *testing.T) { }) } } + +func TestMaxOfThree(t *testing.T) { + testCases := []struct { + name string + left int + middle int + right int + max int + }{ + { + name: "right is max", + left: 1, + middle: 5, + right: 10, + max: 10, + }, + { + name: "left is max", + left: 10, + middle: 5, + right: 9, + max: 10, + }, + { + name: "left is max", + left: 10, + middle: 8, + right: 6, + max: 10, + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + actualMax := Int(test.left, test.middle, test.right) + if actualMax != test.max { + t.Errorf("Failed test %s\n\tleft: %v, middle: %v, right: %v, max: %v but received: %v", + test.name, test.left, test.middle, test.right, test.max, actualMax) + } + }) + } +} diff --git a/math/min/min.go b/math/min/min.go index 965018f1f..03fd090ba 100644 --- a/math/min/min.go +++ b/math/min/min.go @@ -1,6 +1,6 @@ package min -// Int is a function which returns the minimum of two integers. +// Int is a function which returns the minimum of all the integers provided as arguments. func Int(values ...int) int { min := values[0] for _, value := range values { diff --git a/sort/pigeonholesort.go b/sort/pigeonholesort.go new file mode 100644 index 000000000..bfc20244e --- /dev/null +++ b/sort/pigeonholesort.go @@ -0,0 +1,39 @@ +// Pigeonhole algorithm's working at wikipedia. +// https://en.wikipedia.org/wiki/Pigeonhole_sort + +package sort + +import ( + "github.com/TheAlgorithms/Go/math/max" + "github.com/TheAlgorithms/Go/math/min" +) + +// Pigeonhole sorts a slice using pigeonhole sorting algorithm. +func Pigeonhole(arr []int) []int { + if len(arr) == 0 { + return arr + } + + max := max.Int(arr...) + min := min.Int(arr...) + + size := max - min + 1 + + holes := make([]int, size) + + for _, element := range arr { + holes[element-min]++ + } + + i := 0 + + for j := 0; j < size; j++ { + for holes[j] > 0 { + holes[j]-- + arr[i] = j + min + i++ + } + } + + return arr +} diff --git a/sort/radixsort.go b/sort/radixsort.go index c499d1a76..7b731cdb1 100644 --- a/sort/radixsort.go +++ b/sort/radixsort.go @@ -1,14 +1,6 @@ package sort -func max(arr []int) int { - max := arr[0] - for _, item := range arr { - if item > max { - max = item - } - } - return max -} +import "github.com/TheAlgorithms/Go/math/max" func countSort(arr []int, exp int) []int { var digits [10]int @@ -33,7 +25,7 @@ func unsignedRadixSort(arr []int) []int { if len(arr) == 0 { return arr } - maxElement := max(arr) + maxElement := max.Int(arr...) for exp := 1; maxElement/exp > 0; exp *= 10 { arr = countSort(arr, exp) } diff --git a/sort/sorts_test.go b/sort/sorts_test.go index 21635514d..5342121cc 100644 --- a/sort/sorts_test.go +++ b/sort/sorts_test.go @@ -122,6 +122,10 @@ func TestSelection(t *testing.T) { testFramework(t, SelectionSort) } +func TestPigeonhole(t *testing.T) { + testFramework(t, Pigeonhole) +} + //END TESTS func benchmarkFramework(b *testing.B, f func(arr []int) []int) { @@ -212,4 +216,6 @@ func BenchmarkSelection(b *testing.B) { benchmarkFramework(b, SelectionSort) } -//END BENCHMARKS +func BenchmarkPigeonhole(b *testing.B) { + benchmarkFramework(b, Pigeonhole) +} From 3c8c506eceeb4e1baf27e7e2b98dee07f97d2381 Mon Sep 17 00:00:00 2001 From: Calebe Oliveira <30943380+calebeof@users.noreply.github.com> Date: Sun, 24 Oct 2021 08:18:02 -0300 Subject: [PATCH 279/488] merge: add Subset Sum problem (#410) Co-authored-by: Rak Laptudirm --- dynamic/subsetsum.go | 55 ++++++++++++++++++++++ dynamic/subsetsum_test.go | 96 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 dynamic/subsetsum.go create mode 100644 dynamic/subsetsum_test.go diff --git a/dynamic/subsetsum.go b/dynamic/subsetsum.go new file mode 100644 index 000000000..1f7da69b8 --- /dev/null +++ b/dynamic/subsetsum.go @@ -0,0 +1,55 @@ +//Given a set of non-negative integers, and a (positive) value sum, +//determine if there is a subset of the given set with sum +//equal to given sum. +//Complexity: O(n*sum) +//references: https://www.geeksforgeeks.org/subset-sum-problem-dp-25/ + +package dynamic + +import "fmt" + +var ErrInvalidPosition = fmt.Errorf("invalid position in subset") +var ErrNegativeSum = fmt.Errorf("negative sum is not allowed") + +func IsSubsetSum(array []int, sum int) (bool, error) { + if sum < 0 { + //not allow negative sum + return false, ErrNegativeSum + } + + //create subset matrix + arraySize := len(array) + subset := make([][]bool, arraySize+1) + for i := 0; i <= arraySize; i++ { + subset[i] = make([]bool, sum+1) + } + + for i := 0; i <= arraySize; i++ { + //sum 0 is always true + subset[i][0] = true + } + + for i := 1; i <= sum; i++ { + //empty set is false when sum is not 0 + subset[0][i] = false + } + + for i := 1; i <= arraySize; i++ { + for j := 1; j <= sum; j++ { + if array[i-1] > j { + subset[i][j] = subset[i-1][j] + } + + if array[i-1] <= j { + if j-array[i-1] < 0 || j-array[i-1] > sum { + //out of bounds + return false, ErrInvalidPosition + } + + subset[i][j] = subset[i-1][j] || subset[i-1][j-array[i-1]] + } + } + } + + return subset[arraySize][sum], nil +} diff --git a/dynamic/subsetsum_test.go b/dynamic/subsetsum_test.go new file mode 100644 index 000000000..2fdfb6cc5 --- /dev/null +++ b/dynamic/subsetsum_test.go @@ -0,0 +1,96 @@ +package dynamic + +import ( + "fmt" + "testing" +) + +func TestSubsetSum(t *testing.T) { + + var subsetSumTestData = []struct { + description string + array []int + sum int + expectedResult bool + expectedError error + }{ + { + description: "array of size 0 and sum 0", + array: []int{}, + sum: 0, + expectedResult: true, + expectedError: nil, + }, + { + description: "array of size 0 and non-zero sum", + array: []int{}, + sum: 2, + expectedResult: false, + expectedError: nil, + }, + { + description: "array of size 2 and sum 0", + array: []int{1, 2}, + sum: 0, + expectedResult: true, + expectedError: nil, + }, + { + description: "array of size 5 and sum 6", + array: []int{1, 2, 3, 4, 5}, + sum: 6, + expectedResult: true, + expectedError: nil, + }, + { + description: "array of size 5 and sum 7", + array: []int{1, 2, 3, 4, 5}, + sum: 7, + expectedResult: true, + expectedError: nil, + }, + { + description: "array of size 5 and sum 17", + array: []int{1, 2, 3, 4, 5}, + sum: 17, + expectedResult: false, + expectedError: nil, + }, + { + description: "array of size 6 negative values and sum positive", + array: []int{-1, -2, -3, -4, -5, -6}, + sum: 1, + expectedResult: false, + expectedError: ErrInvalidPosition, + }, + { + description: "array of size 6 with positive and negative values, also with a negative sum", + array: []int{-1, -1, 3, 4, 5, 6}, + sum: -2, + expectedResult: false, + expectedError: ErrNegativeSum, + }, + } + + for i := range subsetSumTestData { + + t.Run(fmt.Sprintf(subsetSumTestData[i].description), func(t *testing.T) { + array := subsetSumTestData[i].array + sum := subsetSumTestData[i].sum + + expectedResult := subsetSumTestData[i].expectedResult + result, err := IsSubsetSum(array, sum) + expectedError := subsetSumTestData[i].expectedError + + if err != expectedError { + t.Logf("FAIL: %s", subsetSumTestData[i].description) + t.Fatalf("Expected error:%t\nFound: %t", expectedError, err) + } + + if result != expectedResult { + t.Logf("FAIL: %s", subsetSumTestData[i].description) + t.Fatalf("Expected result:%t\nFound: %t", expectedResult, result) + } + }) + } +} From 36a2297a29cb3bbddafef682db462f745c57e666 Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Wed, 27 Oct 2021 06:10:36 +0200 Subject: [PATCH 280/488] merge: test: add coverage for the set data structure (#409) Co-authored-by: Michele Caci Co-authored-by: Rak Laptudirm --- structure/set/set_test.go | 203 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 structure/set/set_test.go diff --git a/structure/set/set_test.go b/structure/set/set_test.go new file mode 100644 index 000000000..35ccaa5d7 --- /dev/null +++ b/structure/set/set_test.go @@ -0,0 +1,203 @@ +// package set implements a Set using a golang map. +// This implies that only the types that are accepted as valid map keys can be used as set elements. +// For instance, do not try to Add a slice, or the program will panic. +package set + +import ( + "testing" +) + +func TestNew(t *testing.T) { + set := New(1, 2, 3) + if set.Len() != 3 { + t.Errorf("expecting 3 elements in the set but got %v: %v", set.Len(), set.GetItems()) + } + for _, n := range []int{1, 2, 3} { + if !set.In(n) { + t.Errorf("expecting %d to be present in the set but was not; set is %v", n, set.GetItems()) + } + } + if set.In(5) { + t.Errorf("expecting 5 not to be present in the set but it was; set is %v", set.GetItems()) + } +} + +func TestAdd(t *testing.T) { + td := []struct { + name string + input int + expElems []int + }{ + {"add new element", 5, []int{1, 2, 3, 5}}, + {"add exiting element", 3, []int{1, 2, 3}}, + } + for _, tc := range td { + t.Run(tc.name, func(t *testing.T) { + s := New(1, 2, 3) + s.Add(tc.input) + if s.Len() != len(tc.expElems) { + t.Errorf("expecting %d elements in the set but got %d: set is %v", len(tc.expElems), s.Len(), s.GetItems()) + } + for _, n := range tc.expElems { + if !s.In(n) { + t.Errorf("expecting %d to be present in the set but was not; set is %v", n, s.GetItems()) + } + } + }) + } +} + +func TestDelete(t *testing.T) { + td := []struct { + name string + input int + expElems []int + }{ + {"delete exiting element", 3, []int{1, 2}}, + {"delete not existing element", 5, []int{1, 2, 3}}, + } + for _, tc := range td { + t.Run(tc.name, func(t *testing.T) { + s := New(1, 2, 3) + s.Delete(tc.input) + if s.Len() != len(tc.expElems) { + t.Errorf("expecting %d elements in the set but got %d: set is %v", len(tc.expElems), s.Len(), s.GetItems()) + } + for _, n := range tc.expElems { + if !s.In(n) { + t.Errorf("expecting %d to be present in the set but was not; set is %v", n, s.GetItems()) + } + } + }) + } +} + +func TestIsSubsetOf(t *testing.T) { + s1, s2 := New(1, 2, 3), New(1, 2, 3, 4) + if !s1.IsSubsetOf(s2) { + t.Errorf("expecting %v to be a subset of %v", s1, s2) + } + if s2.IsSubsetOf(s1) { + t.Errorf("expecting %v not to be a subset of %v", s2, s1) + } + if s3 := New(1, 2, 5, 6); s1.IsSubsetOf(s3) { + t.Errorf("expecting %v not to be a subset of %v", s1, s3) + } +} + +func TestIsSupersetOf(t *testing.T) { + s1, s2 := New(1, 2, 3), New(1, 2, 3, 4) + if !s2.IsSupersetOf(s1) { + t.Errorf("expecting %v to be a superset of %v", s2, s1) + } + if s1.IsSupersetOf(s2) { + t.Errorf("expecting %v not to be a superset of %v", s1, s2) + } + if s3 := New(1, 2, 5); s2.IsSupersetOf(s3) { + t.Errorf("expecting %v not to be a superset of %v", s2, s3) + } +} + +func TestUnion(t *testing.T) { + td := []struct { + name string + s1 Set + s2 Set + expSet Set + }{ + {"union of different sets", New(1, 2, 3), New(4, 5, 6), New(1, 2, 3, 4, 5, 6)}, + {"union of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(1, 2, 3, 4)}, + {"union of same sets", New(1, 2, 3), New(1, 2, 3), New(1, 2, 3)}, + } + for _, tc := range td { + t.Run(tc.name, func(t *testing.T) { + s := tc.s1.Union(tc.s2) + if s.Len() != tc.expSet.Len() { + t.Errorf("expecting %d elements in the set but got %d: set is %v", tc.expSet.Len(), s.Len(), s.GetItems()) + } + for _, n := range tc.expSet.GetItems() { + if !s.In(n) { + t.Errorf("expecting %d to be present in the set but was not; set is %v", n, s.GetItems()) + } + } + }) + } +} + +func TestIntersection(t *testing.T) { + td := []struct { + name string + s1 Set + s2 Set + expSet Set + }{ + {"intersection of different sets", New(0, 1, 2, 3), New(4, 5, 6), New()}, + {"intersection of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(1, 2)}, + {"intersection of same sets", New(1, 2, 3), New(1, 2, 3), New(1, 2, 3)}, + } + for _, tc := range td { + t.Run(tc.name, func(t *testing.T) { + s := tc.s1.Intersection(tc.s2) + if s.Len() != tc.expSet.Len() { + t.Errorf("expecting %d elements in the set but got %d: set is %v", tc.expSet.Len(), s.Len(), s.GetItems()) + } + for _, n := range tc.expSet.GetItems() { + if !s.In(n) { + t.Errorf("expecting %d to be present in the set but was not; set is %v", n, s.GetItems()) + } + } + }) + } +} + +func TestDifference(t *testing.T) { + td := []struct { + name string + s1 Set + s2 Set + expSet Set + }{ + {"difference of different sets", New(1, 2, 3), New(4, 5, 6), New(1, 2, 3)}, + {"difference of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(3)}, + {"difference of same sets", New(1, 2, 3), New(1, 2, 3), New()}, + } + for _, tc := range td { + t.Run(tc.name, func(t *testing.T) { + s := tc.s1.Difference(tc.s2) + if s.Len() != tc.expSet.Len() { + t.Errorf("expecting %d elements in the set but got %d: set is %v", tc.expSet.Len(), s.Len(), s.GetItems()) + } + for _, n := range tc.expSet.GetItems() { + if !s.In(n) { + t.Errorf("expecting %d to be present in the set but was not; set is %v", n, s.GetItems()) + } + } + }) + } +} + +func TestSymmetricDifference(t *testing.T) { + td := []struct { + name string + s1 Set + s2 Set + expSet Set + }{ + {"symmetric difference of different sets", New(1, 2, 3), New(4, 5, 6), New(1, 2, 3, 4, 5, 6)}, + {"symmetric difference of sets with elements in common", New(1, 2, 3), New(1, 2, 4), New(3, 4)}, + {"symmetric difference of same sets", New(1, 2, 3), New(1, 2, 3), New()}, + } + for _, tc := range td { + t.Run(tc.name, func(t *testing.T) { + s := tc.s1.SymmetricDifference(tc.s2) + if s.Len() != tc.expSet.Len() { + t.Errorf("expecting %d elements in the set but got %d: set is %v", tc.expSet.Len(), s.Len(), s.GetItems()) + } + for _, n := range tc.expSet.GetItems() { + if !s.In(n) { + t.Errorf("expecting %d to be present in the set but was not; set is %v", n, s.GetItems()) + } + } + }) + } +} From 8e43694561abd98767963cd4f3e4f04bac9638bd Mon Sep 17 00:00:00 2001 From: Michele Caci Date: Wed, 27 Oct 2021 20:02:26 +0200 Subject: [PATCH 281/488] merge: feat: add longestincreasingsubsequence algorithm and test (#414) * feat: add longestincreasingsubsequence algorithm and test * Update dynamic/longestincreasingsubsequence.go Co-authored-by: Taj * feat: add longestincreasingsubsequence algorithm and test * Update dynamic/longestincreasingsubsequence.go Co-authored-by: Taj Co-authored-by: Michele Caci Co-authored-by: Taj Co-authored-by: Rak Laptudirm --- dynamic/longestincreasingsubsequence.go | 27 ++++++++++++++++++ dynamic/longestincreasingsubsequence_test.go | 30 ++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 dynamic/longestincreasingsubsequence.go create mode 100644 dynamic/longestincreasingsubsequence_test.go diff --git a/dynamic/longestincreasingsubsequence.go b/dynamic/longestincreasingsubsequence.go new file mode 100644 index 000000000..cce099510 --- /dev/null +++ b/dynamic/longestincreasingsubsequence.go @@ -0,0 +1,27 @@ +package dynamic + +import ( + "github.com/TheAlgorithms/Go/math/max" +) + +// LongestIncreasingSubsequence returns the longest increasing subsequence +// where all elements of the subsequence are sorted in increasing order +func LongestIncreasingSubsequence(elements []int) int { + n := len(elements) + lis := make([]int, n) + for i := range lis { + lis[i] = 1 + } + for i := range lis { + for j := 0; j < i; j++ { + if elements[i] > elements[j] && lis[i] < lis[j]+1 { + lis[i] = lis[j] + 1 + } + } + } + res := 0 + for _, value := range lis { + res = max.Int(res, value) + } + return res +} diff --git a/dynamic/longestincreasingsubsequence_test.go b/dynamic/longestincreasingsubsequence_test.go new file mode 100644 index 000000000..ed021db1e --- /dev/null +++ b/dynamic/longestincreasingsubsequence_test.go @@ -0,0 +1,30 @@ +package dynamic_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +func TestLongestIncreasingSubsequence(t *testing.T) { + td := []struct { + elements []int + expectedLen int + }{ + {[]int{1, 2, 3, 4, 5, 10}, 6}, + {[]int{1, 7, 3, 4, 5}, 4}, // 1,3,4,5 + {[]int{1, 3, 5}, 3}, + {[]int{7, 1, 6}, 2}, + {[]int{4, 1, 6, 2}, 2}, + {[]int{11, 9, 6}, 1}, + } + for _, tc := range td { + t.Run(fmt.Sprint("test with", tc.elements), func(t *testing.T) { + actualLen := dynamic.LongestIncreasingSubsequence(tc.elements) + if tc.expectedLen != actualLen { + t.Fatalf("expecting a sequence of len %d to be found but the actual len was %d; input: %v", tc.expectedLen, actualLen, tc.elements) + } + }) + } +} From cc80617c62515b45c273d9522a682ed543e08504 Mon Sep 17 00:00:00 2001 From: Ayoub Chegraoui Date: Thu, 28 Oct 2021 05:24:20 +0100 Subject: [PATCH 282/488] merge: feat: add ternary search algorithm (#417) Co-authored-by: Rak Laptudirm --- search/ternary.go | 40 ++++++++++++++++++++++++++++++ search/ternary_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 search/ternary.go create mode 100644 search/ternary_test.go diff --git a/search/ternary.go b/search/ternary.go new file mode 100644 index 000000000..81b0ce135 --- /dev/null +++ b/search/ternary.go @@ -0,0 +1,40 @@ +package search + +import ( + "fmt" + "math" +) + +// TernaryMax is a function to search for maximum value of a uni-modal function `f` +// in the interval [a, b]. a and b should be finit numbers +func TernaryMax(a, b, epsilon float64, f func(x float64) float64) (float64, error) { + if a == math.Inf(-1) || b == math.Inf(1) { + return -1, fmt.Errorf("interval boundries should be finite numbers") + } + if math.Abs(a-b) <= epsilon { + return f((a + b) / 2), nil + } + left := (2*a + b) / 3 + right := (a + 2*b) / 3 + if f(left) < f(right) { + return TernaryMax(left, b, epsilon, f) + } + return TernaryMax(a, right, epsilon, f) +} + +// TernaryMin is a function to search for minimum value of a uni-modal function `f` +// in the interval [a, b]. a and b should be finit numbers. +func TernaryMin(a, b, epsilon float64, f func(x float64) float64) (float64, error) { + if a == math.Inf(-1) || b == math.Inf(1) { + return -1, fmt.Errorf("interval boundries should be finite numbers") + } + if math.Abs(a-b) <= epsilon { + return f((a + b) / 2), nil + } + left := (2*a + b) / 3 + right := (a + 2*b) / 3 + if f(left) > f(right) { + return TernaryMin(left, b, epsilon, f) + } + return TernaryMin(a, right, epsilon, f) +} diff --git a/search/ternary_test.go b/search/ternary_test.go new file mode 100644 index 000000000..15db89dba --- /dev/null +++ b/search/ternary_test.go @@ -0,0 +1,56 @@ +package search + +import ( + "math" + "testing" +) + +const EPS = 1e-6 + +func equal(a, b float64) bool { + return math.Abs(a-b) <= EPS +} + +func TestTernaryMax(t *testing.T) { + + var tests = []struct { + f func(x float64) float64 + a float64 + b float64 + expected float64 + }{ + {f: func(x float64) float64 { return -x * x }, a: 1, b: -1, expected: 0}, + {f: func(x float64) float64 { return -2*x*x - x + 1 }, a: -1, b: 1, expected: 1.125}, + } + for _, test := range tests { + result, err := TernaryMax(test.a, test.b, EPS, test.f) + if err != nil { + t.Errorf("error occured: %v", err) + } + if !equal(result, test.expected) { + t.Errorf("Wrong result! Expected:%v, returned:%v ", test.expected, result) + } + } +} + +func TestTernaryMin(t *testing.T) { + + var tests = []struct { + f func(x float64) float64 + a float64 + b float64 + expected float64 + }{ + {f: func(x float64) float64 { return x * x }, a: -1, b: 1, expected: 0}, + {f: func(x float64) float64 { return 2*x*x + x + 1 }, a: -1, b: 1, expected: 0.875}, + } + for _, test := range tests { + result, err := TernaryMin(test.a, test.b, EPS, test.f) + if err != nil { + t.Errorf("error occured: %v", err) + } + if !equal(result, test.expected) { + t.Errorf("Wrong result! Expected:%v, returned:%v ", test.expected, result) + } + } +} From 2485670be23fbcb0830005092020c5e68eb450fb Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Thu, 28 Oct 2021 19:16:33 +0530 Subject: [PATCH 283/488] Add codespell workflow (#421) * feat: add codespell workflow * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: rename variables * chore: fix spellings * chore: fix spelling * chore: fix spellings * chore: fix spellings * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: fix spelling * chore: undo variable renaming * chore: join `fmt.Print`s together * chore: add ignore list for words * fix: use correct property name * fix: change words to lowercase * fix: change `Print` to `Printf` Co-authored-by: Christian Clauss * chore: move workflow * chore: add codespell workflow here * Update .github/workflows/golang_lint_and_test.yml Co-authored-by: Christian Clauss --- .github/workflows/golang_lint_and_test.yml | 4 ++++ cipher/polybius/polybius_test.go | 2 +- cipher/rsa/rsa_test.go | 2 +- conversion/binarytodecimal.go | 2 +- conversion/decimaltobinary.go | 2 +- graph/topological.go | 6 +++--- math/geometry/straightlines.go | 2 +- other/maxsubarraysum/maxsubarraysum.go | 2 +- other/nested/nestedbrackets.go | 4 ++-- search/ternary.go | 4 ++-- search/ternary_test.go | 4 ++-- strings/ahocorasick/advancedahocorasick.go | 2 +- strings/ahocorasick/shared.go | 2 +- strings/bom/bom.go | 4 ++-- strings/genetic/genetic.go | 2 +- strings/kmp/kmp.go | 2 +- structure/hashmap/hashmap_test.go | 2 +- structure/linkedlist/doubly.go | 2 +- structure/linkedlist/shared.go | 2 +- structure/set/set.go | 6 +++--- structure/stack/stack_test.go | 8 ++++---- structure/trie/trie_test.go | 2 +- 22 files changed, 36 insertions(+), 32 deletions(-) diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index 5ad79ff72..f065817f4 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -8,6 +8,10 @@ jobs: fail-fast: false steps: - uses: actions/checkout@v2 + - uses: codespell-project/actions-codespell@master + with: + ignore_words_list: "actualy,nwe" + skip: "go.mod,go.sum" - uses: actions/setup-go@v2 - run: go version - uses: golangci/golangci-lint-action@v2 diff --git a/cipher/polybius/polybius_test.go b/cipher/polybius/polybius_test.go index d607884e3..89b4769fc 100644 --- a/cipher/polybius/polybius_test.go +++ b/cipher/polybius/polybius_test.go @@ -51,7 +51,7 @@ func TestNewPolybius(t *testing.T) { name: "truncate characters", size: 5, characters: "HogeFuga", key: "abcdefghijklmnopqrstuvwxy", wantErr: "", }, { - name: "invaid key", size: 5, characters: "HogeFuga", key: "abcdefghi", wantErr: "len(key): 9 must be as long as size squared: 25", + name: "invalid key", size: 5, characters: "HogeFuga", key: "abcdefghi", wantErr: "len(key): 9 must be as long as size squared: 25", }, { name: "invalid characters", size: 5, characters: "HogeH", key: "abcdefghijklmnopqrstuvwxy", wantErr: "\"chars\" contains same character: H", diff --git a/cipher/rsa/rsa_test.go b/cipher/rsa/rsa_test.go index daeb5d4d7..fde10be33 100644 --- a/cipher/rsa/rsa_test.go +++ b/cipher/rsa/rsa_test.go @@ -47,7 +47,7 @@ func TestEncryptDecrypt(t *testing.T) { e := int64(17) // Coprime with delta if gcd.Recursive(e, delta) != 1 { - t.Fatal("Algorithm failed in preamble stage:\n\tPrime numbers are chosed statically and it shouldn't fail at this stage") + t.Fatal("Algorithm failed in preamble stage:\n\tPrime numbers are chosen statically and it shouldn't fail at this stage") } d, err := modular.Inverse(e, delta) diff --git a/conversion/binarytodecimal.go b/conversion/binarytodecimal.go index 5cfada517..54ac7993a 100644 --- a/conversion/binarytodecimal.go +++ b/conversion/binarytodecimal.go @@ -8,7 +8,7 @@ Date: 19-Oct-2021 // https://en.wikipedia.org/wiki/Binary_number // https://en.wikipedia.org/wiki/Decimal // Function receives a Binary Number as string and returns the Decimal number as integer. -// Suppoted Binary number range is 0 to 2^(31-1). +// Supported Binary number range is 0 to 2^(31-1). // Package name. package conversion diff --git a/conversion/decimaltobinary.go b/conversion/decimaltobinary.go index 6b78bb16c..f5cc9bbbe 100644 --- a/conversion/decimaltobinary.go +++ b/conversion/decimaltobinary.go @@ -7,7 +7,7 @@ Date: 14-Oct-2021 // This algorithm will convert any Decimal (+ve integer) number to Binary number. // https://en.wikipedia.org/wiki/Binary_number // Function receives a integer as a Decimal number and returns the Binary number. -// Suppoted integer value range is 0 to 2^(31 -1). +// Supported integer value range is 0 to 2^(31 -1). // Package name. package conversion diff --git a/graph/topological.go b/graph/topological.go index 89fe46c42..feef703f1 100644 --- a/graph/topological.go +++ b/graph/topological.go @@ -22,14 +22,14 @@ func Topological(N int, constraints [][]int) []int { edges[a][b] = true } - ans := []int{} + answer := []int{} for s := 0; s < N; s++ { // Only start walking from top level nodes if dependencies[s] == 0 { route, _ := DepthFirstSearchHelper(s, N, nodes, edges, true) - ans = append(ans, route...) + answer = append(answer, route...) } } - return ans + return answer } diff --git a/math/geometry/straightlines.go b/math/geometry/straightlines.go index 5595069d4..355263581 100644 --- a/math/geometry/straightlines.go +++ b/math/geometry/straightlines.go @@ -18,7 +18,7 @@ func Distance(a, b *Point) float64 { return math.Sqrt(math.Pow(a.X-b.X, 2) + math.Pow(a.Y-b.Y, 2)) } -// Calcualtes the Point that divides a line in specific ratio. +// Calculates the Point that divides a line in specific ratio. // DO NOT specify the ratio in the form m:n, specify it as r, where r = m / n. func Section(p1, p2 *Point, r float64) Point { var point Point diff --git a/other/maxsubarraysum/maxsubarraysum.go b/other/maxsubarraysum/maxsubarraysum.go index 81c5042f7..731907284 100644 --- a/other/maxsubarraysum/maxsubarraysum.go +++ b/other/maxsubarraysum/maxsubarraysum.go @@ -2,7 +2,7 @@ maximum contiguous sum in the given array. */ // Package maxsubarraysum is a package containing a solution to a common -// problem of finding max contigious sum within a array of ints. +// problem of finding max contiguous sum within a array of ints. package maxsubarraysum import ( diff --git a/other/nested/nestedbrackets.go b/other/nested/nestedbrackets.go index 330f78fbb..f127acc93 100644 --- a/other/nested/nestedbrackets.go +++ b/other/nested/nestedbrackets.go @@ -1,5 +1,5 @@ // Package nested provides functions for testing -// strings propper brackets nesting. +// strings proper brackets nesting. package nested // IsBalanced returns true if provided input string is properly nested. @@ -16,7 +16,7 @@ package nested // // **Note** Providing characters other then brackets would return false, // despite brackets sequence in the string. Make sure to filter -// input before useage. +// input before usage. func IsBalanced(input string) bool { if len(input) == 0 { return true diff --git a/search/ternary.go b/search/ternary.go index 81b0ce135..1e594f8d7 100644 --- a/search/ternary.go +++ b/search/ternary.go @@ -9,7 +9,7 @@ import ( // in the interval [a, b]. a and b should be finit numbers func TernaryMax(a, b, epsilon float64, f func(x float64) float64) (float64, error) { if a == math.Inf(-1) || b == math.Inf(1) { - return -1, fmt.Errorf("interval boundries should be finite numbers") + return -1, fmt.Errorf("interval boundaries should be finite numbers") } if math.Abs(a-b) <= epsilon { return f((a + b) / 2), nil @@ -26,7 +26,7 @@ func TernaryMax(a, b, epsilon float64, f func(x float64) float64) (float64, erro // in the interval [a, b]. a and b should be finit numbers. func TernaryMin(a, b, epsilon float64, f func(x float64) float64) (float64, error) { if a == math.Inf(-1) || b == math.Inf(1) { - return -1, fmt.Errorf("interval boundries should be finite numbers") + return -1, fmt.Errorf("interval boundaries should be finite numbers") } if math.Abs(a-b) <= epsilon { return f((a + b) / 2), nil diff --git a/search/ternary_test.go b/search/ternary_test.go index 15db89dba..eb89c161a 100644 --- a/search/ternary_test.go +++ b/search/ternary_test.go @@ -25,7 +25,7 @@ func TestTernaryMax(t *testing.T) { for _, test := range tests { result, err := TernaryMax(test.a, test.b, EPS, test.f) if err != nil { - t.Errorf("error occured: %v", err) + t.Errorf("error occurred: %v", err) } if !equal(result, test.expected) { t.Errorf("Wrong result! Expected:%v, returned:%v ", test.expected, result) @@ -47,7 +47,7 @@ func TestTernaryMin(t *testing.T) { for _, test := range tests { result, err := TernaryMin(test.a, test.b, EPS, test.f) if err != nil { - t.Errorf("error occured: %v", err) + t.Errorf("error occurred: %v", err) } if !equal(result, test.expected) { t.Errorf("Wrong result! Expected:%v, returned:%v ", test.expected, result) diff --git a/strings/ahocorasick/advancedahocorasick.go b/strings/ahocorasick/advancedahocorasick.go index e465903a9..c53939eac 100644 --- a/strings/ahocorasick/advancedahocorasick.go +++ b/strings/ahocorasick/advancedahocorasick.go @@ -5,7 +5,7 @@ import ( "time" ) -// Advanced Function performing the Advanced Aho-Corasick alghoritm. +// Advanced Function performing the Advanced Aho-Corasick algorithm. // Finds and prints occurrences of each pattern. func Advanced(t string, p []string) Result { startTime := time.Now() diff --git a/strings/ahocorasick/shared.go b/strings/ahocorasick/shared.go index eee95c1b7..700dbcd0b 100644 --- a/strings/ahocorasick/shared.go +++ b/strings/ahocorasick/shared.go @@ -35,7 +35,7 @@ func ConstructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bo return trie, stateIsTerminal, f } -// Contains Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. +// Contains Returns 'true' if array of int's 's' contains int 'e', 'false' otherwise. func Contains(s []int, e int) bool { for _, a := range s { if a == e { diff --git a/strings/bom/bom.go b/strings/bom/bom.go index b237eb05b..86112f649 100644 --- a/strings/bom/bom.go +++ b/strings/bom/bom.go @@ -49,11 +49,11 @@ package bom // log.Fatal("Pattern is longer than text!") // } // if debugMode == true { -// fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") +// fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") // fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile) // fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile) // } else { -// fmt.Printf("\nRunning: Backward Oracle Matching alghoritm.\n\n") +// fmt.Printf("\nRunning: Backward Oracle Matching algorithm.\n\n") // } // bom(string(textFile), string(patFile)) // } diff --git a/strings/genetic/genetic.go b/strings/genetic/genetic.go index 14aa8fa82..95fc05fa6 100644 --- a/strings/genetic/genetic.go +++ b/strings/genetic/genetic.go @@ -103,7 +103,7 @@ func GeneticString(target string, charmap []rune, conf *Conf) (*Result, error) { } } if invalid { - message := fmt.Sprintf("character not aviable in charmap at position: %v", position) + message := fmt.Sprintf("character not available in charmap at position: %v", position) return nil, errors.New(message) } } diff --git a/strings/kmp/kmp.go b/strings/kmp/kmp.go index 425c52a51..a0f138724 100644 --- a/strings/kmp/kmp.go +++ b/strings/kmp/kmp.go @@ -95,7 +95,7 @@ func Kmp(text string, word string) Result { } } -// Table building alghoritm. +// Table building algorithm. // Takes word to be analyzed and table to be filled. func kmpTable(word string) (t []int) { t = make([]int, len(word)) diff --git a/structure/hashmap/hashmap_test.go b/structure/hashmap/hashmap_test.go index 1abe50f1a..64a276d46 100644 --- a/structure/hashmap/hashmap_test.go +++ b/structure/hashmap/hashmap_test.go @@ -48,7 +48,7 @@ func TestHashMap(t *testing.T) { } }) - t.Run("Test 6: Checking if the key that doesnt exists returns false", func(t *testing.T) { + t.Run("Test 6: Checking if the key that doesn't exists returns false", func(t *testing.T) { want := false got := mp.Contains(2) if got != want { diff --git a/structure/linkedlist/doubly.go b/structure/linkedlist/doubly.go index b0c1970f3..5a76e7cf9 100644 --- a/structure/linkedlist/doubly.go +++ b/structure/linkedlist/doubly.go @@ -116,7 +116,7 @@ func (ll *Doubly) Reverse() { ll.Head = Prev } -// Display diplay the linked list +// Display display the linked list func (ll *Doubly) Display() { for cur := ll.Head; cur != nil; cur = cur.Next { fmt.Print(cur.Val, " ") diff --git a/structure/linkedlist/shared.go b/structure/linkedlist/shared.go index b9d228f6f..de92a8fcb 100644 --- a/structure/linkedlist/shared.go +++ b/structure/linkedlist/shared.go @@ -1,7 +1,7 @@ package linkedlist // Node Structure representing the linkedlist node. -// This node is shared accross different implementations. +// This node is shared across different implementations. type Node struct { Val interface{} Prev *Node diff --git a/structure/set/set.go b/structure/set/set.go index 70c215f8e..32624b63a 100644 --- a/structure/set/set.go +++ b/structure/set/set.go @@ -15,7 +15,7 @@ func New(items ...interface{}) Set { type Set interface { // Add: adds new element to the set Add(item interface{}) - // Delete: delets the passed element from the set if present + // Delete: deletes the passed element from the set if present Delete(item interface{}) // Len: gives the length of the set (total no. of elements in set) Len() int @@ -23,9 +23,9 @@ type Set interface { GetItems() []interface{} // In: checks whether item is present in set or not. In(item interface{}) bool - // IsSubsetOf: checks wether set is subset of set2 or not. + // IsSubsetOf: checks whether set is subset of set2 or not. IsSubsetOf(set2 Set) bool - // IsSupersetOf: checks wether set is superset of set2 or not. + // IsSupersetOf: checks whether set is superset of set2 or not. IsSupersetOf(set2 Set) bool // Union: gives new union set of both sets. // ex: [1,2,3] union [3,4,5] -> [1,2,3,4,5] diff --git a/structure/stack/stack_test.go b/structure/stack/stack_test.go index 1e31dbc6b..6bc01ed79 100644 --- a/structure/stack/stack_test.go +++ b/structure/stack/stack_test.go @@ -105,7 +105,7 @@ func TestStackArray(t *testing.T) { t.Run("Stack Empty", func(t *testing.T) { if stackEmpty() == true { - t.Errorf("Stack Emtpy is not work we expected %v but got %v", false, stackEmpty()) + t.Errorf("Stack Empty is not work we expected %v but got %v", false, stackEmpty()) } stackPop() @@ -113,7 +113,7 @@ func TestStackArray(t *testing.T) { stackPop() if stackEmpty() == false { - t.Errorf("Stack Emtpy is not work we expected %v but got %v", true, stackEmpty()) + t.Errorf("Stack Empty is not work we expected %v but got %v", true, stackEmpty()) } }) }) @@ -161,7 +161,7 @@ func TestStackLinkedListWithList(t *testing.T) { t.Run("Stack Empty", func(t *testing.T) { if stackList.Empty() == true { - t.Errorf("Stack Emtpy is not work we expected %v but got %v", false, stackList.Empty()) + t.Errorf("Stack Empty is not work we expected %v but got %v", false, stackList.Empty()) } d1, err := stackList.Pop() @@ -173,7 +173,7 @@ func TestStackLinkedListWithList(t *testing.T) { } if stackList.Empty() == false { - t.Errorf("Stack Emtpy is not work we expected %v but got %v", true, stackList.Empty()) + t.Errorf("Stack Empty is not work we expected %v but got %v", true, stackList.Empty()) } }) } diff --git a/structure/trie/trie_test.go b/structure/trie/trie_test.go index 8747a0e1b..7080b5898 100644 --- a/structure/trie/trie_test.go +++ b/structure/trie/trie_test.go @@ -91,7 +91,7 @@ func TestTrieRemove(t *testing.T) { n.verify(t, checkWords) n.verifySizeCapa(t, size, capa) - n.Remove("marcel") // no effect since ,o, existant + n.Remove("marcel") // no effect since ,o, existent n.verify(t, checkWords) n.verifySizeCapa(t, size, capa) From e192812d760f4ea88c6ca350d2154f4f2bf2411c Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Thu, 28 Oct 2021 20:45:53 +0300 Subject: [PATCH 284/488] feat: Manacher's algorithm (#408) --- strings/manacher/longestpalindrome.go | 63 ++++++++++++++++++++++ strings/manacher/longestpalindrome_test.go | 38 +++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 strings/manacher/longestpalindrome.go create mode 100644 strings/manacher/longestpalindrome_test.go diff --git a/strings/manacher/longestpalindrome.go b/strings/manacher/longestpalindrome.go new file mode 100644 index 000000000..e49ae0f94 --- /dev/null +++ b/strings/manacher/longestpalindrome.go @@ -0,0 +1,63 @@ +// longestpalindrome.go +// description: Manacher's algorithm (Longest palindromic substring) +// details: +// An algorithm with linear running time that allows you to get compressed information about all palindromic substrings of a given string. - [Manacher's algorithm](https://en.wikipedia.org/wiki/Longest_palindromic_substring) +// author(s) [red_byte](https://github.com/i-redbyte) +// see longestpalindrome_test.go + +package manacher + +import ( + "github.com/TheAlgorithms/Go/math/min" + "strings" +) + +func makeBoundaries(s string) string { + var result strings.Builder + result.WriteRune('#') + for _, ch := range s { + if ch != ' ' { //ignore space as palindrome character + result.WriteRune(ch) + } + result.WriteRune('#') + } + return result.String() +} + +func nextBoundary(s string) string { + var result strings.Builder + for _, ch := range s { + if ch != '#' { + result.WriteRune(ch) + } + } + return result.String() +} + +func LongestPalindrome(s string) string { + boundaries := makeBoundaries(s) + b := make([]int, len(boundaries)) + k := 0 + index := 0 + maxLen := 0 + maxCenterSize := 0 + for i := range b { + if i < k { + b[i] = min.Int(b[2*index-i], k-i) + } else { + b[i] = 1 + } + for i-b[i] >= 0 && i+b[i] < len(boundaries) && boundaries[i-b[i]] == boundaries[i+b[i]] { + b[i] += 1 + } + if maxLen < b[i]-1 { + maxLen = b[i] - 1 + maxCenterSize = i + } + if b[i]+i-1 > k { + k = b[i] + i - 1 + index = i + } + } + return nextBoundary(boundaries[maxCenterSize-maxLen : maxCenterSize+maxLen]) +} diff --git a/strings/manacher/longestpalindrome_test.go b/strings/manacher/longestpalindrome_test.go new file mode 100644 index 000000000..af08fa0b4 --- /dev/null +++ b/strings/manacher/longestpalindrome_test.go @@ -0,0 +1,38 @@ +// longestpalindrome_test.go +// description: Manacher's algorithm (Longest palindromic substring) +// author(s) [red_byte](https://github.com/i-redbyte) +// see longestpalindrome.go + +package manacher + +import "testing" + +func getTests() []struct { + s string + result string +} { + var tests = []struct { + s string + result string + }{ + {"olokazakabba", "kazak"}, + {"abaacakkkkk", "kkkkk"}, + {"qqqq C++ groovy mom pooop", "pooop"}, + {"CCCPCCC @@@ hello", "CCCPCCC"}, + {"goog gogogogogog -go- gogogogo ", "gogogogogog"}, + } + return tests +} + +func TestLongestPalindrome(t *testing.T) { + tests := getTests() + for _, tv := range tests { + t.Run(tv.s, func(t *testing.T) { + result := LongestPalindrome(tv.s) + t.Log(tv.s, " ", result) + if result != tv.result { + t.Errorf("Wrong result! Expected:%s, returned:%s ", tv.result, result) + } + }) + } +} From ea1a59f8b16d89feb6fbedea519cfb840ff93d1a Mon Sep 17 00:00:00 2001 From: Tahmeed Tarek Date: Fri, 29 Oct 2021 22:48:17 +0600 Subject: [PATCH 285/488] merge: feat: improving implementation of graphs (#418) * feat: improving implementation of graphs * Minor refactoring in constructors Remove separate constructors for each type of class. Instead export the attribute `Directed` so that users can customize the `Graph` the way that they want. Similar to the implementation of `DefaultServer` in `net/http` package. Co-authored-by: Taj --- graph/graph.go | 49 +++++++++++------ graph/graph_test.go | 130 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 162 insertions(+), 17 deletions(-) diff --git a/graph/graph.go b/graph/graph.go index 6d00d1661..b6392c422 100644 --- a/graph/graph.go +++ b/graph/graph.go @@ -1,37 +1,54 @@ -// This file contains the simple structural implementation of undirected -// graph. Used in coloring algorithms [here](./coloring) -// Author(s): [Shivam](https://github.com/Shivam010) +// This file contains the simple structural implementation of +// directed & undirected graphs used within the graph package +// Author(s): [Shivam](https://github.com/Shivam010), [Tahmeed](https://github.com/Tahmeed156) package graph -// UndirectedGraph provides a structure to store an undirected graph. +// Graph provides a structure to store the graph. // It is safe to use its empty object. -type UndirectedGraph struct { +type Graph struct { vertices int - edges map[int]map[int]struct{} + edges map[int]map[int]int // Stores weight of an edge + Directed bool // Differentiate directed/undirected graphs } -// AddVertex will add a new vertex in the graph, if the vertex already -// exist it will do nothing -func (g *UndirectedGraph) AddVertex(v int) { +// Constructor functions for graphs (undirected by default) +func New(v int) *Graph { + return &Graph{ + vertices: v, + } +} + +// AddVertex will add a new vertex in the graph. +// If the vertex already exists it will do nothing. +func (g *Graph) AddVertex(v int) { if g.edges == nil { - g.edges = make(map[int]map[int]struct{}) + g.edges = make(map[int]map[int]int) } // Check if vertex is present or not if _, ok := g.edges[v]; !ok { - g.vertices++ - g.edges[v] = make(map[int]struct{}) + g.edges[v] = make(map[int]int) } } // AddEdge will add a new edge between the provided vertices in the graph -func (g *UndirectedGraph) AddEdge(one, two int) { +func (g *Graph) AddEdge(one, two int) { + // Add an edge with 0 weight + g.AddWeightedEdge(one, two, 0) +} + +// AddWeightedEdge will add a new weighted edge between the provided vertices in the graph +func (g *Graph) AddWeightedEdge(one, two, weight int) { // Add vertices: one and two to the graph if they are not present g.AddVertex(one) g.AddVertex(two) - // and finally add the edges: one->two and two->one for undirected graph - g.edges[one][two] = struct{}{} - g.edges[two][one] = struct{}{} + // And finally add the edges + // one->two and two->one for undirected graph + // one->two for directed graphs + g.edges[one][two] = weight + if !g.Directed { + g.edges[two][one] = weight + } } diff --git a/graph/graph_test.go b/graph/graph_test.go index db9fd54ce..032fcc529 100644 --- a/graph/graph_test.go +++ b/graph/graph_test.go @@ -1,3 +1,131 @@ -// Empty test file to keep track of all the tests for the algorithms. +// Tests for directed and undirected graphs package graph + +import ( + "fmt" + "testing" +) + +var graphTestCases = []struct { + name string + edges [][]int + vertices int +}{ + { + "single edge", + [][]int{ + {0, 1, 1}, + }, + 2, + }, + { + "many edges", + [][]int{ + {0, 1, 1}, + {0, 2, 2}, + {1, 3, 4}, + {3, 4, 3}, + {4, 8, 3}, + {4, 9, 1}, + {7, 8, 2}, + {8, 9, 2}, + }, + 10, + }, + { + "cycles", + [][]int{ + {0, 1, 1}, + {0, 2, 2}, + {1, 3, 4}, + {3, 4, 3}, + {4, 2, 1}, + }, + 5, + }, + { + "disconnected graphs", + [][]int{ + {0, 1, 5}, + {2, 4, 5}, + {3, 8, 5}, + }, + 2, + }, +} + +func TestDirectedGraph(t *testing.T) { + + // Testing self-loops separately only for directed graphs. + // For undirected graphs each edge already creates a self-loop. + directedGraphTestCases := append(graphTestCases, struct { + name string + edges [][]int + vertices int + }{ + "self-loops", + [][]int{ + {0, 1, 1}, + {1, 2, 2}, + {2, 1, 3}, + }, + 3, + }) + + for _, test := range directedGraphTestCases { + t.Run(fmt.Sprint(test.name), func(t *testing.T) { + // Initializing graph, adding edges + graph := New(test.vertices) + graph.Directed = true + for _, edge := range test.edges { + graph.AddWeightedEdge(edge[0], edge[1], edge[2]) + } + + if graph.vertices != test.vertices { + t.Errorf("Number of vertices, Expected: %d, Computed: %d", test.vertices, graph.vertices) + } + edgeCount := 0 + for _, e := range graph.edges { + edgeCount += len(e) + } + if edgeCount != len(test.edges) { + t.Errorf("Number of edges, Expected: %d, Computed: %d", len(test.edges), edgeCount) + } + for _, edge := range test.edges { + if val, found := graph.edges[edge[0]][edge[1]]; !found || val != edge[2] { + t.Errorf("Edge {%d->%d (%d)} not found", edge[0], edge[1], edge[2]) + } + } + }) + } +} + +func TestUndirectedGraph(t *testing.T) { + + for _, test := range graphTestCases { + t.Run(fmt.Sprint(test.name), func(t *testing.T) { + // Initializing graph, adding edges + graph := New(test.vertices) + for _, edge := range test.edges { + graph.AddWeightedEdge(edge[0], edge[1], edge[2]) + } + + if graph.vertices != test.vertices { + t.Errorf("Number of vertices, Expected: %d, Computed: %d", test.vertices, graph.vertices) + } + edgeCount := 0 + for _, e := range graph.edges { + edgeCount += len(e) + } + if edgeCount != len(test.edges)*2 { + t.Errorf("Number of edges, Expected: %d, Computed: %d", len(test.edges)*2, edgeCount) + } + for _, edge := range test.edges { + if val, found := graph.edges[edge[0]][edge[1]]; !found || val != edge[2] { + t.Errorf("Edge {%d->%d (%d)} not found", edge[0], edge[1], edge[2]) + } + } + }) + } +} From 44a0622d6dfba6503a1f9309e58afbe560c4f66b Mon Sep 17 00:00:00 2001 From: automoto Date: Mon, 1 Nov 2021 11:05:30 -0500 Subject: [PATCH 286/488] Fix broken link in README (#426) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6932d69d..81696afd9 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ### Data Structures * [AVL Tree](./structure/avl/avl.go) -* [Binary Tree](./structure/binarytree/btree.go) +* [Binary Tree](./structure/binarysearchtree/bstree.go) * [Dynamic Array](./structure/dynamicarray/dynamicarray.go) * [Hashmap](./structure/hashmap/hashmap.go) * Linked-List From 153ee2ceba76db27474ebdbd8e81218fa1e89306 Mon Sep 17 00:00:00 2001 From: Tahmeed Tarek Date: Wed, 3 Nov 2021 20:13:45 +0600 Subject: [PATCH 287/488] chore: feat: implement Bellman Ford algorithm (#423) Co-authored-by: Taj --- graph/bellmanford.go | 48 +++++++++++++ graph/bellmanford_test.go | 137 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 graph/bellmanford.go create mode 100644 graph/bellmanford_test.go diff --git a/graph/bellmanford.go b/graph/bellmanford.go new file mode 100644 index 000000000..6fe3e42c9 --- /dev/null +++ b/graph/bellmanford.go @@ -0,0 +1,48 @@ +// The Bellman–Ford algorithm is an algorithm that computes shortest paths from a +// single source vertex to all of the other vertices in a weighted durected graph. +// It is slower than Dijkstra but capable of handling negative edge weights. +// https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm +// Implementation is based on the book 'Introduction to Algorithms' (CLRS) +package graph + +import ( + "errors" + "math" +) + +func (g *Graph) BellmanFord(start, end int) (isReachable bool, distance int, err error) { + INF := math.Inf(1) + distances := make([]float64, g.vertices) + + // Set all vertices to unreachable, initialize source + for i := 0; i < g.vertices; i++ { + distances[i] = INF + } + distances[start] = 0 + + // Making iterations equal to #vertices + for n := 0; n < g.vertices; n++ { + + // Looping over all edges + for u, adjacents := range g.edges { + for v, weightUV := range adjacents { + + // If new shorter distance is found, update distance value (relaxation step) + if newDistance := distances[u] + float64(weightUV); distances[v] > newDistance { + distances[v] = newDistance + } + } + } + } + + // Check for negative weight cycle + for u, adjacents := range g.edges { + for v, weightUV := range adjacents { + if newDistance := distances[u] + float64(weightUV); distances[v] > newDistance { + return false, -1, errors.New("negative weight cycle present") + } + } + } + + return distances[end] != INF, int(distances[end]), nil +} diff --git a/graph/bellmanford_test.go b/graph/bellmanford_test.go new file mode 100644 index 000000000..2f9d57ea6 --- /dev/null +++ b/graph/bellmanford_test.go @@ -0,0 +1,137 @@ +package graph + +import ( + "errors" + "fmt" + "math" + "testing" +) + +func TestBellmanford(t *testing.T) { + + var testCases = []struct { + name string + edges [][]int + vertices int + start int + end int + isReachable bool + distance int + err error + }{ + { + "single edge", + [][]int{ + {0, 1, 1}, + }, + 2, 0, 1, true, 1, nil, + }, + { + "negative weights", + [][]int{ + {0, 1, 1}, + {1, 2, -3}, + {2, 1, 4}, + {2, 3, 1}, + }, + 4, 0, 1, true, 1, nil, + }, + { + "negative cycle", + [][]int{ + {0, 1, 1}, + {1, 2, -3}, + {2, 1, 1}, + {2, 3, 1}, + }, + 4, 0, 1, false, -1, errors.New("negative weight cycle present"), + }, + { + "unreachable vertex", + [][]int{ + {0, 6, 771}, + {0, 9, 782}, + {1, 2, 454}, + {2, 8, 48}, + {3, 8, 249}, + {3, 9, 880}, + {3, 5, 280}, + {7, 1, 92}, + {7, 2, 497}, + {8, 1, 102}, + {8, 4, 977}, + }, + 10, 8, 3, false, int(math.Inf(1)), nil, + }, + { + "disconnected graph", + [][]int{ + {0, 1, 10}, + {2, 3, 15}, + {3, 5, 10}, + }, + 6, 0, 3, false, int(math.Inf(1)), nil, + }, + { + "multiple paths", + [][]int{ + {0, 1, 5}, + {1, 2, 10}, + {1, 3, 30}, + {2, 4, 10}, + {4, 5, 15}, + {3, 5, 10}, + }, + 6, 0, 5, true, 40, nil, + }, + { + "random 1", + [][]int{ + {0, 1, 10}, + {1, 2, 10}, + {0, 2, 100}, + {2, 0, -10}, + {1, 2, 1}, + }, + 3, 0, 1, true, 10, nil, + }, + { + "random 2", + [][]int{ + {0, 1, 5498}, + {2, 0, 7679}, + {0, 3, 4999}, + {1, 2, 8629}, + {1, 3, -948}, + {2, 3, 6231}, + }, + 4, 0, 3, true, 4550, nil, + }, + } + + for _, test := range testCases { + t.Run(fmt.Sprint(test.name), func(t *testing.T) { + // Initializing graph, adding edges + graph := New(test.vertices) + graph.Directed = true + for _, edge := range test.edges { + graph.AddWeightedEdge(edge[0], edge[1], edge[2]) + } + + resIsReachable, resDistance, resError := graph.BellmanFord(test.start, test.end) + if resDistance != test.distance { + t.Errorf("Distance, Expected: %d, Computed: %d", test.distance, resDistance) + } + if resIsReachable != test.isReachable { + t.Errorf("Reachable, Expected: %t, Computed: %t", test.isReachable, resIsReachable) + } + if resError != test.err { + if resError == nil || test.err == nil { + t.Errorf("Reachable, Expected: %s, Computed: %s", test.err, resError) + } else if resError.Error() != test.err.Error() { + t.Errorf("Reachable, Expected: %s, Computed: %s", test.err.Error(), resError.Error()) + } + } + }) + } +} From 3a02506b7a663c034125bd7cf98bc97ecf374747 Mon Sep 17 00:00:00 2001 From: Metta Ong Date: Wed, 3 Nov 2021 22:17:32 +0800 Subject: [PATCH 288/488] merge: feat: dijkstra closest distance implementation (#415) * refactor * feat: implement dijkstra * test: adding multi path test cases * fix: varible naming in test * refactor * feat: generalize heap * feat: new implementation * cleanup * codespell * nit * fix conflict * Update graph/dijkstra.go Co-authored-by: Taj * Update graph/dijkstra.go Co-authored-by: Taj * (refactor) Co-authored-by: Taj Co-authored-by: Rak Laptudirm --- graph/dijkstra.go | 62 +++++++++++++++++++++ graph/dijkstra_test.go | 51 +++++++++++++++++ sort/heapsort.go | 124 ++++++++++++++++++++++++++++++++++------- 3 files changed, 217 insertions(+), 20 deletions(-) create mode 100644 graph/dijkstra.go create mode 100644 graph/dijkstra_test.go diff --git a/graph/dijkstra.go b/graph/dijkstra.go new file mode 100644 index 000000000..26b2becbc --- /dev/null +++ b/graph/dijkstra.go @@ -0,0 +1,62 @@ +package graph + +import "github.com/TheAlgorithms/Go/sort" + +type Item struct { + node int + dist int +} + +func (a Item) More(b interface{}) bool { + // reverse direction for minheap + return a.dist < b.(Item).dist +} +func (a Item) Idx() int { + return a.node +} + +func (g *Graph) Dijkstra(start, end int) (int, bool) { + visited := make(map[int]bool) + nodes := make(map[int]*Item) + + nodes[start] = &Item{ + dist: 0, + node: start, + } + pq := sort.MaxHeap{} + pq.Init(nil) + pq.Push(*nodes[start]) + + visit := func(curr Item) { + visited[curr.node] = true + for n, d := range g.edges[curr.node] { + if visited[n] { + continue + } + + item := nodes[n] + dist2 := curr.dist + d + if item == nil { + nodes[n] = &Item{node: n, dist: dist2} + pq.Push(*nodes[n]) + } else if item.dist > dist2 { + item.dist = dist2 + pq.Update(*item) + } + } + } + + for pq.Size() > 0 { + curr := pq.Pop().(Item) + if curr.node == end { + break + } + visit(curr) + } + + item := nodes[end] + if item == nil { + return -1, false + } + return item.dist, true +} diff --git a/graph/dijkstra_test.go b/graph/dijkstra_test.go new file mode 100644 index 000000000..168c7da69 --- /dev/null +++ b/graph/dijkstra_test.go @@ -0,0 +1,51 @@ +package graph + +import ( + "testing" +) + +var tc_dijkstra = []struct { + name string + edges [][]int + node0 int + node1 int + expected int +}{ + { + "straight line graph", + [][]int{{0, 1, 5}, {1, 2, 2}}, + 0, 2, 7, + }, + { + "unconnected node", + [][]int{{0, 1, 5}}, + 0, 2, -1, + }, + { + "double paths", + [][]int{{0, 1, 5}, {1, 3, 5}, {0, 2, 5}, {2, 3, 4}}, + 0, 3, 9, + }, + { + "double paths extended", + [][]int{{0, 1, 5}, {1, 3, 5}, {0, 2, 5}, {2, 3, 4}, {3, 4, 1}}, + 0, 4, 10, + }, +} + +func TestDijkstra(t *testing.T) { + for _, tc := range tc_dijkstra { + t.Run(tc.name, func(t *testing.T) { + var graph Graph + for _, edge := range tc.edges { + graph.AddWeightedEdge(edge[0], edge[1], edge[2]) + } + + actual, _ := graph.Dijkstra(tc.node0, tc.node1) + if actual != tc.expected { + t.Errorf("expected %d, got %d, from node %d to %d, with %v", + tc.expected, actual, tc.node0, tc.node1, tc.edges) + } + }) + } +} diff --git a/sort/heapsort.go b/sort/heapsort.go index 698c7610f..0c44eb515 100644 --- a/sort/heapsort.go +++ b/sort/heapsort.go @@ -1,50 +1,134 @@ package sort -type maxHeap struct { - slice []int +type MaxHeap struct { + slice []Comparable heapSize int + indices map[int]int } -func buildMaxHeap(slice []int) maxHeap { - h := maxHeap{slice: slice, heapSize: len(slice)} - for i := len(slice) / 2; i >= 0; i-- { - h.MaxHeapify(i) +func buildMaxHeap(slice0 []int) MaxHeap { + var slice []Comparable + for _, i := range slice0 { + slice = append(slice, Int(i)) } + h := MaxHeap{} + h.Init(slice) return h } -func (h maxHeap) MaxHeapify(i int) { +func (h *MaxHeap) Init(slice []Comparable) { + if slice == nil { + slice = make([]Comparable, 0) + } + + h.slice = slice + h.heapSize = len(slice) + h.indices = make(map[int]int) + h.Heapify() +} + +func (h MaxHeap) Heapify() { + for i, v := range h.slice { + h.indices[v.Idx()] = i + } + for i := h.heapSize / 2; i >= 0; i-- { + h.heapifyDown(i) + } +} + +func (h *MaxHeap) Pop() Comparable { + if h.heapSize == 0 { + return nil + } + + i := h.slice[0] + h.heapSize-- + + h.slice[0] = h.slice[h.heapSize] + h.updateidx(0) + h.heapifyDown(0) + + h.slice = h.slice[0:h.heapSize] + return i +} + +func (h *MaxHeap) Push(i Comparable) { + h.slice = append(h.slice, i) + h.updateidx(h.heapSize) + h.heapifyUp(h.heapSize) + h.heapSize++ +} + +func (h MaxHeap) Size() int { + return h.heapSize +} + +func (h MaxHeap) Update(i Comparable) { + h.slice[h.indices[i.Idx()]] = i + h.heapifyUp(h.indices[i.Idx()]) + h.heapifyDown(h.indices[i.Idx()]) +} + +func (h MaxHeap) updateidx(i int) { + h.indices[h.slice[i].Idx()] = i +} + +func (h MaxHeap) heapifyUp(i int) { + if i == 0 { + return + } + p := i / 2 + + if h.slice[i].More(h.slice[p]) { + h.slice[i], h.slice[p] = h.slice[p], h.slice[i] + h.updateidx(i) + h.updateidx(p) + h.heapifyUp(p) + } +} + +func (h MaxHeap) heapifyDown(i int) { l, r := 2*i+1, 2*i+2 max := i - if l < h.size() && h.slice[l] > h.slice[max] { + if l < h.heapSize && h.slice[l].More(h.slice[max]) { max = l } - if r < h.size() && h.slice[r] > h.slice[max] { + if r < h.heapSize && h.slice[r].More(h.slice[max]) { max = r } - //log.Printf("MaxHeapify(%v): l,r=%v,%v; max=%v\t%v\n", i, l, r, max, h.slice) if max != i { h.slice[i], h.slice[max] = h.slice[max], h.slice[i] - h.MaxHeapify(max) + h.updateidx(i) + h.updateidx(max) + h.heapifyDown(max) } } -func (h maxHeap) size() int { return h.heapSize } // ??? +type Comparable interface { + Idx() int + More(interface{}) bool +} +type Int int + +func (a Int) More(b interface{}) bool { + return a > b.(Int) +} +func (a Int) Idx() int { + return int(a) +} func HeapSort(slice []int) []int { h := buildMaxHeap(slice) - //log.Println(slice) for i := len(h.slice) - 1; i >= 1; i-- { h.slice[0], h.slice[i] = h.slice[i], h.slice[0] h.heapSize-- - h.MaxHeapify(0) - /*if i == len(h.slice)-1 || i == len(h.slice)-3 || i == len(h.slice)-5 { - element := (i - len(h.slice)) * -1 - fmt.Println("Heap after removing ", element, " elements") - fmt.Println(h.slice) + h.heapifyDown(0) + } - }*/ + res := []int{} + for _, i := range h.slice { + res = append(res, int(i.(Int))) } - return h.slice + return res } From 7ccc45ec7cb4fc03bb431fe72a711cbad455147d Mon Sep 17 00:00:00 2001 From: Ilya Sokolov Date: Mon, 8 Nov 2021 12:27:25 +0300 Subject: [PATCH 289/488] merge: feat: bitwise min (#427) * feat: bitwise min * fix: bitwise min, change for vararg * fix: change min tests * fix: benchmark for bitwise * fix: rename tests * fix: add value param * fix: change condition Co-authored-by: Rak Laptudirm --- math/min/bitwisemin.go | 16 +++++++ math/min/min_test.go | 103 +++++++++++++++++------------------------ 2 files changed, 58 insertions(+), 61 deletions(-) create mode 100644 math/min/bitwisemin.go diff --git a/math/min/bitwisemin.go b/math/min/bitwisemin.go new file mode 100644 index 000000000..9710910aa --- /dev/null +++ b/math/min/bitwisemin.go @@ -0,0 +1,16 @@ +// bitwisemin.go +// description: Gives min of two integers +// details: +// implementation of finding the minimum of two numbers using only binary operations without using conditions +// author(s) [red_byte](https://github.com/i-redbyte) +// see bitwisemin_test.go + +package min + +func Bitwise(base int, value int, values ...int) int { + min := value + for _, val := range values { + min = min&((min-val)>>base) | val&(^(min-val)>>base) + } + return min +} diff --git a/math/min/min_test.go b/math/min/min_test.go index 663f5b734..ec63ed0b8 100644 --- a/math/min/min_test.go +++ b/math/min/min_test.go @@ -1,81 +1,62 @@ -package min_test +package min import ( "testing" - - "github.com/TheAlgorithms/Go/math/min" ) -func TestMin(t *testing.T) { - testCases := []struct { - name string - left int - right int - min int +func getTestCases() []struct { + name string + base int + numbers []int + min int +} { + var tests = []struct { + name string + base int + numbers []int + min int }{ - { - name: "left is min", - left: 1, - right: 10, - min: 1, - }, - { - name: "right is min", - left: 10, - right: 9, - min: 9, - }, + {"Minimum of [128, 127], min = 117", 8, []int{128, 127}, 127}, + {"Minimum of [5], min = 5", 32, []int{5}, 5}, + {"Minimum of [-8, 32, 64, -1, 0], min = -8", 64, []int{-8, 32, 64, -1, 0}, -8}, + {"Minimum of [1, 2, 3, 4, 5], min = 1", 32, []int{1, 2, 3, 4, 5}, 1}, + {"Minimum of [1024, 512, 256, 333, 777], min = 256", 64, []int{1024, 512, 256, 333, 777}, 256}, + {"Minimum of [-9223372036854770001, -9223372036854770000, 256, 333, 777], min = 256", 64, []int{-9223372036854770001, -9223372036854770000, 256, 333, 777}, -9223372036854770001}, } + return tests +} - for _, test := range testCases { +func TestBitwiseMin(t *testing.T) { + tests := getTestCases() + for _, test := range tests { t.Run(test.name, func(t *testing.T) { - actualMin := min.Int(test.left, test.right) - if actualMin != test.min { - t.Errorf("Failed test %s\n\tleft: %v, right: %v, min: %v but received: %v", - test.name, test.left, test.right, test.min, actualMin) + result := Bitwise(test.base, 999, test.numbers...) + if result != test.min { + t.Errorf("Wrong result! Expected:%v, returned:%v ", test.min, result) } }) } } -func TestMinOfThree(t *testing.T) { - testCases := []struct { - name string - left int - middle int - right int - min int - }{ - { - name: "left is min", - left: 1, - middle: 5, - right: 10, - min: 1, - }, - { - name: "middle is min", - left: 10, - middle: 5, - right: 9, - min: 5, - }, - { - name: "right is min", - left: 10, - middle: 8, - right: 6, - min: 6, - }, - } - - for _, test := range testCases { +func TestMin(t *testing.T) { + for _, test := range getTestCases() { t.Run(test.name, func(t *testing.T) { - actualMin := min.Int(test.left, test.middle, test.right) + actualMin := Int(test.numbers...) if actualMin != test.min { - t.Errorf("Failed test %s\n\tleft: %v, middle: %v, right: %v, min: %v but received: %v", - test.name, test.left, test.middle, test.right, test.min, actualMin) + t.Errorf("Wrong result! Expected:%v, returned:%v ", test.min, actualMin) } }) } } + +func BenchmarkTestMinInt(b *testing.B) { + for i := 0; i < b.N; i++ { + Int(0, 10, 9, 7, 2, 1, 4, 3, 5, 6) + } +} + +func BenchmarkTestBitwiseMin(b *testing.B) { + for i := 0; i < b.N; i++ { + Bitwise(32, 10, 9, 7, 2, 1, 4, 3, 5, 6) + } +} From ec28323411dc5381c897fc49703f8ba1974c5536 Mon Sep 17 00:00:00 2001 From: Taj Date: Tue, 9 Nov 2021 19:12:47 +0000 Subject: [PATCH 290/488] feat: Godocmd action added for updating readme automatically. (#429) * workflow * fix: workflow * feat: workflow * Updated README.md * Update README.md * Updated README.md * Update generate_readme.yml * Update generate_readme.yml * Updated Documentation in README.md * Update generate_readme.yml * Updated Documentation in README.md * Update README.md * Updated Documentation in README.md * Update generate_readme.yml * Updated Documentation in README.md * Update README.md * Updated Documentation in README.md * fix: package level documentation * Updated Documentation in README.md * fix: incorrect package level documentation * Updated Documentation in README.md * Update README.md * Updated Documentation in README.md * Update decimaltobinary.go * Updated Documentation in README.md * fix: incorrect documentation format * Updated Documentation in README.md * fix: documentation format * Updated Documentation in README.md * fix: documentation format * Updated Documentation in README.md * fix: documentation * Updated Documentation in README.md * fix: documentation * Updated Documentation in README.md * Update generate_readme.yml * Update golang_lint_and_test.yml * Update generate_readme.yml * Update generate_readme.yml * fix: documentation * fix: godocmd badge * Update README.md * Update godocmd.yml * Updated Documentation in README.md Co-authored-by: godocmd-action <${GITHUB_ACTOR}@users.noreply.github.com> --- .github/workflows/godocmd.yml | 28 + .github/workflows/golang_lint_and_test.yml | 13 +- README.md | 934 ++++++++++++++++++--- conversion/binarytodecimal.go | 1 - conversion/decimaltobinary.go | 1 - graph/bellmanford.go | 1 + math/binary/xorsearch_test.go | 1 + sort/countingsort.go | 1 - structure/set/set.go | 3 + structure/set/set_test.go | 3 - structure/set/setexample_test.go | 4 - 11 files changed, 870 insertions(+), 120 deletions(-) create mode 100644 .github/workflows/godocmd.yml diff --git a/.github/workflows/godocmd.yml b/.github/workflows/godocmd.yml new file mode 100644 index 000000000..86abaa4cc --- /dev/null +++ b/.github/workflows/godocmd.yml @@ -0,0 +1,28 @@ +name: godocmd +on: [push, pull_request] +jobs: + generate_readme: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: '^1.17' + - name: Install GoDocMD + run: | + go install github.com/tjgurwara99/godocmd@v0.1.2 + - name: Configure Github Action + run: | + git config --global user.name github-action + git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com' + - name: Update README.md file + run: | + godocmd -r -module ./ -w + - name: Commit changes if README.md is different + run: | + if [[ `git status --porcelain` ]]; then + git commit -am "Updated Documentation in README.md" + git push + else + echo "NO CHANGES DETECTED" + fi diff --git a/.github/workflows/golang_lint_and_test.yml b/.github/workflows/golang_lint_and_test.yml index f065817f4..4cb59f712 100644 --- a/.github/workflows/golang_lint_and_test.yml +++ b/.github/workflows/golang_lint_and_test.yml @@ -8,14 +8,17 @@ jobs: fail-fast: false steps: - uses: actions/checkout@v2 - - uses: codespell-project/actions-codespell@master + - name: Codespell + uses: codespell-project/actions-codespell@master with: ignore_words_list: "actualy,nwe" skip: "go.mod,go.sum" - - uses: actions/setup-go@v2 - - run: go version - - uses: golangci/golangci-lint-action@v2 + - name: Setup Go + uses: actions/setup-go@v2 + - name: Run Golang CI Lint + uses: golangci/golangci-lint-action@v2 with: version: latest args: -E gofmt - - run: go test ./... + - name: Run tests + run: go test ./... diff --git a/README.md b/README.md index 81696afd9..9d6dc902a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # The Algorithms - Go [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/TheAlgorithms/Go)  ![golangci-lint](https://github.com/TheAlgorithms/Go/workflows/golangci-lint/badge.svg) +![godocmd](https://github.com/tjgurwara99/Go/workflows/godocmd/badge.svg) ![](https://img.shields.io/github/repo-size/TheAlgorithms/Go.svg?label=Repo%20size&style=flat-square)  ![update_directory_md](https://github.com/TheAlgorithms/Go/workflows/update_directory_md/badge.svg) [![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=7289DA&style=flat-square)](https://discord.gg/c7MnfGFGa6)  @@ -12,109 +13,832 @@ The repository is a collection of open-source implementation of a variety of alg Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute. ## List of Algorithms + +# Packages: -### Ciphers -* [Caesar](./cipher/caesar/caesar.go) -* [Diffie Hellman Key Exchange](./cipher/diffiehellman/diffiehellmankeyexchange.go) -* [Polybius](./cipher/polybius/polybius.go) -* [Rot13](./cipher/rot13/rot13.go) -* [Rsa](./cipher/rsa/rsa.go) -* [Xor](./cipher/xor/xor.go) - -### Conversions -* [Roman Numeral To Integer](./conversion/romantointeger.go) -* [Integer To Roman Numeral](./conversion/integertoroman.go) -* [Decimal To Binary](./conversion/decimaltobinary.go) -* [Binary To Decimal](./conversion/binarytodecimal.go) - -### Data Structures -* [AVL Tree](./structure/avl/avl.go) -* [Binary Tree](./structure/binarysearchtree/bstree.go) -* [Dynamic Array](./structure/dynamicarray/dynamicarray.go) -* [Hashmap](./structure/hashmap/hashmap.go) -* Linked-List - * [Doubly Linked List](./structure/linkedlist/doubly.go) - * [Singly Linked List](./structure/linkedlist/singlylinkedlist.go) - * [Cyclic Linked List AKA Looped Linked List](./structure/linkedlist/cyclic.go) -* [Queue](./structure/queue) - * [Array Based](./structure/queue/queuearray.go) - * [Custom Linked List Based](./structure/queue/queuelinkedlist.go) - * [Standard Library Container/List Based](./structure/queue/queuelinkedlist.go) -* [Set](./structure/set/set.go) -* [Stack](./structure/stack) - * [Array Based](./structure/stack/stackarray.go) - * [Custom Linked List](./structure/stack/stacklinkedlist.go) - * [Standard Library Container/List Based](structure/stack/stacklinkedlistwithlist.go) -* [Trie](./structure/trie/trie.go) - -### Dynamic Programming -* [Binomial Coefficient](./dynamic/binomialcoefficient.go) -* [Fibonacci](./dynamic/fibonacci.go) -* [Knapsack](./dynamic/knapsack.go) -* [Longest Common Subsequence](./dynamic/longestcommonsubsequence.go) -* [Longest Palindromic Subsequence](./dynamic/longestpalindromicsubsequence.go) -* [Matrix Multiplication](./dynamic/matrixmultiplication.go) -* [Cutting a Rod](./dynamic/rodcutting.go) - -### Graphs -* [Breadth First Search](./graph/breadthfirstsearch.go) -* [Depth First Search](./graph/depthfirstsearch.go) -* [Floyd Warshall](./graph/floydwarshall.go) -* [Coloring Algorithms](./graph/coloring) - * [Using BFS](./graph/coloring/bfs.go) - * [Using Backtracking](./graph/coloring/backtracking.go) - * [Using Greedy Approach](./graph/coloring/greedy.go) - -### Math -* [Gcd](./math/gcd) - * [Extended](./math/gcd/extended.go) - * [Recursive](./math/gcd/gcd.go) - * [Iterative](./math/gcd/gcditerative.go) -* [Lcm](./math/lcm/lcm.go) -* [Max](./math/max/max.go) -* [Modular](./math/modular) - * [Exponentiation](./math/modular/exponentiation.go) - * [Inverse](./math/modular/inverse.go) -* [Moser-de Bruijn sequence](./math/moserdebruijnsequence/sequence.go) -* [Permutation](./math/permutation/heaps.go) -* [Power](./math/power/fastexponent.go) -* [Prime](./math/prime) - * [Miller Rabin Primality Test](./math/prime/millerrabinprimalitytest.go) - * [Naive and Pair Approach](./math/prime/primecheck.go) - * [Sieve](./math/prime/sieve.go) -* [Pythagoras](./math/pythagoras/pythagoras.go) -* [Sieve](./math/prime/sieve.go) -* [Straight Lines](./math/geometry/straightlines.go) - -### Other -* [Max Subarray Sum](./other/maxsubarraysum/maxsubarraysum.go) -* [Nested Brackets](./other/nested/nestedbrackets.go) -* [Password Generator](./other/password/generator.go) - -### Searches -* [Binary Search](./search/binary.go) -* [Linear Search](./search/linear.go) -* [Interpolation Search](./search/interpolation.go) - -### Sorts -* [Bubble Sort](./sort/bubblesort.go) -* [Heap Sort](./sort/heapsort.go) -* [Insertion Sort](./sort/insertionsort.go) -* [Merge Sort](./sort/mergesort.go) -* [Quick Sort](./sort/quicksort.go) -* [Radix Sort](./sort/radixsort.go) -* [Selection Sort](./sort/selectionsort.go) -* [Shell Sort](./sort/shellsort.go) - - -* [Sorts Test](./sort/sorts_test.go) - -### Strings -* [Levenshtein Distance](./strings/levenshtein/levenshteindistance.go) -* Multiple String Matching - * [Advanced Aho Corasick](./strings/ahocorasick/advancedahocorasick.go) - * [Aho Corasick](./strings/ahocorasick/ahocorasick.go) -* Single String Matching - * [Bom](./strings/bom/bom.go) - * [Horspool](./strings/horspool/horspool.go) - * [Kmp](./strings/kmp/kmp.go) +

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 z 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