├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── algorithms └── astar │ ├── README.md │ ├── a_star.go │ └── grids │ ├── grid_generator.go │ ├── grid_node.go │ ├── grid_world.go │ ├── grid_world_test.go │ └── output.png ├── datastructures ├── linkedlists │ ├── doublylinkedlists │ │ ├── README.md │ │ ├── doubly_linked_lists.go │ │ └── doubly_linked_lists_test.go │ └── singlylinkedlists │ │ ├── README.md │ │ ├── singly_linked_lists.go │ │ └── singly_linked_lists_test.go ├── maps │ ├── hashmultimaps │ │ ├── README.md │ │ ├── hash_multi_map.go │ │ └── hash_multi_map_test.go │ └── lrucaches │ │ ├── README.md │ │ ├── lru_cache.go │ │ └── lru_cache_test.go ├── priorityqueues │ ├── README.md │ ├── heap.go │ ├── priority_queues.go │ └── priorityqueues_test.go ├── queues │ ├── README.md │ ├── queues.go │ └── queues_test.go ├── sets │ ├── hashmultisets │ │ ├── README.md │ │ ├── hash_multi_set.go │ │ └── hash_multi_set_test.go │ └── hashsets │ │ ├── README.md │ │ ├── hash_set.go │ │ └── hash_set_test.go ├── stacks │ ├── linkedliststacks │ │ ├── README.md │ │ ├── linked_list_stacks.go │ │ └── linked_list_stacks_test.go │ ├── minmaxstacks │ │ ├── README.md │ │ ├── min_max_stacks.go │ │ └── min_max_stacks_test.go │ └── slicestacks │ │ ├── README.md │ │ ├── slice_stacks.go │ │ └── slice_stacks_test.go └── trees │ └── trees.go ├── evaluations ├── postfixes │ ├── README.md │ ├── postfixes.go │ └── postfixes_test.go └── repeatingfractions │ ├── README.md │ ├── repeating_fractions.go │ └── repeating_fractions_test.go ├── go.mod ├── go.sum ├── lists ├── detectcycles │ ├── README.md │ ├── detect_cycles.go │ └── detect_cycles_test.go ├── detectintersections │ ├── README.md │ ├── detect_intersections.go │ └── detect_intersections_test.go └── reverses │ ├── README.md │ ├── reverses.go │ └── reverses_test.go ├── numbers ├── armstrongs │ ├── README.md │ ├── armstrongs.go │ └── armstrongs_test.go ├── bases │ ├── README.md │ ├── bases.go │ └── bases_test.go ├── countdigits │ ├── README.md │ ├── count_digits.go │ └── count_digits_test.go ├── countprimes │ ├── README.md │ ├── count_primes.go │ └── count_primes_test.go ├── excels │ ├── README.md │ ├── excels.go │ └── excels_test.go ├── fibonaccis │ ├── README.md │ ├── fibonaccis.go │ └── fibonaccis_test.go ├── leapyears │ ├── README.md │ ├── leap_years.go │ └── leap_years_test.go ├── palindromes │ ├── README.md │ ├── palindromes.go │ └── palindromes_test.go ├── perfects │ ├── README.md │ ├── perfects.go │ └── perfects_test.go ├── powers │ ├── README.md │ ├── powers.go │ └── powers_test.go ├── primes │ ├── README.md │ ├── primes.go │ └── primes_test.go └── reverses │ ├── README.md │ ├── reverses.go │ └── reverses_test.go ├── slices ├── duplicates │ ├── README.md │ ├── duplicates.go │ └── duplicates_test.go ├── groupanagrams │ ├── README.md │ ├── group_anagrams.go │ └── group_anagrams_test.go ├── minmeetingrooms │ ├── README.md │ ├── min_meeting_rooms.go │ └── min_meeting_rooms_test.go └── rotations │ ├── countrotations │ ├── README.md │ ├── count_rotations.go │ └── count_rotations_test.go │ └── minrotations │ ├── README.md │ ├── min_rotations.go │ └── min_rotations_test.go ├── stacks └── balancedparantheses │ ├── README.md │ ├── balanced_parantheses.go │ └── balanced_parantheses_test.go ├── streams ├── movingaverages │ ├── README.md │ ├── moving_averages.go │ └── moving_averages_test.go ├── runningaverages │ ├── README.md │ ├── running_averages.go │ └── running_averages_test.go └── runningmedians │ ├── README.md │ ├── running_medians.go │ └── running_medians_test.go ├── strings ├── addbinaries │ ├── README.md │ ├── add_binaries.go │ └── add_binaries_test.go ├── palindromes │ ├── palindromesentences │ │ ├── README.md │ │ ├── palindrome_sentences.go │ │ └── palindrome_sentences_test.go │ └── palindromestrings │ │ ├── README.md │ │ ├── palindrome_strings.go │ │ └── palindrome_strings_test.go ├── reverses │ ├── reversesentences │ │ ├── README.md │ │ ├── reverse_sentences.go │ │ └── reverse_sentences_test.go │ └── reversestrings │ │ ├── README.md │ │ ├── reverse_strings.go │ │ └── reverse_strings_test.go ├── sorts │ ├── README.md │ ├── sorts.go │ └── sorts_test.go └── wordbreakers │ ├── README.md │ ├── word_breaker.go │ └── word_breaker_test.go └── trees ├── balancedtrees ├── balancedbinarytrees │ ├── README.md │ ├── balanced_binary_trees.go │ └── balanced_binary_trees_test.go └── balancedmultitrees │ ├── README.md │ ├── balanced_multi_trees.go │ └── balanced_multi_trees_test.go ├── heights ├── binarytreeheights │ ├── README.md │ ├── binary_tree_heights.go │ └── binary_tree_heights_test.go └── multitreeheights │ ├── README.md │ ├── multi_tree_heights.go │ └── multi_tree_heights_test.go ├── inverttrees ├── invertbinarytrees │ ├── README.md │ ├── invert_binary_trees.go │ └── invert_binary_trees_test.go └── invertmultitrees │ ├── README.md │ ├── invert_multi_trees.go │ └── invert_multi_trees_test.go ├── longestdistinctpaths ├── README.md ├── longest_distinct_paths.go └── longest_distinct_paths_test.go ├── printcolumns ├── README.md ├── print_columns.go └── print_columns_test.go ├── printlevels ├── README.md ├── print_levels.go └── print_levels_test.go └── printzigzag ├── README.md ├── print_zigzag.go └── print_zigzag_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.x -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Raed Shomali 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-interview [![Build Status](https://travis-ci.com/shomali11/go-interview.svg?branch=master)](https://travis-ci.com/shomali11/go-interview) [![Go Report Card](https://goreportcard.com/badge/github.com/shomali11/go-interview)](https://goreportcard.com/report/github.com/shomali11/go-interview) [![GoDoc](https://godoc.org/github.com/shomali11/go-interview?status.svg)](https://godoc.org/github.com/shomali11/go-interview) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | 3 | Collection of Technical Interview Questions solved with Go 4 | 5 | * [Algorithms](https://github.com/shomali11/go-interview/tree/master/algorithms) 6 | * [A Star](https://github.com/shomali11/go-interview/tree/master/algorithms/astar) 7 | * [Datastructures](https://github.com/shomali11/go-interview/tree/master/datastructures) 8 | * [Linked Lists](https://github.com/shomali11/go-interview/tree/master/datastructures/linkedlists) 9 | * [Doubly Linked List](https://github.com/shomali11/go-interview/tree/master/datastructures/linkedlists/doublylinkedlists) 10 | * [Singly Linked List](https://github.com/shomali11/go-interview/tree/master/datastructures/linkedlists/singlylinkedlists) 11 | * [Maps](https://github.com/shomali11/go-interview/tree/master/datastructures/maps) 12 | * [Hash Multi Maps](https://github.com/shomali11/go-interview/tree/master/datastructures/maps/hashmultimaps) 13 | * [LRU Caches](https://github.com/shomali11/go-interview/tree/master/datastructures/maps/lrucaches) 14 | * [Trees](https://github.com/shomali11/go-interview/tree/master/datastructures/trees) 15 | * [Priority Queues](https://github.com/shomali11/go-interview/tree/master/datastructures/priorityqueues) 16 | * [Queues](https://github.com/shomali11/go-interview/tree/master/datastructures/queues) 17 | * [Sets](https://github.com/shomali11/go-interview/tree/master/datastructures/sets) 18 | * [Hash Multi Sets](https://github.com/shomali11/go-interview/tree/master/datastructures/sets/hashmultisets) 19 | * [Hash Sets](https://github.com/shomali11/go-interview/tree/master/datastructures/sets/hashsets) 20 | * [Stacks](https://github.com/shomali11/go-interview/tree/master/datastructures/stacks) 21 | * [Linked List Stacks](https://github.com/shomali11/go-interview/tree/master/datastructures/stacks/linkedliststacks) 22 | * [Min/Max Stacks](https://github.com/shomali11/go-interview/tree/master/datastructures/stacks/minmaxstacks) 23 | * [Slice Stacks](https://github.com/shomali11/go-interview/tree/master/datastructures/stacks/slicestacks) 24 | * [Evaluations](https://github.com/shomali11/go-interview/tree/master/evaluations) 25 | * [Postfix](https://github.com/shomali11/go-interview/tree/master/evaluations/postfixes) 26 | * [Repeating Fractions](https://github.com/shomali11/go-interview/tree/master/evaluations/repeatingfractions) 27 | * [Lists](https://github.com/shomali11/go-interview/tree/master/lists) 28 | * [Detect Cycle](https://github.com/shomali11/go-interview/tree/master/lists/detectcycles) 29 | * [Detect Intersection](https://github.com/shomali11/go-interview/tree/master/lists/detectintersections) 30 | * [Reverse List](https://github.com/shomali11/go-interview/tree/master/lists/reverses) 31 | * [Numbers](https://github.com/shomali11/go-interview/tree/master/numbers) 32 | * [Armstrong Number](https://github.com/shomali11/go-interview/tree/master/numbers/armstrongs) 33 | * [Base Conversions](https://github.com/shomali11/go-interview/tree/master/numbers/bases) 34 | * [Count Digits](https://github.com/shomali11/go-interview/tree/master/numbers/countdigits) 35 | * [Count Primes](https://github.com/shomali11/go-interview/tree/master/numbers/countprimes) 36 | * [Excel Column Conversions](https://github.com/shomali11/go-interview/tree/master/numbers/excels) 37 | * [Fibonacci Number](https://github.com/shomali11/go-interview/tree/master/numbers/fibonaccis) 38 | * [Leap Years](https://github.com/shomali11/go-interview/tree/master/numbers/leapyears) 39 | * [Palindromes](https://github.com/shomali11/go-interview/tree/master/numbers/palindromes) 40 | * [Perfect Number](https://github.com/shomali11/go-interview/tree/master/numbers/perfects) 41 | * [Power Function](https://github.com/shomali11/go-interview/tree/master/numbers/powers) 42 | * [Prime Number](https://github.com/shomali11/go-interview/tree/master/numbers/primes) 43 | * [Reverse](https://github.com/shomali11/go-interview/tree/master/numbers/reverses) 44 | * [Stacks](https://github.com/shomali11/go-interview/tree/master/stacks) 45 | * [Balanced Parantheses](https://github.com/shomali11/go-interview/tree/master/stacks/balancedparantheses) 46 | * [Slices](https://github.com/shomali11/go-interview/tree/master/slices) 47 | * [Duplicates](https://github.com/shomali11/go-interview/tree/master/slices/duplicates) 48 | * [Group Anagrams](https://github.com/shomali11/go-interview/tree/master/slices/groupanagrams) 49 | * [Min Meeting Rooms](https://github.com/shomali11/go-interview/tree/master/slices/minmeetingrooms) 50 | * [Rotations](https://github.com/shomali11/go-interview/tree/master/slices/rotations) 51 | * [Count Rotations](https://github.com/shomali11/go-interview/tree/master/slices/rotations/countrotations) 52 | * [Minimum in Rotated Array](https://github.com/shomali11/go-interview/tree/master/slices/rotations/minrotations) 53 | * [Streams](https://github.com/shomali11/go-interview/tree/master/streams) 54 | * [Moving Average](https://github.com/shomali11/go-interview/tree/master/streams/movingaverages) 55 | * [Running Average](https://github.com/shomali11/go-interview/tree/master/streams/runningaverages) 56 | * [Running Median](https://github.com/shomali11/go-interview/tree/master/streams/runningmedians) 57 | * [Strings](https://github.com/shomali11/go-interview/tree/master/strings) 58 | * [Add Binary Strings](https://github.com/shomali11/go-interview/tree/master/strings/addbinaries) 59 | * [Palindromes](https://github.com/shomali11/go-interview/tree/master/strings/palindromes) 60 | * [Palindrome Sentences](https://github.com/shomali11/go-interview/tree/master/strings/palindromes/palindromesentences) 61 | * [Palindrome Strings](https://github.com/shomali11/go-interview/tree/master/strings/palindromes/palindromestrings) 62 | * [Reverses](https://github.com/shomali11/go-interview/tree/master/strings/reverses) 63 | * [Reverse Sentences](https://github.com/shomali11/go-interview/tree/master/strings/reverses/reversesentences) 64 | * [Reverse Strings](https://github.com/shomali11/go-interview/tree/master/strings/reverses/reversestrings) 65 | * [Sort](https://github.com/shomali11/go-interview/tree/master/strings/sorts) 66 | * [Break Words](https://github.com/shomali11/go-interview/tree/master/strings/wordbreakers) 67 | * [Trees](https://github.com/shomali11/go-interview/tree/master/trees) 68 | * [Balanced Trees](https://github.com/shomali11/go-interview/tree/master/trees/balancedtrees) 69 | * [Balanced Binary Trees](https://github.com/shomali11/go-interview/tree/master/trees/balancedtrees/balancedbinarytrees) 70 | * [Balanced Trees](https://github.com/shomali11/go-interview/tree/master/trees/balancedtrees/balancedmultitrees) 71 | * [Heights](https://github.com/shomali11/go-interview/tree/master/trees/heights) 72 | * [Binary Tree Heights](https://github.com/shomali11/go-interview/tree/master/trees/heights/binarytreeheights) 73 | * [Tree Heights](https://github.com/shomali11/go-interview/tree/master/trees/heights/multitreeheights) 74 | * [Invert Trees](https://github.com/shomali11/go-interview/tree/master/trees/inverttrees) 75 | * [Invert Binary Trees](https://github.com/shomali11/go-interview/tree/master/trees/inverttrees/invertbinarytrees) 76 | * [Invert Trees](https://github.com/shomali11/go-interview/tree/master/trees/inverttrees/invertmultitrees) 77 | * [Longest Distinct Paths](https://github.com/shomali11/go-interview/tree/master/trees/longestdistinctpaths) 78 | * [Print By Columns](https://github.com/shomali11/go-interview/tree/master/trees/printcolumns) 79 | * [Print By Levels](https://github.com/shomali11/go-interview/tree/master/trees/printlevels) 80 | * [Print Zig Zag](https://github.com/shomali11/go-interview/tree/master/trees/printzigzag) -------------------------------------------------------------------------------- /algorithms/astar/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement the A* algorithm. A* is a graph traversal and path search algorithm 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Start (0,0) Goal (8,8) 9 | 10 | [1 1 1 3 1 1 1 1 1] 11 | [1 1 X 1 1 1 1 1 1] 12 | [1 X 1 1 1 1 1 1 1] 13 | [X 1 1 1 1 1 1 1 1] 14 | [1 1 1 1 1 1 1 1 1] 15 | [1 1 1 1 1 1 1 1 1] 16 | [1 1 1 1 1 1 1 1 1] 17 | [1 1 1 1 1 1 1 1 1] 18 | [1 1 1 1 1 1 1 1 1] 19 | 20 | Output: 21 | 22 | Distance: 15.313708498984763 23 | 24 | [* * * 3 1 1 1 1 1] 25 | [1 1 X * 1 1 1 1 1] 26 | [1 X 1 1 * 1 1 1 1] 27 | [X 1 1 1 1 * 1 1 1] 28 | [1 1 1 1 1 1 * 1 1] 29 | [1 1 1 1 1 1 1 * 1] 30 | [1 1 1 1 1 1 1 * 1] 31 | [1 1 1 1 1 1 1 1 *] 32 | [1 1 1 1 1 1 1 1 *] 33 | ``` 34 | 35 | ![Result](grids/output.png) 36 | 37 | *Image generated using https://github.com/shomali11/gridder* -------------------------------------------------------------------------------- /algorithms/astar/a_star.go: -------------------------------------------------------------------------------- 1 | package astar 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 7 | "github.com/shomali11/go-interview/datastructures/priorityqueues" 8 | "github.com/shomali11/go-interview/datastructures/sets/hashsets" 9 | ) 10 | 11 | var ( 12 | positiveInfinity = math.Inf(1) 13 | ) 14 | 15 | // Node a node interface 16 | type Node interface { 17 | EstimateDistanceToGoal(goal Node) float64 18 | ActualDistanceToNeighbor(neighbor Node) float64 19 | GetNeighbors() []Node 20 | } 21 | 22 | type wrapper struct { 23 | h float64 24 | g float64 25 | node Node 26 | parent *wrapper 27 | } 28 | 29 | // New new factory 30 | func New() *AStar { 31 | compare := func(one, two *wrapper) bool { 32 | f1 := one.g + one.h 33 | f2 := two.g + two.h 34 | 35 | // Tie Breaker ... Maximum G Value 36 | if f1 == f2 { 37 | g1 := one.g 38 | g2 := two.g 39 | 40 | // Maximum G Value 41 | return g1 > g2 42 | } 43 | 44 | // Minimum F Value 45 | return f1 < f2 46 | } 47 | return &AStar{ 48 | openPQ: priorityqueues.New[*wrapper](compare), 49 | closedSet: hashsets.New[*wrapper](), 50 | nodeWrapperMap: make(map[Node]*wrapper), 51 | } 52 | } 53 | 54 | // AStar a star 55 | type AStar struct { 56 | openPQ *priorityqueues.PriorityQueue[*wrapper] 57 | closedSet *hashsets.HashSet[*wrapper] 58 | nodeWrapperMap map[Node]*wrapper 59 | } 60 | 61 | // Search search 62 | func (s *AStar) Search(start Node, goal Node) ([]Node, float64) { 63 | defer s.clear() 64 | 65 | startWrapper := s.getWrapper(start) 66 | startWrapper.h = start.EstimateDistanceToGoal(goal) 67 | 68 | goalWrapper := s.getWrapper(goal) 69 | 70 | s.openPQ.Push(startWrapper) 71 | 72 | // While not Empty ... 73 | for !s.openPQ.IsEmpty() { 74 | // Extract Top of the Heap ... 75 | currentElement, _ := s.openPQ.Pop() 76 | 77 | // Did we reach Goal ? 78 | if currentElement == goalWrapper { 79 | // Shortest Path ... 80 | return getPath(goalWrapper), goalWrapper.g 81 | } 82 | 83 | // Set Node to Visited ... 84 | s.closedSet.Add(currentElement) 85 | 86 | // Get List of neighbors .. 87 | neighbors := currentElement.node.GetNeighbors() 88 | 89 | // Traverse the neighbors ... 90 | for _, neighborNode := range neighbors { 91 | neighborWrapper := s.getWrapper(neighborNode) 92 | 93 | // We only care about the ones we did not visit ... 94 | if !s.closedSet.Contains(neighborWrapper) { 95 | // Is not in the Heap .. 96 | if !s.openPQ.Contains(neighborWrapper) { 97 | neighborWrapper.g = positiveInfinity 98 | neighborWrapper.parent = nil 99 | } 100 | 101 | s.updateVertex(currentElement, neighborWrapper, goalWrapper) 102 | } 103 | } 104 | } 105 | return make([]Node, 0), 0 106 | } 107 | 108 | func (s *AStar) updateVertex(currentWrapper *wrapper, neighborWrapper *wrapper, goalWrapper *wrapper) { 109 | // Check for Consistency .. 110 | totalCostToNeighbor := currentWrapper.g + currentWrapper.node.ActualDistanceToNeighbor(neighborWrapper.node) 111 | if totalCostToNeighbor < neighborWrapper.g { 112 | // Update the G Function 113 | neighborWrapper.g = totalCostToNeighbor 114 | neighborWrapper.parent = currentWrapper 115 | 116 | // If Min Heap Has the Node .. 117 | if s.openPQ.Contains(neighborWrapper) { 118 | // Remove it .. 119 | s.openPQ.Remove(neighborWrapper) 120 | } 121 | 122 | // Add the state with the new function value .. 123 | neighborWrapper.h = neighborWrapper.node.EstimateDistanceToGoal(goalWrapper.node) 124 | s.openPQ.Push(neighborWrapper) 125 | } 126 | } 127 | 128 | func (s *AStar) clear() { 129 | s.nodeWrapperMap = make(map[Node]*wrapper) 130 | s.closedSet.Clear() 131 | s.openPQ.Clear() 132 | } 133 | 134 | func (s *AStar) getWrapper(node Node) *wrapper { 135 | w, ok := s.nodeWrapperMap[node] 136 | if ok { 137 | return w 138 | } 139 | 140 | w = &wrapper{node: node} 141 | s.nodeWrapperMap[node] = w 142 | return w 143 | } 144 | 145 | func getPath(goalWrapper *wrapper) []Node { 146 | path := singlylinkedlists.New[Node]() 147 | currentWrapper := goalWrapper 148 | for currentWrapper != nil { 149 | path.InsertAt(0, currentWrapper.node) 150 | currentWrapper = currentWrapper.parent 151 | } 152 | 153 | nodeList := make([]Node, 0) 154 | for _, value := range path.GetValues() { 155 | nodeList = append(nodeList, value.(Node)) 156 | } 157 | return nodeList 158 | } 159 | -------------------------------------------------------------------------------- /algorithms/astar/grids/grid_generator.go: -------------------------------------------------------------------------------- 1 | package grids 2 | 3 | import ( 4 | "image/color" 5 | "log" 6 | "strconv" 7 | 8 | "github.com/golang/freetype/truetype" 9 | "github.com/shomali11/go-interview/algorithms/astar" 10 | "github.com/shomali11/gridder" 11 | "golang.org/x/image/font/gofont/goregular" 12 | ) 13 | 14 | func createImage(rows int, columns int, start *GridNode, goal *GridNode, path []astar.Node, world *GridWorld) { 15 | imageConfig := gridder.ImageConfig{ 16 | Width: 2000, 17 | Height: 2000, 18 | Name: "output.png", 19 | } 20 | gridConfig := gridder.GridConfig{ 21 | Rows: rows, 22 | Columns: rows, 23 | MarginWidth: 32, 24 | LineStrokeWidth: 2, 25 | BorderStrokeWidth: 20, 26 | } 27 | 28 | grid, err := gridder.New(imageConfig, gridConfig) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | 33 | font, err := truetype.Parse(goregular.TTF) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | 38 | fontFace := truetype.NewFace(font, &truetype.Options{Size: 48}) 39 | lineConfig := gridder.PathConfig{Dashes: 10} 40 | 41 | for row := 0; row < rows; row++ { 42 | for column := 0; column < columns; column++ { 43 | node := world.Get(row, column) 44 | if node.IsObstacle { 45 | grid.PaintCell(row, column, color.NRGBA{R: 0, G: 0, B: 0, A: 255 / 2}) 46 | grid.DrawString(row, column, "Block", fontFace) 47 | } else { 48 | cost := strconv.FormatFloat(node.Cost, 'f', 0, 64) 49 | grid.DrawString(row, column, cost, fontFace) 50 | } 51 | } 52 | } 53 | 54 | currentX := start.X 55 | currentY := start.Y 56 | grid.DrawCircle(start.X, start.Y, gridder.CircleConfig{Color: color.NRGBA{R: 255 / 2, G: 0, B: 0, A: 255 / 2}, Radius: 60}) 57 | for i := 1; i < len(path)-1; i++ { 58 | node := path[i].(*GridNode) 59 | grid.DrawPath(currentX, currentY, node.X, node.Y, lineConfig) 60 | currentX = node.X 61 | currentY = node.Y 62 | } 63 | grid.DrawPath(currentX, currentY, goal.X, goal.Y, lineConfig) 64 | grid.DrawCircle(goal.X, goal.Y, gridder.CircleConfig{Color: color.NRGBA{R: 0, G: 255 / 2, B: 0, A: 255 / 2}, Radius: 60}) 65 | 66 | grid.SavePNG() 67 | } 68 | -------------------------------------------------------------------------------- /algorithms/astar/grids/grid_node.go: -------------------------------------------------------------------------------- 1 | package grids 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/shomali11/go-interview/algorithms/astar" 7 | ) 8 | 9 | // GridNode grid node 10 | type GridNode struct { 11 | X int 12 | Y int 13 | Cost float64 14 | IsObstacle bool 15 | world *GridWorld 16 | } 17 | 18 | // EstimateDistanceToGoal get distance to the goal 19 | func (n *GridNode) EstimateDistanceToGoal(goal astar.Node) float64 { 20 | return distance(n, goal.(*GridNode)) 21 | } 22 | 23 | // ActualDistanceToNeighbor get distance to a neighbor 24 | func (n *GridNode) ActualDistanceToNeighbor(node astar.Node) float64 { 25 | if isDiagonal(n, node.(*GridNode)) { 26 | return math.Sqrt2 * n.Cost 27 | } 28 | return n.Cost 29 | } 30 | 31 | // GetNeighbors get neighbors 32 | func (n *GridNode) GetNeighbors() []astar.Node { 33 | nodes := make([]astar.Node, 0) 34 | 35 | for i := -1; i <= 1; i++ { 36 | for j := -1; j <= 1; j++ { 37 | // If Same Object ... 38 | if i == 0 && j == 0 { 39 | // Skip ... 40 | continue 41 | } 42 | 43 | if !n.world.IsValid(n.X+i, n.Y+j) { 44 | continue 45 | } 46 | 47 | node := n.world.Get(n.X+i, n.Y+j) 48 | if node.IsObstacle { 49 | continue 50 | } 51 | 52 | if n.isBehindObstacles(node) { 53 | continue 54 | } 55 | nodes = append(nodes, node) 56 | } 57 | } 58 | return nodes 59 | } 60 | 61 | func (n *GridNode) isBehindObstacles(node *GridNode) bool { 62 | dx := node.X - n.X 63 | dy := node.Y - n.Y 64 | 65 | i := node.X 66 | j := node.Y 67 | 68 | if dx == 1 && dy == 1 { // Lower Right 69 | if n.world.IsValid(i, j-1) && n.world.IsValid(i-1, j) { 70 | right := n.world.Get(i, j-1) 71 | bottom := n.world.Get(i-1, j) 72 | 73 | if right.IsObstacle && bottom.IsObstacle { 74 | return true 75 | } 76 | } 77 | } else if dx == -1 && dy == -1 { // Upper Left 78 | if n.world.IsValid(i+1, j) && n.world.IsValid(i, j+1) { 79 | top := n.world.Get(i+1, j) 80 | left := n.world.Get(i, j+1) 81 | 82 | if top.IsObstacle && left.IsObstacle { 83 | return true 84 | } 85 | } 86 | } else if dx == 1 && dy == -1 { // Upper Right 87 | if n.world.IsValid(i-1, j) && n.world.IsValid(i, j+1) { 88 | top := n.world.Get(i-1, j) 89 | right := n.world.Get(i, j+1) 90 | 91 | if top.IsObstacle && right.IsObstacle { 92 | return true 93 | } 94 | } 95 | } else if dx == -1 && dy == 1 { // Lower Left 96 | if n.world.IsValid(i, j-1) && n.world.IsValid(i+1, j) { 97 | left := n.world.Get(i, j-1) 98 | bottom := n.world.Get(i+1, j) 99 | 100 | if left.IsObstacle && bottom.IsObstacle { 101 | return true 102 | } 103 | } 104 | } 105 | return false 106 | } 107 | 108 | func isDiagonal(n *GridNode, node *GridNode) bool { 109 | dx := node.X - n.X 110 | dy := node.Y - n.Y 111 | 112 | if dx == 1 && dy == 1 { // Lower Right 113 | return true 114 | } else if dx == -1 && dy == -1 { // Upper Left 115 | return true 116 | } else if dx == 1 && dy == -1 { // Upper Right 117 | return true 118 | } else if dx == -1 && dy == 1 { // Lower Left 119 | return true 120 | } 121 | return false 122 | } 123 | 124 | func distance(current *GridNode, other *GridNode) float64 { 125 | currentX := float64(current.X) 126 | currentY := float64(current.Y) 127 | otherX := float64(other.X) 128 | otherY := float64(other.Y) 129 | return math.Sqrt(math.Pow(currentX-otherX, 2) + math.Pow(currentY-otherY, 2)) 130 | } 131 | -------------------------------------------------------------------------------- /algorithms/astar/grids/grid_world.go: -------------------------------------------------------------------------------- 1 | package grids 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/shomali11/go-interview/algorithms/astar" 8 | ) 9 | 10 | // New creates a 2D grid of nodes 11 | func New(rows, columns int) *GridWorld { 12 | grid := make([][]*GridNode, rows) 13 | world := GridWorld{grid: grid} 14 | 15 | for i := range grid { 16 | grid[i] = make([]*GridNode, columns) 17 | } 18 | 19 | for row := 0; row < rows; row++ { 20 | for column := 0; column < columns; column++ { 21 | grid[row][column] = &GridNode{X: row, Y: column, Cost: 1, world: &world} 22 | } 23 | } 24 | return &world 25 | } 26 | 27 | // GridWorld grid world 28 | type GridWorld struct { 29 | grid [][]*GridNode 30 | } 31 | 32 | // Get retrieves a Grid Node 33 | func (n *GridWorld) Get(i int, j int) *GridNode { 34 | return n.grid[i][j] 35 | } 36 | 37 | // IsValid checks whether coordinates are within the grid 38 | func (n *GridWorld) IsValid(i int, j int) bool { 39 | return i >= 0 && i < len(n.grid) && j >= 0 && j < len(n.grid[0]) 40 | } 41 | 42 | // PrintGrid prints a Grid 43 | func (n *GridWorld) PrintGrid(nodes []astar.Node) { 44 | rows := len(n.grid) 45 | if rows == 0 { 46 | return 47 | } 48 | 49 | columns := len(n.grid[0]) 50 | 51 | printGrid := make([][]string, rows) 52 | for i := range printGrid { 53 | printGrid[i] = make([]string, columns) 54 | } 55 | 56 | for i := range printGrid { 57 | for j := range printGrid[0] { 58 | node := n.Get(i, j) 59 | if node.IsObstacle { 60 | printGrid[i][j] = "X" 61 | } else { 62 | printGrid[i][j] = strconv.FormatFloat(node.Cost, 'f', 0, 64) 63 | } 64 | } 65 | } 66 | 67 | for _, value := range nodes { 68 | node := value.(*GridNode) 69 | printGrid[node.X][node.Y] = "*" 70 | } 71 | 72 | for i := range printGrid { 73 | fmt.Println(printGrid[i]) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /algorithms/astar/grids/grid_world_test.go: -------------------------------------------------------------------------------- 1 | package grids 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/shomali11/go-interview/algorithms/astar" 8 | ) 9 | 10 | func TestSearch(t *testing.T) { 11 | columns := 9 12 | rows := 9 13 | world := New(rows, columns) 14 | 15 | start := world.Get(0, 0) 16 | goal := world.Get(rows-1, columns-1) 17 | 18 | world.Get(1, 2).IsObstacle = true 19 | world.Get(2, 1).IsObstacle = true 20 | world.Get(3, 0).IsObstacle = true 21 | world.Get(0, 2).Cost = 3 22 | world.Get(0, 3).Cost = 3 23 | 24 | aStar := astar.New() 25 | path, distance := aStar.Search(start, goal) 26 | 27 | fmt.Println("Distance:", distance) 28 | fmt.Println() 29 | 30 | world.PrintGrid(path) 31 | 32 | createImage(rows, columns, start, goal, path, world) 33 | } 34 | -------------------------------------------------------------------------------- /algorithms/astar/grids/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shomali11/go-interview/5ce2504b62fa55e7be88f65f707c796c9a91eb44/algorithms/astar/grids/output.png -------------------------------------------------------------------------------- /datastructures/linkedlists/doublylinkedlists/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Doubly Linked List. A doubly Linked List is a variation of Linked list in which navigation is possible in both ways, either forward and backward easily as compared to singly linked list. 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Insert "value1", Insert "value2", Insert "value3", Remove First 9 | Output: ["value2", "value3"] 10 | ``` -------------------------------------------------------------------------------- /datastructures/linkedlists/doublylinkedlists/doubly_linked_lists.go: -------------------------------------------------------------------------------- 1 | package doublylinkedlists 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | ) 7 | 8 | var ( 9 | errEmptyList = errors.New("list is empty") 10 | errIndexOutOfBounds = errors.New("index is out of bounds") 11 | ) 12 | 13 | // New factory to generate new doubly linked lists 14 | func New[T any](values ...T) *DoublyLinkedList[T] { 15 | list := DoublyLinkedList[T]{} 16 | list.Add(values...) 17 | return &list 18 | } 19 | 20 | // DLLNode doubly linked list node 21 | type DLLNode[T any] struct { 22 | Value T 23 | Previous *DLLNode[T] 24 | Next *DLLNode[T] 25 | } 26 | 27 | // DoublyLinkedList doubly linked list structure 28 | type DoublyLinkedList[T any] struct { 29 | count int 30 | head *DLLNode[T] 31 | tail *DLLNode[T] 32 | } 33 | 34 | // IsEmpty checks if the list is empty 35 | func (s *DoublyLinkedList[T]) IsEmpty() bool { 36 | return s.Size() == 0 37 | } 38 | 39 | // Size returns size of the list 40 | func (s *DoublyLinkedList[T]) Size() int { 41 | return s.count 42 | } 43 | 44 | // Clear clears list 45 | func (s *DoublyLinkedList[T]) Clear() { 46 | current := s.head 47 | for current != nil { 48 | temp := current 49 | current = current.Next 50 | temp.Previous = nil 51 | temp.Next = nil 52 | temp = nil 53 | } 54 | current = nil 55 | s.count = 0 56 | s.head = nil 57 | s.tail = nil 58 | } 59 | 60 | // GetValues returns values from head to tail 61 | func (s *DoublyLinkedList[T]) GetValues() []T { 62 | values := make([]T, 0, s.Size()) 63 | current := s.head 64 | for current != nil { 65 | values = append(values, current.Value) 66 | current = current.Next 67 | } 68 | current = nil 69 | return values 70 | } 71 | 72 | // GetReverseValues returns values from tail to head 73 | func (s *DoublyLinkedList[T]) GetReverseValues() []T { 74 | values := make([]T, 0, s.Size()) 75 | current := s.tail 76 | for current != nil { 77 | values = append(values, current.Value) 78 | current = current.Previous 79 | } 80 | current = nil 81 | return values 82 | } 83 | 84 | // GetIndexOf returns the index of the first occurence 85 | func (s *DoublyLinkedList[T]) GetIndexOf(value T) int { 86 | index := 0 87 | current := s.head 88 | for current != nil { 89 | if reflect.DeepEqual(value, current.Value) { 90 | return index 91 | } 92 | current = current.Next 93 | index++ 94 | } 95 | current = nil 96 | return -1 97 | } 98 | 99 | // GetLastIndexOf returns the index of the last occurence 100 | func (s *DoublyLinkedList[T]) GetLastIndexOf(value T) int { 101 | index := s.Size() - 1 102 | current := s.tail 103 | for current != nil { 104 | if reflect.DeepEqual(value, current.Value) { 105 | return index 106 | } 107 | current = current.Previous 108 | index-- 109 | } 110 | current = nil 111 | return -1 112 | } 113 | 114 | // Add add to the list 115 | func (s *DoublyLinkedList[T]) Add(values ...T) { 116 | for _, value := range values { 117 | s.InsertAt(s.Size(), value) 118 | } 119 | } 120 | 121 | // InsertAt insert value at specific index in the list 122 | func (s *DoublyLinkedList[T]) InsertAt(index int, value T) error { 123 | if index < 0 || index > s.count { 124 | return errIndexOutOfBounds 125 | } 126 | 127 | element := &DLLNode[T]{Value: value} 128 | if s.IsEmpty() { 129 | s.head = element 130 | s.tail = element 131 | s.count++ 132 | element = nil 133 | return nil 134 | } 135 | 136 | if index == 0 { 137 | element.Next = s.head 138 | s.head.Previous = element 139 | s.head = element 140 | s.count++ 141 | element = nil 142 | return nil 143 | } 144 | 145 | if index == s.count { 146 | s.tail.Next = element 147 | element.Previous = s.tail 148 | s.tail = element 149 | s.count++ 150 | element = nil 151 | return nil 152 | } 153 | 154 | current, err := s.getNode(index) 155 | if err != nil { 156 | return err 157 | } 158 | 159 | current.Previous.Next = element 160 | element.Previous = current.Previous 161 | element.Next = current 162 | current.Previous = element 163 | s.count++ 164 | current = nil 165 | element = nil 166 | return nil 167 | } 168 | 169 | // RemoveAt remove value from the list at specific index 170 | func (s *DoublyLinkedList[T]) RemoveAt(index int) (res T, err error) { 171 | if index < 0 || index >= s.count { 172 | return res, errIndexOutOfBounds 173 | } 174 | 175 | if s.count == 1 { 176 | res = s.head.Value 177 | s.head = nil 178 | s.tail = nil 179 | s.count-- 180 | return res, nil 181 | } 182 | 183 | if index == 0 { 184 | current := s.head 185 | s.head = current.Next 186 | current.Next.Previous = nil 187 | current.Next = nil 188 | res = current.Value 189 | s.count-- 190 | current = nil 191 | return res, nil 192 | } 193 | 194 | if index == s.count-1 { 195 | current := s.tail 196 | s.tail = current.Previous 197 | current.Previous.Next = nil 198 | current.Previous = nil 199 | res = current.Value 200 | s.count-- 201 | current = nil 202 | return res, nil 203 | } 204 | 205 | current, err := s.getNode(index) 206 | if err != nil { 207 | return res, err 208 | } 209 | 210 | res = current.Value 211 | current.Previous.Next = current.Next 212 | current.Next.Previous = current.Previous 213 | s.count-- 214 | current = nil 215 | return res, nil 216 | } 217 | 218 | // GetValueAt returns value at a specific index in the list 219 | func (s *DoublyLinkedList[T]) GetValueAt(index int) (res T, err error) { 220 | current, err := s.getNode(index) 221 | if err != nil { 222 | return res, err 223 | } 224 | return current.Value, nil 225 | } 226 | 227 | // GetFirstValue returns first value in the list 228 | func (s *DoublyLinkedList[T]) GetFirstValue() (res T, err error) { 229 | if s.IsEmpty() { 230 | return res, errEmptyList 231 | } 232 | return s.head.Value, nil 233 | } 234 | 235 | // GetLastValue returns last value in the list 236 | func (s *DoublyLinkedList[T]) GetLastValue() (res T, err error) { 237 | if s.IsEmpty() { 238 | return res, errEmptyList 239 | } 240 | return s.tail.Value, nil 241 | } 242 | 243 | // GetHead returns head node of the list 244 | func (s *DoublyLinkedList[T]) GetHead() *DLLNode[T] { 245 | return s.head 246 | } 247 | 248 | // GetTail returns tail node of the list 249 | func (s *DoublyLinkedList[T]) GetTail() *DLLNode[T] { 250 | return s.tail 251 | } 252 | 253 | func (s *DoublyLinkedList[T]) getNode(index int) (*DLLNode[T], error) { 254 | if index < 0 || index >= s.count { 255 | return nil, errIndexOutOfBounds 256 | } 257 | 258 | var current *DLLNode[T] 259 | if index-0 <= s.count-1-index { 260 | current = s.head 261 | for i := 0; i < index; i++ { 262 | current = current.Next 263 | } 264 | } else { 265 | current = s.tail 266 | for i := 0; i < s.count-1-index; i++ { 267 | current = current.Previous 268 | } 269 | } 270 | return current, nil 271 | } 272 | -------------------------------------------------------------------------------- /datastructures/linkedlists/doublylinkedlists/doubly_linked_lists_test.go: -------------------------------------------------------------------------------- 1 | package doublylinkedlists 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestDoublyLinked_GetFirstValue(t *testing.T) { 11 | list := New[string]() 12 | 13 | _, err := list.GetFirstValue() 14 | assert.NotNil(t, err) 15 | 16 | list.Add("abc") 17 | 18 | value, err := list.GetFirstValue() 19 | assert.Nil(t, err) 20 | assert.Equal(t, value, "abc") 21 | 22 | list.Add("def") 23 | 24 | value, err = list.GetFirstValue() 25 | assert.Nil(t, err) 26 | assert.Equal(t, value, "abc") 27 | 28 | list.InsertAt(0, "xyz") 29 | 30 | value, err = list.GetFirstValue() 31 | assert.Nil(t, err) 32 | assert.Equal(t, value, "xyz") 33 | } 34 | 35 | func TestDoublyLinked_GetLastValue(t *testing.T) { 36 | list := New[string]() 37 | 38 | _, err := list.GetLastValue() 39 | assert.NotNil(t, err) 40 | 41 | list.Add("abc") 42 | 43 | value, err := list.GetLastValue() 44 | assert.Nil(t, err) 45 | assert.Equal(t, value, "abc") 46 | 47 | list.Add("def") 48 | 49 | value, err = list.GetLastValue() 50 | assert.Nil(t, err) 51 | assert.Equal(t, value, "def") 52 | 53 | list.InsertAt(2, "xyz") 54 | 55 | value, err = list.GetLastValue() 56 | assert.Nil(t, err) 57 | assert.Equal(t, value, "xyz") 58 | } 59 | 60 | func TestDoublyLinked_GetValues(t *testing.T) { 61 | list := New[string]() 62 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{})) 63 | 64 | list.Add("a", "b", "c") 65 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{"a", "b", "c"})) 66 | 67 | list.InsertAt(1, "d") 68 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{"a", "d", "b", "c"})) 69 | } 70 | 71 | func TestDoublyLinked_GetReverseValues(t *testing.T) { 72 | list := New[string]() 73 | assert.True(t, reflect.DeepEqual(list.GetReverseValues(), []string{})) 74 | 75 | list.Add("a", "b", "c") 76 | assert.True(t, reflect.DeepEqual(list.GetReverseValues(), []string{"c", "b", "a"})) 77 | 78 | list.InsertAt(1, "d") 79 | assert.True(t, reflect.DeepEqual(list.GetReverseValues(), []string{"c", "b", "d", "a"})) 80 | } 81 | 82 | func TestDoublyLinkedList_IsEmpty(t *testing.T) { 83 | list := New[string]() 84 | assert.Equal(t, list.IsEmpty(), true) 85 | 86 | list.Add("hello") 87 | assert.Equal(t, list.IsEmpty(), false) 88 | 89 | list.RemoveAt(0) 90 | assert.Equal(t, list.IsEmpty(), true) 91 | } 92 | 93 | func TestDoublyLinkedList_Size(t *testing.T) { 94 | list := New[string]() 95 | assert.Equal(t, list.Size(), 0) 96 | 97 | list.Add("hello") 98 | assert.Equal(t, list.Size(), 1) 99 | 100 | list.Add("abc") 101 | assert.Equal(t, list.Size(), 2) 102 | 103 | list.RemoveAt(0) 104 | assert.Equal(t, list.Size(), 1) 105 | 106 | list.RemoveAt(0) 107 | assert.Equal(t, list.Size(), 0) 108 | } 109 | 110 | func TestDoublyLinkedList_GetIndexOf(t *testing.T) { 111 | list := New[string]() 112 | assert.Equal(t, list.GetIndexOf("hello"), -1) 113 | 114 | list.Add("hello") 115 | assert.Equal(t, list.GetIndexOf("hello"), 0) 116 | 117 | list.Add("abc") 118 | assert.Equal(t, list.GetIndexOf("abc"), 1) 119 | 120 | list.Add("abc") 121 | assert.Equal(t, list.GetIndexOf("abc"), 1) 122 | } 123 | 124 | func TestDoublyLinkedList_GetLastIndexOf(t *testing.T) { 125 | list := New[string]() 126 | assert.Equal(t, list.GetLastIndexOf("hello"), -1) 127 | 128 | list.Add("hello") 129 | assert.Equal(t, list.GetLastIndexOf("hello"), 0) 130 | 131 | list.Add("abc") 132 | assert.Equal(t, list.GetLastIndexOf("abc"), 1) 133 | 134 | list.Add("abc") 135 | assert.Equal(t, list.GetLastIndexOf("abc"), 2) 136 | } 137 | 138 | func TestDoublyLinkedList_InsertAt(t *testing.T) { 139 | list := New[string]() 140 | 141 | err := list.InsertAt(3, "hello") 142 | assert.NotNil(t, err) 143 | 144 | err = list.InsertAt(0, "hello") 145 | assert.Nil(t, err) 146 | } 147 | 148 | func TestDoublyLinkedList_RemoveAt(t *testing.T) { 149 | list := New[string]() 150 | 151 | _, err := list.RemoveAt(0) 152 | assert.NotNil(t, err) 153 | 154 | list.Add("hello") 155 | value, err := list.RemoveAt(0) 156 | assert.Equal(t, value, "hello") 157 | assert.Nil(t, err) 158 | } 159 | 160 | func TestDoublyLinkedList_Clear(t *testing.T) { 161 | list := New[string]() 162 | 163 | list.Clear() 164 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{})) 165 | assert.True(t, reflect.DeepEqual(list.GetReverseValues(), []string{})) 166 | assert.Equal(t, list.IsEmpty(), true) 167 | assert.Equal(t, list.Size(), 0) 168 | 169 | list.Add("hello") 170 | 171 | list.Clear() 172 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{})) 173 | assert.True(t, reflect.DeepEqual(list.GetReverseValues(), []string{})) 174 | assert.Equal(t, list.IsEmpty(), true) 175 | assert.Equal(t, list.Size(), 0) 176 | } 177 | -------------------------------------------------------------------------------- /datastructures/linkedlists/singlylinkedlists/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Singly Linked List. A singly linked list is a type of linked list that is unidirectional, that is, it can be traversed in only one direction from head to the last node (tail). 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Insert "value1", Insert "value2", Insert "value3", Remove Last 9 | Output: ["value1", "value2"] 10 | ``` -------------------------------------------------------------------------------- /datastructures/linkedlists/singlylinkedlists/singly_linked_lists.go: -------------------------------------------------------------------------------- 1 | package singlylinkedlists 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | ) 7 | 8 | var ( 9 | errEmptyList = errors.New("list is empty") 10 | errIndexOutOfBounds = errors.New("index is out of bounds") 11 | ) 12 | 13 | // New factory to generate new singly linked lists 14 | func New[T any](values ...T) *SinglyLinkedList[T] { 15 | list := SinglyLinkedList[T]{} 16 | list.Add(values...) 17 | return &list 18 | } 19 | 20 | // SLLNode singly linked list node 21 | type SLLNode[T any] struct { 22 | Value T 23 | Next *SLLNode[T] 24 | } 25 | 26 | // SinglyLinkedList singly linked list structure 27 | type SinglyLinkedList[T any] struct { 28 | count int 29 | head *SLLNode[T] 30 | tail *SLLNode[T] 31 | } 32 | 33 | // IsEmpty checks if the list is empty 34 | func (s *SinglyLinkedList[T]) IsEmpty() bool { 35 | return s.Size() == 0 36 | } 37 | 38 | // Size returns size of the list 39 | func (s *SinglyLinkedList[T]) Size() int { 40 | return s.count 41 | } 42 | 43 | // Clear clears list 44 | func (s *SinglyLinkedList[T]) Clear() { 45 | current := s.head 46 | for current != nil { 47 | temp := current 48 | current = current.Next 49 | temp.Next = nil 50 | temp = nil 51 | } 52 | current = nil 53 | s.count = 0 54 | s.head = nil 55 | s.tail = nil 56 | } 57 | 58 | // GetValues returns values 59 | func (s *SinglyLinkedList[T]) GetValues() []T { 60 | values := make([]T, 0, s.Size()) 61 | current := s.head 62 | for current != nil { 63 | values = append(values, current.Value) 64 | current = current.Next 65 | } 66 | current = nil 67 | return values 68 | } 69 | 70 | // GetIndexOf returns the index of the first occurence 71 | func (s *SinglyLinkedList[T]) GetIndexOf(value T) int { 72 | index := 0 73 | current := s.head 74 | for current != nil { 75 | if reflect.DeepEqual(value, current.Value) { 76 | return index 77 | } 78 | current = current.Next 79 | index++ 80 | } 81 | current = nil 82 | return -1 83 | } 84 | 85 | // Add add to the list 86 | func (s *SinglyLinkedList[T]) Add(values ...T) { 87 | for _, value := range values { 88 | s.InsertAt(s.Size(), value) 89 | } 90 | } 91 | 92 | // InsertAt insert value at specific index in the list 93 | func (s *SinglyLinkedList[T]) InsertAt(index int, value T) error { 94 | if index < 0 || index > s.count { 95 | return errIndexOutOfBounds 96 | } 97 | 98 | element := &SLLNode[T]{Value: value} 99 | if s.IsEmpty() { 100 | s.head = element 101 | s.tail = element 102 | s.count++ 103 | element = nil 104 | return nil 105 | } 106 | 107 | if index == 0 { 108 | element.Next = s.head 109 | s.head = element 110 | s.count++ 111 | element = nil 112 | return nil 113 | } 114 | 115 | if index == s.count { 116 | s.tail.Next = element 117 | s.tail = element 118 | s.count++ 119 | element = nil 120 | return nil 121 | } 122 | 123 | current, err := s.getNode(index - 1) 124 | if err != nil { 125 | return err 126 | } 127 | 128 | element.Next = current.Next 129 | current.Next = element 130 | s.count++ 131 | current = nil 132 | element = nil 133 | return nil 134 | } 135 | 136 | // RemoveAt remove value from the list at specific index 137 | func (s *SinglyLinkedList[T]) RemoveAt(index int) (res T, err error) { 138 | if index < 0 || index >= s.count { 139 | return res, errIndexOutOfBounds 140 | } 141 | 142 | if s.count == 1 { 143 | res = s.head.Value 144 | s.head = nil 145 | s.tail = nil 146 | s.count-- 147 | return res, nil 148 | } 149 | 150 | if index == 0 { 151 | current := s.head 152 | s.head = current.Next 153 | current.Next = nil 154 | res = current.Value 155 | s.count-- 156 | current = nil 157 | return res, nil 158 | } 159 | 160 | current, err := s.getNode(index - 1) 161 | if err != nil { 162 | return res, err 163 | } 164 | 165 | res = current.Next.Value 166 | current.Next = current.Next.Next 167 | if index == s.count-1 { 168 | s.tail = current 169 | } 170 | s.count-- 171 | current = nil 172 | return res, nil 173 | } 174 | 175 | // GetValueAt returns value at a specific index in the list 176 | func (s *SinglyLinkedList[T]) GetValueAt(index int) (res T, err error) { 177 | current, err := s.getNode(index) 178 | if err != nil { 179 | return res, err 180 | } 181 | return current.Value, nil 182 | } 183 | 184 | // GetFirstValue returns first value in the list 185 | func (s *SinglyLinkedList[T]) GetFirstValue() (res T, err error) { 186 | if s.IsEmpty() { 187 | return res, errEmptyList 188 | } 189 | return s.head.Value, nil 190 | } 191 | 192 | // GetLastValue returns last value in the list 193 | func (s *SinglyLinkedList[T]) GetLastValue() (res T, err error) { 194 | if s.IsEmpty() { 195 | return res, errEmptyList 196 | } 197 | return s.tail.Value, nil 198 | } 199 | 200 | // GetHead returns head node of the list 201 | func (s *SinglyLinkedList[T]) GetHead() *SLLNode[T] { 202 | return s.head 203 | } 204 | 205 | func (s *SinglyLinkedList[T]) getNode(index int) (*SLLNode[T], error) { 206 | if index < 0 || index >= s.count { 207 | return nil, errIndexOutOfBounds 208 | } 209 | 210 | current := s.head 211 | for i := 0; i < index; i++ { 212 | current = current.Next 213 | } 214 | return current, nil 215 | } 216 | -------------------------------------------------------------------------------- /datastructures/linkedlists/singlylinkedlists/singly_linked_lists_test.go: -------------------------------------------------------------------------------- 1 | package singlylinkedlists 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestSinglyLinked_GetFirstValue(t *testing.T) { 11 | list := New[string]() 12 | 13 | _, err := list.GetFirstValue() 14 | assert.NotNil(t, err) 15 | 16 | list.Add("abc") 17 | 18 | value, err := list.GetFirstValue() 19 | assert.Nil(t, err) 20 | assert.Equal(t, value, "abc") 21 | 22 | list.Add("def") 23 | 24 | value, err = list.GetFirstValue() 25 | assert.Nil(t, err) 26 | assert.Equal(t, value, "abc") 27 | 28 | list.InsertAt(0, "xyz") 29 | 30 | value, err = list.GetFirstValue() 31 | assert.Nil(t, err) 32 | assert.Equal(t, value, "xyz") 33 | } 34 | 35 | func TestSinglyLinked_GetLastValue(t *testing.T) { 36 | list := New[string]() 37 | 38 | _, err := list.GetLastValue() 39 | assert.NotNil(t, err) 40 | 41 | list.Add("abc") 42 | 43 | value, err := list.GetLastValue() 44 | assert.Nil(t, err) 45 | assert.Equal(t, value, "abc") 46 | 47 | list.Add("def") 48 | 49 | value, err = list.GetLastValue() 50 | assert.Nil(t, err) 51 | assert.Equal(t, value, "def") 52 | 53 | list.InsertAt(2, "xyz") 54 | 55 | value, err = list.GetLastValue() 56 | assert.Nil(t, err) 57 | assert.Equal(t, value, "xyz") 58 | } 59 | 60 | func TestSinglyLinked_GetValues(t *testing.T) { 61 | list := New[string]() 62 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{})) 63 | 64 | list.Add("a", "b", "c") 65 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{"a", "b", "c"})) 66 | 67 | list.InsertAt(1, "d") 68 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{"a", "d", "b", "c"})) 69 | } 70 | 71 | func TestSinglyLinkedList_IsEmpty(t *testing.T) { 72 | list := New[string]() 73 | assert.Equal(t, list.IsEmpty(), true) 74 | 75 | list.Add("hello") 76 | assert.Equal(t, list.IsEmpty(), false) 77 | 78 | list.RemoveAt(0) 79 | assert.Equal(t, list.IsEmpty(), true) 80 | } 81 | 82 | func TestSinglyLinkedList_Size(t *testing.T) { 83 | list := New[string]() 84 | assert.Equal(t, list.Size(), 0) 85 | 86 | list.Add("hello") 87 | assert.Equal(t, list.Size(), 1) 88 | 89 | list.Add("abc") 90 | assert.Equal(t, list.Size(), 2) 91 | 92 | list.RemoveAt(0) 93 | assert.Equal(t, list.Size(), 1) 94 | 95 | list.RemoveAt(0) 96 | assert.Equal(t, list.Size(), 0) 97 | } 98 | 99 | func TestSinglyLinkedList_GetIndexOf(t *testing.T) { 100 | list := New[string]() 101 | assert.Equal(t, list.GetIndexOf("hello"), -1) 102 | 103 | list.Add("hello") 104 | assert.Equal(t, list.GetIndexOf("hello"), 0) 105 | 106 | list.Add("abc") 107 | assert.Equal(t, list.GetIndexOf("abc"), 1) 108 | 109 | list.Add("abc") 110 | assert.Equal(t, list.GetIndexOf("abc"), 1) 111 | } 112 | 113 | func TestSinglyLinkedList_InsertAt(t *testing.T) { 114 | list := New[string]() 115 | 116 | err := list.InsertAt(3, "hello") 117 | assert.NotNil(t, err) 118 | 119 | err = list.InsertAt(0, "hello") 120 | assert.Nil(t, err) 121 | } 122 | 123 | func TestSinglyLinkedList_RemoveAt(t *testing.T) { 124 | list := New[string]() 125 | 126 | _, err := list.RemoveAt(0) 127 | assert.NotNil(t, err) 128 | 129 | list.Add("hello") 130 | value, err := list.RemoveAt(0) 131 | assert.Equal(t, value, "hello") 132 | assert.Nil(t, err) 133 | } 134 | 135 | func TestSinglyLinkedList_Clear(t *testing.T) { 136 | list := New[string]() 137 | 138 | list.Clear() 139 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{})) 140 | assert.Equal(t, list.IsEmpty(), true) 141 | assert.Equal(t, list.Size(), 0) 142 | 143 | list.Add("hello") 144 | 145 | list.Clear() 146 | assert.True(t, reflect.DeepEqual(list.GetValues(), []string{})) 147 | assert.Equal(t, list.IsEmpty(), true) 148 | assert.Equal(t, list.Size(), 0) 149 | } 150 | -------------------------------------------------------------------------------- /datastructures/maps/hashmultimaps/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Multi Map. A collection that maps keys to values, similar to Map, but in which each key may be associated with multiple values. 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Push ("key1", "1"), Push ("key1", "2"), Push ("key2", "3"), Get "key1" 9 | Output: ["1", "2"] 10 | ``` -------------------------------------------------------------------------------- /datastructures/maps/hashmultimaps/hash_multi_map.go: -------------------------------------------------------------------------------- 1 | package hashmultimaps 2 | 3 | // New factory that creates a new Hash Multi Map 4 | func New[K, V comparable]() *HashMultiMap[K, V] { 5 | multiMap := HashMultiMap[K, V]{data: make(map[K][]V)} 6 | return &multiMap 7 | } 8 | 9 | // HashMultiMap a data structure representing a map of keys with lists of values 10 | type HashMultiMap[K, V comparable] struct { 11 | data map[K][]V 12 | } 13 | 14 | // Merge merge multiple multi maps 15 | func (s *HashMultiMap[K, V]) Merge(maps ...*HashMultiMap[K, V]) { 16 | for _, multiMap := range maps { 17 | for _, key := range multiMap.GetKeys() { 18 | values := multiMap.GetValues(key) 19 | s.PutAll(key, values...) 20 | } 21 | } 22 | } 23 | 24 | // Put key/value pair to the multi map 25 | func (s *HashMultiMap[K, V]) Put(key K, value V) { 26 | values, ok := s.data[key] 27 | if !ok { 28 | values = make([]V, 0) 29 | } 30 | values = append(values, value) 31 | s.data[key] = values 32 | } 33 | 34 | // PutAll put key/values to the multi map 35 | func (s *HashMultiMap[K, V]) PutAll(key K, values ...V) { 36 | for _, value := range values { 37 | s.Put(key, value) 38 | } 39 | } 40 | 41 | // GetKeys returns a list of the multi map's keys 42 | func (s *HashMultiMap[K, V]) GetKeys() []K { 43 | keys := make([]K, 0, s.Size()) 44 | for key := range s.data { 45 | keys = append(keys, key) 46 | } 47 | return keys 48 | } 49 | 50 | // Contains checks if a key is in the multi map 51 | func (s *HashMultiMap[K, V]) Contains(key K) bool { 52 | _, exists := s.data[key] 53 | return exists 54 | } 55 | 56 | // ContainsAll checks if all keys are in the multi map 57 | func (s *HashMultiMap[K, V]) ContainsAll(keys ...K) bool { 58 | for _, key := range keys { 59 | if !s.Contains(key) { 60 | return false 61 | } 62 | } 63 | return true 64 | } 65 | 66 | // ContainsAny checks if any keys are in the multi map 67 | func (s *HashMultiMap[K, V]) ContainsAny(keys ...K) bool { 68 | for _, key := range keys { 69 | if s.Contains(key) { 70 | return true 71 | } 72 | } 73 | return false 74 | } 75 | 76 | // GetValues returns values associated with the key 77 | func (s *HashMultiMap[K, V]) GetValues(key K) []V { 78 | values, ok := s.data[key] 79 | if !ok { 80 | return make([]V, 0) 81 | } 82 | return values 83 | } 84 | 85 | // RemoveKey removes a key and all its values 86 | func (s *HashMultiMap[K, V]) RemoveKey(keys ...K) { 87 | for _, key := range keys { 88 | delete(s.data, key) 89 | } 90 | } 91 | 92 | // Remove removes a value from a key's values 93 | func (s *HashMultiMap[K, V]) Remove(key K, value V) { 94 | values, ok := s.data[key] 95 | if !ok { 96 | return 97 | } 98 | 99 | index := getIndex(value, values...) 100 | if index == -1 { 101 | return 102 | } 103 | 104 | newValues := make([]V, 0) 105 | newValues = append(newValues, values[:index]...) 106 | s.data[key] = append(newValues, values[index+1:]...) 107 | } 108 | 109 | // Clear clears the multiMap 110 | func (s *HashMultiMap[K, V]) Clear() { 111 | s.data = make(map[K][]V) 112 | } 113 | 114 | // IsEmpty checks if the multiMap is empty 115 | func (s *HashMultiMap[K, V]) IsEmpty() bool { 116 | return s.Size() == 0 117 | } 118 | 119 | // Size returns size of the multiMap 120 | func (s *HashMultiMap[K, V]) Size() int { 121 | return len(s.data) 122 | } 123 | 124 | func getIndex[V comparable](value V, values ...V) int { 125 | for i, v := range values { 126 | if v == value { 127 | return i 128 | } 129 | } 130 | return -1 131 | } 132 | -------------------------------------------------------------------------------- /datastructures/maps/hashmultimaps/hash_multi_map_test.go: -------------------------------------------------------------------------------- 1 | package hashmultimaps 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestHashMultiMap_GetValues(t *testing.T) { 11 | multiMap := New[string, int]() 12 | multiMap.Put("hello", 1) 13 | 14 | assert.True(t, reflect.DeepEqual(multiMap.GetValues("hello"), []int{1})) 15 | assert.True(t, reflect.DeepEqual(multiMap.GetValues("unknown"), []int{})) 16 | } 17 | 18 | func TestHashMultiMap_Contains(t *testing.T) { 19 | multiMap := New[string, int]() 20 | multiMap.Put("hello", 1) 21 | 22 | assert.Equal(t, multiMap.Contains("hello"), true) 23 | assert.Equal(t, multiMap.Contains("unknown"), false) 24 | assert.Equal(t, multiMap.ContainsAll("hello", "unknown"), false) 25 | assert.Equal(t, multiMap.ContainsAny("hello", "unknown"), true) 26 | } 27 | 28 | func TestHashMultiMap_Clear(t *testing.T) { 29 | multiMap := New[string, int]() 30 | assert.Equal(t, multiMap.IsEmpty(), true) 31 | assert.Equal(t, multiMap.Size(), 0) 32 | 33 | multiMap.Put("hello", 1) 34 | assert.Equal(t, multiMap.IsEmpty(), false) 35 | assert.Equal(t, multiMap.Size(), 1) 36 | 37 | multiMap.Clear() 38 | assert.Equal(t, multiMap.IsEmpty(), true) 39 | assert.Equal(t, multiMap.Size(), 0) 40 | } 41 | 42 | func TestHashMultiMap_PutAll(t *testing.T) { 43 | multiMap := New[int, string]() 44 | 45 | multiMap.PutAll(111, "x", "x", "y", "z") 46 | assert.True(t, reflect.DeepEqual(multiMap.GetValues(111), []string{"x", "x", "y", "z"})) 47 | assert.Equal(t, multiMap.Size(), 1) 48 | assert.Equal(t, multiMap.GetKeys()[0], 111) 49 | } 50 | 51 | func TestHashMultiMap_Remove(t *testing.T) { 52 | multiMap := New[int, string]() 53 | 54 | multiMap.PutAll(111, "x", "x", "y", "z") 55 | multiMap.Remove(111, "x") 56 | 57 | assert.True(t, reflect.DeepEqual(multiMap.GetValues(111), []string{"x", "y", "z"})) 58 | assert.Equal(t, multiMap.Size(), 1) 59 | assert.Equal(t, multiMap.GetKeys()[0], 111) 60 | } 61 | 62 | func TestHashMultiMap_RemoveKey(t *testing.T) { 63 | multiMap := New[int, string]() 64 | 65 | multiMap.PutAll(111, "x", "x", "y", "z") 66 | multiMap.RemoveKey(111) 67 | 68 | assert.Equal(t, multiMap.Size(), 0) 69 | assert.True(t, reflect.DeepEqual(multiMap.GetValues(111), []string{})) 70 | } 71 | 72 | func TestHashMultiMapMerge(t *testing.T) { 73 | multiMap1 := New[bool, string]() 74 | multiMap1.Put(true, "true") 75 | 76 | multiMap2 := New[bool, string]() 77 | multiMap2.Put(true, "false") 78 | 79 | multiMap3 := New[bool, string]() 80 | multiMap3.Merge(multiMap1, multiMap2) 81 | 82 | values := multiMap3.GetValues(true) 83 | 84 | assert.Equal(t, multiMap3.Size(), 1) 85 | assert.True(t, reflect.DeepEqual(values, []string{"true", "false"})) 86 | assert.Equal(t, multiMap3.ContainsAll(true), true) 87 | } 88 | -------------------------------------------------------------------------------- /datastructures/maps/lrucaches/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement an LRU Cache. Similar to a Map in storing and retrieving data efficiently, but an LRU (Least Recently Used) cache evicts the least recently used entry when it is full. 4 | 5 | ### Example: 6 | 7 | ``` 8 | Size 3 9 | 10 | Input: Put ("key1", "1"), Put ("key2", "2"), Put ("key3", "3"), Get "key1", Put ("key4", "4"), GetEntries 11 | Output: [("key4", "4"), ("key1", "1"), ("key3", "3")] 12 | ``` -------------------------------------------------------------------------------- /datastructures/maps/lrucaches/lru_cache.go: -------------------------------------------------------------------------------- 1 | package lrucaches 2 | 3 | import ( 4 | "container/list" 5 | ) 6 | 7 | // New factory that creates a new LRU Cache 8 | func New[K comparable, V any](capacity int) *LRUCache[K, V] { 9 | multiMap := LRUCache[K, V]{ 10 | capacity: capacity, 11 | linkedList: list.New(), 12 | hashMap: make(map[K]*list.Element), 13 | } 14 | return &multiMap 15 | } 16 | 17 | // LRUEntry holds a key/value pair 18 | type LRUEntry[K comparable, V any] struct { 19 | Key K 20 | Value V 21 | } 22 | 23 | // LRUCache a data structure representing a map of keys with lists of values 24 | type LRUCache[K comparable, V any] struct { 25 | capacity int 26 | linkedList *list.List 27 | hashMap map[K]*list.Element 28 | } 29 | 30 | // Merge merge multiple lru caches 31 | func (s *LRUCache[K, V]) Merge(caches ...*LRUCache[K, V]) { 32 | for _, cache := range caches { 33 | for _, key := range cache.GetKeys() { 34 | value, ok := cache.GetValue(key) 35 | if !ok { 36 | continue 37 | } 38 | 39 | s.Put(key, value) 40 | } 41 | } 42 | } 43 | 44 | // Put key/value pair into the cache 45 | func (s *LRUCache[K, V]) Put(key K, value V) { 46 | if s.capacity == s.Size() { 47 | element := s.linkedList.Back() 48 | if element == nil { 49 | return 50 | } 51 | s.remove(element.Value.(*LRUEntry[K, V]).Key) 52 | } 53 | 54 | lruEntry := &LRUEntry[K, V]{Key: key, Value: value} 55 | listElement := s.linkedList.PushFront(lruEntry) 56 | s.hashMap[key] = listElement 57 | } 58 | 59 | // GetKeys returns a list of the cache's keys in most recently used order 60 | func (s *LRUCache[K, V]) GetKeys() []K { 61 | keys := make([]K, 0, s.Size()) 62 | currentListElement := s.linkedList.Front() 63 | for currentListElement != nil { 64 | entry := currentListElement.Value.(*LRUEntry[K, V]) 65 | keys = append(keys, entry.Key) 66 | currentListElement = currentListElement.Next() 67 | } 68 | return keys 69 | } 70 | 71 | // GetEntries returns a list of the cache's entries in most recently used order 72 | func (s *LRUCache[K, V]) GetEntries() []*LRUEntry[K, V] { 73 | entries := make([]*LRUEntry[K, V], 0, s.Size()) 74 | currentListElement := s.linkedList.Front() 75 | for currentListElement != nil { 76 | entry := currentListElement.Value.(*LRUEntry[K, V]) 77 | entries = append(entries, entry) 78 | currentListElement = currentListElement.Next() 79 | } 80 | return entries 81 | } 82 | 83 | // Contains checks if a key is in cache 84 | func (s *LRUCache[K, V]) Contains(key K) bool { 85 | _, exists := s.hashMap[key] 86 | return exists 87 | } 88 | 89 | // ContainsAll checks if all keys are in the cache 90 | func (s *LRUCache[K, V]) ContainsAll(keys ...K) bool { 91 | for _, key := range keys { 92 | if !s.Contains(key) { 93 | return false 94 | } 95 | } 96 | return true 97 | } 98 | 99 | // ContainsAny checks if any keys are in the cache 100 | func (s *LRUCache[K, V]) ContainsAny(keys ...K) bool { 101 | for _, key := range keys { 102 | if s.Contains(key) { 103 | return true 104 | } 105 | } 106 | return false 107 | } 108 | 109 | // GetValue returns value associated with the key 110 | func (s *LRUCache[K, V]) GetValue(key K) (res V, found bool) { 111 | listElement, ok := s.hashMap[key] 112 | if !ok { 113 | return res, false 114 | } 115 | 116 | s.linkedList.MoveToFront(listElement) 117 | lruEntry := listElement.Value.(*LRUEntry[K, V]) 118 | return lruEntry.Value, true 119 | } 120 | 121 | // Remove removes a key and its value 122 | func (s *LRUCache[K, V]) Remove(keys ...K) { 123 | for _, key := range keys { 124 | s.remove(key) 125 | } 126 | } 127 | 128 | // Clear clears the multiMap 129 | func (s *LRUCache[K, V]) Clear() { 130 | s.hashMap = make(map[K]*list.Element) 131 | s.linkedList.Init() 132 | } 133 | 134 | // IsEmpty checks if the multiMap is empty 135 | func (s *LRUCache[K, V]) IsEmpty() bool { 136 | return s.Size() == 0 137 | } 138 | 139 | // Size returns size of the multiMap 140 | func (s *LRUCache[K, V]) Size() int { 141 | return len(s.hashMap) 142 | } 143 | 144 | func (s *LRUCache[K, V]) remove(key K) { 145 | listElement, ok := s.hashMap[key] 146 | if !ok { 147 | return 148 | } 149 | 150 | s.linkedList.Remove(listElement) 151 | delete(s.hashMap, key) 152 | } 153 | -------------------------------------------------------------------------------- /datastructures/maps/lrucaches/lru_cache_test.go: -------------------------------------------------------------------------------- 1 | package lrucaches 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestLRUCache_Contains(t *testing.T) { 11 | cache := New[string, int](5) 12 | cache.Put("hello", 1) 13 | 14 | assert.Equal(t, cache.Contains("hello"), true) 15 | assert.Equal(t, cache.Contains("unknown"), false) 16 | assert.Equal(t, cache.ContainsAll("hello", "unknown"), false) 17 | assert.Equal(t, cache.ContainsAny("hello", "unknown"), true) 18 | } 19 | 20 | func TestLRUCache_Clear(t *testing.T) { 21 | cache := New[string, int](5) 22 | assert.Equal(t, cache.IsEmpty(), true) 23 | assert.Equal(t, cache.Size(), 0) 24 | 25 | cache.Put("hello", 1) 26 | assert.Equal(t, cache.IsEmpty(), false) 27 | assert.Equal(t, cache.Size(), 1) 28 | 29 | cache.Clear() 30 | assert.Equal(t, cache.IsEmpty(), true) 31 | assert.Equal(t, cache.Size(), 0) 32 | } 33 | 34 | func TestLRUCache_GetKeys(t *testing.T) { 35 | cache := New[int, string](3) 36 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{})) 37 | assert.Equal(t, cache.Size(), 0) 38 | 39 | cache.Put(111, "a") 40 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{111})) 41 | assert.Equal(t, cache.Size(), 1) 42 | 43 | cache.Put(222, "b") 44 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{222, 111})) 45 | assert.Equal(t, cache.Size(), 2) 46 | 47 | cache.Put(333, "c") 48 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{333, 222, 111})) 49 | assert.Equal(t, cache.Size(), 3) 50 | 51 | cache.Put(444, "d") 52 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{444, 333, 222})) 53 | assert.Equal(t, cache.Size(), 3) 54 | 55 | cache.GetValue(333) 56 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{333, 444, 222})) 57 | assert.Equal(t, cache.Size(), 3) 58 | 59 | cache.Put(555, "f") 60 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{555, 333, 444})) 61 | assert.Equal(t, cache.Size(), 3) 62 | 63 | cache.Remove(333) 64 | assert.True(t, reflect.DeepEqual(cache.GetKeys(), []int{555, 444})) 65 | assert.Equal(t, cache.Size(), 2) 66 | } 67 | 68 | func TestLRUCache_GetEntries(t *testing.T) { 69 | cache := New[int, string](3) 70 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{})) 71 | assert.Equal(t, cache.Size(), 0) 72 | 73 | cache.Put(111, "a") 74 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{{Key: 111, Value: "a"}})) 75 | assert.Equal(t, cache.Size(), 1) 76 | 77 | cache.Put(222, "b") 78 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{{Key: 222, Value: "b"}, {Key: 111, Value: "a"}})) 79 | assert.Equal(t, cache.Size(), 2) 80 | 81 | cache.Put(333, "c") 82 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{{Key: 333, Value: "c"}, {Key: 222, Value: "b"}, {Key: 111, Value: "a"}})) 83 | assert.Equal(t, cache.Size(), 3) 84 | 85 | cache.Put(444, "d") 86 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{{Key: 444, Value: "d"}, {Key: 333, Value: "c"}, {Key: 222, Value: "b"}})) 87 | assert.Equal(t, cache.Size(), 3) 88 | 89 | cache.GetValue(333) 90 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{{Key: 333, Value: "c"}, {Key: 444, Value: "d"}, {Key: 222, Value: "b"}})) 91 | assert.Equal(t, cache.Size(), 3) 92 | 93 | cache.Put(555, "f") 94 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{{Key: 555, Value: "f"}, {Key: 333, Value: "c"}, {Key: 444, Value: "d"}})) 95 | assert.Equal(t, cache.Size(), 3) 96 | 97 | cache.Remove(333) 98 | assert.True(t, reflect.DeepEqual(cache.GetEntries(), []*LRUEntry[int, string]{{Key: 555, Value: "f"}, {Key: 444, Value: "d"}})) 99 | assert.Equal(t, cache.Size(), 2) 100 | } 101 | 102 | func TestLRUCacheMerge(t *testing.T) { 103 | cache1 := New[bool, string](5) 104 | cache1.Put(true, "true") 105 | 106 | cache2 := New[bool, string](5) 107 | cache2.Put(true, "false") 108 | 109 | cache3 := New[bool, string](5) 110 | cache3.Merge(cache1, cache2) 111 | 112 | value, ok := cache3.GetValue(true) 113 | 114 | assert.Equal(t, cache3.Size(), 1) 115 | assert.True(t, ok) 116 | assert.Equal(t, value, "false") 117 | assert.Equal(t, cache3.ContainsAll(true), true) 118 | } 119 | -------------------------------------------------------------------------------- /datastructures/priorityqueues/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Priority Queue. A priority queue is a collection in which items can be added at any time, but the only item that can be removed is the one with the highest priority. 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Push ("value1", 5), Push ("value2", 10), Push ("value3", 3), Pop 9 | Output: [("value1", 5), ("value3", 3)] 10 | ``` -------------------------------------------------------------------------------- /datastructures/priorityqueues/heap.go: -------------------------------------------------------------------------------- 1 | package priorityqueues 2 | 3 | /* 4 | https://golang.org/pkg/container/heap/ 5 | */ 6 | 7 | // pqElement is an value in a priority queue. 8 | type pqElement[T any] struct { 9 | value T 10 | 11 | // The index is needed by update and is maintained by the heap.Interface methods. 12 | index int // The index of the item in the heap. 13 | } 14 | 15 | // A heapArray implements heap.Interface and holds Items. 16 | type heapArray[T any] struct { 17 | compare func(i, j T) bool 18 | array []*pqElement[T] 19 | } 20 | 21 | // Len length of the queue 22 | func (h heapArray[T]) Len() int { return len(h.array) } 23 | 24 | // Less compares priority of two elements in the queue 25 | func (h heapArray[T]) Less(i, j int) bool { 26 | return h.compare(h.array[i].value, h.array[j].value) 27 | } 28 | 29 | // Swap swaps two elements in the queue 30 | func (h heapArray[T]) Swap(i, j int) { 31 | h.array[i], h.array[j] = h.array[j], h.array[i] 32 | h.array[i].index = i 33 | h.array[j].index = j 34 | } 35 | 36 | // Push pushes to the queue 37 | func (h *heapArray[T]) Push(x any) { 38 | n := len(h.array) 39 | item := x.(*pqElement[T]) 40 | item.index = n 41 | h.array = append(h.array, item) 42 | } 43 | 44 | // Pop pops from the queue 45 | func (h *heapArray[T]) Pop() any { 46 | old := h.array 47 | n := len(old) 48 | item := old[n-1] 49 | old[n-1] = nil // avoid memory leak 50 | item.index = -1 // for safety 51 | h.array = old[0 : n-1] 52 | return item 53 | } 54 | 55 | // update modifies the priority and value of an Item in the queue. 56 | // func (h *heapArray) update(element *pqElement, value string, priority int) { 57 | // element.Value = value 58 | // element.Priority = priority 59 | // heap.Fix(h, element.index) 60 | // } 61 | -------------------------------------------------------------------------------- /datastructures/priorityqueues/priority_queues.go: -------------------------------------------------------------------------------- 1 | package priorityqueues 2 | 3 | import ( 4 | "container/heap" 5 | "errors" 6 | 7 | "github.com/shomali11/go-interview/datastructures/maps/hashmultimaps" 8 | ) 9 | 10 | var ( 11 | errEmptyQueue = errors.New("queue is empty") 12 | ) 13 | 14 | // New factory to generate new priority queues 15 | func New[T comparable](compare func(i, j T) bool, values ...T) *PriorityQueue[T] { 16 | priorityQueue := PriorityQueue[T]{ 17 | pq: &heapArray[T]{compare: compare}, 18 | multiMap: hashmultimaps.New[T, *pqElement[T]](), 19 | } 20 | heap.Init(priorityQueue.pq) 21 | priorityQueue.Push(values...) 22 | return &priorityQueue 23 | } 24 | 25 | // PriorityQueue Priority Queue structure 26 | type PriorityQueue[T comparable] struct { 27 | pq *heapArray[T] 28 | multiMap *hashmultimaps.HashMultiMap[T, *pqElement[T]] 29 | } 30 | 31 | // Push pushes to the Priority Queue 32 | func (s *PriorityQueue[T]) Push(values ...T) { 33 | for _, value := range values { 34 | element := &pqElement[T]{value: value} 35 | heap.Push(s.pq, element) 36 | s.multiMap.Put(value, element) 37 | } 38 | } 39 | 40 | // Contains checks if the value exists in the Priority Queue 41 | func (s *PriorityQueue[T]) Contains(value T) bool { 42 | return s.multiMap.Contains(value) 43 | } 44 | 45 | // Remove removes from the Priority Queue 46 | func (s *PriorityQueue[T]) Remove(values ...T) { 47 | for _, value := range values { 48 | elements := s.multiMap.GetValues(value) 49 | if len(elements) == 0 { 50 | continue 51 | } 52 | 53 | element := elements[0] 54 | heap.Remove(s.pq, element.index) 55 | s.multiMap.Remove(value, element) 56 | } 57 | } 58 | 59 | // IsEmpty checks if the Priority Queue is empty 60 | func (s *PriorityQueue[T]) IsEmpty() bool { 61 | return s.Size() == 0 62 | } 63 | 64 | // Size returns size of the Priority Queue 65 | func (s *PriorityQueue[T]) Size() int { 66 | return len(s.pq.array) 67 | } 68 | 69 | // Clear clears the Priority Queue 70 | func (s *PriorityQueue[T]) Clear() { 71 | s.pq.array = nil 72 | } 73 | 74 | // Pop removes from the Priority Queue 75 | func (s *PriorityQueue[T]) Pop() (res T, err error) { 76 | if s.IsEmpty() { 77 | return res, errEmptyQueue 78 | } 79 | 80 | element := heap.Pop(s.pq).(*pqElement[T]) 81 | return element.value, nil 82 | } 83 | 84 | // Peek returns top of the Priority Queue 85 | func (s *PriorityQueue[T]) Peek() (res T, err error) { 86 | if s.IsEmpty() { 87 | return res, errEmptyQueue 88 | } 89 | 90 | element := s.pq.array[0] 91 | return element.value, nil 92 | } 93 | -------------------------------------------------------------------------------- /datastructures/priorityqueues/priorityqueues_test.go: -------------------------------------------------------------------------------- 1 | package priorityqueues 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMaxStringPriorityQueue_IsEmpty(t *testing.T) { 10 | compare := func(i, j string) bool { 11 | return i > j 12 | } 13 | 14 | priorityQueue := New[string](compare) 15 | assert.Equal(t, priorityQueue.IsEmpty(), true) 16 | assert.Equal(t, priorityQueue.Size(), 0) 17 | 18 | priorityQueue.Push("hello") 19 | assert.Equal(t, priorityQueue.IsEmpty(), false) 20 | assert.Equal(t, priorityQueue.Size(), 1) 21 | } 22 | 23 | func TestMaxStringPriorityQueue_Peek(t *testing.T) { 24 | compare := func(i, j string) bool { 25 | return i > j 26 | } 27 | 28 | priorityQueue := New[string](compare) 29 | _, err := priorityQueue.Peek() 30 | assert.NotNil(t, err) 31 | 32 | priorityQueue.Push("hello") 33 | element, err := priorityQueue.Peek() 34 | assert.Equal(t, element, "hello") 35 | assert.Nil(t, err) 36 | 37 | priorityQueue.Remove(element) 38 | assert.Equal(t, priorityQueue.Size(), 0) 39 | 40 | _, err = priorityQueue.Peek() 41 | assert.NotNil(t, err) 42 | } 43 | 44 | func TestMaxStringPriorityQueue_Clear(t *testing.T) { 45 | compare := func(i, j string) bool { 46 | return i > j 47 | } 48 | 49 | priorityQueue := New[string](compare) 50 | assert.Equal(t, priorityQueue.IsEmpty(), true) 51 | assert.Equal(t, priorityQueue.Size(), 0) 52 | 53 | priorityQueue.Push("hello") 54 | 55 | priorityQueue.Clear() 56 | assert.Equal(t, priorityQueue.IsEmpty(), true) 57 | assert.Equal(t, priorityQueue.Size(), 0) 58 | } 59 | 60 | func TestMaxStringPriorityQueue_Pop(t *testing.T) { 61 | compare := func(i, j string) bool { 62 | return i > j 63 | } 64 | 65 | priorityQueue := New[string](compare) 66 | priorityQueue.Push("abc") 67 | priorityQueue.Push("sweet", "xyz") 68 | 69 | element, err := priorityQueue.Pop() 70 | assert.Nil(t, err) 71 | assert.Equal(t, priorityQueue.Size(), 2) 72 | assert.Equal(t, element, "xyz") 73 | 74 | element, err = priorityQueue.Pop() 75 | assert.Nil(t, err) 76 | assert.Equal(t, priorityQueue.Size(), 1) 77 | assert.Equal(t, element, "sweet") 78 | 79 | element, err = priorityQueue.Pop() 80 | assert.Nil(t, err) 81 | assert.Equal(t, priorityQueue.Size(), 0) 82 | assert.Equal(t, element, "abc") 83 | 84 | _, err = priorityQueue.Pop() 85 | assert.NotNil(t, err) 86 | } 87 | -------------------------------------------------------------------------------- /datastructures/queues/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Queue. 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) 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Enqueue "value1", Enqueue "value2", Enqueue "value3", Dequeue 9 | Output: ["value2", "value3"] 10 | ``` -------------------------------------------------------------------------------- /datastructures/queues/queues.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | errEmptyQueue = errors.New("queue is empty") 9 | ) 10 | 11 | // New factory to generate new Queues 12 | func New[T any](values ...T) *Queue[T] { 13 | Queue := Queue[T]{make([]T, 0, len(values))} 14 | Queue.Enqueue(values...) 15 | return &Queue 16 | } 17 | 18 | // Queue Queue structure 19 | type Queue[T any] struct { 20 | array []T 21 | } 22 | 23 | // Enqueue add to the Queue 24 | func (q *Queue[T]) Enqueue(values ...T) { 25 | q.array = append(q.array, values...) 26 | } 27 | 28 | // IsEmpty checks if the Queue is empty 29 | func (q *Queue[T]) IsEmpty() bool { 30 | return q.Size() == 0 31 | } 32 | 33 | // Size returns size of the Queue 34 | func (q *Queue[T]) Size() int { 35 | return len(q.array) 36 | } 37 | 38 | // Clear clears Queue 39 | func (q *Queue[T]) Clear() { 40 | q.array = nil 41 | } 42 | 43 | // Dequeue remove from the Queue 44 | func (q *Queue[T]) Dequeue() (res T, err error) { 45 | if q.IsEmpty() { 46 | return res, errEmptyQueue 47 | } 48 | 49 | res = q.array[0] 50 | q.array = q.array[1:] 51 | return res, nil 52 | } 53 | 54 | // Peek returns front of the Queue 55 | func (q *Queue[T]) Peek() (res T, err error) { 56 | if q.IsEmpty() { 57 | return res, errEmptyQueue 58 | } 59 | 60 | res = q.array[0] 61 | return res, nil 62 | } 63 | 64 | // GetValues returns values 65 | func (q *Queue[T]) GetValues() []T { 66 | values := make([]T, 0, q.Size()) 67 | values = append(values, q.array...) 68 | return values 69 | } 70 | -------------------------------------------------------------------------------- /datastructures/queues/queues_test.go: -------------------------------------------------------------------------------- 1 | package queues 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestQueue_Clear(t *testing.T) { 11 | queue := New[string]() 12 | assert.Equal(t, queue.Size(), 0) 13 | assert.Equal(t, queue.IsEmpty(), true) 14 | 15 | queue.Enqueue("hello") 16 | assert.Equal(t, queue.IsEmpty(), false) 17 | assert.Equal(t, queue.Size(), 1) 18 | 19 | queue.Clear() 20 | assert.Equal(t, queue.IsEmpty(), true) 21 | assert.Equal(t, queue.Size(), 0) 22 | } 23 | 24 | func TestQueue_GetValues(t *testing.T) { 25 | queue := New[string]() 26 | 27 | queue.Enqueue("hello", "abc", "xyz") 28 | assert.True(t, reflect.DeepEqual(queue.GetValues(), []string{"hello", "abc", "xyz"})) 29 | } 30 | 31 | func TestQueue_Peek(t *testing.T) { 32 | queue := New[string]() 33 | 34 | queue.Enqueue("hello") 35 | value, err := queue.Peek() 36 | assert.Equal(t, value, "hello") 37 | assert.Nil(t, err) 38 | 39 | queue.Enqueue("abc") 40 | value, err = queue.Peek() 41 | assert.Equal(t, value, "hello") 42 | assert.Nil(t, err) 43 | } 44 | 45 | func TestQueue_Dequeue(t *testing.T) { 46 | queue := New[int]() 47 | 48 | queue.Enqueue(111, 222) 49 | 50 | value, err := queue.Dequeue() 51 | assert.Nil(t, err) 52 | assert.Equal(t, queue.IsEmpty(), false) 53 | assert.Equal(t, queue.Size(), 1) 54 | assert.Equal(t, value, 111) 55 | 56 | value, err = queue.Dequeue() 57 | assert.Nil(t, err) 58 | assert.Equal(t, queue.IsEmpty(), true) 59 | assert.Equal(t, queue.Size(), 0) 60 | assert.Equal(t, value, 222) 61 | 62 | _, err = queue.Dequeue() 63 | assert.NotNil(t, err) 64 | } 65 | -------------------------------------------------------------------------------- /datastructures/sets/hashmultisets/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Multi Set. Like a set, it allows for efficient storage and retrieval of items without a guaranteed order. 4 | 5 | However, unlike a set, it allows for multiple occurrences of the same element by tracking the count of each unique element it contains. 6 | 7 | ### Example: 8 | 9 | ``` 10 | Input: values = "value1", "value2" 11 | Output: [[{key: "value1", count:2}, {key: "value2", count:1}]] 12 | ``` -------------------------------------------------------------------------------- /datastructures/sets/hashmultisets/hash_multi_set.go: -------------------------------------------------------------------------------- 1 | package hashmultisets 2 | 3 | import "sort" 4 | 5 | // New factory that creates a new Hash Multi Set 6 | func New[T comparable](values ...T) *HashMultiSet[T] { 7 | set := HashMultiSet[T]{data: make(map[T]int, len(values))} 8 | set.Add(values...) 9 | return &set 10 | } 11 | 12 | // MultiSetPair a set's key/count pair 13 | type MultiSetPair[T comparable] struct { 14 | Key T 15 | Count int 16 | } 17 | 18 | // HashMultiSet a data structure representing a set with counts 19 | type HashMultiSet[T comparable] struct { 20 | data map[T]int 21 | } 22 | 23 | // Merge merge multiple sets 24 | func (s *HashMultiSet[T]) Merge(sets ...*HashMultiSet[T]) { 25 | for _, set := range sets { 26 | for _, value := range set.GetValues() { 27 | s.IncrementBy(value, set.GetCount(value)) 28 | } 29 | } 30 | } 31 | 32 | // Add adds a value to the set 33 | func (s *HashMultiSet[T]) Add(values ...T) { 34 | for _, value := range values { 35 | s.IncrementBy(value, 1) 36 | } 37 | } 38 | 39 | // IncrementBy increments a value's count by a number 40 | func (s *HashMultiSet[T]) IncrementBy(value T, count int) { 41 | existingCount := s.data[value] 42 | s.data[value] = existingCount + count 43 | } 44 | 45 | // GetValues returns a list of the set's values 46 | func (s *HashMultiSet[T]) GetValues() []T { 47 | values := make([]T, 0, s.Size()) 48 | for key := range s.data { 49 | values = append(values, key) 50 | } 51 | return values 52 | } 53 | 54 | // Contains checks if a value is in the set 55 | func (s *HashMultiSet[T]) Contains(value T) bool { 56 | _, exists := s.data[value] 57 | return exists 58 | } 59 | 60 | // ContainsAll checks if all values are in the set 61 | func (s *HashMultiSet[T]) ContainsAll(values ...T) bool { 62 | for _, value := range values { 63 | if !s.Contains(value) { 64 | return false 65 | } 66 | } 67 | return true 68 | } 69 | 70 | // ContainsAny checks if any values are in the set 71 | func (s *HashMultiSet[T]) ContainsAny(values ...T) bool { 72 | for _, value := range values { 73 | if s.Contains(value) { 74 | return true 75 | } 76 | } 77 | return false 78 | } 79 | 80 | // GetCount returns count associated with the value 81 | func (s *HashMultiSet[T]) GetCount(value T) int { 82 | return s.data[value] 83 | } 84 | 85 | // Remove removes a value 86 | func (s *HashMultiSet[T]) Remove(values ...T) { 87 | for _, value := range values { 88 | delete(s.data, value) 89 | } 90 | } 91 | 92 | // Clear clears the set 93 | func (s *HashMultiSet[T]) Clear() { 94 | s.data = make(map[T]int) 95 | } 96 | 97 | // IsEmpty checks if the set is empty 98 | func (s *HashMultiSet[T]) IsEmpty() bool { 99 | return s.Size() == 0 100 | } 101 | 102 | // Size returns size of the set 103 | func (s *HashMultiSet[T]) Size() int { 104 | return len(s.data) 105 | } 106 | 107 | // GetTopValues returns values ordered in descending order 108 | func (s *HashMultiSet[T]) GetTopValues() []MultiSetPair[T] { 109 | setPairs := make([]MultiSetPair[T], 0, s.Size()) 110 | for key, count := range s.data { 111 | setPairs = append(setPairs, MultiSetPair[T]{Key: key, Count: count}) 112 | } 113 | 114 | sort.SliceStable(setPairs, func(i, j int) bool { 115 | return setPairs[i].Count > setPairs[j].Count 116 | }) 117 | return setPairs 118 | } 119 | -------------------------------------------------------------------------------- /datastructures/sets/hashmultisets/hash_multi_set_test.go: -------------------------------------------------------------------------------- 1 | package hashmultisets 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestHashMultiSet(t *testing.T) { 10 | set := New[string]() 11 | set.Add("hello") 12 | 13 | assert.Equal(t, set.Contains("hello"), true) 14 | assert.Equal(t, set.GetCount("hello"), 1) 15 | assert.Equal(t, set.Contains("unknown"), false) 16 | assert.Equal(t, set.GetCount("unknown"), 0) 17 | assert.Equal(t, set.ContainsAll("hello", "unknown"), false) 18 | assert.Equal(t, set.ContainsAny("hello", "unknown"), true) 19 | assert.Equal(t, set.Size(), 1) 20 | assert.Equal(t, set.GetValues()[0], "hello") 21 | 22 | set.Clear() 23 | assert.Equal(t, set.Size(), 0) 24 | 25 | set.Add("111") 26 | assert.Equal(t, set.Contains("111"), true) 27 | assert.Equal(t, set.ContainsAll("111"), true) 28 | assert.Equal(t, set.ContainsAny("111"), true) 29 | assert.Equal(t, set.GetCount("111"), 1) 30 | assert.Equal(t, set.Size(), 1) 31 | assert.Equal(t, set.GetValues()[0], "111") 32 | 33 | set.Remove("111") 34 | assert.Equal(t, set.Size(), 0) 35 | assert.Equal(t, set.Contains("111"), false) 36 | assert.Equal(t, set.ContainsAll("111"), false) 37 | assert.Equal(t, set.ContainsAny("111"), false) 38 | assert.Equal(t, set.GetCount("111"), 0) 39 | } 40 | 41 | func TestHashMultiSetMerge(t *testing.T) { 42 | set1 := New[int]() 43 | set1.Add(1, 2) 44 | 45 | set2 := New[int](1, 3) 46 | 47 | set3 := New[int]() 48 | set3.Merge(set1, set2) 49 | 50 | assert.Equal(t, set3.Size(), 3) 51 | assert.Equal(t, set3.GetCount(1), 2) 52 | assert.Equal(t, set3.GetCount(2), 1) 53 | assert.Equal(t, set3.GetCount(3), 1) 54 | assert.Equal(t, set3.ContainsAll(1, 2, 3), true) 55 | } 56 | 57 | func TestHashMultiSetTop(t *testing.T) { 58 | set := New[string]() 59 | set.IncrementBy("key1", 10) 60 | set.IncrementBy("key2", 15) 61 | 62 | pairs := set.GetTopValues() 63 | assert.Equal(t, len(pairs), 2) 64 | 65 | pair1 := pairs[0] 66 | assert.Equal(t, pair1.Key, "key2") 67 | assert.Equal(t, pair1.Count, 15) 68 | 69 | pair2 := pairs[1] 70 | assert.Equal(t, pair2.Key, "key1") 71 | assert.Equal(t, pair2.Count, 10) 72 | } 73 | -------------------------------------------------------------------------------- /datastructures/sets/hashsets/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Set. A set is a collection that cannot contain duplicate elements 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: values = "value1", "value1", "value2" 9 | Output: ["value1", "value2"] 10 | ``` -------------------------------------------------------------------------------- /datastructures/sets/hashsets/hash_set.go: -------------------------------------------------------------------------------- 1 | package hashsets 2 | 3 | // New factory that creates a hash set 4 | func New[T comparable](values ...T) *HashSet[T] { 5 | set := HashSet[T]{data: make(map[T]struct{}, len(values))} 6 | set.Add(values...) 7 | return &set 8 | } 9 | 10 | // HashSet datastructure 11 | type HashSet[T comparable] struct { 12 | data map[T]struct{} 13 | } 14 | 15 | // Add adds values to the set 16 | func (s *HashSet[T]) Add(values ...T) { 17 | for _, value := range values { 18 | s.data[value] = struct{}{} 19 | } 20 | } 21 | 22 | // Remove removes values from the set 23 | func (s *HashSet[T]) Remove(values ...T) { 24 | for _, value := range values { 25 | delete(s.data, value) 26 | } 27 | } 28 | 29 | // Contains checks if the value is in the set 30 | func (s *HashSet[T]) Contains(value T) bool { 31 | _, exists := s.data[value] 32 | return exists 33 | } 34 | 35 | // ContainsAll checks if all values are in the set 36 | func (s *HashSet[T]) ContainsAll(values ...T) bool { 37 | for _, value := range values { 38 | if !s.Contains(value) { 39 | return false 40 | } 41 | } 42 | return true 43 | } 44 | 45 | // ContainsAny checks if any of the values are in the set 46 | func (s *HashSet[T]) ContainsAny(values ...T) bool { 47 | for _, value := range values { 48 | if s.Contains(value) { 49 | return true 50 | } 51 | } 52 | return false 53 | } 54 | 55 | // Merge the two sets 56 | func (s *HashSet[T]) Merge(sets ...*HashSet[T]) { 57 | for _, set := range sets { 58 | for _, value := range set.GetValues() { 59 | s.Add(value) 60 | } 61 | } 62 | } 63 | 64 | // Clear clears set 65 | func (s *HashSet[T]) Clear() { 66 | s.data = make(map[T]struct{}) 67 | } 68 | 69 | // GetValues returns values 70 | func (s *HashSet[T]) GetValues() []T { 71 | values := make([]T, 0, s.Size()) 72 | for key := range s.data { 73 | values = append(values, key) 74 | } 75 | return values 76 | } 77 | 78 | // IsEmpty checks if the set is empty 79 | func (s *HashSet[T]) IsEmpty() bool { 80 | return s.Size() == 0 81 | } 82 | 83 | // Size returns size of the set 84 | func (s *HashSet[T]) Size() int { 85 | return len(s.data) 86 | } 87 | 88 | // Common set functions 89 | 90 | // Copy makes an identical copy of the set 91 | func (s *HashSet[T]) Copy() *HashSet[T] { 92 | return New[T](s.GetValues()...) 93 | } 94 | 95 | // Union makes a set that has all of the elements in either of two sets 96 | func (s *HashSet[T]) Union(ss *HashSet[T]) *HashSet[T] { 97 | new := s.Copy() 98 | new.Merge(ss) 99 | return new 100 | } 101 | 102 | // Intersection makes a set that has only the elements common to both of two sets 103 | func (s *HashSet[T]) Intersection(ss *HashSet[T]) *HashSet[T] { 104 | new := s.Copy() 105 | for _, v := range new.GetValues() { 106 | if !ss.Contains(v) { 107 | new.Remove(v) 108 | } 109 | } 110 | return new 111 | } 112 | 113 | // SymmetricDifference makes a set that has elements that are in one of two sets, but not both 114 | func (s *HashSet[T]) SymmetricDifference(ss *HashSet[T]) *HashSet[T] { 115 | new := &HashSet[T]{make(map[T]struct{}, s.Size())} 116 | for _, v := range s.GetValues() { 117 | if !ss.Contains(v) { 118 | new.Add(v) 119 | } 120 | } 121 | for _, v := range ss.GetValues() { 122 | if !s.Contains(v) { 123 | new.Add(v) 124 | } 125 | } 126 | return new 127 | } 128 | 129 | // Subtraction makes a set with the elements that are in the first set, but not the second 130 | func (s *HashSet[T]) Subtraction(ss *HashSet[T]) *HashSet[T] { 131 | new := s.Copy() 132 | for _, v := range ss.GetValues() { 133 | new.Remove(v) 134 | } 135 | return new 136 | } 137 | -------------------------------------------------------------------------------- /datastructures/sets/hashsets/hash_set_test.go: -------------------------------------------------------------------------------- 1 | package hashsets 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestHashSet(t *testing.T) { 9 | set := New[string]() 10 | assert.Equal(t, set.IsEmpty(), true) 11 | 12 | set.Add("hello") 13 | 14 | assert.Equal(t, set.Contains("hello"), true) 15 | assert.Equal(t, set.Contains("unknown"), false) 16 | assert.Equal(t, set.ContainsAll("hello", "unknown"), false) 17 | assert.Equal(t, set.ContainsAny("hello", "unknown"), true) 18 | assert.Equal(t, set.IsEmpty(), false) 19 | assert.Equal(t, set.Size(), 1) 20 | assert.Equal(t, set.GetValues()[0], "hello") 21 | 22 | set.Clear() 23 | assert.Equal(t, set.IsEmpty(), true) 24 | assert.Equal(t, set.Size(), 0) 25 | 26 | set.Add("cool") 27 | assert.Equal(t, set.Contains("cool"), true) 28 | assert.Equal(t, set.ContainsAll("cool"), true) 29 | assert.Equal(t, set.ContainsAny("cool"), true) 30 | assert.Equal(t, set.Size(), 1) 31 | assert.Equal(t, set.GetValues()[0], "cool") 32 | 33 | set.Remove("cool") 34 | assert.Equal(t, set.Size(), 0) 35 | assert.Equal(t, set.Contains("cool"), false) 36 | assert.Equal(t, set.ContainsAll("cool"), false) 37 | assert.Equal(t, set.ContainsAny("cool"), false) 38 | } 39 | 40 | func TestHashSetMerge(t *testing.T) { 41 | set1 := New[string]() 42 | set1.Add("hello", "cool") 43 | 44 | set2 := New[string]("hello", "sweet") 45 | 46 | set3 := New[string]() 47 | set3.Merge(set1, set2) 48 | 49 | assert.Equal(t, set3.Size(), 3) 50 | assert.Equal(t, set3.ContainsAll("hello", "cool", "sweet"), true) 51 | } 52 | 53 | func TestHashSetCopy(t *testing.T) { 54 | set1 := New[string]() 55 | set1.Add("a", "b", "c") 56 | set2 := set1.Copy() 57 | assert.Equal(t, set2.Size(), 3) 58 | assert.Equal(t, set2.ContainsAll("a", "b", "c"), true) 59 | } 60 | 61 | func TestHashSetUnion(t *testing.T) { 62 | set1 := New[string]() 63 | set1.Add("a", "b") 64 | set2 := New[string]() 65 | set2.Add("c", "d") 66 | set3 := set1.Union(set2) 67 | assert.Equal(t, set3.Size(), 4) 68 | assert.Equal(t, set3.ContainsAll("a", "b", "c", "d"), true) 69 | } 70 | 71 | func TestHashSetIntersection(t *testing.T) { 72 | set1 := New[string]() 73 | set1.Add("a", "b", "c", "d", "e") 74 | set2 := New[string]() 75 | set2.Add("c", "d", "e", "f", "g") 76 | set3 := set1.Intersection(set2) 77 | assert.Equal(t, set3.Size(), 3) 78 | assert.Equal(t, set3.ContainsAll("c", "d", "e"), true) 79 | } 80 | 81 | func TestHashSetSymmetricDifference(t *testing.T) { 82 | set1 := New[string]() 83 | set1.Add("a", "b", "c", "d", "e") 84 | set2 := New[string]() 85 | set2.Add("c", "d", "e", "f", "g") 86 | set3 := set1.SymmetricDifference(set2) 87 | assert.Equal(t, set3.Size(), 4) 88 | assert.Equal(t, set3.ContainsAll("a", "b", "f", "g"), true) 89 | } 90 | 91 | func TestHashSetSubtraction(t *testing.T) { 92 | set1 := New[string]() 93 | set1.Add("a", "b", "c", "d", "e") 94 | set2 := New[string]() 95 | set2.Add("c", "d", "e", "f", "g") 96 | set3 := set1.Subtraction(set2) 97 | assert.Equal(t, set3.Size(), 2) 98 | assert.Equal(t, set3.ContainsAll("a", "b"), true) 99 | } 100 | -------------------------------------------------------------------------------- /datastructures/stacks/linkedliststacks/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Stack using a linked list. A stack is an abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the most recently added element that was not yet removed 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Push "value1", Push "value2", Push "value3", Pop 9 | Output: ["value2", "value1"] 10 | ``` -------------------------------------------------------------------------------- /datastructures/stacks/linkedliststacks/linked_list_stacks.go: -------------------------------------------------------------------------------- 1 | package linkedliststacks 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 7 | ) 8 | 9 | var ( 10 | errEmptyStack = errors.New("stack is empty") 11 | ) 12 | 13 | // New factory to generate new stacks 14 | func New[T any](values ...T) *Stack[T] { 15 | return &Stack[T]{list: singlylinkedlists.New[T](values...)} 16 | } 17 | 18 | // Stack stack structure 19 | type Stack[T any] struct { 20 | list *singlylinkedlists.SinglyLinkedList[T] 21 | } 22 | 23 | // Push add to the stack 24 | func (s *Stack[T]) Push(values ...T) { 25 | s.list.Add(values...) 26 | } 27 | 28 | // IsEmpty checks if the stack is empty 29 | func (s *Stack[T]) IsEmpty() bool { 30 | return s.Size() == 0 31 | } 32 | 33 | // Size returns size of the stack 34 | func (s *Stack[T]) Size() int { 35 | return s.list.Size() 36 | } 37 | 38 | // Clear clears stack 39 | func (s *Stack[T]) Clear() { 40 | s.list.Clear() 41 | } 42 | 43 | // Pop remove from the stack 44 | func (s *Stack[T]) Pop() (res T, err error) { 45 | if s.IsEmpty() { 46 | return res, errEmptyStack 47 | } 48 | return s.list.RemoveAt(s.Size() - 1) 49 | } 50 | 51 | // Peek returns top of the stack 52 | func (s *Stack[T]) Peek() (res T, err error) { 53 | if s.IsEmpty() { 54 | return res, errEmptyStack 55 | } 56 | return s.list.GetLastValue() 57 | } 58 | 59 | // GetValues returns values 60 | func (s *Stack[T]) GetValues() []T { 61 | return s.list.GetValues() 62 | } 63 | -------------------------------------------------------------------------------- /datastructures/stacks/linkedliststacks/linked_list_stacks_test.go: -------------------------------------------------------------------------------- 1 | package linkedliststacks 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestStack_Clear(t *testing.T) { 11 | stack := New[string]() 12 | assert.Equal(t, stack.Size(), 0) 13 | assert.Equal(t, stack.IsEmpty(), true) 14 | 15 | stack.Push("hello") 16 | assert.Equal(t, stack.IsEmpty(), false) 17 | assert.Equal(t, stack.Size(), 1) 18 | 19 | stack.Clear() 20 | assert.Equal(t, stack.IsEmpty(), true) 21 | assert.Equal(t, stack.Size(), 0) 22 | } 23 | 24 | func TestStack_GetValues(t *testing.T) { 25 | stack := New[string]() 26 | 27 | stack.Push("hello", "abc", "xyz") 28 | assert.True(t, reflect.DeepEqual(stack.GetValues(), []string{"hello", "abc", "xyz"})) 29 | } 30 | 31 | func TestStack_Peek(t *testing.T) { 32 | stack := New[string]() 33 | 34 | stack.Push("hello") 35 | value, err := stack.Peek() 36 | assert.Equal(t, value, "hello") 37 | assert.Nil(t, err) 38 | 39 | stack.Push("abc") 40 | value, err = stack.Peek() 41 | assert.Equal(t, value, "abc") 42 | assert.Nil(t, err) 43 | } 44 | 45 | func TestStack_Pop(t *testing.T) { 46 | stack := New[int]() 47 | 48 | stack.Push(111, 222) 49 | 50 | value, err := stack.Pop() 51 | assert.Nil(t, err) 52 | assert.Equal(t, stack.IsEmpty(), false) 53 | assert.Equal(t, stack.Size(), 1) 54 | assert.Equal(t, value, 222) 55 | 56 | value, err = stack.Pop() 57 | assert.Nil(t, err) 58 | assert.Equal(t, stack.IsEmpty(), true) 59 | assert.Equal(t, stack.Size(), 0) 60 | assert.Equal(t, value, 111) 61 | 62 | _, err = stack.Pop() 63 | assert.NotNil(t, err) 64 | } 65 | -------------------------------------------------------------------------------- /datastructures/stacks/minmaxstacks/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Min/Max Stack. A Stack that can tell you the Minimum or Maximum value 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Push 15, Push 11, Push 100, Pop, Get Max 9 | Output: 15 10 | ``` -------------------------------------------------------------------------------- /datastructures/stacks/minmaxstacks/min_max_stacks.go: -------------------------------------------------------------------------------- 1 | package minmaxstacks 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/shomali11/go-interview/datastructures/stacks/slicestacks" 7 | ) 8 | 9 | var ( 10 | errEmptyStack = errors.New("stack is empty") 11 | ) 12 | 13 | // New factory to generate new stacks 14 | func New[T any](compare func(i, j T) bool, values ...T) *Stack[T] { 15 | stack := Stack[T]{ 16 | valuesStack: slicestacks.New[T](), 17 | minMaxStack: slicestacks.New[[]T](), 18 | compare: compare, 19 | } 20 | stack.Push(values...) 21 | return &stack 22 | } 23 | 24 | // Stack stack structure 25 | type Stack[T any] struct { 26 | valuesStack *slicestacks.Stack[T] 27 | minMaxStack *slicestacks.Stack[[]T] 28 | compare func(i, j T) bool 29 | } 30 | 31 | // Push add to the stack 32 | func (s *Stack[T]) Push(values ...T) { 33 | if len(values) == 0 { 34 | return 35 | } 36 | 37 | var min T 38 | var max T 39 | 40 | if s.IsEmpty() { 41 | min = values[0] 42 | max = values[0] 43 | } else { 44 | minMaxInterface, _ := s.minMaxStack.Peek() 45 | min = minMaxInterface[0] 46 | max = minMaxInterface[1] 47 | } 48 | 49 | for i := 0; i < len(values); i++ { 50 | value := values[i] 51 | 52 | if s.compare(value, min) { 53 | min = value 54 | } 55 | 56 | if s.compare(max, value) { 57 | max = value 58 | } 59 | 60 | s.valuesStack.Push(value) 61 | s.minMaxStack.Push([]T{min, max}) 62 | } 63 | } 64 | 65 | // IsEmpty checks if the stack is empty 66 | func (s *Stack[T]) IsEmpty() bool { 67 | return s.Size() == 0 68 | } 69 | 70 | // Size returns size of the stack 71 | func (s *Stack[T]) Size() int { 72 | return s.valuesStack.Size() 73 | } 74 | 75 | // Clear clears stack 76 | func (s *Stack[T]) Clear() { 77 | s.valuesStack.Clear() 78 | s.minMaxStack.Clear() 79 | } 80 | 81 | // Pop remove from the stack 82 | func (s *Stack[T]) Pop() (res T, err error) { 83 | if s.IsEmpty() { 84 | return res, errEmptyStack 85 | } 86 | 87 | s.minMaxStack.Pop() 88 | return s.valuesStack.Pop() 89 | } 90 | 91 | // Peek returns top of the stack 92 | func (s *Stack[T]) Peek() (res T, err error) { 93 | if s.IsEmpty() { 94 | return res, errEmptyStack 95 | } 96 | 97 | return s.valuesStack.Peek() 98 | } 99 | 100 | // GetValues returns values 101 | func (s *Stack[T]) GetValues() []T { 102 | return s.valuesStack.GetValues() 103 | } 104 | 105 | // GetMinMax returns the min and max values 106 | func (s *Stack[T]) GetMinMax() (min T, max T, err error) { 107 | if s.IsEmpty() { 108 | return min, max, errEmptyStack 109 | } 110 | 111 | minMaxInterface, err := s.minMaxStack.Peek() 112 | minMax := minMaxInterface 113 | return minMax[0], minMax[1], err 114 | } 115 | -------------------------------------------------------------------------------- /datastructures/stacks/minmaxstacks/min_max_stacks_test.go: -------------------------------------------------------------------------------- 1 | package minmaxstacks 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestStack_Clear(t *testing.T) { 11 | compare := func(i, j string) bool { 12 | return i < j 13 | } 14 | 15 | stack := New[string](compare) 16 | assert.Equal(t, stack.Size(), 0) 17 | assert.Equal(t, stack.IsEmpty(), true) 18 | 19 | stack.Push("hello") 20 | assert.Equal(t, stack.IsEmpty(), false) 21 | assert.Equal(t, stack.Size(), 1) 22 | 23 | stack.Clear() 24 | assert.Equal(t, stack.IsEmpty(), true) 25 | assert.Equal(t, stack.Size(), 0) 26 | } 27 | 28 | func TestStack_GetValues(t *testing.T) { 29 | compare := func(i, j string) bool { 30 | return i < j 31 | } 32 | 33 | stack := New[string](compare) 34 | 35 | stack.Push("hello", "abc", "xyz") 36 | assert.True(t, reflect.DeepEqual(stack.GetValues(), []string{"hello", "abc", "xyz"})) 37 | } 38 | 39 | func TestStack_Peek(t *testing.T) { 40 | compare := func(i, j string) bool { 41 | return i < j 42 | } 43 | 44 | stack := New[string](compare) 45 | 46 | stack.Push("hello") 47 | value, err := stack.Peek() 48 | assert.Equal(t, value, "hello") 49 | assert.Nil(t, err) 50 | 51 | stack.Push("abc") 52 | value, err = stack.Peek() 53 | assert.Equal(t, value, "abc") 54 | assert.Nil(t, err) 55 | } 56 | 57 | func TestStack_Pop(t *testing.T) { 58 | compare := func(i, j int) bool { 59 | return i < j 60 | } 61 | 62 | stack := New[int](compare) 63 | 64 | stack.Push(111, 222) 65 | 66 | value, err := stack.Pop() 67 | assert.Nil(t, err) 68 | assert.Equal(t, stack.IsEmpty(), false) 69 | assert.Equal(t, stack.Size(), 1) 70 | assert.Equal(t, value, 222) 71 | 72 | value, err = stack.Pop() 73 | assert.Nil(t, err) 74 | assert.Equal(t, stack.IsEmpty(), true) 75 | assert.Equal(t, stack.Size(), 0) 76 | assert.Equal(t, value, 111) 77 | 78 | _, err = stack.Pop() 79 | assert.NotNil(t, err) 80 | } 81 | 82 | func TestStack_GetMinMax(t *testing.T) { 83 | compare := func(i, j int) bool { 84 | return i < j 85 | } 86 | 87 | stack := New[int](compare) 88 | 89 | stack.Push(111, 222, 55, 333) 90 | 91 | min, max, err := stack.GetMinMax() 92 | assert.Nil(t, err) 93 | assert.Equal(t, min, 55) 94 | assert.Equal(t, max, 333) 95 | 96 | stack.Pop() 97 | 98 | min, max, err = stack.GetMinMax() 99 | assert.Nil(t, err) 100 | assert.Equal(t, min, 55) 101 | assert.Equal(t, max, 222) 102 | 103 | stack.Pop() 104 | 105 | min, max, err = stack.GetMinMax() 106 | assert.Nil(t, err) 107 | assert.Equal(t, min, 111) 108 | assert.Equal(t, max, 222) 109 | 110 | stack.Pop() 111 | 112 | min, max, err = stack.GetMinMax() 113 | assert.Nil(t, err) 114 | assert.Equal(t, min, 111) 115 | assert.Equal(t, max, 111) 116 | 117 | stack.Pop() 118 | 119 | _, _, err = stack.GetMinMax() 120 | assert.NotNil(t, err) 121 | } 122 | -------------------------------------------------------------------------------- /datastructures/stacks/slicestacks/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement a Stack using a slice. A stack is an abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the most recently added element that was not yet removed 4 | 5 | ### Example: 6 | 7 | ``` 8 | Input: Push "value1", Push "value2", Push "value3", Pop 9 | Output: ["value2", "value1"] 10 | ``` -------------------------------------------------------------------------------- /datastructures/stacks/slicestacks/slice_stacks.go: -------------------------------------------------------------------------------- 1 | package slicestacks 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | var ( 8 | errEmptyStack = errors.New("stack is empty") 9 | ) 10 | 11 | // New factory to generate new stacks 12 | func New[T any](values ...T) *Stack[T] { 13 | stack := Stack[T]{make([]T, 0, len(values))} 14 | stack.Push(values...) 15 | return &stack 16 | } 17 | 18 | // Stack stack structure 19 | type Stack[T any] struct { 20 | array []T 21 | } 22 | 23 | // Push add to the stack 24 | func (s *Stack[T]) Push(values ...T) { 25 | s.array = append(s.array, values...) 26 | } 27 | 28 | // IsEmpty checks if the stack is empty 29 | func (s *Stack[T]) IsEmpty() bool { 30 | return s.Size() == 0 31 | } 32 | 33 | // Size returns size of the stack 34 | func (s *Stack[T]) Size() int { 35 | return len(s.array) 36 | } 37 | 38 | // Clear clears stack 39 | func (s *Stack[T]) Clear() { 40 | s.array = nil 41 | } 42 | 43 | // Pop remove from the stack 44 | func (s *Stack[T]) Pop() (res T, err error) { 45 | if s.IsEmpty() { 46 | return res, errEmptyStack 47 | } 48 | 49 | size := s.Size() 50 | value := s.array[size-1] 51 | s.array = s.array[:size-1] 52 | return value, nil 53 | } 54 | 55 | // Peek returns top of the stack 56 | func (s *Stack[T]) Peek() (res T, err error) { 57 | if s.IsEmpty() { 58 | return res, errEmptyStack 59 | } 60 | 61 | value := s.array[s.Size()-1] 62 | return value, nil 63 | } 64 | 65 | // GetValues returns values 66 | func (s *Stack[T]) GetValues() []T { 67 | values := make([]T, 0, s.Size()) 68 | values = append(values, s.array...) 69 | return values 70 | } 71 | -------------------------------------------------------------------------------- /datastructures/stacks/slicestacks/slice_stacks_test.go: -------------------------------------------------------------------------------- 1 | package slicestacks 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestStack_Clear(t *testing.T) { 11 | stack := New[string]() 12 | assert.Equal(t, stack.Size(), 0) 13 | assert.Equal(t, stack.IsEmpty(), true) 14 | 15 | stack.Push("hello") 16 | assert.Equal(t, stack.IsEmpty(), false) 17 | assert.Equal(t, stack.Size(), 1) 18 | 19 | stack.Clear() 20 | assert.Equal(t, stack.IsEmpty(), true) 21 | assert.Equal(t, stack.Size(), 0) 22 | } 23 | 24 | func TestStack_GetValues(t *testing.T) { 25 | stack := New[string]() 26 | 27 | stack.Push("hello", "abc", "xyz") 28 | assert.True(t, reflect.DeepEqual(stack.GetValues(), []string{"hello", "abc", "xyz"})) 29 | } 30 | 31 | func TestStack_Peek(t *testing.T) { 32 | stack := New[string]() 33 | 34 | stack.Push("hello") 35 | value, err := stack.Peek() 36 | assert.Equal(t, value, "hello") 37 | assert.Nil(t, err) 38 | 39 | stack.Push("abc") 40 | value, err = stack.Peek() 41 | assert.Equal(t, value, "abc") 42 | assert.Nil(t, err) 43 | } 44 | 45 | func TestStack_Pop(t *testing.T) { 46 | stack := New[int]() 47 | 48 | stack.Push(111, 222) 49 | 50 | value, err := stack.Pop() 51 | assert.Nil(t, err) 52 | assert.Equal(t, stack.IsEmpty(), false) 53 | assert.Equal(t, stack.Size(), 1) 54 | assert.Equal(t, value, 222) 55 | 56 | value, err = stack.Pop() 57 | assert.Nil(t, err) 58 | assert.Equal(t, stack.IsEmpty(), true) 59 | assert.Equal(t, stack.Size(), 0) 60 | assert.Equal(t, value, 111) 61 | 62 | _, err = stack.Pop() 63 | assert.NotNil(t, err) 64 | } 65 | -------------------------------------------------------------------------------- /datastructures/trees/trees.go: -------------------------------------------------------------------------------- 1 | package trees 2 | 3 | // MultiNode multi node 4 | type MultiNode[T any] struct { 5 | Parent *MultiNode[T] 6 | Data T 7 | Children []*MultiNode[T] 8 | } 9 | 10 | // BinaryNode binary node 11 | type BinaryNode[T any] struct { 12 | Parent *BinaryNode[T] 13 | Data T 14 | Left *BinaryNode[T] 15 | Right *BinaryNode[T] 16 | } 17 | -------------------------------------------------------------------------------- /evaluations/postfixes/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Postfix notation is a notation for writing arithmetic expressions in which the operands appear before their operators. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 4 5 + 9 | Output: 9 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: 9 3 / 16 | Output: 3 17 | ``` 18 | 19 | ### Example 3: 20 | 21 | ``` 22 | Input: 17 8 - 23 | Output: 9 24 | ``` -------------------------------------------------------------------------------- /evaluations/postfixes/postfixes.go: -------------------------------------------------------------------------------- 1 | package postfixes 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/shomali11/go-interview/datastructures/stacks/slicestacks" 9 | ) 10 | 11 | var ( 12 | errERR = errors.New("#ERR") 13 | ) 14 | 15 | // Evaluate evaluates postfix expressions 16 | func Evaluate(expression string) (float64, error) { 17 | stack := slicestacks.New[float64]() 18 | tokens := strings.Fields(expression) 19 | 20 | for i := 0; i < len(tokens); i++ { 21 | token := tokens[i] 22 | number, ok := isNumber(token) 23 | if ok { 24 | stack.Push(number) 25 | continue 26 | } 27 | 28 | num2, err := pop(stack) 29 | if err != nil { 30 | return 0, err 31 | } 32 | 33 | num1, err := pop(stack) 34 | if err != nil { 35 | return 0, err 36 | } 37 | 38 | switch token { 39 | case "+": 40 | stack.Push(num1 + num2) 41 | case "-": 42 | stack.Push(num1 - num2) 43 | case "*": 44 | stack.Push(num1 * num2) 45 | case "/": 46 | if num2 == 0 { 47 | return 0, errERR 48 | } 49 | stack.Push(num1 / num2) 50 | default: 51 | return 0, errERR 52 | } 53 | } 54 | 55 | if stack.Size() != 1 { 56 | return 0, errERR 57 | } 58 | return pop(stack) 59 | } 60 | 61 | func isNumber(text string) (float64, bool) { 62 | number, err := strconv.ParseFloat(text, 64) 63 | return number, err == nil 64 | } 65 | 66 | func pop(stack *slicestacks.Stack[float64]) (float64, error) { 67 | numberInterface, err := stack.Pop() 68 | if err != nil { 69 | return 0, err 70 | } 71 | 72 | return numberInterface, nil 73 | } 74 | -------------------------------------------------------------------------------- /evaluations/postfixes/postfixes_test.go: -------------------------------------------------------------------------------- 1 | package postfixes 2 | 3 | import "testing" 4 | 5 | func TestPostfix(t *testing.T) { 6 | type args struct { 7 | expression string 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want float64 13 | wantErr bool 14 | }{ 15 | { 16 | "Test valid postfix", 17 | args{"2 3 +"}, 18 | 5.0, 19 | false, 20 | }, 21 | { 22 | "Test valid postfix with plenty of whitespace", 23 | args{" 2 3 + "}, 24 | 5.0, 25 | false, 26 | }, 27 | { 28 | "Test invalid empty postfix", 29 | args{""}, 30 | 0, 31 | true, 32 | }, 33 | { 34 | "Test invalid postfix of one number", 35 | args{"3 +"}, 36 | 0, 37 | true, 38 | }, 39 | { 40 | "Test invalid postfix of too many numbers", 41 | args{"1 2 3 +"}, 42 | 0, 43 | true, 44 | }, 45 | } 46 | for _, tt := range tests { 47 | t.Run(tt.name, func(t *testing.T) { 48 | got, err := Evaluate(tt.args.expression) 49 | if (err != nil) != tt.wantErr { 50 | t.Errorf("Evaluate() error = %v, wantErr %v", err, tt.wantErr) 51 | return 52 | } 53 | if got != tt.want { 54 | t.Errorf("Evaluate() = %v, want %v", got, tt.want) 55 | } 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /evaluations/repeatingfractions/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given two integers representing the numerator and denominator of a fraction, return the fraction in string format. 4 | 5 | If the fractional part is repeating, enclose the repeating part in parentheses. 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input: numerator = 1, denominator = 2 11 | Output: "0.5" 12 | ``` 13 | 14 | ### Example 2: 15 | 16 | ``` 17 | Input: numerator = 2, denominator = 1 18 | Output: "2" 19 | ``` 20 | 21 | ### Example 3: 22 | 23 | ``` 24 | Input: numerator = 2, denominator = 3 25 | Output: "0.(6)" 26 | ``` -------------------------------------------------------------------------------- /evaluations/repeatingfractions/repeating_fractions.go: -------------------------------------------------------------------------------- 1 | package repeatingfractions 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strconv" 7 | ) 8 | 9 | const ( 10 | resultFormat = "%d.%s" 11 | errorResult = "ERROR" 12 | leftParenthesis = "(" 13 | rightParenthesis = ")" 14 | ) 15 | 16 | // Divide divides two integer values and displays the repeating part of the fraction in parenthesis. 17 | func Divide(a int, b int) string { 18 | if b == 0 { 19 | return errorResult 20 | } 21 | 22 | quotient := a / b 23 | remainder := a % b 24 | fractionString := divide(remainder, b) 25 | 26 | // If no fraction result 27 | if len(fractionString) == 0 { 28 | return fmt.Sprint(quotient) 29 | } 30 | return fmt.Sprintf(resultFormat, quotient, fractionString) 31 | } 32 | 33 | // divide returns the fraction with repeating parts between paranthesis 34 | func divide(a int, b int) string { 35 | remainderIndexMap := make(map[int]int) 36 | digits := make([]int, 0) 37 | 38 | digit := 0 39 | remainder := a 40 | 41 | // While we have not seen that digit before 42 | for !exists(remainderIndexMap, remainder) { 43 | remainderIndexMap[remainder] = len(digits) 44 | 45 | remainder *= 10 46 | digit = remainder / b 47 | remainder = remainder % b 48 | digits = append(digits, digit) 49 | } 50 | 51 | repeatingDigitIndex := remainderIndexMap[remainder] 52 | return concat(digits, repeatingDigitIndex) 53 | } 54 | 55 | // concat create the string result 56 | func concat(digits []int, repeatingDigitIndex int) string { 57 | var buffer bytes.Buffer 58 | for i := 0; i < repeatingDigitIndex; i++ { 59 | buffer.WriteString(strconv.Itoa(digits[i])) 60 | } 61 | 62 | // If the repeating result is a 0, return 63 | if repeatingDigitIndex == len(digits)-1 && digits[repeatingDigitIndex] == 0 { 64 | return buffer.String() 65 | } 66 | 67 | // Collect repeating digits between paranthesis 68 | buffer.WriteString(leftParenthesis) 69 | for i := repeatingDigitIndex; i < len(digits); i++ { 70 | buffer.WriteString(strconv.Itoa(digits[i])) 71 | } 72 | buffer.WriteString(rightParenthesis) 73 | return buffer.String() 74 | } 75 | 76 | // exists Determines whether a key exists 77 | func exists(myMap map[int]int, key int) bool { 78 | _, ok := myMap[key] 79 | return ok 80 | } 81 | -------------------------------------------------------------------------------- /evaluations/repeatingfractions/repeating_fractions_test.go: -------------------------------------------------------------------------------- 1 | package repeatingfractions 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestDivide(t *testing.T) { 10 | assert.Equal(t, Divide(0, 0), "ERROR") 11 | assert.Equal(t, Divide(2, 1), "2") 12 | assert.Equal(t, Divide(1, 2), "0.5") 13 | assert.Equal(t, Divide(0, 3), "0") 14 | assert.Equal(t, Divide(2, 3), "0.(6)") 15 | assert.Equal(t, Divide(10, 3), "3.(3)") 16 | assert.Equal(t, Divide(22, 7), "3.(142857)") 17 | assert.Equal(t, Divide(100, 145), "0.(6896551724137931034482758620)") 18 | } 19 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/shomali11/go-interview 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 7 | github.com/shomali11/gridder v0.0.0-20210930173142-5f3b82d74585 8 | github.com/stretchr/testify v1.7.1 9 | golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 10 | golang.org/x/image v0.0.0-20220302094943-723b81ca9867 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/fogleman/gg v1.3.0 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | github.com/stretchr/objx v0.1.0 // indirect 18 | gopkg.in/yaml.v2 v2.4.0 // indirect 19 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= 6 | github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 7 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 8 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 9 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 10 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 11 | github.com/shomali11/gridder v0.0.0-20200411014130-6eb52d16b35b h1:oQH8Xkir0/u+Fn7GUJLRpBNWvjMYwbpSTVtrfU1QF7c= 12 | github.com/shomali11/gridder v0.0.0-20200411014130-6eb52d16b35b/go.mod h1:Jk/769IHgi/W7e4vZf6D3QKWTm8i40LFn+63M3qJOrw= 13 | github.com/shomali11/gridder v0.0.0-20210930173142-5f3b82d74585 h1:WsfT2BQs5kovue4LeytDQEJAtli+gHl9q4JoRUSrfyM= 14 | github.com/shomali11/gridder v0.0.0-20210930173142-5f3b82d74585/go.mod h1:GkufrYjZLwzKPY2dBoteg8j6MEkDiywCqkXrZXAckgA= 15 | github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 18 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 19 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= 20 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 21 | golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU= 22 | golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= 23 | golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg= 24 | golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 25 | golang.org/x/image v0.0.0-20220302094943-723b81ca9867 h1:TcHcE0vrmgzNH1v3ppjcMGbhG5+9fMuvOmUYwNEF4q4= 26 | golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= 27 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 28 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 29 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 30 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 31 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 32 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 33 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 34 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 35 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 36 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 37 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 38 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 39 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 40 | -------------------------------------------------------------------------------- /lists/detectcycles/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a singly linked list, check if it has loop or not. 4 | -------------------------------------------------------------------------------- /lists/detectcycles/detect_cycles.go: -------------------------------------------------------------------------------- 1 | package detectcycles 2 | 3 | import "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 4 | 5 | // ContainsCycle checks if the list contains a cycle 6 | func ContainsCycle[T comparable](head *singlylinkedlists.SLLNode[T]) bool { 7 | fastPointer := head 8 | slowPointer := head 9 | for fastPointer != nil && fastPointer.Next != nil { 10 | fastPointer = fastPointer.Next.Next 11 | slowPointer = slowPointer.Next 12 | if slowPointer == fastPointer { 13 | return true 14 | } 15 | } 16 | return false 17 | } 18 | -------------------------------------------------------------------------------- /lists/detectcycles/detect_cycles_test.go: -------------------------------------------------------------------------------- 1 | package detectcycles 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestContainsCycle(t *testing.T) { 11 | emptyList := singlylinkedlists.New[string]() 12 | assert.False(t, ContainsCycle(emptyList.GetHead())) 13 | 14 | nonEmptyList := singlylinkedlists.New("A", "B", "C") 15 | assert.False(t, ContainsCycle(nonEmptyList.GetHead())) 16 | 17 | node1 := &singlylinkedlists.SLLNode[string]{Value: "X"} 18 | node2 := &singlylinkedlists.SLLNode[string]{Value: "X"} 19 | node3 := &singlylinkedlists.SLLNode[string]{Value: "X"} 20 | node4 := &singlylinkedlists.SLLNode[string]{Value: "X"} 21 | 22 | node1.Next = node2 23 | node2.Next = node3 24 | node3.Next = node4 25 | node4.Next = node2 26 | assert.True(t, ContainsCycle(node1)) 27 | } 28 | -------------------------------------------------------------------------------- /lists/detectintersections/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a two singly linked lists, check if they intersect. 4 | -------------------------------------------------------------------------------- /lists/detectintersections/detect_intersections.go: -------------------------------------------------------------------------------- 1 | package detectintersections 2 | 3 | import "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 4 | 5 | // DoIntersect checks if the two lists intersect 6 | func DoIntersect[T comparable](head1 *singlylinkedlists.SLLNode[T], head2 *singlylinkedlists.SLLNode[T]) bool { 7 | head1ListCount := getCountNodes(head1) 8 | head2ListCount := getCountNodes(head2) 9 | 10 | current1 := getStartingNode(head1, head1ListCount-head2ListCount) 11 | current2 := getStartingNode(head2, head2ListCount-head1ListCount) 12 | 13 | for current1 != nil { 14 | if current1 == current2 { 15 | return true 16 | } 17 | current1 = current1.Next 18 | current2 = current2.Next 19 | } 20 | return false 21 | } 22 | 23 | func getStartingNode[T comparable](head *singlylinkedlists.SLLNode[T], moves int) *singlylinkedlists.SLLNode[T] { 24 | current := head 25 | for moves > 0 { 26 | current = current.Next 27 | moves-- 28 | } 29 | return current 30 | } 31 | 32 | func getCountNodes[T comparable](head *singlylinkedlists.SLLNode[T]) int { 33 | count := 0 34 | current := head 35 | for current != nil { 36 | current = current.Next 37 | count++ 38 | } 39 | return count 40 | } 41 | -------------------------------------------------------------------------------- /lists/detectintersections/detect_intersections_test.go: -------------------------------------------------------------------------------- 1 | package detectintersections 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestDoIntersect(t *testing.T) { 11 | emptyList1 := singlylinkedlists.New[string]() 12 | emptyList2 := singlylinkedlists.New[string]() 13 | assert.False(t, DoIntersect(emptyList1.GetHead(), emptyList2.GetHead())) 14 | 15 | nonEmptyList1 := singlylinkedlists.New("A", "B", "C") 16 | nonEmptyList2 := singlylinkedlists.New("A", "B", "C") 17 | assert.False(t, DoIntersect(nonEmptyList1.GetHead(), nonEmptyList2.GetHead())) 18 | 19 | node1 := &singlylinkedlists.SLLNode[string]{Value: "X"} 20 | node2 := &singlylinkedlists.SLLNode[string]{Value: "X"} 21 | node3 := &singlylinkedlists.SLLNode[string]{Value: "X"} 22 | node4 := &singlylinkedlists.SLLNode[string]{Value: "X"} 23 | 24 | node1.Next = node2 25 | node2.Next = node3 26 | node3.Next = node4 27 | 28 | node5 := &singlylinkedlists.SLLNode[string]{Value: "X"} 29 | node6 := &singlylinkedlists.SLLNode[string]{Value: "X"} 30 | 31 | node5.Next = node6 32 | node6.Next = node4 33 | assert.True(t, DoIntersect(node1, node5)) 34 | } 35 | -------------------------------------------------------------------------------- /lists/reverses/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Reverse a singly linked list 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: ["1"] -> ["2"] -> ["3"] 9 | Output: ["3"] -> ["2"] -> ["1"] 10 | ``` 11 | -------------------------------------------------------------------------------- /lists/reverses/reverses.go: -------------------------------------------------------------------------------- 1 | package reverses 2 | 3 | import "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 4 | 5 | // Reverse reverse a singly linked list 6 | func Reverse[T any](node *singlylinkedlists.SLLNode[T]) *singlylinkedlists.SLLNode[T] { 7 | current := node 8 | var previous *singlylinkedlists.SLLNode[T] 9 | var next *singlylinkedlists.SLLNode[T] 10 | for current != nil { 11 | next = current.Next 12 | current.Next = previous 13 | previous = current 14 | current = next 15 | } 16 | return previous 17 | } 18 | -------------------------------------------------------------------------------- /lists/reverses/reverses_test.go: -------------------------------------------------------------------------------- 1 | package reverses 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/linkedlists/singlylinkedlists" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestReverse(t *testing.T) { 11 | node1 := &singlylinkedlists.SLLNode[string]{Value: "1"} 12 | node2 := &singlylinkedlists.SLLNode[string]{Value: "2"} 13 | node3 := &singlylinkedlists.SLLNode[string]{Value: "3"} 14 | 15 | node1.Next = node2 16 | node2.Next = node3 17 | node3.Next = nil 18 | 19 | newHead := Reverse(node1) 20 | 21 | assert.Equal(t, newHead.Value, "3") 22 | assert.NotNil(t, newHead.Next) 23 | assert.Equal(t, newHead.Next.Value, "2") 24 | assert.NotNil(t, newHead.Next.Next) 25 | assert.Equal(t, newHead.Next.Next.Value, "1") 26 | assert.Nil(t, newHead.Next.Next.Next) 27 | } 28 | -------------------------------------------------------------------------------- /numbers/armstrongs/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a number x, determine whether the given number is Armstrong number or not. An integer of n digits is called an Armstrong number if 4 | 5 | `abcd... = pow(a,n) + pow(b,n) + pow(c,n) + pow(d,n) + ....` 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input : 153 11 | Output : Yes 12 | 153 is an Armstrong number. 13 | 1*1*1 + 5*5*5 + 3*3*3 = 153 14 | ``` 15 | 16 | ### Example 2: 17 | 18 | ``` 19 | Input : 120 20 | Output : No 21 | 120 is not a Armstrong number. 22 | 1*1*1 + 2*2*2 + 0*0*0 = 9 23 | ``` 24 | 25 | ### Example 3: 26 | 27 | ``` 28 | Input : 1253 29 | Output : No 30 | 1253 is not a Armstrong Number 31 | 1*1*1*1 + 2*2*2*2 + 5*5*5*5 + 3*3*3*3 = 723 32 | ``` 33 | 34 | ### Example 4: 35 | 36 | ``` 37 | Input : 1634 38 | Output : Yes 39 | 1*1*1*1 + 6*6*6*6 + 3*3*3*3 + 4*4*4*4 = 1634 40 | ``` -------------------------------------------------------------------------------- /numbers/armstrongs/armstrongs.go: -------------------------------------------------------------------------------- 1 | package armstrongs 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/shomali11/go-interview/numbers/countdigits" 7 | ) 8 | 9 | // IsArmstrong determines if a number is an armstrong number 10 | func IsArmstrong(number int) bool { 11 | digits := float64(countdigits.CountDigits(number)) 12 | 13 | current := number 14 | sum := 0 15 | for current != 0 { 16 | sum += int(math.Pow(float64(current%10), digits)) 17 | current /= 10 18 | } 19 | return sum == number 20 | } 21 | -------------------------------------------------------------------------------- /numbers/armstrongs/armstrongs_test.go: -------------------------------------------------------------------------------- 1 | package armstrongs 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsPerfect(t *testing.T) { 10 | assert.True(t, IsArmstrong(0)) 11 | assert.True(t, IsArmstrong(1)) 12 | assert.True(t, IsArmstrong(153)) 13 | assert.True(t, IsArmstrong(370)) 14 | assert.True(t, IsArmstrong(371)) 15 | assert.True(t, IsArmstrong(1634)) 16 | } 17 | -------------------------------------------------------------------------------- /numbers/bases/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Convert from any base to decimal and vice versa. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: string = "1100", base = 2 9 | Output: 12 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: string = "11A", base = 16 16 | Output: 282 17 | ``` 18 | 19 | ### Example 3: 20 | 21 | ``` 22 | Input: string = "123", base = 8 23 | Output: 83 24 | ``` -------------------------------------------------------------------------------- /numbers/bases/bases.go: -------------------------------------------------------------------------------- 1 | package bases 2 | 3 | import ( 4 | "bytes" 5 | "math" 6 | "strings" 7 | 8 | "github.com/shomali11/go-interview/strings/reverses/reversestrings" 9 | ) 10 | 11 | const ( 12 | codes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 13 | ) 14 | 15 | // Encode converts a number to a given base 16 | func Encode(number int, base int) string { 17 | var buffer bytes.Buffer 18 | remainder := 0 19 | for number > 0 { 20 | remainder = number % base 21 | buffer.WriteString(string(codes[remainder])) 22 | number /= base 23 | } 24 | return reversestrings.ReverseString(buffer.String()) 25 | } 26 | 27 | // Decode converts a number of a specific base 28 | func Decode(number string, base int) int { 29 | sum := 0 30 | exponent := len(number) - 1 31 | digits := []rune(number) 32 | for i := 0; i < len(number); i++ { 33 | index := float64(strings.Index(codes, string(digits[i]))) 34 | power := math.Pow(float64(base), float64(exponent)) 35 | sum += int(index * power) 36 | exponent-- 37 | } 38 | return int(sum) 39 | } 40 | -------------------------------------------------------------------------------- /numbers/bases/bases_test.go: -------------------------------------------------------------------------------- 1 | package bases 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestEncode(t *testing.T) { 10 | assert.Equal(t, Encode(2, 2), "10") 11 | assert.Equal(t, Encode(10, 10), "10") 12 | assert.Equal(t, Encode(10, 8), "12") 13 | assert.Equal(t, Encode(10, 16), "A") 14 | assert.Equal(t, Encode(12, 2), "1100") 15 | assert.Equal(t, Encode(282, 16), "11A") 16 | assert.Equal(t, Encode(83, 8), "123") 17 | assert.Equal(t, Encode(9696041034, 62), "AaBbCc") 18 | } 19 | 20 | func TestDecode(t *testing.T) { 21 | assert.Equal(t, Decode("10", 2), 2) 22 | assert.Equal(t, Decode("10", 10), 10) 23 | assert.Equal(t, Decode("12", 8), 10) 24 | assert.Equal(t, Decode("A", 16), 10) 25 | assert.Equal(t, Decode("1100", 2), 12) 26 | assert.Equal(t, Decode("11A", 16), 282) 27 | assert.Equal(t, Decode("123", 8), 83) 28 | assert.Equal(t, Decode("AaBbCc", 62), 9696041034) 29 | } 30 | -------------------------------------------------------------------------------- /numbers/countdigits/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Count the number of digits in a number 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 100 9 | Output: 3 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: 42974 16 | Output: 5 17 | ``` -------------------------------------------------------------------------------- /numbers/countdigits/count_digits.go: -------------------------------------------------------------------------------- 1 | package countdigits 2 | 3 | // CountDigits counts the number of digits 4 | func CountDigits(number int) int { 5 | if number == 0 { 6 | return 1 7 | } 8 | 9 | count := 0 10 | for number != 0 { 11 | number /= 10 12 | count++ 13 | } 14 | return count 15 | } 16 | -------------------------------------------------------------------------------- /numbers/countdigits/count_digits_test.go: -------------------------------------------------------------------------------- 1 | package countdigits 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestCountDigits(t *testing.T) { 10 | assert.Equal(t, CountDigits(0), 1) 11 | assert.Equal(t, CountDigits(1), 1) 12 | assert.Equal(t, CountDigits(19), 2) 13 | assert.Equal(t, CountDigits(123), 3) 14 | } 15 | -------------------------------------------------------------------------------- /numbers/countprimes/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Count the number of prime numbers up to a non-negative number, n. 4 | 5 | A prime number is a numeral that is greater than 1 and cannot be divided evenly by any other number except 1 and itself. If a number can be divided evenly by any other number not counting itself and 1, it is not prime and is referred to as a composite number. 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input: 2 11 | Output: 1 12 | ``` 13 | 14 | ### Example 2: 15 | 16 | ``` 17 | Input: 10 18 | Output: 4 19 | ``` 20 | -------------------------------------------------------------------------------- /numbers/countprimes/count_primes.go: -------------------------------------------------------------------------------- 1 | package countprimes 2 | 3 | // CountPrimes returns the number of prime numbers up to given number 4 | func CountPrimes(number int) int { 5 | if number <= 1 { 6 | return 0 7 | } 8 | 9 | isPrimeNumbers := make([]bool, number+1) 10 | for i := range isPrimeNumbers { 11 | isPrimeNumbers[i] = true 12 | } 13 | 14 | for i := 2; i*i <= number; i++ { 15 | if isPrimeNumbers[i] { 16 | for j := i * i; j <= number; j += i { 17 | isPrimeNumbers[j] = false 18 | } 19 | } 20 | } 21 | 22 | count := 0 23 | for i := 2; i <= number; i++ { 24 | if isPrimeNumbers[i] { 25 | count++ 26 | } 27 | } 28 | return count 29 | } 30 | -------------------------------------------------------------------------------- /numbers/countprimes/count_primes_test.go: -------------------------------------------------------------------------------- 1 | package countprimes 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestCountPrimes(t *testing.T) { 10 | assert.Equal(t, CountPrimes(1), 0) 11 | assert.Equal(t, CountPrimes(2), 1) 12 | assert.Equal(t, CountPrimes(3), 2) 13 | assert.Equal(t, CountPrimes(4), 2) 14 | assert.Equal(t, CountPrimes(10), 4) 15 | } 16 | -------------------------------------------------------------------------------- /numbers/excels/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a column number, find its corresponding Excel column name. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 26 9 | Output: Z 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: 51 16 | Output: AY 17 | ``` 18 | 19 | ### Example 3: 20 | 21 | ``` 22 | Input: 705 23 | Output: AAC 24 | ``` -------------------------------------------------------------------------------- /numbers/excels/excels.go: -------------------------------------------------------------------------------- 1 | package excels 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | 7 | "github.com/shomali11/go-interview/strings/reverses/reversestrings" 8 | ) 9 | 10 | const ( 11 | characterA = 'A' 12 | characterZ = 'Z' 13 | alphabetsCount = 26 14 | ) 15 | 16 | // Encode converts a number to an Excel Column Name 17 | func Encode(number int) string { 18 | var buffer bytes.Buffer 19 | remainder := 0 20 | for number > 0 { 21 | remainder = (number - 1) % alphabetsCount 22 | buffer.WriteString(string(rune(characterA + remainder))) 23 | number = (number - remainder) / alphabetsCount 24 | } 25 | return reversestrings.ReverseString(buffer.String()) 26 | } 27 | 28 | // Decode converts an Excel Column Name to a number 29 | func Decode(value string) int { 30 | value = strings.ToUpper(value) 31 | number := 0 32 | pow := 1 33 | for i := len(value) - 1; i >= 0; i-- { 34 | if value[i] < characterA || value[i] > characterZ { 35 | continue 36 | } 37 | 38 | number += (int(value[i]-characterA) + 1) * pow 39 | pow *= alphabetsCount 40 | } 41 | return number 42 | 43 | } 44 | -------------------------------------------------------------------------------- /numbers/excels/excels_test.go: -------------------------------------------------------------------------------- 1 | package excels 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestEncode(t *testing.T) { 10 | assert.Equal(t, Encode(1), "A") 11 | assert.Equal(t, Encode(2), "B") 12 | assert.Equal(t, Encode(26), "Z") 13 | assert.Equal(t, Encode(27), "AA") 14 | assert.Equal(t, Encode(100), "CV") 15 | } 16 | 17 | func TestDecode(t *testing.T) { 18 | assert.Equal(t, Decode("A"), 1) 19 | assert.Equal(t, Decode("B"), 2) 20 | assert.Equal(t, Decode("Z"), 26) 21 | assert.Equal(t, Decode("AA"), 27) 22 | assert.Equal(t, Decode("CV"), 100) 23 | } 24 | -------------------------------------------------------------------------------- /numbers/fibonaccis/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. 5 | 6 | That is, 7 | 8 | ``` 9 | F(0) = 0, F(1) = 1 10 | F(N) = F(N - 1) + F(N - 2), for N > 1. 11 | ``` 12 | 13 | Given N, calculate F(N). 14 | 15 | ### Example 1: 16 | 17 | ``` 18 | Input: 2 19 | Output: 1 20 | ``` 21 | 22 | ### Example 2: 23 | 24 | ``` 25 | Input: 3 26 | Output: 2 27 | ``` 28 | 29 | ### Example 3: 30 | 31 | ``` 32 | Input: 4 33 | Output: 3 34 | ``` -------------------------------------------------------------------------------- /numbers/fibonaccis/fibonaccis.go: -------------------------------------------------------------------------------- 1 | package fibonaccis 2 | 3 | // Fibonacci returns fibonacci number 4 | func Fibonacci(number int) int { 5 | if number <= 0 { 6 | return 0 7 | } 8 | 9 | n2 := 0 10 | n1 := 0 11 | current := 1 12 | 13 | for i := 1; i < number; i++ { 14 | n2 = n1 15 | n1 = current 16 | current = n2 + n1 17 | } 18 | return current 19 | } 20 | -------------------------------------------------------------------------------- /numbers/fibonaccis/fibonaccis_test.go: -------------------------------------------------------------------------------- 1 | package fibonaccis 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestFibonacci(t *testing.T) { 10 | assert.Equal(t, Fibonacci(0), 0) 11 | assert.Equal(t, Fibonacci(1), 1) 12 | assert.Equal(t, Fibonacci(2), 1) 13 | assert.Equal(t, Fibonacci(3), 2) 14 | assert.Equal(t, Fibonacci(4), 3) 15 | assert.Equal(t, Fibonacci(5), 5) 16 | assert.Equal(t, Fibonacci(6), 8) 17 | assert.Equal(t, Fibonacci(7), 13) 18 | assert.Equal(t, Fibonacci(8), 21) 19 | assert.Equal(t, Fibonacci(9), 34) 20 | assert.Equal(t, Fibonacci(10), 55) 21 | } 22 | -------------------------------------------------------------------------------- /numbers/leapyears/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Determine if a year is a leap year. A leap year is every 4 years, but not every 100 years, then again every 400 years. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 2000 9 | Output: true 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: 2001 16 | Output: false 17 | ``` -------------------------------------------------------------------------------- /numbers/leapyears/leap_years.go: -------------------------------------------------------------------------------- 1 | package leapyears 2 | 3 | // IsLeapYear determines if a year is a leap year 4 | func IsLeapYear(number int) bool { 5 | if number%4 != 0 { 6 | return false 7 | } 8 | 9 | if number%100 != 0 { 10 | return true 11 | } 12 | 13 | return number%400 == 0 14 | } 15 | -------------------------------------------------------------------------------- /numbers/leapyears/leap_years_test.go: -------------------------------------------------------------------------------- 1 | package leapyears 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsLeapYear(t *testing.T) { 10 | for year := 1804; year <= 1896; year = year + 4 { 11 | assert.True(t, IsLeapYear(year)) 12 | } 13 | 14 | for year := 1904; year <= 2000; year = year + 4 { 15 | assert.True(t, IsLeapYear(year)) 16 | } 17 | 18 | for year := 2004; year <= 2096; year = year + 4 { 19 | assert.True(t, IsLeapYear(year)) 20 | } 21 | 22 | for year := 2104; year <= 2196; year = year + 4 { 23 | assert.True(t, IsLeapYear(year)) 24 | } 25 | 26 | for year := 2204; year <= 2296; year = year + 4 { 27 | assert.True(t, IsLeapYear(year)) 28 | } 29 | 30 | for year := 2304; year <= 2400; year = year + 4 { 31 | assert.True(t, IsLeapYear(year)) 32 | } 33 | 34 | assert.False(t, IsLeapYear(1900)) 35 | assert.False(t, IsLeapYear(2100)) 36 | assert.False(t, IsLeapYear(2200)) 37 | assert.False(t, IsLeapYear(2300)) 38 | } 39 | -------------------------------------------------------------------------------- /numbers/palindromes/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Determine if a number is a palindrome. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 12321 9 | Output: true 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: 12345 16 | Output: false 17 | ``` 18 | -------------------------------------------------------------------------------- /numbers/palindromes/palindromes.go: -------------------------------------------------------------------------------- 1 | package palindromestrings 2 | 3 | import "github.com/shomali11/go-interview/numbers/reverses" 4 | 5 | // IsPalindrome determines if the input is a palindrome 6 | func IsPalindrome(number int) bool { 7 | return number == reverses.Reverse(number) 8 | } 9 | -------------------------------------------------------------------------------- /numbers/palindromes/palindromes_test.go: -------------------------------------------------------------------------------- 1 | package palindromestrings 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsPalindrome(t *testing.T) { 10 | assert.True(t, IsPalindrome(12321)) 11 | assert.True(t, IsPalindrome(8998)) 12 | assert.False(t, IsPalindrome(12345)) 13 | } 14 | -------------------------------------------------------------------------------- /numbers/perfects/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | A number is a perfect number if is equal to sum of its proper divisors, that is, sum of its positive divisors excluding the number itself. Write a function to check if a given number is perfect or not. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: number = 15 9 | Output: false 10 | 11 | Divisors of 15 are 1, 3 and 5. 12 | Sum of divisors is 9 which is not equal to 15. 13 | ``` 14 | 15 | ### Example 2: 16 | 17 | ``` 18 | Input: number = 6 19 | Output: true 20 | 21 | Divisors of 6 are 1, 2 and 3. 22 | Sum of divisors is 6. 23 | ``` 24 | -------------------------------------------------------------------------------- /numbers/perfects/perfects.go: -------------------------------------------------------------------------------- 1 | package perfects 2 | 3 | // IsPerfect determines if a number is perfect 4 | func IsPerfect(number int) bool { 5 | if number <= 0 { 6 | return false 7 | } 8 | 9 | sum := 0 10 | for i := 1; i <= number/2; i++ { 11 | if number%i == 0 { 12 | sum += i 13 | } 14 | } 15 | return sum == number 16 | } 17 | -------------------------------------------------------------------------------- /numbers/perfects/perfects_test.go: -------------------------------------------------------------------------------- 1 | package perfects 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsPerfect(t *testing.T) { 10 | assert.False(t, IsPerfect(0)) 11 | assert.False(t, IsPerfect(1)) 12 | assert.False(t, IsPerfect(2)) 13 | assert.False(t, IsPerfect(3)) 14 | assert.False(t, IsPerfect(4)) 15 | assert.False(t, IsPerfect(5)) 16 | assert.True(t, IsPerfect(6)) 17 | assert.False(t, IsPerfect(15)) 18 | assert.True(t, IsPerfect(28)) 19 | assert.True(t, IsPerfect(496)) 20 | assert.True(t, IsPerfect(8128)) 21 | } 22 | -------------------------------------------------------------------------------- /numbers/powers/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Implement the Power function 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: number = 2, exponent = 2 9 | Output: 4 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: number = 2, exponent = -3 16 | Output: 1/8 17 | ``` 18 | -------------------------------------------------------------------------------- /numbers/powers/powers.go: -------------------------------------------------------------------------------- 1 | package powers 2 | 3 | // Power calculates the power 4 | func Power(number int, exponent int) float64 { 5 | if exponent == 0 { 6 | return 1 7 | } 8 | 9 | if exponent == 1 { 10 | return float64(number) 11 | } 12 | 13 | if exponent < 0 { 14 | return 1.0 / Power(number, -exponent) 15 | } 16 | 17 | result := Power(number, exponent/2) 18 | if exponent%2 == 0 { 19 | return result * result 20 | } 21 | return float64(number) * result * result 22 | } 23 | -------------------------------------------------------------------------------- /numbers/powers/powers_test.go: -------------------------------------------------------------------------------- 1 | package powers 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsPerfect(t *testing.T) { 10 | assert.Equal(t, Power(2, -3), 1.0/8) 11 | assert.Equal(t, Power(2, -2), 1.0/4) 12 | assert.Equal(t, Power(2, -1), 1.0/2) 13 | assert.Equal(t, Power(2, 0), 1.0) 14 | assert.Equal(t, Power(2, 1), 2.0) 15 | assert.Equal(t, Power(2, 2), 4.0) 16 | assert.Equal(t, Power(2, 3), 8.0) 17 | } 18 | -------------------------------------------------------------------------------- /numbers/primes/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Determine if a number is a prime. 4 | 5 | A prime number is a numeral that is greater than 1 and cannot be divided evenly by any other number except 1 and itself. If a number can be divided evenly by any other number not counting itself and 1, it is not prime and is referred to as a composite number. 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input: 7 11 | Output: true 12 | ``` 13 | 14 | ### Example 2: 15 | 16 | ``` 17 | Input: 4 18 | Output: false 19 | ``` 20 | -------------------------------------------------------------------------------- /numbers/primes/primes.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | // IsPrime determines if a number is prime 4 | func IsPrime(number int) bool { 5 | if number <= 1 { 6 | return false 7 | } 8 | 9 | if number == 2 { 10 | return true 11 | } 12 | 13 | if number%2 == 0 { 14 | return false 15 | } 16 | 17 | for i := 3; i*i <= number; i = i + 2 { 18 | if number%i == 0 { 19 | return false 20 | } 21 | } 22 | return true 23 | } 24 | -------------------------------------------------------------------------------- /numbers/primes/primes_test.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsPrime(t *testing.T) { 10 | assert.True(t, IsPrime(2)) 11 | assert.True(t, IsPrime(7)) 12 | assert.True(t, IsPrime(31)) 13 | assert.False(t, IsPrime(4)) 14 | } 15 | -------------------------------------------------------------------------------- /numbers/reverses/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Reverse a number 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 12321 9 | Output: 12321 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: 12345 16 | Output: 54321 17 | ``` 18 | -------------------------------------------------------------------------------- /numbers/reverses/reverses.go: -------------------------------------------------------------------------------- 1 | package reverses 2 | 3 | // Reverse reverses a number 4 | func Reverse(number int) int { 5 | reverse := 0 6 | for number != 0 { 7 | reverse *= 10 8 | reverse += number % 10 9 | number /= 10 10 | } 11 | return reverse 12 | } 13 | -------------------------------------------------------------------------------- /numbers/reverses/reverses_test.go: -------------------------------------------------------------------------------- 1 | package reverses 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestReverse(t *testing.T) { 10 | assert.Equal(t, Reverse(12321), 12321) 11 | assert.Equal(t, Reverse(8998), 8998) 12 | assert.Equal(t, Reverse(12345), 54321) 13 | } 14 | -------------------------------------------------------------------------------- /slices/duplicates/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given an array of values. Determine if there is a duplicate one 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: {1, 2, 3} 9 | Output: false 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: {"key1", "key2", "key1"} 16 | Output: true 17 | ``` 18 | -------------------------------------------------------------------------------- /slices/duplicates/duplicates.go: -------------------------------------------------------------------------------- 1 | package duplicates 2 | 3 | import "github.com/shomali11/go-interview/datastructures/sets/hashsets" 4 | 5 | // ContainsDuplicates checks if the list contains duplicates 6 | func ContainsDuplicates[T comparable](values ...T) bool { 7 | set := hashsets.New[T]() 8 | for _, value := range values { 9 | if set.Contains(value) { 10 | return true 11 | } 12 | set.Add(value) 13 | } 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /slices/duplicates/duplicates_test.go: -------------------------------------------------------------------------------- 1 | package duplicates 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestContainsDuplicates(t *testing.T) { 10 | assert.Equal(t, ContainsDuplicates(1, 2, 3), false) 11 | assert.Equal(t, ContainsDuplicates(1, 2, 1), true) 12 | assert.Equal(t, ContainsDuplicates(true, false), false) 13 | assert.Equal(t, ContainsDuplicates(true, false, true), true) 14 | assert.Equal(t, ContainsDuplicates("1", "2", "3"), false) 15 | assert.Equal(t, ContainsDuplicates("1", "2", "1"), true) 16 | } 17 | -------------------------------------------------------------------------------- /slices/groupanagrams/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given an array of strings, group anagrams together. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: ["eat", "tea", "tan", "ate", "nat", "bat"], 9 | Output: 10 | [ 11 | ["ate","eat","tea"], 12 | ["nat","tan"], 13 | ["bat"] 14 | ] 15 | ``` -------------------------------------------------------------------------------- /slices/groupanagrams/group_anagrams.go: -------------------------------------------------------------------------------- 1 | package groupanagrams 2 | 3 | import ( 4 | "github.com/shomali11/go-interview/datastructures/maps/hashmultimaps" 5 | "github.com/shomali11/go-interview/strings/sorts" 6 | ) 7 | 8 | // GroupAnagrams groups anagrams 9 | func GroupAnagrams(list []string) *hashmultimaps.HashMultiMap[string, string] { 10 | multimap := hashmultimaps.New[string, string]() 11 | for _, value := range list { 12 | sortedValue := sorts.Sort(value) 13 | multimap.Put(sortedValue, value) 14 | } 15 | return multimap 16 | } 17 | -------------------------------------------------------------------------------- /slices/groupanagrams/group_anagrams_test.go: -------------------------------------------------------------------------------- 1 | package groupanagrams 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestGroupAnagrams(t *testing.T) { 11 | values := []string{"eat", "tea", "tan", "ate", "nat", "bat"} 12 | multimap := GroupAnagrams(values) 13 | 14 | assert.Equal(t, multimap.Size(), 3) 15 | assert.True(t, reflect.DeepEqual(multimap.GetValues("aet"), []string{"eat", "tea", "ate"})) 16 | assert.True(t, reflect.DeepEqual(multimap.GetValues("ant"), []string{"tan", "nat"})) 17 | assert.True(t, reflect.DeepEqual(multimap.GetValues("abt"), []string{"bat"})) 18 | } 19 | -------------------------------------------------------------------------------- /slices/minmeetingrooms/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given an array of meeting time intervals consisting of start and end times, find the minimum number of conference rooms required. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: [[0, 30],[5, 10],[15, 20]] 9 | Output: 2 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: [[7,10],[2,4]] 16 | Output: 1 17 | ``` -------------------------------------------------------------------------------- /slices/minmeetingrooms/min_meeting_rooms.go: -------------------------------------------------------------------------------- 1 | package minmeetingrooms 2 | 3 | import "github.com/shomali11/go-interview/datastructures/sets/hashmultisets" 4 | 5 | // MinMeetingRooms returns minimum meeting rooms required 6 | func MinMeetingRooms(intervals [][]int) int { 7 | multiset := hashmultisets.New[int]() 8 | for _, interval := range intervals { 9 | for i := interval[0]; i <= interval[1]; i++ { 10 | multiset.Add(i) 11 | } 12 | } 13 | 14 | multiSetPairs := multiset.GetTopValues() 15 | if len(multiSetPairs) == 0 { 16 | return 0 17 | } 18 | return multiSetPairs[0].Count 19 | } 20 | -------------------------------------------------------------------------------- /slices/minmeetingrooms/min_meeting_rooms_test.go: -------------------------------------------------------------------------------- 1 | package minmeetingrooms 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMinMeetingRooms(t *testing.T) { 10 | meetings := [][]int{ 11 | {0, 30}, {5, 10}, {15, 20}, 12 | } 13 | assert.Equal(t, MinMeetingRooms(meetings), 2) 14 | } 15 | -------------------------------------------------------------------------------- /slices/rotations/countrotations/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given an array of distinct integers sorted in increasing order. The array has been rotated (clockwise) k number of times. 4 | Find the value of k. 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: {15, 18, 2, 3, 6, 12} 10 | Output: 4 11 | ``` 12 | 13 | ### Example 2: 14 | 15 | ``` 16 | Input: {7, 9, 11, 12, 5} 17 | Output: 1 18 | ``` 19 | 20 | ### Example 3: 21 | 22 | ``` 23 | Input: {7, 9, 11, 12, 15}; 24 | Output: 0 25 | ``` 26 | -------------------------------------------------------------------------------- /slices/rotations/countrotations/count_rotations.go: -------------------------------------------------------------------------------- 1 | package countrotations 2 | 3 | import "github.com/shomali11/go-interview/slices/rotations/minrotations" 4 | 5 | // Count counts the number of rotations 6 | func Count(array []int) int { 7 | minimumIndex := minrotations.Min(array) 8 | if minimumIndex == 0 { 9 | return 0 10 | } 11 | return len(array) - minimumIndex 12 | } 13 | -------------------------------------------------------------------------------- /slices/rotations/countrotations/count_rotations_test.go: -------------------------------------------------------------------------------- 1 | package countrotations 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestCountRotations(t *testing.T) { 10 | assert.Equal(t, Count([]int{1, 2, 3, 4, 5}), 0) 11 | assert.Equal(t, Count([]int{2, 3, 4, 5, 1}), 1) 12 | assert.Equal(t, Count([]int{3, 4, 5, 1, 2}), 2) 13 | assert.Equal(t, Count([]int{4, 5, 1, 2, 3}), 3) 14 | assert.Equal(t, Count([]int{5, 1, 2, 3, 4}), 4) 15 | } 16 | -------------------------------------------------------------------------------- /slices/rotations/minrotations/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given an array of distinct integers sorted in increasing order. The array has been rotated (clockwise) k number of times. 4 | Find the index of the minimum value. 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: {15, 18, 2, 3, 6, 12} 10 | Output: 2 11 | ``` 12 | 13 | ### Example 2: 14 | 15 | ``` 16 | Input: {7, 9, 11, 12, 5} 17 | Output: 4 18 | ``` 19 | 20 | ### Example 3: 21 | 22 | ``` 23 | Input: {7, 9, 11, 12, 15}; 24 | Output: 0 25 | ``` 26 | -------------------------------------------------------------------------------- /slices/rotations/minrotations/min_rotations.go: -------------------------------------------------------------------------------- 1 | package minrotations 2 | 3 | // Min finds minimum in array 4 | func Min(array []int) int { 5 | size := len(array) 6 | if size <= 1 { 7 | return 0 8 | } 9 | 10 | lowIndex := 0 11 | middleIndex := 0 12 | highIndex := size - 1 13 | for array[lowIndex] > array[highIndex] { 14 | middleIndex = (lowIndex + highIndex) / 2 15 | if array[middleIndex] > array[highIndex] { 16 | lowIndex = middleIndex + 1 17 | } else { 18 | highIndex = middleIndex 19 | } 20 | } 21 | return lowIndex 22 | } 23 | -------------------------------------------------------------------------------- /slices/rotations/minrotations/min_rotations_test.go: -------------------------------------------------------------------------------- 1 | package minrotations 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMin(t *testing.T) { 10 | assert.Equal(t, Min([]int{1, 2, 3, 4, 5}), 0) 11 | assert.Equal(t, Min([]int{2, 3, 4, 5, 1}), 4) 12 | assert.Equal(t, Min([]int{3, 4, 5, 1, 2}), 3) 13 | assert.Equal(t, Min([]int{4, 5, 1, 2, 3}), 2) 14 | assert.Equal(t, Min([]int{5, 1, 2, 3, 4}), 1) 15 | } 16 | -------------------------------------------------------------------------------- /stacks/balancedparantheses/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a string expression, examine whether the pairs and the orders of `{`,`}`,`(`,`)`,`[`,`]` are correct 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: “[()]{}{[()()]()}” 9 | Output: true 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: “[(])” 16 | Output: false 17 | ``` -------------------------------------------------------------------------------- /stacks/balancedparantheses/balanced_parantheses.go: -------------------------------------------------------------------------------- 1 | package balancedparantheses 2 | 3 | import ( 4 | "github.com/shomali11/go-interview/datastructures/stacks/slicestacks" 5 | ) 6 | 7 | const ( 8 | openParanthesis1 = '[' 9 | openParanthesis2 = '{' 10 | openParanthesis3 = '(' 11 | 12 | closeParanthesis1 = ']' 13 | closeParanthesis2 = '}' 14 | closeParanthesis3 = ')' 15 | ) 16 | 17 | // IsBalancedParantheses determines if the parantheses are balanced 18 | func IsBalancedParantheses(expression string) bool { 19 | stack := slicestacks.New[rune]() 20 | 21 | for _, char := range []rune(expression) { 22 | if isOpenParantheses(char) { 23 | stack.Push(char) 24 | continue 25 | } 26 | 27 | if !isCloseParantheses(char) { 28 | continue 29 | } 30 | 31 | value, err := stack.Pop() 32 | if err != nil { 33 | return false 34 | } 35 | 36 | if !isMatchingParanthesis(value, char) { 37 | return false 38 | } 39 | } 40 | return stack.IsEmpty() 41 | } 42 | 43 | func isOpenParantheses(character rune) bool { 44 | return character == openParanthesis1 || character == openParanthesis2 || character == openParanthesis3 45 | } 46 | 47 | func isCloseParantheses(character rune) bool { 48 | return character == closeParanthesis1 || character == closeParanthesis2 || character == closeParanthesis3 49 | } 50 | 51 | func isMatchingParanthesis(open rune, close rune) bool { 52 | switch open { 53 | case openParanthesis1: 54 | return close == closeParanthesis1 55 | case openParanthesis2: 56 | return close == closeParanthesis2 57 | case openParanthesis3: 58 | return close == closeParanthesis3 59 | } 60 | return false 61 | } 62 | -------------------------------------------------------------------------------- /stacks/balancedparantheses/balanced_parantheses_test.go: -------------------------------------------------------------------------------- 1 | package balancedparantheses 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestBalancedParantheses(t *testing.T) { 10 | assert.True(t, IsBalancedParantheses("")) 11 | assert.True(t, IsBalancedParantheses(" ")) 12 | assert.True(t, IsBalancedParantheses("{}")) 13 | assert.True(t, IsBalancedParantheses("[]")) 14 | assert.True(t, IsBalancedParantheses("()")) 15 | assert.True(t, IsBalancedParantheses("{()}")) 16 | assert.True(t, IsBalancedParantheses("[{()}]")) 17 | assert.True(t, IsBalancedParantheses("[](){}")) 18 | assert.True(t, IsBalancedParantheses("[()]{}")) 19 | assert.True(t, IsBalancedParantheses("[ (X)]{ }")) 20 | 21 | assert.False(t, IsBalancedParantheses("{")) 22 | assert.False(t, IsBalancedParantheses("(")) 23 | assert.False(t, IsBalancedParantheses("[")) 24 | assert.False(t, IsBalancedParantheses("}")) 25 | assert.False(t, IsBalancedParantheses(")")) 26 | assert.False(t, IsBalancedParantheses("]")) 27 | assert.False(t, IsBalancedParantheses("}{")) 28 | assert.False(t, IsBalancedParantheses(")(")) 29 | assert.False(t, IsBalancedParantheses("][")) 30 | assert.False(t, IsBalancedParantheses("{[}]")) 31 | assert.False(t, IsBalancedParantheses("(((()))")) 32 | } 33 | -------------------------------------------------------------------------------- /streams/movingaverages/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a stream of integers, calculate the moving average within a fixed sliding window 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: Numbers 1, 2, 3, 4, 5 - Sliding Window of 3 9 | Output: 4 10 | ``` 11 | -------------------------------------------------------------------------------- /streams/movingaverages/moving_averages.go: -------------------------------------------------------------------------------- 1 | package movingaverages 2 | 3 | import ( 4 | "github.com/shomali11/go-interview/datastructures/queues" 5 | ) 6 | 7 | // New creates a new moving average structure with a fixed sliding window 8 | func New(windowSize int) *MovingAverage { 9 | return &MovingAverage{sum: 0, windowSize: windowSize, queue: queues.New[int]()} 10 | } 11 | 12 | // MovingAverage keeps track of the moving average 13 | type MovingAverage struct { 14 | sum int 15 | windowSize int 16 | queue *queues.Queue[int] 17 | } 18 | 19 | // Add adds a number to the moving average calculations 20 | func (ma *MovingAverage) Add(number int) { 21 | ma.sum += number 22 | ma.queue.Enqueue(number) 23 | if ma.queue.Size() <= ma.windowSize { 24 | return 25 | } 26 | 27 | value, _ := ma.queue.Dequeue() 28 | ma.sum -= value 29 | } 30 | 31 | // GetAverage calculates the moving average 32 | func (ma *MovingAverage) GetAverage() float64 { 33 | return float64(ma.sum) / float64(ma.queue.Size()) 34 | } 35 | 36 | // GetSum returns the sum within the sliding window 37 | func (ma *MovingAverage) GetSum() int { 38 | return ma.sum 39 | } 40 | -------------------------------------------------------------------------------- /streams/movingaverages/moving_averages_test.go: -------------------------------------------------------------------------------- 1 | package movingaverages 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMovingAverage(t *testing.T) { 10 | movingAverage := New(3) 11 | 12 | movingAverage.Add(1) 13 | assert.Equal(t, movingAverage.GetAverage(), float64(1)) 14 | assert.Equal(t, movingAverage.GetSum(), 1) 15 | 16 | movingAverage.Add(2) 17 | assert.Equal(t, movingAverage.GetAverage(), float64(1.5)) 18 | assert.Equal(t, movingAverage.GetSum(), 3) 19 | 20 | movingAverage.Add(3) 21 | assert.Equal(t, movingAverage.GetAverage(), float64(2)) 22 | assert.Equal(t, movingAverage.GetSum(), 6) 23 | 24 | movingAverage.Add(4) 25 | assert.Equal(t, movingAverage.GetAverage(), float64(3)) 26 | assert.Equal(t, movingAverage.GetSum(), 9) 27 | 28 | movingAverage.Add(5) 29 | assert.Equal(t, movingAverage.GetAverage(), float64(4)) 30 | assert.Equal(t, movingAverage.GetSum(), 12) 31 | } 32 | -------------------------------------------------------------------------------- /streams/runningaverages/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a stream of integers, calculate the running average 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 1, 2, 3 9 | Output: 2 10 | ``` 11 | -------------------------------------------------------------------------------- /streams/runningaverages/running_averages.go: -------------------------------------------------------------------------------- 1 | package runningaverages 2 | 3 | // RunningAverage keeps track of the running average 4 | type RunningAverage struct { 5 | sum int 6 | count int 7 | } 8 | 9 | // Add adds a number to the running average calculations 10 | func (ra *RunningAverage) Add(number int) { 11 | ra.sum += number 12 | ra.count++ 13 | } 14 | 15 | // GetAverage calculates the running average 16 | func (ra *RunningAverage) GetAverage() float64 { 17 | return float64(ra.sum) / float64(ra.count) 18 | } 19 | 20 | // GetSum returns the running sum 21 | func (ra *RunningAverage) GetSum() int { 22 | return ra.sum 23 | } 24 | 25 | // GetCount returns the running count 26 | func (ra *RunningAverage) GetCount() int { 27 | return ra.count 28 | } 29 | -------------------------------------------------------------------------------- /streams/runningaverages/running_averages_test.go: -------------------------------------------------------------------------------- 1 | package runningaverages 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestRunningAverage(t *testing.T) { 10 | runningAverage := RunningAverage{} 11 | 12 | runningAverage.Add(1) 13 | assert.Equal(t, runningAverage.GetAverage(), float64(1)) 14 | assert.Equal(t, runningAverage.GetSum(), 1) 15 | assert.Equal(t, runningAverage.GetCount(), 1) 16 | 17 | runningAverage.Add(2) 18 | assert.Equal(t, runningAverage.GetAverage(), float64(1.5)) 19 | assert.Equal(t, runningAverage.GetSum(), 3) 20 | assert.Equal(t, runningAverage.GetCount(), 2) 21 | 22 | runningAverage.Add(3) 23 | assert.Equal(t, runningAverage.GetAverage(), float64(2)) 24 | assert.Equal(t, runningAverage.GetSum(), 6) 25 | assert.Equal(t, runningAverage.GetCount(), 3) 26 | } 27 | -------------------------------------------------------------------------------- /streams/runningmedians/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a stream of integers, calculate the running median 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: 5, 6, 7 9 | Output: 6 10 | ``` 11 | 12 | ### Example 2: 13 | 14 | ``` 15 | Input: 5, 6, 7, 8 16 | Output: 6.5 17 | ``` 18 | -------------------------------------------------------------------------------- /streams/runningmedians/running_medians.go: -------------------------------------------------------------------------------- 1 | package runningmedians 2 | 3 | import "github.com/shomali11/go-interview/datastructures/priorityqueues" 4 | 5 | // New generates a Running Median 6 | func New() *RunningMedian { 7 | maxCompare := func(i, j int) bool { 8 | return i > j 9 | } 10 | 11 | minCompare := func(i, j int) bool { 12 | return i < j 13 | } 14 | return &RunningMedian{minPQ: priorityqueues.New[int](minCompare), maxPQ: priorityqueues.New[int](maxCompare)} 15 | } 16 | 17 | // RunningMedian keeps track of the running median 18 | type RunningMedian struct { 19 | minPQ *priorityqueues.PriorityQueue[int] 20 | maxPQ *priorityqueues.PriorityQueue[int] 21 | } 22 | 23 | // Add adds a number to the running median calculations 24 | func (rm *RunningMedian) Add(number int) { 25 | rm.minPQ.Push(number) 26 | rm.maxPQ.Push(pop(rm.minPQ)) 27 | 28 | if rm.minPQ.Size() < rm.maxPQ.Size() { 29 | rm.minPQ.Push(pop(rm.maxPQ)) 30 | } 31 | } 32 | 33 | // GetMedian calculates median 34 | func (rm *RunningMedian) GetMedian() float64 { 35 | if rm.minPQ.Size() > rm.maxPQ.Size() { 36 | return peek(rm.minPQ) 37 | } 38 | return (peek(rm.minPQ) + peek(rm.maxPQ)) / 2.0 39 | } 40 | 41 | func pop(pq *priorityqueues.PriorityQueue[int]) int { 42 | value, _ := pq.Pop() 43 | return value 44 | } 45 | 46 | func peek(pq *priorityqueues.PriorityQueue[int]) float64 { 47 | value, _ := pq.Peek() 48 | return float64(value) 49 | } 50 | -------------------------------------------------------------------------------- /streams/runningmedians/running_medians_test.go: -------------------------------------------------------------------------------- 1 | package runningmedians 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestRunningMedian(t *testing.T) { 10 | runningMedian := New() 11 | 12 | runningMedian.Add(1) 13 | assert.Equal(t, runningMedian.GetMedian(), float64(1)) 14 | 15 | runningMedian.Add(2) 16 | assert.Equal(t, runningMedian.GetMedian(), float64(1.5)) 17 | 18 | runningMedian.Add(3) 19 | assert.Equal(t, runningMedian.GetMedian(), float64(2)) 20 | } 21 | -------------------------------------------------------------------------------- /strings/addbinaries/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given two binary strings, return their sum (also a binary string). 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: a = "11", b = "1" 9 | Output: "100" 10 | ``` 11 | -------------------------------------------------------------------------------- /strings/addbinaries/add_binaries.go: -------------------------------------------------------------------------------- 1 | package addbinaries 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "strconv" 7 | 8 | "github.com/shomali11/go-interview/strings/reverses/reversestrings" 9 | ) 10 | 11 | const ( 12 | empty = "" 13 | ) 14 | 15 | var ( 16 | errRuneNotInt = errors.New("digit is not an integer") 17 | ) 18 | 19 | // Add adds two binary string numbers 20 | func Add(number1 string, number2 string) (string, error) { 21 | var result bytes.Buffer 22 | 23 | number1Runes := []rune(number1) 24 | number2Runes := []rune(number2) 25 | 26 | number1Index := len(number1) - 1 27 | number2Index := len(number2) - 1 28 | 29 | carry := 0 30 | 31 | for number1Index >= 0 && number2Index >= 0 { 32 | value1, err := getNumber(number1Runes, number1Index) 33 | if err != nil { 34 | return empty, err 35 | } 36 | 37 | value2, err := getNumber(number2Runes, number2Index) 38 | if err != nil { 39 | return empty, err 40 | } 41 | 42 | result.WriteString(strconv.Itoa((value1 + value2 + carry) % 2)) 43 | carry = (value1 + value2 + carry) / 2 44 | 45 | number1Index-- 46 | number2Index-- 47 | } 48 | 49 | for ; number1Index >= 0; number1Index-- { 50 | value, err := getNumber(number1Runes, number1Index) 51 | if err != nil { 52 | return empty, err 53 | } 54 | 55 | result.WriteString(strconv.Itoa((value + carry) % 2)) 56 | carry = (value + carry) / 2 57 | } 58 | 59 | for ; number2Index >= 0; number2Index-- { 60 | value, err := getNumber(number2Runes, number2Index) 61 | if err != nil { 62 | return empty, err 63 | } 64 | 65 | result.WriteString(strconv.Itoa((value + carry) % 2)) 66 | carry = (value + carry) / 2 67 | } 68 | 69 | if carry > 0 { 70 | result.WriteString(strconv.Itoa(carry)) 71 | } 72 | return reversestrings.ReverseString(result.String()), nil 73 | } 74 | 75 | func getNumber(numberRunes []rune, index int) (int, error) { 76 | number, err := characterToNumber(numberRunes[index]) 77 | if err != nil { 78 | return 0, err 79 | } 80 | return number, nil 81 | } 82 | 83 | func characterToNumber(r rune) (int, error) { 84 | if '0' <= r && r <= '9' { 85 | return int(r) - '0', nil 86 | } 87 | return 0, errRuneNotInt 88 | } 89 | -------------------------------------------------------------------------------- /strings/addbinaries/add_binaries_test.go: -------------------------------------------------------------------------------- 1 | package addbinaries 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestAdd(t *testing.T) { 10 | value, err := Add("11", "") 11 | assert.Nil(t, err) 12 | assert.Equal(t, value, "11") 13 | 14 | value, err = Add("11", "1") 15 | assert.Nil(t, err) 16 | assert.Equal(t, value, "100") 17 | 18 | value, err = Add("10", "11") 19 | assert.Nil(t, err) 20 | assert.Equal(t, value, "101") 21 | 22 | _, err = Add("a", "11") 23 | assert.NotNil(t, err) 24 | } 25 | -------------------------------------------------------------------------------- /strings/palindromes/palindromesentences/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Determine if a sentence is a palindrome. 4 | 5 | A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward, such as "madam" and "racecar". 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input: "too hot to hoot." 11 | Output: true 12 | ``` 13 | 14 | ### Example 2: 15 | 16 | ``` 17 | Input: "hello world" 18 | Output: false 19 | ``` 20 | -------------------------------------------------------------------------------- /strings/palindromes/palindromesentences/palindrome_sentences.go: -------------------------------------------------------------------------------- 1 | package palindromesentences 2 | 3 | const ( 4 | capitalA = 'A' 5 | capitalZ = 'Z' 6 | smallA = 'a' 7 | smallZ = 'z' 8 | ) 9 | 10 | // IsPalindrome determines if the input is a palindrome 11 | func IsPalindrome(sentence string) bool { 12 | runes := []rune(sentence) 13 | length := len(runes) 14 | 15 | i := 0 16 | j := length - 1 17 | 18 | for i < j { 19 | if !isCharacter(runes[i]) { 20 | i++ 21 | continue 22 | } 23 | 24 | if !isCharacter(runes[j]) { 25 | j-- 26 | continue 27 | } 28 | 29 | if runes[i] != runes[j] { 30 | return false 31 | } 32 | i++ 33 | j-- 34 | } 35 | return true 36 | } 37 | 38 | func isCharacter(character rune) bool { 39 | if character >= capitalA && character <= capitalZ { 40 | return true 41 | } 42 | if character >= smallA && character <= smallZ { 43 | return true 44 | } 45 | return false 46 | } 47 | -------------------------------------------------------------------------------- /strings/palindromes/palindromesentences/palindrome_sentences_test.go: -------------------------------------------------------------------------------- 1 | package palindromesentences 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsPalindrome(t *testing.T) { 10 | assert.True(t, IsPalindrome("hannah")) 11 | assert.True(t, IsPalindrome("too hot to hoot.")) 12 | assert.False(t, IsPalindrome("hello")) 13 | } 14 | -------------------------------------------------------------------------------- /strings/palindromes/palindromestrings/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Determine if a string is a palindrome. 4 | 5 | A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward, such as "madam" and "racecar". 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input: "madam" 11 | Output: true 12 | ``` 13 | 14 | ### Example 2: 15 | 16 | ``` 17 | Input: "hello" 18 | Output: false 19 | ``` 20 | -------------------------------------------------------------------------------- /strings/palindromes/palindromestrings/palindrome_strings.go: -------------------------------------------------------------------------------- 1 | package palindromestrings 2 | 3 | // IsPalindrome determines if the input is a palindrome 4 | func IsPalindrome(text string) bool { 5 | runes := []rune(text) 6 | length := len(runes) 7 | for i, j := 0, length-1; i < length/2; i, j = i+1, j-1 { 8 | if runes[i] != runes[j] { 9 | return false 10 | } 11 | } 12 | return true 13 | } 14 | -------------------------------------------------------------------------------- /strings/palindromes/palindromestrings/palindrome_strings_test.go: -------------------------------------------------------------------------------- 1 | package palindromestrings 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestIsPalindrome(t *testing.T) { 10 | assert.True(t, IsPalindrome("hannah")) 11 | assert.True(t, IsPalindrome("hanah")) 12 | assert.False(t, IsPalindrome("hello")) 13 | } 14 | -------------------------------------------------------------------------------- /strings/reverses/reversesentences/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a sentence, reverse it word by word. 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: "Hello! How are you?" 9 | Output: "you? are How Hello!" 10 | ``` 11 | -------------------------------------------------------------------------------- /strings/reverses/reversesentences/reverse_sentences.go: -------------------------------------------------------------------------------- 1 | package reversesentences 2 | 3 | import "github.com/shomali11/go-interview/strings/reverses/reversestrings" 4 | 5 | // ReverseSentence reverse a sentence 6 | func ReverseSentence(sentence string) string { 7 | runes := []rune(sentence) 8 | size := len(runes) 9 | 10 | // Reverse entire string 11 | reversestrings.Reverse(runes, 0, size-1) 12 | 13 | start := 0 14 | end := 0 15 | 16 | for start < size && end < size { 17 | if runes[start] == ' ' { 18 | start++ 19 | end++ 20 | continue 21 | } 22 | 23 | if runes[end] != ' ' { 24 | end++ 25 | continue 26 | } 27 | 28 | reversestrings.Reverse(runes, start, end-1) 29 | start = end 30 | } 31 | 32 | reversestrings.Reverse(runes, start, end-1) 33 | return string(runes) 34 | } 35 | -------------------------------------------------------------------------------- /strings/reverses/reversesentences/reverse_sentences_test.go: -------------------------------------------------------------------------------- 1 | package reversesentences 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestReverse(t *testing.T) { 10 | assert.Equal(t, ReverseSentence("hello"), "hello") 11 | assert.Equal(t, ReverseSentence("this is a sentence"), "sentence a is this") 12 | assert.Equal(t, ReverseSentence(" hello "), " hello ") 13 | assert.Equal(t, ReverseSentence(" this is a sentence"), "sentence a is this ") 14 | assert.Equal(t, ReverseSentence("What is happening?"), "happening? is What") 15 | assert.Equal(t, ReverseSentence("Hello! How are you?"), "you? are How Hello!") 16 | } 17 | -------------------------------------------------------------------------------- /strings/reverses/reversestrings/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Reverse a string 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: "hello" 9 | Output: "olleh" 10 | ``` 11 | -------------------------------------------------------------------------------- /strings/reverses/reversestrings/reverse_strings.go: -------------------------------------------------------------------------------- 1 | package reversestrings 2 | 3 | // ReverseString reverse a string 4 | func ReverseString(text string) string { 5 | runes := []rune(text) 6 | Reverse(runes, 0, len(runes)-1) 7 | return string(runes) 8 | } 9 | 10 | // Reverse reverse a string 11 | func Reverse(runes []rune, start int, end int) { 12 | for i, j := start, end; i < j; i, j = i+1, j-1 { 13 | runes[i], runes[j] = runes[j], runes[i] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /strings/reverses/reversestrings/reverse_strings_test.go: -------------------------------------------------------------------------------- 1 | package reversestrings 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestReverse(t *testing.T) { 10 | assert.Equal(t, ReverseString("hello"), "olleh") 11 | } 12 | -------------------------------------------------------------------------------- /strings/sorts/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given a string, return a sorted version 4 | 5 | ### Example 1: 6 | 7 | ``` 8 | Input: "cba" 9 | Output: "abc" 10 | ``` 11 | -------------------------------------------------------------------------------- /strings/sorts/sorts.go: -------------------------------------------------------------------------------- 1 | package sorts 2 | 3 | import "sort" 4 | 5 | // Sort sort a string 6 | func Sort(text string) string { 7 | runes := []rune(text) 8 | sort.Slice(runes, func(i, j int) bool { 9 | return runes[i] < runes[j] 10 | }) 11 | return string(runes) 12 | } 13 | -------------------------------------------------------------------------------- /strings/sorts/sorts_test.go: -------------------------------------------------------------------------------- 1 | package sorts 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestSort(t *testing.T) { 10 | assert.Equal(t, Sort(""), "") 11 | assert.Equal(t, Sort("a"), "a") 12 | assert.Equal(t, Sort("abc"), "abc") 13 | assert.Equal(t, Sort("cba"), "abc") 14 | } 15 | -------------------------------------------------------------------------------- /strings/wordbreakers/README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Given an input string and a dictionary of words, segment the input string into a space-separated sequence of dictionary words if possible. 4 | 5 | For example, if the input string is "applepie" and dictionary contains a standard set of English words, then we would return the string "apple pie" as output. 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input: string = "applepie", dictionary = "apple", "pie" 11 | Output: "apple pie" 12 | ``` 13 | -------------------------------------------------------------------------------- /strings/wordbreakers/word_breaker.go: -------------------------------------------------------------------------------- 1 | package wordbreakers 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/shomali11/go-interview/datastructures/sets/hashsets" 7 | ) 8 | 9 | const ( 10 | empty = "" 11 | stringFormat = "%s" 12 | stringSpaceStringFormat = "%s %s" 13 | ) 14 | 15 | // BreakWord breaks into possible words 16 | func BreakWord(input string, values []string) string { 17 | dictionary := hashsets.New[string]() 18 | for _, value := range values { 19 | dictionary.Add(value) 20 | } 21 | return breakWord(input, dictionary, make(map[string]string)) 22 | } 23 | 24 | func breakWord(input string, dictionary *hashsets.HashSet[string], cache map[string]string) string { 25 | if dictionary.Contains(input) { 26 | return input 27 | } 28 | 29 | cachedValue, exists := cache[input] 30 | if exists { 31 | return cachedValue 32 | } 33 | 34 | inputRunes := []rune(input) 35 | for i := 1; i < len(input); i++ { 36 | prefix := string(inputRunes[0:i]) 37 | if dictionary.Contains(prefix) { 38 | suffix := string(inputRunes[i:]) 39 | brokenSuffix := breakWord(suffix, dictionary, cache) 40 | if len(brokenSuffix) > 0 { 41 | result := fmt.Sprintf(stringSpaceStringFormat, prefix, brokenSuffix) 42 | cache[input] = result 43 | return result 44 | } 45 | } 46 | } 47 | return empty 48 | } 49 | 50 | // ExtractWords extracts all possible words 51 | func ExtractWords(input string, values []string) []string { 52 | dictionary := hashsets.New[string]() 53 | for _, value := range values { 54 | dictionary.Add(value) 55 | } 56 | 57 | resultSet := extractWords(input, dictionary, make(map[string]string)) 58 | 59 | results := make([]string, 0) 60 | for _, item := range resultSet.GetValues() { 61 | results = append(results, item) 62 | } 63 | return results 64 | } 65 | 66 | func extractWords(input string, dictionary *hashsets.HashSet[string], cache map[string]string) *hashsets.HashSet[string] { 67 | resultSet := hashsets.New[string]() 68 | if dictionary.Contains(input) { 69 | resultSet.Add(input) 70 | } 71 | 72 | cachedValue, exists := cache[input] 73 | if exists { 74 | resultSet.Add(cachedValue) 75 | return resultSet 76 | } 77 | 78 | inputRunes := []rune(input) 79 | for i := 1; i < len(input); i++ { 80 | prefix := string(inputRunes[0:i]) 81 | if dictionary.Contains(prefix) { 82 | suffix := string(inputRunes[i:]) 83 | brokenSuffixes := extractWords(suffix, dictionary, cache) 84 | for _, brokenSuffix := range brokenSuffixes.GetValues() { 85 | result := fmt.Sprintf(stringSpaceStringFormat, prefix, brokenSuffix) 86 | cache[input] = result 87 | resultSet.Add(result) 88 | } 89 | } 90 | } 91 | return resultSet 92 | } 93 | -------------------------------------------------------------------------------- /strings/wordbreakers/word_breaker_test.go: -------------------------------------------------------------------------------- 1 | package wordbreakers 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var ( 11 | dictionary = []string{"app", "apple", "pie", "applet", "let", "table", "tablet", "able", "t"} 12 | ) 13 | 14 | func TestBreakWord(t *testing.T) { 15 | assert.Equal(t, BreakWord("applepie", dictionary), "apple pie") 16 | assert.Equal(t, BreakWord("applet", dictionary), "applet") 17 | assert.Equal(t, BreakWord("apples", dictionary), "") 18 | assert.Equal(t, BreakWord("boo", dictionary), "") 19 | } 20 | 21 | func TestExtractWords(t *testing.T) { 22 | values := ExtractWords("applet", dictionary) 23 | assert.True(t, contains(values, "applet")) 24 | assert.True(t, contains(values, "app let")) 25 | assert.True(t, contains(values, "apple t")) 26 | assert.True(t, reflect.DeepEqual(ExtractWords("apples", dictionary), []string{})) 27 | assert.True(t, reflect.DeepEqual(ExtractWords("boo", dictionary), []string{})) 28 | } 29 | 30 | func contains(values []string, value string) bool { 31 | for _, v := range values { 32 | if v == value { 33 | return true 34 | } 35 | } 36 | return false 37 | } 38 | -------------------------------------------------------------------------------- /trees/balancedtrees/balancedbinarytrees/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Check if a binary tree is balanced. A balanced tree is a tree where every leaf is “not more than a certain distance” away from the root than any other leaf. 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 11 | 4 12 | / \ 13 | 2 7 14 | / \ / \ 15 | 1 3 6 9 16 | 17 | Output: 18 | true 19 | ``` 20 | 21 | ### Example 2: 22 | 23 | ``` 24 | Input: 25 | 26 | 4 27 | / 28 | 2 29 | / \ 30 | 1 3 31 | 32 | Output: 33 | false 34 | ``` -------------------------------------------------------------------------------- /trees/balancedtrees/balancedbinarytrees/balanced_binary_trees.go: -------------------------------------------------------------------------------- 1 | package balancedbinarytrees 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | ) 8 | 9 | // IsBalanced checks if a binary tree is balanced 10 | func IsBalanced[T any](node *trees.BinaryNode[T]) bool { 11 | _, balanced := isBalanced(node) 12 | return balanced 13 | } 14 | 15 | func isBalanced[T any](node *trees.BinaryNode[T]) (int, bool) { 16 | if node == nil { 17 | return 0, true 18 | } 19 | 20 | left, balanced := isBalanced(node.Left) 21 | if !balanced { 22 | return 0, false 23 | } 24 | 25 | right, balanced := isBalanced(node.Right) 26 | if !balanced { 27 | return 0, false 28 | } 29 | 30 | if math.Abs(float64(left-right)) > 1 { 31 | return 0, false 32 | } 33 | 34 | if left > right { 35 | return 1 + left, true 36 | } 37 | return 1 + right, true 38 | } 39 | -------------------------------------------------------------------------------- /trees/balancedtrees/balancedbinarytrees/balanced_binary_trees_test.go: -------------------------------------------------------------------------------- 1 | package balancedbinarytrees 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestIsBalanced_EmptyNode(t *testing.T) { 11 | assert.True(t, IsBalanced[int](nil)) 12 | } 13 | 14 | func TestIsBalanced_RootNode(t *testing.T) { 15 | node := &trees.BinaryNode[int]{Data: 1} 16 | 17 | assert.True(t, IsBalanced(node)) 18 | } 19 | 20 | func TestIsBalanced_HalfTree(t *testing.T) { 21 | node2 := &trees.BinaryNode[int]{Data: 2} 22 | node := &trees.BinaryNode[int]{Data: 1, Left: node2} 23 | 24 | assert.True(t, IsBalanced(node)) 25 | } 26 | 27 | func TestIsBalanced_FullTree(t *testing.T) { 28 | node2 := &trees.BinaryNode[int]{Data: 2} 29 | node3 := &trees.BinaryNode[int]{Data: 3} 30 | node := &trees.BinaryNode[int]{Data: 1, Left: node2, Right: node3} 31 | 32 | assert.True(t, IsBalanced(node)) 33 | } 34 | 35 | func TestIsBalanced_NotBalancedTree(t *testing.T) { 36 | node2 := &trees.BinaryNode[int]{Data: 2} 37 | node3 := &trees.BinaryNode[int]{Data: 3, Left: node2} 38 | node := &trees.BinaryNode[int]{Data: 1, Right: node3} 39 | 40 | assert.False(t, IsBalanced(node)) 41 | } 42 | -------------------------------------------------------------------------------- /trees/balancedtrees/balancedmultitrees/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Check if a multi tree is balanced. A balanced tree is a tree where every leaf is “not more than a certain distance” away from the root than any other leaf. 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 11 | 4 12 | | 13 | 2 14 | | 15 | 1 16 | 17 | Output: 18 | true 19 | ``` 20 | 21 | ### Example 2: 22 | 23 | ``` 24 | Input: 25 | 26 | 4 27 | / \ 28 | 2 5 29 | | 30 | 1 31 | / | \ 32 | 3 2 6 33 | 34 | Output: 35 | false 36 | ``` -------------------------------------------------------------------------------- /trees/balancedtrees/balancedmultitrees/balanced_multi_trees.go: -------------------------------------------------------------------------------- 1 | package balancedmultitrees 2 | 3 | import ( 4 | "math" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | ) 8 | 9 | // IsBalanced checks if a multi tree is balanced 10 | func IsBalanced[T any](node *trees.MultiNode[T]) bool { 11 | _, balanced := isBalanced(node) 12 | return balanced 13 | } 14 | 15 | func isBalanced[T any](node *trees.MultiNode[T]) (int, bool) { 16 | if node == nil { 17 | return 0, true 18 | } 19 | 20 | if len(node.Children) == 0 { 21 | return 1, true 22 | } 23 | 24 | height, balanced := isBalanced(node.Children[0]) 25 | if !balanced { 26 | return 0, false 27 | } 28 | 29 | min := height 30 | max := height 31 | 32 | for i := 1; i < len(node.Children); i++ { 33 | height, balanced := isBalanced(node.Children[i]) 34 | if !balanced { 35 | return 0, false 36 | } 37 | 38 | if height < min { 39 | min = height 40 | } 41 | 42 | if height > max { 43 | max = height 44 | } 45 | } 46 | 47 | if math.Abs(float64(min-max)) > 1 { 48 | return 0, false 49 | } 50 | return 1 + max, true 51 | } 52 | -------------------------------------------------------------------------------- /trees/balancedtrees/balancedmultitrees/balanced_multi_trees_test.go: -------------------------------------------------------------------------------- 1 | package balancedmultitrees 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestIsBalanced_EmptyNode(t *testing.T) { 11 | assert.True(t, IsBalanced[int](nil)) 12 | } 13 | 14 | func TestIsBalanced_RootNode(t *testing.T) { 15 | node := &trees.MultiNode[int]{Data: 1} 16 | 17 | assert.True(t, IsBalanced(node)) 18 | } 19 | 20 | func TestIsBalanced_HalfTree(t *testing.T) { 21 | node2 := &trees.MultiNode[int]{Data: 2} 22 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node2}} 23 | 24 | assert.True(t, IsBalanced(node)) 25 | } 26 | 27 | func TestIsBalanced_FullTree(t *testing.T) { 28 | node2 := &trees.MultiNode[int]{Data: 2} 29 | node3 := &trees.MultiNode[int]{Data: 3} 30 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node2, node3}} 31 | 32 | assert.True(t, IsBalanced(node)) 33 | } 34 | 35 | func TestIsBalanced_NotBalancedTree(t *testing.T) { 36 | node2 := &trees.MultiNode[int]{Data: 2} 37 | node3 := &trees.MultiNode[int]{Data: 3, Children: []*trees.MultiNode[int]{node2}} 38 | node4 := &trees.MultiNode[int]{Data: 4, Children: []*trees.MultiNode[int]{node3}} 39 | node5 := &trees.MultiNode[int]{Data: 5} 40 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node4, node5}} 41 | 42 | assert.False(t, IsBalanced(node)) 43 | } 44 | -------------------------------------------------------------------------------- /trees/heights/binarytreeheights/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Determine a binary tree's height 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 11 | 4 12 | / \ 13 | 2 7 14 | 15 | Output: 16 | 2 17 | ``` 18 | 19 | ### Example 2: 20 | 21 | ``` 22 | Input: 23 | 24 | 4 25 | / 26 | 2 27 | / \ 28 | 1 3 29 | 30 | Output: 31 | 3 32 | ``` -------------------------------------------------------------------------------- /trees/heights/binarytreeheights/binary_tree_heights.go: -------------------------------------------------------------------------------- 1 | package binarytreeheights 2 | 3 | import ( 4 | "github.com/shomali11/go-interview/datastructures/trees" 5 | ) 6 | 7 | // Height returns a tree's height 8 | func Height[T any](node *trees.BinaryNode[T]) int { 9 | if node == nil { 10 | return 0 11 | } 12 | 13 | left := Height(node.Left) 14 | right := Height(node.Right) 15 | 16 | if left > right { 17 | return 1 + left 18 | } 19 | return 1 + right 20 | } 21 | -------------------------------------------------------------------------------- /trees/heights/binarytreeheights/binary_tree_heights_test.go: -------------------------------------------------------------------------------- 1 | package binarytreeheights 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestHeight_EmptyNode(t *testing.T) { 11 | assert.Equal(t, Height[int](nil), 0) 12 | } 13 | 14 | func TestHeight_RootNode(t *testing.T) { 15 | node := &trees.BinaryNode[int]{Data: 1} 16 | 17 | assert.Equal(t, Height(node), 1) 18 | } 19 | 20 | func TestHeight_HalfTree(t *testing.T) { 21 | node2 := &trees.BinaryNode[int]{Data: 2} 22 | node := &trees.BinaryNode[int]{Data: 1, Left: node2} 23 | 24 | assert.Equal(t, Height(node), 2) 25 | } 26 | 27 | func TestHeight_FullTree(t *testing.T) { 28 | node2 := &trees.BinaryNode[int]{Data: 2} 29 | node3 := &trees.BinaryNode[int]{Data: 3} 30 | node := &trees.BinaryNode[int]{Data: 1, Left: node2, Right: node3} 31 | 32 | assert.Equal(t, Height(node), 2) 33 | } 34 | 35 | func TestHeight_LongerTree(t *testing.T) { 36 | node2 := &trees.BinaryNode[int]{Data: 2} 37 | node3 := &trees.BinaryNode[int]{Data: 3, Left: node2} 38 | node := &trees.BinaryNode[int]{Data: 1, Right: node3} 39 | 40 | assert.Equal(t, Height(node), 3) 41 | } 42 | -------------------------------------------------------------------------------- /trees/heights/multitreeheights/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Determine a tree's height 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 11 | 4 12 | | 13 | 2 14 | | 15 | 1 16 | 17 | Output: 18 | 3 19 | ``` 20 | 21 | ### Example 2: 22 | 23 | ``` 24 | Input: 25 | 26 | 4 27 | / \ 28 | 2 5 29 | | 30 | 1 31 | / | \ 32 | 3 2 6 33 | 34 | Output: 35 | 4 36 | ``` -------------------------------------------------------------------------------- /trees/heights/multitreeheights/multi_tree_heights.go: -------------------------------------------------------------------------------- 1 | package multitreeheights 2 | 3 | import ( 4 | "github.com/shomali11/go-interview/datastructures/trees" 5 | ) 6 | 7 | // Height returns a tree's height 8 | func Height[T any](node *trees.MultiNode[T]) int { 9 | if node == nil { 10 | return 0 11 | } 12 | 13 | if len(node.Children) == 0 { 14 | return 1 15 | } 16 | 17 | max := Height(node.Children[0]) 18 | for i := 1; i < len(node.Children); i++ { 19 | current := Height(node.Children[i]) 20 | if max < current { 21 | max = current 22 | } 23 | } 24 | return 1 + max 25 | } 26 | -------------------------------------------------------------------------------- /trees/heights/multitreeheights/multi_tree_heights_test.go: -------------------------------------------------------------------------------- 1 | package multitreeheights 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestHeight_EmptyNode(t *testing.T) { 11 | assert.Equal(t, Height[int](nil), 0) 12 | } 13 | 14 | func TestHeight_RootNode(t *testing.T) { 15 | node := &trees.MultiNode[int]{Data: 1} 16 | 17 | assert.Equal(t, Height(node), 1) 18 | } 19 | 20 | func TestHeight_HalfTree(t *testing.T) { 21 | node2 := &trees.MultiNode[int]{Data: 2} 22 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node2}} 23 | 24 | assert.Equal(t, Height(node), 2) 25 | } 26 | 27 | func TestHeight_FullTree(t *testing.T) { 28 | node2 := &trees.MultiNode[int]{Data: 2} 29 | node3 := &trees.MultiNode[int]{Data: 3} 30 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node2, node3}} 31 | 32 | assert.Equal(t, Height(node), 2) 33 | } 34 | 35 | func TestHeight_NotBalancedTree(t *testing.T) { 36 | node2 := &trees.MultiNode[int]{Data: 2} 37 | node3 := &trees.MultiNode[int]{Data: 3, Children: []*trees.MultiNode[int]{node2}} 38 | node4 := &trees.MultiNode[int]{Data: 4, Children: []*trees.MultiNode[int]{node3}} 39 | node5 := &trees.MultiNode[int]{Data: 5} 40 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node4, node5}} 41 | 42 | assert.Equal(t, Height(node), 4) 43 | } 44 | -------------------------------------------------------------------------------- /trees/inverttrees/invertbinarytrees/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Invert a binary tree. 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 11 | 4 12 | / \ 13 | 2 7 14 | / \ / \ 15 | 1 3 6 9 16 | 17 | Output: 18 | 19 | 4 20 | / \ 21 | 7 2 22 | / \ / \ 23 | 9 6 3 1 24 | ``` -------------------------------------------------------------------------------- /trees/inverttrees/invertbinarytrees/invert_binary_trees.go: -------------------------------------------------------------------------------- 1 | package invertbinarytrees 2 | 3 | import "github.com/shomali11/go-interview/datastructures/trees" 4 | 5 | // InvertTree inverts a binary tree 6 | func InvertTree[T any](node *trees.BinaryNode[T]) *trees.BinaryNode[T] { 7 | if node == nil { 8 | return nil 9 | } 10 | 11 | node.Left, node.Right = InvertTree(node.Right), InvertTree(node.Left) 12 | return node 13 | } 14 | -------------------------------------------------------------------------------- /trees/inverttrees/invertbinarytrees/invert_binary_trees_test.go: -------------------------------------------------------------------------------- 1 | package invertbinarytrees 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestInvertTrees(t *testing.T) { 11 | node2 := &trees.BinaryNode[int]{Data: 2} 12 | node3 := &trees.BinaryNode[int]{Data: 3} 13 | node := &trees.BinaryNode[int]{Data: 1, Left: node2, Right: node3} 14 | 15 | node = InvertTree(node) 16 | 17 | assert.Equal(t, node.Left.Data, 3) 18 | assert.Equal(t, node.Right.Data, 2) 19 | } 20 | -------------------------------------------------------------------------------- /trees/inverttrees/invertmultitrees/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Invert a tree. 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 11 | 4 12 | / \ 13 | 2 7 14 | / \ / \ 15 | 1 3 6 9 16 | 17 | Output: 18 | 19 | 4 20 | / \ 21 | 7 2 22 | / \ / \ 23 | 9 6 3 1 24 | ``` -------------------------------------------------------------------------------- /trees/inverttrees/invertmultitrees/invert_multi_trees.go: -------------------------------------------------------------------------------- 1 | package invertmultitrees 2 | 3 | import "github.com/shomali11/go-interview/datastructures/trees" 4 | 5 | // InvertTree inverts a binary tree 6 | func InvertTree[T any](node *trees.MultiNode[T]) *trees.MultiNode[T] { 7 | if node == nil { 8 | return nil 9 | } 10 | 11 | children := node.Children 12 | for i, j := 0, len(children)-1; i < j; i, j = i+1, j-1 { 13 | children[i], children[j] = InvertTree(children[j]), InvertTree(children[i]) 14 | } 15 | return node 16 | } 17 | -------------------------------------------------------------------------------- /trees/inverttrees/invertmultitrees/invert_multi_trees_test.go: -------------------------------------------------------------------------------- 1 | package invertmultitrees 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestInvertTrees(t *testing.T) { 11 | node2 := &trees.MultiNode[int]{Data: 2} 12 | node3 := &trees.MultiNode[int]{Data: 3} 13 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node2, node3}} 14 | 15 | node = InvertTree(node) 16 | 17 | assert.Equal(t, node.Children[0].Data, 3) 18 | assert.Equal(t, node.Children[1].Data, 2) 19 | } 20 | -------------------------------------------------------------------------------- /trees/longestdistinctpaths/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Given a Tree, find count of distinct nodes in a root to leaf path with maximum distinct nodes. 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input : 10 | 1 11 | / \ 12 | 2 3 13 | / \ / \ 14 | 4 5 6 3 15 | \ \ 16 | 8 9 17 | 18 | Output : 4 19 | 20 | The root to leaf path with maximum distinct 21 | nodes is 1-3-6-8. 22 | ``` -------------------------------------------------------------------------------- /trees/longestdistinctpaths/longest_distinct_paths.go: -------------------------------------------------------------------------------- 1 | package longestdistinctpaths 2 | 3 | import ( 4 | "github.com/shomali11/go-interview/datastructures/sets/hashmultisets" 5 | "github.com/shomali11/go-interview/datastructures/trees" 6 | ) 7 | 8 | // LongestDistinctPath returns the length of the longest distinct path 9 | func LongestDistinctPath[T comparable](node *trees.MultiNode[T]) int { 10 | multiSet := hashmultisets.New[T]() 11 | return longestDistinctPath(node, multiSet) 12 | } 13 | 14 | func longestDistinctPath[T comparable](node *trees.MultiNode[T], multiSet *hashmultisets.HashMultiSet[T]) int { 15 | if node == nil || multiSet.Contains(node.Data) { 16 | return multiSet.Size() 17 | } 18 | 19 | multiSet.Add(node.Data) 20 | 21 | maxPath := 0 22 | for _, child := range node.Children { 23 | length := longestDistinctPath(child, multiSet) 24 | if length > maxPath { 25 | maxPath = length 26 | } 27 | } 28 | 29 | if len(node.Children) == 0 { 30 | maxPath = multiSet.Size() 31 | } 32 | 33 | multiSet.IncrementBy(node.Data, -1) 34 | if multiSet.GetCount(node.Data) == 0 { 35 | multiSet.Remove(node.Data) 36 | } 37 | return maxPath 38 | } 39 | -------------------------------------------------------------------------------- /trees/longestdistinctpaths/longest_distinct_paths_test.go: -------------------------------------------------------------------------------- 1 | package longestdistinctpaths 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestLongestDistinctPath1(t *testing.T) { 11 | node4 := &trees.MultiNode[int]{Data: 5, Children: make([]*trees.MultiNode[int], 0)} 12 | node5 := &trees.MultiNode[int]{Data: 6, Children: make([]*trees.MultiNode[int], 0)} 13 | 14 | node6 := &trees.MultiNode[int]{Data: 7, Children: make([]*trees.MultiNode[int], 0)} 15 | node7 := &trees.MultiNode[int]{Data: 8, Children: make([]*trees.MultiNode[int], 0)} 16 | 17 | node1 := &trees.MultiNode[int]{Data: 2, Children: []*trees.MultiNode[int]{node4, node5}} 18 | node2 := &trees.MultiNode[int]{Data: 3, Children: []*trees.MultiNode[int]{node6, node7}} 19 | node3 := &trees.MultiNode[int]{Data: 4, Children: make([]*trees.MultiNode[int], 0)} 20 | 21 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node1, node2, node3}} 22 | assert.Equal(t, LongestDistinctPath(node), 3) 23 | } 24 | 25 | func TestLongestDistinctPath2(t *testing.T) { 26 | node4 := &trees.MultiNode[int]{Data: 1, Children: make([]*trees.MultiNode[int], 0)} 27 | node5 := &trees.MultiNode[int]{Data: 1, Children: make([]*trees.MultiNode[int], 0)} 28 | 29 | node6 := &trees.MultiNode[int]{Data: 1, Children: make([]*trees.MultiNode[int], 0)} 30 | node7 := &trees.MultiNode[int]{Data: 1, Children: make([]*trees.MultiNode[int], 0)} 31 | 32 | node1 := &trees.MultiNode[int]{Data: 2, Children: []*trees.MultiNode[int]{node4, node5}} 33 | node2 := &trees.MultiNode[int]{Data: 3, Children: []*trees.MultiNode[int]{node6, node7}} 34 | node3 := &trees.MultiNode[int]{Data: 4, Children: make([]*trees.MultiNode[int], 0)} 35 | 36 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node1, node2, node3}} 37 | assert.Equal(t, LongestDistinctPath(node), 2) 38 | } 39 | 40 | func TestLongestDistinctPath3(t *testing.T) { 41 | node4 := &trees.MultiNode[int]{Data: 14, Children: make([]*trees.MultiNode[int], 0)} 42 | node5 := &trees.MultiNode[int]{Data: 13, Children: make([]*trees.MultiNode[int], 0)} 43 | 44 | node6 := &trees.MultiNode[int]{Data: 12, Children: make([]*trees.MultiNode[int], 0)} 45 | node7 := &trees.MultiNode[int]{Data: 10, Children: make([]*trees.MultiNode[int], 0)} 46 | 47 | node1 := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node4, node5}} 48 | node2 := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node6, node7}} 49 | node3 := &trees.MultiNode[int]{Data: 1, Children: make([]*trees.MultiNode[int], 0)} 50 | 51 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node1, node2, node3}} 52 | assert.Equal(t, LongestDistinctPath(node), 1) 53 | } 54 | 55 | func TestLongestDistinctPath4(t *testing.T) { 56 | assert.Equal(t, LongestDistinctPath[int](nil), 0) 57 | } 58 | -------------------------------------------------------------------------------- /trees/printcolumns/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Given a binary tree, print column by column 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 1 11 | / \ 12 | 2 3 13 | / \ \ 14 | 4 5 6 15 | / \ / 16 | 7 8 9 17 | 18 | Output: 19 | 4 20 | 2 7 21 | 1 5 22 | 3 8 9 23 | 6 24 | ``` -------------------------------------------------------------------------------- /trees/printcolumns/print_columns.go: -------------------------------------------------------------------------------- 1 | package printcolumns 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/shomali11/go-interview/datastructures/maps/hashmultimaps" 7 | "github.com/shomali11/go-interview/datastructures/queues" 8 | "github.com/shomali11/go-interview/datastructures/trees" 9 | 10 | "golang.org/x/exp/constraints" 11 | ) 12 | 13 | // PrintColumns prints a tree column by column 14 | func PrintColumns[T constraints.Ordered](node *trees.BinaryNode[T]) { 15 | if node == nil { 16 | return 17 | } 18 | 19 | queue := queues.New[*trees.BinaryNode[T]]() 20 | queue.Enqueue(node) 21 | 22 | multimap := hashmultimaps.New[int, *trees.BinaryNode[T]]() 23 | multimap.Put(0, node) 24 | 25 | mapNodeIndex := make(map[*trees.BinaryNode[T]]int) 26 | mapNodeIndex[node] = 0 27 | 28 | for !queue.IsEmpty() { 29 | element, _ := queue.Dequeue() 30 | nodeIndex := mapNodeIndex[element] 31 | 32 | if element.Left != nil { 33 | queue.Enqueue(element.Left) 34 | multimap.Put(nodeIndex-1, element.Left) 35 | mapNodeIndex[element.Left] = nodeIndex - 1 36 | } 37 | 38 | if element.Right != nil { 39 | queue.Enqueue(element.Right) 40 | multimap.Put(nodeIndex+1, element.Right) 41 | mapNodeIndex[element.Right] = nodeIndex + 1 42 | } 43 | } 44 | 45 | keys := multimap.GetKeys() 46 | minIndex, maxIndex := minMax(keys...) 47 | for i := minIndex; i <= maxIndex; i++ { 48 | for _, value := range multimap.GetValues(i) { 49 | fmt.Print(value.Data, " ") 50 | } 51 | fmt.Println() 52 | } 53 | } 54 | 55 | func minMax[T constraints.Ordered](values ...T) (T, T) { 56 | first := values[0] 57 | min := first 58 | max := first 59 | 60 | for i := 1; i < len(values); i++ { 61 | current := values[i] 62 | if current < min { 63 | min = current 64 | } 65 | if current > max { 66 | max = current 67 | } 68 | } 69 | return min, max 70 | } 71 | -------------------------------------------------------------------------------- /trees/printcolumns/print_columns_test.go: -------------------------------------------------------------------------------- 1 | package printcolumns 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | ) 8 | 9 | func TestPrintColumns(t *testing.T) { 10 | node4 := &trees.BinaryNode[int]{Data: 5} 11 | node5 := &trees.BinaryNode[int]{Data: 6} 12 | 13 | node6 := &trees.BinaryNode[int]{Data: 7} 14 | node7 := &trees.BinaryNode[int]{Data: 8} 15 | 16 | node1 := &trees.BinaryNode[int]{Data: 2, Left: node4, Right: node5} 17 | node2 := &trees.BinaryNode[int]{Data: 3, Left: node6, Right: node7} 18 | 19 | node := &trees.BinaryNode[int]{Data: 1, Left: node1, Right: node2} 20 | PrintColumns(node) 21 | } 22 | -------------------------------------------------------------------------------- /trees/printlevels/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Given a tree, print level by level 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 1 11 | / \ 12 | 2 3 13 | / \ \ 14 | 4 5 6 15 | / \ / 16 | 7 8 9 17 | 18 | Output: 19 | 1 20 | 2 3 21 | 4 5 6 22 | 7 8 9 23 | ``` -------------------------------------------------------------------------------- /trees/printlevels/print_levels.go: -------------------------------------------------------------------------------- 1 | package printlevels 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/shomali11/go-interview/datastructures/queues" 7 | "github.com/shomali11/go-interview/datastructures/trees" 8 | ) 9 | 10 | // PrintLevels prints a tree level by level 11 | func PrintLevels[T any](node *trees.MultiNode[T]) { 12 | if node == nil { 13 | return 14 | } 15 | 16 | queue := queues.New[*trees.MultiNode[T]]() 17 | queue.Enqueue(node) 18 | 19 | for !queue.IsEmpty() { 20 | for size := queue.Size(); size > 0; size-- { 21 | element, _ := queue.Dequeue() 22 | fmt.Print(element.Data, " ") 23 | 24 | for _, child := range element.Children { 25 | queue.Enqueue(child) 26 | } 27 | } 28 | fmt.Println() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /trees/printlevels/print_levels_test.go: -------------------------------------------------------------------------------- 1 | package printlevels 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | ) 8 | 9 | func TestPrintLevels(t *testing.T) { 10 | node4 := &trees.MultiNode[int]{Data: 5, Children: make([]*trees.MultiNode[int], 0)} 11 | node5 := &trees.MultiNode[int]{Data: 6, Children: make([]*trees.MultiNode[int], 0)} 12 | 13 | node6 := &trees.MultiNode[int]{Data: 7, Children: make([]*trees.MultiNode[int], 0)} 14 | node7 := &trees.MultiNode[int]{Data: 8, Children: make([]*trees.MultiNode[int], 0)} 15 | 16 | node1 := &trees.MultiNode[int]{Data: 2, Children: []*trees.MultiNode[int]{node4, node5}} 17 | node2 := &trees.MultiNode[int]{Data: 3, Children: []*trees.MultiNode[int]{node6, node7}} 18 | node3 := &trees.MultiNode[int]{Data: 4, Children: make([]*trees.MultiNode[int], 0)} 19 | 20 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node1, node2, node3}} 21 | PrintLevels(node) 22 | } 23 | -------------------------------------------------------------------------------- /trees/printzigzag/README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Description 3 | 4 | Given a tree, print in zig zag basis 5 | 6 | ### Example 1: 7 | 8 | ``` 9 | Input: 10 | 1 11 | / \ 12 | 2 3 13 | / \ | \ 14 | 5 6 7 8 15 | 16 | Output: 17 | 1 18 | 2 3 19 | 8 7 6 5 20 | ``` -------------------------------------------------------------------------------- /trees/printzigzag/print_zigzag.go: -------------------------------------------------------------------------------- 1 | package printzigzag 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/shomali11/go-interview/datastructures/linkedlists/doublylinkedlists" 7 | "github.com/shomali11/go-interview/datastructures/queues" 8 | "github.com/shomali11/go-interview/datastructures/trees" 9 | ) 10 | 11 | // PrintZigZag prints a tree zig zag 12 | func PrintZigZag[T any](node *trees.MultiNode[T]) { 13 | if node == nil { 14 | return 15 | } 16 | 17 | queue := queues.New[*trees.MultiNode[T]]() 18 | queue.Enqueue(node) 19 | 20 | list := doublylinkedlists.New[*trees.MultiNode[T]]() 21 | 22 | isForwardDirection := true 23 | for !queue.IsEmpty() { 24 | for size := queue.Size(); size > 0; size-- { 25 | element, _ := queue.Dequeue() 26 | fmt.Print(element.Data, " ") 27 | 28 | for _, child := range element.Children { 29 | list.Add(child) 30 | } 31 | } 32 | 33 | if isForwardDirection { 34 | for _, value := range list.GetValues() { 35 | queue.Enqueue(value) 36 | } 37 | } else { 38 | for _, value := range list.GetReverseValues() { 39 | queue.Enqueue(value) 40 | } 41 | } 42 | 43 | list.Clear() 44 | isForwardDirection = !isForwardDirection 45 | fmt.Println() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /trees/printzigzag/print_zigzag_test.go: -------------------------------------------------------------------------------- 1 | package printzigzag 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/shomali11/go-interview/datastructures/trees" 7 | ) 8 | 9 | func TestPrintZigZag(t *testing.T) { 10 | node4 := &trees.MultiNode[int]{Data: 5, Children: make([]*trees.MultiNode[int], 0)} 11 | node5 := &trees.MultiNode[int]{Data: 6, Children: make([]*trees.MultiNode[int], 0)} 12 | 13 | node6 := &trees.MultiNode[int]{Data: 7, Children: make([]*trees.MultiNode[int], 0)} 14 | node7 := &trees.MultiNode[int]{Data: 8, Children: make([]*trees.MultiNode[int], 0)} 15 | 16 | node1 := &trees.MultiNode[int]{Data: 2, Children: []*trees.MultiNode[int]{node4, node5}} 17 | node2 := &trees.MultiNode[int]{Data: 3, Children: []*trees.MultiNode[int]{node6, node7}} 18 | 19 | node := &trees.MultiNode[int]{Data: 1, Children: []*trees.MultiNode[int]{node1, node2}} 20 | PrintZigZag(node) 21 | } 22 | --------------------------------------------------------------------------------