├── .gitignore ├── LICENSE ├── README.md ├── binary_tree ├── Binary_tree.png ├── Complete_binary.png ├── Full_binary.png ├── README.md ├── binary_tree.go ├── binary_tree_test.go ├── bottom_view │ ├── README.md │ └── main.go ├── go.mod ├── minimum_depth │ ├── README.md │ ├── main.go │ └── tree122.gif ├── preorder_traversal │ ├── README.md │ ├── preorder_test.go │ └── test_cases.go ├── remove_nodes │ ├── README.md │ └── main.go └── reverse_alternate │ ├── README.md │ └── main.go ├── bitwise ├── README.md ├── decimal_to_binary │ ├── README.md │ └── main.go ├── max_xor │ ├── README.md │ └── main.go ├── next_sparse │ ├── README.md │ └── main.go ├── rotate_bits │ ├── README.md │ └── main.go └── swapp_odd_even │ ├── README.md │ └── main.go ├── dynamic ├── README.md ├── cover_distance │ ├── README.md │ └── main.go ├── fibonacci.go ├── longest_common_subsequence │ ├── README.md │ └── main.go └── subset_sum │ ├── README.md │ ├── subsetsum.go │ ├── subsetsum_test.go │ └── test_cases.go ├── graph ├── README.md ├── boggle │ ├── README.md │ └── main.go ├── bridges │ ├── README.md │ ├── bridge.png │ └── main.go ├── dijkstra │ ├── README.md │ └── main.go ├── go.mod ├── go.sum ├── graph.go ├── graph.jpg ├── graph_test.go ├── traverse_bfs │ ├── Animated_BFS.gif │ ├── README.md │ └── main.go └── traverse_dfs │ ├── Depth-First-Search.gif │ ├── README.md │ └── main.go ├── linkedlist ├── README.md ├── compare_strings │ ├── README.md │ ├── compare.go │ ├── compare_test.go │ └── test_cases.go ├── go.mod ├── insert_node │ ├── README.md │ └── main.go ├── linked_list.png ├── linkedlist.go ├── linkedlist_test.go ├── random_node │ ├── README.md │ └── main.go ├── remove_loop │ ├── README.md │ └── main.go └── reverse_by_groups │ ├── README.md │ └── main.go ├── numbers ├── README.md ├── eratosthenes │ ├── README.md │ ├── primes.go │ ├── primes_test.go │ └── test_cases.go ├── multiplicative │ ├── README.md │ └── main.go └── segmented │ ├── README.md │ ├── primes.go │ ├── primes_test.go │ └── test_cases.go ├── other_ds ├── README.md ├── hashtable │ ├── README.md │ ├── bin │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── hash_table.png │ ├── hashtable.go │ └── hashtable_test.go ├── queue │ ├── README.md │ ├── go.mod │ ├── queue.go │ ├── queueString.go │ ├── queue_test.go │ └── test_cases.go └── stack │ ├── README.md │ ├── go.mod │ ├── stack.go │ ├── stack_test.go │ └── test_cases.go ├── sorting ├── README.md ├── bubble_sort │ ├── README.md │ ├── bubble.go │ ├── bubble_test.go │ └── test_cases.go ├── heap_sort │ ├── README.md │ ├── heap.go │ ├── heap_test.go │ └── test_cases.go ├── insertion_sort │ ├── README.md │ ├── insertion.go │ ├── insertion_test.go │ └── test_cases.go ├── merge_sort │ ├── README.md │ ├── merge.go │ ├── merge_sort_algorithm.png │ ├── merge_test.go │ └── test_cases.go └── quick_sort │ ├── README.md │ ├── quick.go │ ├── quick_test.go │ └── test_cases.go └── strings ├── README.md ├── largest_subarray ├── README.md ├── largest.go ├── largest_test.go └── test_cases.go ├── reverse_alpha ├── README.md ├── reverse.go ├── reverse_test.go └── test_cases.go ├── smallest_subarray ├── README.md ├── smallest.go ├── smallest_test.go └── test_cases.go └── zig_zag ├── README.md ├── test_cases.go ├── zigzag.go └── zigzag_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dan Rusei 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 - Data Structures and Algorithms 2 | 3 | Inspired by the **[Geeksforgeeks - Top 10 Algorithms in Interview Questions](https://www.geeksforgeeks.org/top-10-algorithms-in-interview-questions/amp/)** article, the intent of this repository is to solve these questions using the **Go Language**. GO is a great language choice for technical interviews and hopefully you can find these solutions to the common algorithms/problems easy to understand. 4 | 5 | Although this is an introductory material to algorithms and data structures, it assumes that you are familiar with GO programming language syntax and basic concepts. 6 | 7 | WIP, the descriptions of the below `unsolved yet` problems can be found in the [orginal article](https://www.geeksforgeeks.org/top-10-algorithms-in-interview-questions/amp/). 8 | 9 | > ***Contributions are welcomed - solve a problem and submit a PR***. 10 | > ***Contribution guidelines*** 11 | > 12 | > * keep the consistency and document the code 13 | > * optimize for readability and simplicity (not over-engineered, best performance is not in scope) 14 | 15 | ## [Graph](https://github.com/danrusei/algorithms_with_Go/tree/main/graph) 16 | 17 | * [x] [Breadth First Search (BFS)](https://github.com/danrusei/algorithms_with_Go/tree/main/graph/traverse_bfs) 18 | * [x] [Depth First Search (DFS)](https://github.com/danrusei/algorithms_with_Go/tree/main/graph/traverse_dfs) 19 | * [x] [Shortest Path from source to all vertices (Dijkstra)](https://github.com/danrusei/algorithms_with_Go/tree/main/graph/dijkstra) 20 | * [] Shortest Path from every vertex to every other vertex (Floyd Warshall) 21 | * [] To detect cycle in a Graph (Union Find) 22 | * [] Minimum Spanning tree (Prim) 23 | * [] Minimum Spanning tree (Kruskal) 24 | * [] Topological Sort 25 | * [x] [Boggle (Find all possible words in a board of characters)](https://github.com/danrusei/algorithms_with_Go/tree/main/graph/boggle) 26 | * [x] [Bridges in a Graph](https://github.com/danrusei/algorithms_with_Go/tree/main/graph/bridges) 27 | 28 | ## [Linked List](https://github.com/danrusei/algorithms_with_Go/tree/main/linkedlist) 29 | 30 | * [x] [Insertion of a node in Linked List (On the basis of some constraints)](https://github.com/danrusei/algorithms_with_Go/tree/main/linkedlist/insert_node) 31 | * [] Delete a given node in Linked List (under given constraints) 32 | * [x] [Compare two strings represented as linked lists](https://github.com/danrusei/algorithms_with_Go/tree/main/linkedlist/compare_strings) 33 | * [] Add Two Numbers Represented By Linked Lists 34 | * [] Merge A Linked List Into Another Linked List At Alternate Positions 35 | * [x] [Reverse A List In Groups Of Given Size](https://github.com/danrusei/algorithms_with_Go/tree/main/linkedlist/reverse_by_groups) 36 | * [] Union And Intersection Of 2 Linked Lists 37 | * [x] [Detect And Remove Loop In A Linked List](https://github.com/danrusei/algorithms_with_Go/tree/main/linkedlist/remove_loop) 38 | * [] Merge Sort For Linked Lists 39 | * [x] [Select A Random Node from A Singly Linked List](https://github.com/danrusei/algorithms_with_Go/tree/main/linkedlist/random_node) 40 | 41 | ## [Tree / Binary Search Tree](https://github.com/danrusei/algorithms_with_Go/tree/main/binary_tree) 42 | 43 | * [x] [Find Minimum Depth of a Binary Tree](https://github.com/danrusei/algorithms_with_Go/tree/main/binary_tree/minimum_depth) 44 | * [] Maximum Path Sum in a Binary Tree 45 | * [x] [Check if a given array can represent Preorder Traversal of Binary Search Tree](https://github.com/danrusei/algorithms_with_Go/tree/main/binary_tree/preorder_traversal) 46 | * [] Check whether a binary tree is a full binary tree or not 47 | * [x] [Bottom View Binary Tree](https://github.com/danrusei/algorithms_with_Go/tree/main/binary_tree/bottom_view) 48 | * [] Print Nodes in Top View of Binary Tree 49 | * [x] [Remove nodes on root to leaf paths of length < K](https://github.com/danrusei/algorithms_with_Go/tree/main/binary_tree/remove_nodes) 50 | * [] Lowest Common Ancestor in a Binary Search Tree 51 | * [] Check if a binary tree is subtree of another binary tree 52 | * [x] [Reverse alternate levels of a perfect binary tree](https://github.com/danrusei/algorithms_with_Go/tree/main/binary_tree/reverse_alternate) 53 | 54 | ## [Other Data Structures](https://github.com/danrusei/algorithms_with_Go/tree/main/other_ds) 55 | 56 | * [x] **[Stack](https://github.com/danrusei/algorithms_with_Go/tree/main/other_ds/stack)** 57 | * [x] **[Queue](https://github.com/danrusei/algorithms_with_Go/tree/main/other_ds/queue)** 58 | * [x] **[HashTable](https://github.com/danrusei/algorithms_with_Go/tree/main/other_ds/hashtable)** 59 | 60 | ## [Sorting And Searching](https://github.com/danrusei/algorithms_with_Go/tree/main/sorting) 61 | 62 | * [] Binary Search 63 | * [] Search an element in a sorted and rotated array 64 | * [x] [Bubble Sort](https://github.com/danrusei/algorithms_with_Go/tree/main/sorting/bubble_sort) 65 | * [x] [Insertion Sort](https://github.com/danrusei/algorithms_with_Go/tree/main/sorting/insertion_sort) 66 | * [x] [Merge Sort](https://github.com/danrusei/algorithms_with_Go/tree/main/sorting/merge_sort) 67 | * [x] [Heap Sort (Binary Heap)](https://github.com/danrusei/algorithms_with_Go/tree/main/sorting/heap_sort) 68 | * [x] [Quick Sort](https://github.com/danrusei/algorithms_with_Go/tree/main/sorting/quick_sort) 69 | * [] Interpolation Search 70 | * [] Find Kth Smallest/Largest Element In Unsorted Array 71 | * [] Given a sorted array and a number x, find the pair in array whose sum is closest to x 72 | 73 | ## [Dynamic Programming](https://github.com/danrusei/algorithms_with_Go/tree/main/dynamic) 74 | 75 | * [x] [Longest Common Subsequence](https://github.com/danrusei/algorithms_with_Go/tree/main/dynamic/longest_common_subsequence) 76 | * [] Longest Increasing Subsequence 77 | * [] Edit Distance 78 | * [] Minimum Partition 79 | * [x] [Ways to Cover a Distance](https://github.com/danrusei/algorithms_with_Go/tree/main/dynamic/cover_distance) 80 | * [] Longest Path In Matrix 81 | * [x] [Subset Sum Problem](https://github.com/danrusei/algorithms_with_Go/tree/main/dynamic/subset_sum) 82 | * [] Optimal Strategy for a Game 83 | * [] 0-1 Knapsack Problem 84 | * [] Boolean Parenthesization Problem 85 | 86 | ## [BIT Manipulation](https://github.com/danrusei/algorithms_with_Go/tree/main/bitwise) 87 | 88 | * [x] [Maximum Subarray XOR](https://github.com/danrusei/algorithms_with_Go/tree/main/bitwise/max_xor) 89 | * [] Magic Number 90 | * [] Sum of bit differences among all pairs 91 | * [x] [Swap All Odds And Even Bits](https://github.com/danrusei/algorithms_with_Go/tree/main/bitwise/swapp_odd_even) 92 | * [] Find the element that appears once 93 | * [x] [Binary representation of a given number](https://github.com/danrusei/algorithms_with_Go/tree/main/bitwise/decimal_to_binary) 94 | * [] Count total set bits in all numbers from 1 to n 95 | * [x] [Rotate bits of a number](https://github.com/danrusei/algorithms_with_Go/tree/main/bitwise/rotate_bits) 96 | * [] Count number of bits to be flipped to convert A to B 97 | * [x] [Find Next Sparse Number](https://github.com/danrusei/algorithms_with_Go/tree/main/bitwise/next_sparse) 98 | 99 | ## [Number Theory](https://github.com/danrusei/algorithms_with_Go/tree/main/numbers) 100 | 101 | * [] Modular Exponentiation 102 | * [x] [Modular multiplicative inverse](https://github.com/danrusei/algorithms_with_Go/tree/main/numbers/multiplicative) 103 | * [] Primality Test | Set 2 (Fermat Method) 104 | * [] Euler’s Totient Function 105 | * [x] [Sieve of Eratosthenes](https://github.com/danrusei/algorithms_with_Go/tree/main/numbers/eratosthenes) 106 | * [] Convex Hull 107 | * [] Basic and Extended Euclidean algorithms 108 | * [x] [Segmented Sieve](https://github.com/danrusei/algorithms_with_Go/tree/main/numbers/segmented) 109 | * [] Chinese remainder theorem 110 | * [] Lucas Theorem 111 | 112 | ## [String / Array](https://github.com/danrusei/algorithms_with_Go/tree/main/strings) 113 | 114 | * [x] [Reverse an array without affecting special characters](https://github.com/danrusei/algorithms_with_Go/tree/main/strings/reverse_alpha) 115 | * [] All Possible Palindromic Partitions 116 | * [] Count triplets with sum smaller than a given value 117 | * [x] [Convert array into Zig-Zag fashion](https://github.com/danrusei/algorithms_with_Go/tree/main/strings/zig_zag) 118 | * [] Generate all possible sorted arrays from alternate elements of two given sorted arrays 119 | * [] Pythagorean Triplet in an array 120 | * [x] [Length of the largest subarray with contiguous elements](https://github.com/danrusei/algorithms_with_Go/tree/main/strings/largest_subarray) 121 | * [] Find the smallest positive integer value that cannot be represented as sum of any subset of a given array 122 | * [x] [Smallest subarray with sum greater than a given value](https://github.com/danrusei/algorithms_with_Go/tree/main/strings/smallest_subarray) 123 | * [] Stock Buy Sell to Maximize Profit 124 | -------------------------------------------------------------------------------- /binary_tree/Binary_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/binary_tree/Binary_tree.png -------------------------------------------------------------------------------- /binary_tree/Complete_binary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/binary_tree/Complete_binary.png -------------------------------------------------------------------------------- /binary_tree/Full_binary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/binary_tree/Full_binary.png -------------------------------------------------------------------------------- /binary_tree/README.md: -------------------------------------------------------------------------------- 1 | # Binary Tree 2 | 3 | **Binary Tree [Source Wikipedia](https://en.wikipedia.org/wiki/Linked_list)** 4 | 5 | In computer science, a binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child. 6 | 7 | ![example binarry tree](Binary_tree.png) 8 | 9 | * A labeled binary tree of size 9 and height 3, with a root node whose value is 2. The above tree is unbalanced and not sorted. 10 | 11 | ## Types of binary trees 12 | 13 | * A **rooted binary tree** has a root node and every node has at most two children. 14 | * A **full binary tree** is a tree in which every node has either 0 or 2 children. 15 | ![full binary tree](Full_binary.png) 16 | * A **complete binary tree** every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. 17 | ![complete binary tree](Complete_binary.png) 18 | * A **perfect binary** tree is a binary tree in which all interior nodes have two children and all leaves have the same depth or same level. 19 | * A **balanced binary tree** is a binary tree structure in which the left and right subtrees of every node differ in height by no more than 1. 20 | 21 | ## Common operations 22 | 23 | * **Insertion** - Nodes can be inserted into binary trees in between two other nodes or added after a leaf node. In binary trees, a node that is inserted is specified as to which child it is. 24 | * **Deletion** - Deletion is the process whereby a node is removed from the tree. Only certain nodes in a binary tree can be removed unambiguously. 25 | * **Traversal** - Pre-order, in-order, and post-order traversal visit each node in a tree by recursively visiting each node in the left and right subtrees of the root. 26 | * **In-Order** -the left subtree is visited first, then the root and later the right sub-tree. 27 | * **Pre-Order** - the root node is visited first, then the left subtree and finally the right subtree. 28 | * **Post-order** - traverse the left subtree, then the right subtree and finally the root node. 29 | -------------------------------------------------------------------------------- /binary_tree/binary_tree.go: -------------------------------------------------------------------------------- 1 | package binarytree 2 | 3 | import "fmt" 4 | 5 | // Tree is a binary tree with integer values. 6 | type Tree struct { 7 | Value int 8 | Left *Tree 9 | Right *Tree 10 | } 11 | 12 | // NewTree instantiate the binary tree 13 | func NewTree(k int) *Tree { 14 | return &Tree{ 15 | Value: k, 16 | Left: nil, 17 | Right: nil, 18 | } 19 | 20 | } 21 | 22 | // Insert a new value to the binary tree 23 | func (t *Tree) Insert(val int) *Tree { 24 | if t == nil { 25 | return NewTree(val) 26 | } 27 | if val < t.Value { 28 | t.Left = t.Left.Insert(val) 29 | } else { 30 | t.Right = t.Right.Insert(val) 31 | } 32 | return t 33 | } 34 | 35 | // InOrderTraverse - the left subtree is visited first, then the root and later the right sub-tree. 36 | func (t *Tree) InOrderTraverse(f func(int)) { 37 | if t != nil { 38 | t.Left.InOrderTraverse(f) 39 | f(t.Value) 40 | t.Right.InOrderTraverse(f) 41 | } 42 | } 43 | 44 | // PreOrderTraverse - the root node is visited first, then the left subtree and finally the right subtree. 45 | func (t *Tree) PreOrderTraverse(f func(int)) { 46 | if t != nil { 47 | f(t.Value) 48 | t.Left.PreOrderTraverse(f) 49 | t.Right.PreOrderTraverse(f) 50 | } 51 | } 52 | 53 | // PostOrderTraverse - traverse the left subtree, then the right subtree and finally the root node 54 | func (t *Tree) PostOrderTraverse(f func(int)) { 55 | if t != nil { 56 | t.Left.PostOrderTraverse(f) 57 | t.Right.PostOrderTraverse(f) 58 | f(t.Value) 59 | } 60 | } 61 | 62 | // Used to print the binary tree 63 | func (t *Tree) String() string { 64 | if t == nil { 65 | return "()" 66 | } 67 | s := "" 68 | if t.Left != nil { 69 | s += t.Left.String() + " " 70 | } 71 | s += fmt.Sprint(t.Value) 72 | if t.Right != nil { 73 | s += " " + t.Right.String() 74 | } 75 | return "(" + s + ")" 76 | } 77 | -------------------------------------------------------------------------------- /binary_tree/binary_tree_test.go: -------------------------------------------------------------------------------- 1 | package binarytree 2 | 3 | import "fmt" 4 | 5 | func createTree() *Tree { 6 | bst := NewTree(5) 7 | bst.Insert(8).Insert(4).Insert(10).Insert(2).Insert(6).Insert(1).Insert(3).Insert(7).Insert(9) 8 | return bst 9 | } 10 | 11 | func ExampleTreeInsert() { 12 | 13 | bst := createTree() 14 | fmt.Println(bst) 15 | // Output: 16 | // ((((1) 2 (3)) 4) 5 ((6 (7)) 8 ((9) 10))) 17 | } 18 | 19 | func ExampleInOrderTraverse() { 20 | 21 | bst := createTree() 22 | bst.InOrderTraverse(func(i int) { 23 | fmt.Printf("%d\t", i) 24 | }) 25 | // Output: 26 | // 1 2 3 4 5 6 7 8 9 10 27 | } 28 | 29 | func ExamplePreOrderTraverse() { 30 | 31 | bst := createTree() 32 | bst.PreOrderTraverse(func(i int) { 33 | fmt.Printf("%d\t", i) 34 | }) 35 | // Output: 36 | // 5 4 2 1 3 8 6 7 10 9 37 | } 38 | 39 | func ExamplePostOrderTraverse() { 40 | 41 | bst := createTree() 42 | bst.PostOrderTraverse(func(i int) { 43 | fmt.Printf("%d\t", i) 44 | }) 45 | // Output: 46 | // 1 3 2 4 7 6 9 10 8 5 47 | } 48 | -------------------------------------------------------------------------------- /binary_tree/bottom_view/README.md: -------------------------------------------------------------------------------- 1 | # Check if a given array can represent Preorder Traversal of Binary Search Tree 2 | 3 | Based on: https://www.geeksforgeeks.org/bottom-view-binary-tree/amp/ 4 | 5 | Given a Binary Tree, we need to print the bottom view from left to right. A node x is there in output if x is the bottommost node at its horizontal distance. Horizontal distance of left child of a node x is equal to horizontal distance of x minus 1, and that of right child is horizontal distance of x plus 1. 6 | 7 | ## Algorithm 8 | 9 | * Tree nodes are added in a queue to do pre-order traversal of the tree 10 | * A HashMap is used to store: key value pairs as **key = column** and **value = a struct** which contain the Value of the Node and the **level in the tree** 11 | * Start with the horizontal distance(col) = 0 and vertical distance (level) = 0 of the root node 12 | * recursively traverse left and right subtree, by adding left child to queue along with the horizontal distance as col-1 and right child as col+1. 13 | 14 | ## Example 15 | 16 | Suppose the binary tree is: 17 | 18 | ```bash 19 | 1 20 | / \ 21 | 2 3 22 | / \ / \ 23 | 4 5 6 7 24 | \ 25 | 8 26 | ``` 27 | 28 | Bottom view of the tree is: **4 2 5 6 8 7** 29 | 30 | > Horizontal distance of node with value 1: 0, level = 1 31 | Horizontal distance of node with value 2: 0 - 1 = -1, level = 2 32 | Horizontal distance of node with value 3: 0 + 1 = 1, level = 2 33 | Horizontal distance of node with value 4: -1 - 1 = -2, level = 3 34 | Horizontal distance of node with value 5: -1 + 1 = 0, level = 3 35 | Horizontal distance of node with value 6: 1 - 1 = 0, level = 3 36 | Horizontal distance of node with value 7: 1 + 1 = 2, level = 3 37 | Horizontal distance of node with value 8: 0 + 1 = 1, level = 4 38 | Print the nodes which appear in the last level of that line. 39 | for hd = -2, print 4 40 | for hd = -1, print 2 41 | for hd = 0, print 5 and 6 because they both appear in the last level of that vertical line 42 | for hd = 1, print 8 43 | for hd = 2, print 7 44 | -------------------------------------------------------------------------------- /binary_tree/bottom_view/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | 7 | binarytree "github.com/danrusei/algorithms_with_go/binary_tree" 8 | ) 9 | 10 | type comb struct { 11 | value int 12 | level int 13 | } 14 | 15 | //recursively traverse the binary tree and append in a map the element with the column as the key and a struct as the value 16 | //the value contains the node value and its level in horizontal hierarchy 17 | func findbottom(root *binarytree.Tree, m map[int]([]comb), col int, level int) { 18 | if root == nil { 19 | return 20 | } 21 | c := comb{root.Value, level} 22 | m[col] = append(m[col], c) 23 | findbottom(root.Left, m, col-1, level+1) 24 | findbottom(root.Right, m, col+1, level+1) 25 | } 26 | 27 | func bottomView(root *binarytree.Tree) { 28 | m := map[int]([]comb){} 29 | findbottom(root, m, 0, 0) 30 | 31 | //store the keys in a slice in order to access map elements in sorted order 32 | keys := make([]int, len(m)) 33 | i := 0 34 | for k := range m { 35 | keys[i] = k 36 | i++ 37 | } 38 | sort.Ints(keys) 39 | 40 | //access the sorted map elements and print the bottom element from each column 41 | for _, k := range keys { 42 | var value int 43 | maxLevel := 0 44 | for _, c := range m[k] { 45 | if c.level > maxLevel { 46 | maxLevel = c.level 47 | value = c.value 48 | } 49 | 50 | } 51 | fmt.Printf("%d ", value) 52 | } 53 | fmt.Println() 54 | } 55 | 56 | func main() { 57 | 58 | tree := binarytree.NewTree(20) 59 | tree.Left = binarytree.NewTree(8) 60 | tree.Right = binarytree.NewTree(22) 61 | tree.Left.Left = binarytree.NewTree(5) 62 | tree.Left.Right = binarytree.NewTree(3) 63 | tree.Right.Right = binarytree.NewTree(25) 64 | tree.Left.Right.Left = binarytree.NewTree(10) 65 | tree.Left.Right.Right = binarytree.NewTree(14) 66 | 67 | bottomView(tree) 68 | } 69 | -------------------------------------------------------------------------------- /binary_tree/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/danrusei/algorithms_with_go/binary_tree 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /binary_tree/minimum_depth/README.md: -------------------------------------------------------------------------------- 1 | # Find Minimum Depth of a Binary Tree 2 | 3 | Based on: https://www.geeksforgeeks.org/find-minimum-depth-of-a-binary-tree/amp/ 4 | 5 | Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. 6 | 7 | ## Example 8 | 9 | Given the below Binary Tree: 10 | ![binary tree](tree122.gif) 11 | 12 | Minimum height of below Binary Tree is 2. Note that the path must end on a leaf node. 13 | 14 | ## Algorithm 15 | 16 | * traverse the given Binary Tree and for every node, check if it is a leaf node 17 | * If yes, then return 1 18 | * If not leaf node then if the left subtree is NULL, then recur for the right subtree 19 | * if the right subtree is NULL, then recur for the left subtree 20 | * if both left and right subtrees are not NULL, then take the minimum of two heights. 21 | -------------------------------------------------------------------------------- /binary_tree/minimum_depth/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | 7 | binarytree "github.com/danrusei/algorithms_with_go/binary_tree" 8 | ) 9 | 10 | func minDepth(tree *binarytree.Tree) int { 11 | 12 | // Corner case. Should never be hit unless the code is called on nil tree 13 | if tree == nil { 14 | return 0 15 | } 16 | 17 | // Base case : Leaf Node. This accounts for height = 1. 18 | if tree.Left == nil && tree.Right == nil { 19 | return 1 20 | } 21 | 22 | // If left subtree is nil, recur for right subtree 23 | if tree.Left == nil { 24 | return minDepth(tree.Right) + 1 25 | } 26 | 27 | // If right subtree is nil, recur for left subtree 28 | if tree.Right == nil { 29 | return minDepth(tree.Left) + 1 30 | } 31 | 32 | return int(math.Min(float64(minDepth(tree.Left)), float64(minDepth(tree.Right))) + 1) 33 | 34 | } 35 | 36 | func main() { 37 | 38 | tree := binarytree.NewTree(1) 39 | tree.Left = binarytree.NewTree(2) 40 | tree.Right = binarytree.NewTree(3) 41 | tree.Left.Left = binarytree.NewTree(4) 42 | tree.Left.Right = binarytree.NewTree(5) 43 | 44 | result := minDepth(tree) 45 | 46 | fmt.Printf("The minimum depth of the binary tree is : %d\n", result) 47 | } 48 | -------------------------------------------------------------------------------- /binary_tree/minimum_depth/tree122.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/binary_tree/minimum_depth/tree122.gif -------------------------------------------------------------------------------- /binary_tree/preorder_traversal/README.md: -------------------------------------------------------------------------------- 1 | # Check if a given array can represent Preorder Traversal of Binary Search Tree 2 | 3 | Based on: https://www.geeksforgeeks.org/check-if-a-given-array-can-represent-preorder-traversal-of-binary-search-tree/amp/ 4 | 5 | Given an array of numbers, return true if given array can represent preorder traversal of a Binary Search Tree, else return false. Expected time complexity is O(n). 6 | 7 | ## Example 8 | 9 | **Input**: {2, 4, 3} 10 | **Output**: true 11 | Given array can represent preorder traversal 12 | of below tree 13 | 2 14 | \ 15 | 4 16 | / 17 | 3 18 | 19 | **Input**: {2, 4, 1} 20 | **Output**: false 21 | Given array cannot represent preorder traversal 22 | of a Binary Search Tree. 23 | 24 | **Input**: {40, 30, 35, 80, 100} 25 | **Output**: true 26 | Given array can represent preorder traversal 27 | of below tree 28 | 40 29 | /...\ 30 | 30 80 31 | \ ......\ 32 | 35 100 33 | 34 | **Input**: {40, 30, 35, 20, 80, 100} 35 | **Output**: false 36 | Given array cannot represent preorder traversal 37 | of a Binary Search Tree. 38 | 39 | ## Algorithm 40 | 41 | Binary Tree Preorder traversal is implemented in the binarytree package. Therefore, here is just used to test out if the list is correct. 42 | 43 | ```bash 44 | $ go test -v 45 | === RUN TestPreorderTraversal 46 | === RUN TestPreorderTraversal/length_3_true 47 | Input: [2 4 3] 48 | Preorder traversal: [2 4 3] 49 | === RUN TestPreorderTraversal/length_3_false 50 | Input: [2 4 1] 51 | Preorder traversal: [2 1 4] 52 | === RUN TestPreorderTraversal/length_5_true 53 | Input: [40 30 35 80 100] 54 | Preorder traversal: [40 30 35 80 100] 55 | === RUN TestPreorderTraversal/length_6_false 56 | Input: [40 30 35 20 80 100] 57 | Preorder traversal: [40 30 20 35 80 100] 58 | --- PASS: TestPreorderTraversal (0.00s) 59 | --- PASS: TestPreorderTraversal/length_3_true (0.00s) 60 | --- PASS: TestPreorderTraversal/length_3_false (0.00s) 61 | --- PASS: TestPreorderTraversal/length_5_true (0.00s) 62 | --- PASS: TestPreorderTraversal/length_6_false (0.00s) 63 | PASS 64 | ok github.com/danrusei/algorithms_with_go/binary_tree/preorder_traversal 0.001s 65 | ``` 66 | -------------------------------------------------------------------------------- /binary_tree/preorder_traversal/preorder_test.go: -------------------------------------------------------------------------------- 1 | package preorder 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | 8 | binarytree "github.com/danrusei/algorithms_with_go/binary_tree" 9 | ) 10 | 11 | func createBinaryTree(treeVals []int) *binarytree.Tree { 12 | 13 | tree := binarytree.NewTree(treeVals[0]) 14 | 15 | for i, num := range treeVals { 16 | if i == 0 { 17 | continue 18 | } 19 | tree.Insert(num) 20 | } 21 | return tree 22 | } 23 | 24 | func TestPreorderTraversal(t *testing.T) { 25 | for _, tc := range testcases { 26 | t.Run(tc.name, func(t *testing.T) { 27 | tree := createBinaryTree(tc.tree) 28 | traverse := []int{} 29 | tree.PreOrderTraverse(func(elem int) { 30 | traverse = append(traverse, elem) 31 | }) 32 | fmt.Printf("Input: %v\n", tc.traversal) 33 | fmt.Printf("Preorder traversal: %v\n", traverse) 34 | if result := reflect.DeepEqual(tc.traversal, traverse); result != tc.ok { 35 | t.Errorf("got: %v, want: %v", result, tc.ok) 36 | } 37 | }) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /binary_tree/preorder_traversal/test_cases.go: -------------------------------------------------------------------------------- 1 | package preorder 2 | 3 | var testcases = []struct { 4 | name string 5 | tree []int 6 | traversal []int 7 | ok bool 8 | }{ 9 | { 10 | name: "length_3_true", 11 | tree: []int{2, 4, 3}, 12 | traversal: []int{2, 4, 3}, 13 | ok: true, 14 | }, 15 | { 16 | name: "length_3_false", 17 | tree: []int{2, 4, 1}, 18 | traversal: []int{2, 4, 1}, 19 | ok: false, 20 | }, 21 | { 22 | name: "length_5_true", 23 | tree: []int{40, 30, 35, 80, 100}, 24 | traversal: []int{40, 30, 35, 80, 100}, 25 | ok: true, 26 | }, 27 | { 28 | name: "length_6_false", 29 | tree: []int{40, 30, 35, 20, 80, 100}, 30 | traversal: []int{40, 30, 35, 20, 80, 100}, 31 | ok: false, 32 | }, 33 | } 34 | -------------------------------------------------------------------------------- /binary_tree/remove_nodes/README.md: -------------------------------------------------------------------------------- 1 | # Remove nodes on root to leaf paths of length < K 2 | 3 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/remove-nodes-root-leaf-paths-length-k/amp/) 4 | 5 | Given a Binary Tree and a number k, remove all nodes that lie only on root to leaf path(s) of length smaller than k. If a node X lies on multiple root-to-leaf paths and if any of the paths has path length >= k, then X is not deleted from Binary Tree. In other words a node is deleted if all paths going through it have lengths smaller than k. 6 | 7 | ## Example 8 | 9 | Consider the following example Binary Tree 10 | 11 | ```bash 12 | 1 13 | / \ 14 | 2 3 15 | / \ \ 16 | 4 5 6 17 | / / 18 | 7 8 19 | 20 | Input: Root of above Binary Tree 21 | k = 4 22 | 23 | Output: The tree should be changed to following 24 | 1 25 | / \ 26 | 2 3 27 | / \ 28 | 4 6 29 | / / 30 | 7 8 31 | 32 | There are 3 paths 33 | i) 1->2->4->7 path length = 4 34 | ii) 1->2->5 path length = 3 35 | iii) 1->3->6->8 path length = 4 36 | 37 | There is only one path " 1->2->5 " of length smaller than 4. The node 5 is the only node that lies only on this path, so node 5 is removed. Nodes 2 and 1 are not removed as they are parts of other paths of length 4 as well. 38 | 39 | If k is 5 or greater than 5, then whole tree is deleted. 40 | If k is 3 or less than 3, then nothing is deleted. 41 | ``` 42 | 43 | ## Algorithm 44 | 45 | * Traverse the tree in postorder fashion so that if a leaf node path length is shorter than k, then that node and all of its descendants till the node which are not on some other path are removed. 46 | * If root is a leaf node and it's level is less than k then remove this node. 47 | 48 | ## Result 49 | 50 | ```bash 51 | $ go run main.go 52 | In order traversal of the original tree: 53 | ((((7) 4) 2 (5)) 1 (3 ((8) 6))) 54 | In order traversal of the modified tree: 55 | ((((7) 4) 2) 1 (3 ((8) 6))) 56 | ``` 57 | -------------------------------------------------------------------------------- /binary_tree/remove_nodes/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | binarytree "github.com/danrusei/algorithms_with_go/binary_tree" 7 | ) 8 | 9 | func removeShortPath(tree *binarytree.Tree, level int, k int) *binarytree.Tree { 10 | if tree == nil { 11 | return nil 12 | } 13 | 14 | // Traverse the tree in postorder fashion so that if a leaf 15 | // node path length is shorter than k, then that node and 16 | // all of its descendants till the node which are not 17 | // on some other path are removed. 18 | tree.Left = removeShortPath(tree.Left, level+1, k) 19 | tree.Right = removeShortPath(tree.Right, level+1, k) 20 | 21 | if tree.Left == nil && tree.Right == nil && level < k { 22 | tree = nil 23 | } 24 | 25 | return tree 26 | } 27 | 28 | func main() { 29 | 30 | tree := binarytree.NewTree(1) 31 | tree.Left = binarytree.NewTree(2) 32 | tree.Right = binarytree.NewTree(3) 33 | tree.Left.Left = binarytree.NewTree(4) 34 | tree.Left.Right = binarytree.NewTree(5) 35 | tree.Left.Left.Left = binarytree.NewTree(7) 36 | tree.Right.Right = binarytree.NewTree(6) 37 | tree.Right.Right.Left = binarytree.NewTree(8) 38 | 39 | fmt.Println("In order traversal of the original tree:") 40 | fmt.Println(tree) 41 | 42 | // this is the distance of the shortest path 43 | k := 4 44 | 45 | modifiedTree := removeShortPath(tree, 1, k) 46 | 47 | fmt.Println("In order traversal of the modified tree:") 48 | fmt.Println(modifiedTree) 49 | 50 | } 51 | -------------------------------------------------------------------------------- /binary_tree/reverse_alternate/README.md: -------------------------------------------------------------------------------- 1 | # Reverse alternate levels of a perfect binary tree 2 | 3 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/reverse-alternate-levels-binary-tree/amp/) 4 | 5 | Given a Perfect Binary Tree, reverse the alternate level nodes of the binary tree. 6 | 7 | ## Example 8 | 9 | ```bash 10 | Given tree: 11 | 11 12 | / \ 13 | 12 13 14 | / \ / \ 15 | 14 15 16 17 16 | / \ / \ / \ / \ 17 | 1 2 3 4 5 6 7 8 18 | 19 | Modified tree: 20 | 11 21 | / \ 22 | 13 12 23 | / \ / \ 24 | 14 15 16 17 25 | / \ / \ / \ / \ 26 | 8 7 6 5 4 3 2 1 27 | 28 | 29 | ``` 30 | 31 | ## Algorithm 32 | 33 | * traverse the given tree in inorder fashion and store all odd level values in a slice 34 | * reverse the slice 35 | * traverse the tree again inorder fashion, take elements from the slice and store the values to every odd level traversed node. 36 | 37 | ## Result 38 | 39 | ```bash 40 | $ go run main.go 41 | In order traversal of the original tree: 42 | ((((1) 14 (2)) 12 ((3) 15 (4))) 11 (((5) 16 (6)) 13 ((7) 16 (8)))) 43 | In order traversal of the modified tree: 44 | ((((8) 14 (7)) 13 ((6) 15 (5))) 11 (((4) 16 (3)) 12 ((2) 16 (1)))) 45 | ``` 46 | -------------------------------------------------------------------------------- /binary_tree/reverse_alternate/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | binarytree "github.com/danrusei/algorithms_with_go/binary_tree" 7 | ) 8 | 9 | // traverse tree and store odd level elements 10 | func storeAlternate(tree *binarytree.Tree, store *[]int, level int) { 11 | if tree == nil { 12 | return 13 | } 14 | 15 | // Inorder traverse the tree and store only the values from alternate levels 16 | storeAlternate(tree.Left, store, level+1) 17 | 18 | if level%2 != 0 { 19 | *store = append(*store, tree.Value) 20 | } 21 | 22 | storeAlternate(tree.Right, store, level+1) 23 | } 24 | 25 | // traverse the tree and take the elements from the slice and store in odd level nodes 26 | func modifyTree(tree *binarytree.Tree, store []int, index int, level int) int { 27 | 28 | if tree == nil { 29 | return index 30 | } 31 | 32 | // Inorder traverse the tree and update level values from the store if the level is odd 33 | index = modifyTree(tree.Left, store, index, level+1) 34 | 35 | if level%2 != 0 { 36 | tree.Value = store[index] 37 | index++ 38 | } 39 | 40 | index = modifyTree(tree.Right, store, index, level+1) 41 | 42 | return index 43 | } 44 | 45 | func reverseAlternate(tree *binarytree.Tree) { 46 | 47 | //store all alternate levels nodes 48 | store := []int{} 49 | 50 | // inorder traverse and store the values from alternate levels 51 | storeAlternate(tree, &store, 0) 52 | 53 | // reverse the slice 54 | for i, j := 0, len(store)-1; i < j; i, j = i+1, j-1 { 55 | store[i], store[j] = store[j], store[i] 56 | } 57 | 58 | index := 0 59 | _ = modifyTree(tree, store, index, 0) 60 | } 61 | 62 | func main() { 63 | 64 | tree := binarytree.NewTree(11) 65 | tree.Left = binarytree.NewTree(12) 66 | tree.Right = binarytree.NewTree(13) 67 | tree.Left.Left = binarytree.NewTree(14) 68 | tree.Left.Left.Left = binarytree.NewTree(1) 69 | tree.Left.Left.Right = binarytree.NewTree(2) 70 | tree.Left.Right = binarytree.NewTree(15) 71 | tree.Left.Right.Left = binarytree.NewTree(3) 72 | tree.Left.Right.Right = binarytree.NewTree(4) 73 | tree.Right.Left = binarytree.NewTree(16) 74 | tree.Right.Left.Left = binarytree.NewTree(5) 75 | tree.Right.Left.Right = binarytree.NewTree(6) 76 | tree.Right.Right = binarytree.NewTree(16) 77 | tree.Right.Right.Left = binarytree.NewTree(7) 78 | tree.Right.Right.Right = binarytree.NewTree(8) 79 | 80 | fmt.Println("In order traversal of the original tree:") 81 | fmt.Println(tree) 82 | 83 | reverseAlternate(tree) 84 | 85 | fmt.Println("In order traversal of the modified tree:") 86 | fmt.Println(tree) 87 | 88 | } 89 | -------------------------------------------------------------------------------- /bitwise/README.md: -------------------------------------------------------------------------------- 1 | # Bitwise Operation 2 | 3 | In computer programming, a bitwise operation operates on a bit string, a bit array or a binary numeral (considered as a bit string) at the level of its individual bits. It is a fast and simple action, basic to the higher level arithmetic operations and directly supported by the processor. Most bitwise operations are presented as two-operand instructions where the result replaces one of the input operands. 4 | 5 | On simple low-cost processors, typically, bitwise operations are substantially faster than division, several times faster than multiplication, and sometimes significantly faster than addition.[clarification needed] While modern processors usually perform addition and multiplication just as fast as bitwise operations due to their longer instruction pipelines and other architectural design choices, bitwise operations do commonly use less power because of the reduced use of resources. 6 | 7 | ***Source: [Wikipedia](https://en.wikipedia.org/wiki/Bitwise_operation)*** 8 | 9 | ## Go built-in operators 10 | 11 | | Operation | Result | Description 12 | | ----------- | ----------- | ----------- | 13 | |0011 & 0101 | 0001 | Bitwise AND 14 | |0011 \| 0101 | 0111 | Bitwise OR 15 | |0011 ^ 0101 | 0110 | Bitwise XOR 16 | |^0101 | 1010 | Bitwise NOT (same as 1111 ^ 0101) 17 | |0011 &^ 0101i | 0010 | Bitclear (AND NOT) 18 | |00110101 << 2 | 11010100 | Left shift 19 | |00110101 << 100 | 00000000 | No upper limit on shift count 20 | |00110101 >> 2 | 00001101 | Right shift 21 | -------------------------------------------------------------------------------- /bitwise/decimal_to_binary/README.md: -------------------------------------------------------------------------------- 1 | # Binary representation of a given number 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/binary-representation-of-a-given-number/amp/) 4 | Write a program to print Binary representation of a given number. 5 | 6 | ## Algorithm 7 | 8 | Recursive using bitwise operator 9 | 10 | * Check n > 1 11 | * **right shift** the number by 1 bit and recursive call the function 12 | * Print the bits of number 13 | 14 | Alternate solution is to use fmt Go package to transform decimal to binary: 15 | 16 | ```go 17 | fmt.Printf("The binary of the %d is: %b\n", x, x) 18 | ``` 19 | -------------------------------------------------------------------------------- /bitwise/decimal_to_binary/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // recursively call this function untill all bits are shifted 6 | func bin(x int) { 7 | 8 | if x > 1 { 9 | bin(x >> 1) 10 | } 11 | // print last bit from the remainder 12 | fmt.Printf("%d", x&1) 13 | } 14 | 15 | func main() { 16 | x := 131 17 | fmt.Printf("Using recursive function, the binary of %d is: ", x) 18 | bin(x) 19 | fmt.Println() 20 | //builtin using fmt package 21 | fmt.Printf("Using fmt package, the binary of %d is: %b\n", x, x) 22 | } 23 | -------------------------------------------------------------------------------- /bitwise/max_xor/README.md: -------------------------------------------------------------------------------- 1 | # Find the maximum subarray XOR in a given array 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/find-the-maximum-subarray-xor-in-a-given-array/amp/) 4 | Given an array of integers. find the maximum XOR subarray value in given array. Expected time complexity O(n). 5 | 6 | > Input: arr[] = {1, 2, 3, 4} 7 | Output: 7 8 | The subarray {3, 4} has maximum XOR value 9 | > 10 | > Input: arr[] = {8, 1, 2, 12, 7, 6} 11 | Output: 15 12 | The subarray {1, 2, 12} has maximum XOR value 13 | > 14 | > Input: arr[] = {4, 6} 15 | Output: 6 16 | The subarray {6} has maximum XOR value 17 | 18 | ## Solution 19 | 20 | * Iterate 2 times over the slice of integers, second time only the ending part 21 | * `currXor` is changed iteratively as it progress through the loop 22 | * `response` value is updated every time when the computed XOR is bigger than the current value 23 | -------------------------------------------------------------------------------- /bitwise/max_xor/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | func maxSubarrayXOR(numbers []int) int { 9 | // Initialize result 10 | response := math.MinInt32 11 | 12 | for i := range numbers { 13 | 14 | //store xor of current subarray 15 | currXor := 0 16 | 17 | // Pick ending points of subarrays starting with i 18 | for j := i; j < len(numbers); j++ { 19 | currXor = currXor ^ numbers[j] 20 | if response < currXor { 21 | response = currXor 22 | } 23 | } 24 | } 25 | return response 26 | } 27 | 28 | func main() { 29 | numbers := []int{8, 1, 2, 12, 7, 6} 30 | result := maxSubarrayXOR(numbers) 31 | fmt.Printf("Max subarray XOR is %d\n", result) 32 | } 33 | -------------------------------------------------------------------------------- /bitwise/next_sparse/README.md: -------------------------------------------------------------------------------- 1 | # Find Next Sparse Number 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/given-a-number-find-next-sparse-number/amp/) 4 | 5 | Given a number x, find the smallest Sparse number which greater than or equal to x. 6 | A number is Sparse if there are no two adjacent 1s in its binary representation. For example 5 (binary representation: 101) is sparse, but 6 (binary representation: 110) is not sparse. 7 | 8 | ## Example 9 | 10 | ```bash 11 | Input: x = 6 12 | Output: Next Sparse Number is 8 13 | 14 | Input: x = 4 15 | Output: Next Sparse Number is 4 16 | 17 | Input: x = 38 18 | Output: Next Sparse Number is 40 19 | 20 | Input: x = 44 21 | Output: Next Sparse Number is 64 22 | ``` 23 | 24 | ## Algorithm 25 | 26 | There is a simple solution which check if the number is sparse, if not it moves to the next decimal number and so on. 27 | Although this is a valid solution is not so efficient, a more efficient solution is described below: 28 | 29 | * store the binary of a given number in a slice 30 | * initialize the last finalized bit position as 0 31 | * traverse the slice, and start with least significatn bit (from right to left) 32 | * if we find two adjacent 1's such that next (or third) bit is not 1, then: 33 | * Make all bits after this 1 to last finalized bit 0 34 | * Update last finalized bit as next bit 35 | 36 | ## Result 37 | 38 | ```bash 39 | $ go run main.go 40 | next sparse number starting from 38 is 40 41 | ``` 42 | -------------------------------------------------------------------------------- /bitwise/next_sparse/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func nextSparse(x int) int { 6 | 7 | // bin store the binary representation of x 8 | // bin[0] contains least significant bit 9 | bin := []int{} 10 | for x != 0 { 11 | bin = append(bin, x&1) 12 | x >>= 1 13 | } 14 | 15 | last := 0 16 | 17 | for i := 1; i < len(bin); i++ { 18 | 19 | if bin[i] == 1 && bin[i-1] == 1 && bin[i+1] != 1 { 20 | 21 | // make the next bit 1 22 | bin[i+1] = 1 23 | 24 | // make all bits before current bit as 0 to make 25 | // sure that we get the smallest next number 26 | for j := i; j >= last; j-- { 27 | bin[j] = 0 28 | 29 | } 30 | 31 | // store position of the bit set so that this bit 32 | // and bits before it are not changed next time. 33 | last = i + 1 34 | } 35 | } 36 | 37 | //create and return the decimal equivalent of modified bin[] 38 | result := 0 39 | for i := 0; i < len(bin); i++ { 40 | result += bin[i] * (1 << i) 41 | } 42 | 43 | return result 44 | } 45 | 46 | func main() { 47 | x := 38 48 | y := nextSparse(x) 49 | 50 | fmt.Printf("next sparse number starting from %d is %d\n", x, y) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /bitwise/rotate_bits/README.md: -------------------------------------------------------------------------------- 1 | # Rotate bits of a number 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/rotate-bits-of-an-integer/amp/) 4 | 5 | Bit Rotation: A rotation (or circular shift) is an operation similar to shift except that the bits that fall off at one end are put back to the other end. 6 | 7 | * In left rotation, the bits that fall off at left end are put back at right end. 8 | * In right rotation, the bits that fall off at right end are put back at left end. 9 | 10 | ## Example 11 | 12 | Let n = 3 is stored using 8 bits. 13 | 14 | * Left rotation of n = 11100101 by 3 makes n = 00101111 15 | * Right rotation of n = 11100101 by 3 makes n = 10111100 16 | 17 | ## Algorithm 18 | 19 | Left Rotation: 20 | 21 | * n << rotate , leaves last "rotate" bits 0 22 | * to populate these with the first "rotate" bits of the original number 23 | * move first bits of the number to the end (n >> (INT_BITS - rotate)) 24 | * and do bitwise OR with the rotated number 25 | 26 | Right Rotation: 27 | 28 | * n >> rotate , leaves first "rotate" bits 0 29 | * to populate these with the last "rotate" bits of the original number 30 | * move last bits of the number to the begining (n << (INT_BITS - rotate)) 31 | * and do bitwise OR with the rotated number 32 | 33 | ## Result 34 | 35 | ```bash 36 | $ go run main.go 37 | The number 152 in bits: 10011000 38 | After left rotation the number is 196 and in bits: 11000100 39 | After right rotation the number is 19 and in bits: 10011 40 | ``` 41 | -------------------------------------------------------------------------------- /bitwise/rotate_bits/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // INT_BITS the number n is stored using 8 bits 6 | const INT_BITS = 8 7 | 8 | // function to left rotate n by rotate bits 9 | func rotateLeft(n int, rotate int) uint8 { 10 | // n << rotate , leaves last "rotate" bits 0 11 | // to populate these with the first "rotate" bits of the original number 12 | // move first bits of the number to the end (n >> (INT_BITS - rotate)) 13 | // and do bitwise OR with the rotated number 14 | return uint8((n << rotate) | (n >> (INT_BITS - rotate))) 15 | } 16 | 17 | // function to right rotate n by rotate bits 18 | func rotateRight(n int, rotate int) uint8 { 19 | // n >> rotate , leaves first "rotate" bits 0 20 | // to populate these with the last "rotate" bits of the original number 21 | // move last bits of the number to the begining (n << (INT_BITS - rotate)) 22 | // and do bitwise OR with the rotated number 23 | return uint8((n >> rotate) | (n << (INT_BITS - rotate))) 24 | } 25 | 26 | func main() { 27 | n := 152 28 | rotate := 3 29 | 30 | fmt.Printf("The number %d in bits: %b\n", n, n) 31 | 32 | rl := rotateLeft(n, rotate) 33 | fmt.Printf("After left rotation the number is %d and in bits: %b\n", rl, rl) 34 | 35 | rr := rotateRight(n, rotate) 36 | fmt.Printf("After right rotation the number is %d and in bits: %b\n", rr, rr) 37 | } 38 | -------------------------------------------------------------------------------- /bitwise/swapp_odd_even/README.md: -------------------------------------------------------------------------------- 1 | # Swap all odd and even bits 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/swap-all-odd-and-even-bits/amp/) 4 | 5 | Given an unsigned integer, swap all odd bits with even bits. For example, if the given number is **23 (00010111)**, it should be converted to **43 (00101011)**. Every even position bit is swapped with adjacent bit on right side (even position bits are highlighted in binary representation of 23), and every odd position bit is swapped with adjacent on left side. 6 | 7 | ## Algorithm 8 | 9 | If we take a closer look at the example, we can observe that we basically need to right shift (>>) all even bits (In the above example, even bits of 23 are highlighted) by 1 so that they become odd bits (highlighted in 43), and left shift (<<) all odd bits by 1 so that they become even bits. The following solution is based on this observation. The solution assumes that input number is stored using 32 bits. 10 | 11 | Let the input number be x: 12 | 13 | * Get all even bits of x by doing **bitwise AND of x with 0xAAAAAAAA**. The number 0xAAAAAAAA is a 32 bit number with all even bits set as 1 and all odd bits as 0. 14 | * Get all odd bits of x by doing **bitwise AND of x with 0x55555555**. The number 0x55555555 is a 32 bit number with all odd bits set as 1 and all even bits as 0. 15 | * Right shift all even bits. 16 | * Left shift all odd bits. 17 | * Combine new even and odd bits using **Bitwise OR** and return. 18 | -------------------------------------------------------------------------------- /bitwise/swapp_odd_even/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func swapBits(x int) int { 6 | 7 | // Get all even bits of x 8 | evenBits := x & 0xAAAAAAAA 9 | 10 | // Get all odd bits of x 11 | oddBits := x & 0x55555555 12 | 13 | // Right shift even bits 14 | evenBits >>= 1 15 | 16 | // Left shift odd bits 17 | oddBits <<= 1 18 | 19 | return evenBits | oddBits 20 | } 21 | 22 | func main() { 23 | 24 | x := 23 25 | y := swapBits(x) 26 | 27 | fmt.Printf("Original number is %d and swapped number is %d\n", x, y) 28 | } 29 | -------------------------------------------------------------------------------- /dynamic/README.md: -------------------------------------------------------------------------------- 1 | # Dynamic Programming 2 | 3 | Dynamic Programming (DP) is an algorithmic technique for solving an optimization problem by breaking it down into simpler subproblems in a `recurisive` manner and utilizing the fact that the optimal solution to the overall problem depends upon the optimal solution to its subproblems. 4 | 5 | It can be achieved in either of two ways: 6 | 7 | * **Top-down approach (Memoization)**: This is the direct fall-out of the recursive formulation of any problem. If the solution to any problem can be formulated recursively using the solution to its sub-problems, and if its sub-problems are overlapping, then one can easily `memoize or store the solutions to the sub-problems in a table`. Whenever we attempt to solve a new sub-problem, we first check the table to see if it is already solved. If a solution has been recorded, we can use it directly, otherwise we solve the sub-problem and add its solution to the table. 8 | * **Bottom-up approach(Tabulation)**: Once we formulate the solution to a problem recursively as in terms of its sub-problems, we can try reformulating the problem in a bottom-up fashion: `try solving the sub-problems first and use their solutions to build-on and arrive at solutions to bigger sub-problems`. This is also usually done in a tabular form by iteratively generating solutions to bigger and bigger sub-problems by using the solutions to small sub-problems. 9 | 10 | ## Example Fibonacci 11 | 12 | If we write simple recursive solution for `Fibonacci Numbers`, we get exponential time complexity and if we optimize it by storing solutions of subproblems, time complexity reduces to linear. 13 | 14 | ***Without dynamic programming, usual recursion:*** 15 | 16 | ```go 17 | func nonDPFibonacci(n int) int { 18 | if n < 2 { 19 | return n 20 | } 21 | return nonDPFibonacci(n-1) + nonDPFibonacci(n-2) 22 | } 23 | ``` 24 | 25 | ***Top-down Dynamic programming, Memoization*** 26 | 27 | ```go 28 | // DP Memoization fibonacci 29 | func memFibonacci(n int) int { 30 | mem := make([]int, n+1) 31 | return calcFibonacci(mem, n) 32 | } 33 | func calcFibonacci(mem []int, n int) int { 34 | if n < 2 { 35 | return n 36 | } 37 | //if we have already solved this subproblem, 38 | //simply return the result from the cache 39 | if mem[n] != 0 { 40 | return mem[n] 41 | } 42 | 43 | mem[n] = calcFibonacci(mem, n-1) + calcFibonacci(mem, n-2) 44 | return mem[n] 45 | } 46 | ``` 47 | 48 | ***Bottom-up Dynamic Programming, Tabulation*** 49 | 50 | ```go 51 | //DP Tabulation fibonacci 52 | func tabFibonacci(n int) int { 53 | if n == 0 { 54 | return 0 55 | } 56 | dp := make([]int, n+1) 57 | dp[0] = 0 58 | dp[1] = 1 59 | for i := 2; i <= n; i++ { 60 | dp[i] = dp[i-1] + dp[i-2] 61 | } 62 | return dp[n] 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /dynamic/cover_distance/README.md: -------------------------------------------------------------------------------- 1 | # Count number of ways to cover a distance 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/count-number-of-ways-to-cover-a-distance/) 4 | 5 | Given a distance ‘dist, count total number of ways to cover the distance with 1, 2 and 3 steps. 6 | 7 | ## Algorithm 8 | 9 | Can be done in 2 ways: 10 | 11 | * the first way is to create a recursive structure and store the value in a HashMap and whenever the function is called, return the value store without computing (Top-Down Approach). 12 | * the second way is to take an extra space of size n and start computing values of states from 1, 2 .. to n, i.e. compute values of i, i+1, i+2 and then use them to calculate the value of i+3 (Bottom-Up Approach). 13 | 14 | This script is using Bottom-Up approach: 15 | 16 | * create an array of size n + 1 and initilize the first 3 variables with 1, 1, 2. The base cases. 17 | * run a loop from 3 to n. 18 | * for each index i, compute the value of i position as dp[i] = dp[i-1] + dp[i-2] + dp[i-3]. 19 | * print the value of dp[n], as the Count of number of ways to cover a distance. 20 | -------------------------------------------------------------------------------- /dynamic/cover_distance/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func printCount(dist int) int { 6 | count := make([]int, dist+1) 7 | 8 | // Initialize base values. There is one way to cover 0 and 1 9 | // distances and two ways to cover 2 distance 10 | count[0], count[1], count[2] = 1, 1, 2 11 | 12 | // Fill the count array in bottom up manner 13 | for i := 3; i <= dist; i++ { 14 | count[i] = count[i-1] + count[i-2] + count[i-3] 15 | } 16 | return count[dist] 17 | } 18 | 19 | func main() { 20 | fmt.Println(printCount(4)) 21 | } 22 | -------------------------------------------------------------------------------- /dynamic/fibonacci.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // non-DP recursive fibonacci solution 6 | func nonDPFibonacci(n int) int { 7 | if n < 2 { 8 | return n 9 | } 10 | return nonDPFibonacci(n-1) + nonDPFibonacci(n-2) 11 | } 12 | 13 | // DP Memoization fibonacci 14 | func memFibonacci(n int) int { 15 | mem := make([]int, n+1) 16 | return calcFibonacci(mem, n) 17 | } 18 | func calcFibonacci(mem []int, n int) int { 19 | if n < 2 { 20 | return n 21 | } 22 | //if we have already solved this subproblem, 23 | //simply return the result from the cache 24 | if mem[n] != 0 { 25 | return mem[n] 26 | } 27 | 28 | mem[n] = calcFibonacci(mem, n-1) + calcFibonacci(mem, n-2) 29 | return mem[n] 30 | } 31 | 32 | //DP Tabulation fibonacci 33 | func tabFibonacci(n int) int { 34 | if n == 0 { 35 | return 0 36 | } 37 | dp := make([]int, n+1) 38 | dp[0] = 0 39 | dp[1] = 1 40 | for i := 2; i <= n; i++ { 41 | dp[i] = dp[i-1] + dp[i-2] 42 | } 43 | return dp[n] 44 | } 45 | 46 | func main() { 47 | fmt.Printf("nonDP recursive Fibonacci(10) = %d \n", nonDPFibonacci(10)) 48 | fmt.Printf("DP Top-Down Fibonacci(10) = %d \n", memFibonacci(10)) 49 | fmt.Printf("DP Bottom-Up Fibonacci(10) = %d \n", tabFibonacci(10)) 50 | } 51 | -------------------------------------------------------------------------------- /dynamic/longest_common_subsequence/README.md: -------------------------------------------------------------------------------- 1 | # Longest Common Subsequence 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/) 4 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem) 5 | Time Complexity: **O(m*n)** 6 | 7 | `LCS Problem Statement`: Given two sequences, find the length of longest subsequence present in both of them. A subsequence is a sequence that appears in the same relative order, but not necessarily contiguous. For example, “abc”, “abg”, “bdf”, “aeg”, ‘”acefg”, .. etc are subsequences of “abcdefg”. 8 | 9 | LCS for input Sequences “ABCDGH” and “AEDFHR” is “ADH” of length 3. 10 | LCS for input Sequences “AGGTAB” and “GXTXAYB” is “GTAB” of length 4. 11 | 12 | ## Algorithm 13 | 14 | * The recursive algorithm controls what order we fill in the computed entries in the array L, and we get the same results if it's filled in some other order. 15 | * use a simple nested loop, that visits the array systematically 16 | * when we fill in a cell L[i,j], we need to already know the values it depends on, in this case L[i+1,j], L[i,j+1], and L[i+1,j+1]. For this reason the array is traversed backwards, from the last row working up to the first and from the last column working up to the first. 17 | * this is iterative (because it uses nested loops instead of recursion) or bottom up (because the order we fill in the array is from smaller simpler subproblems to bigger more complicated ones). 18 | -------------------------------------------------------------------------------- /dynamic/longest_common_subsequence/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func lcs(s1 string, s2 string) int { 6 | 7 | m := len(s1) 8 | n := len(s2) 9 | 10 | //create the m x n matrix 11 | mat := make([][]int, m+1) 12 | for i := range mat { 13 | mat[i] = make([]int, n+1) 14 | } 15 | 16 | //Following steps build mat[m+1][n+1] in bottom up fashion. 17 | //Note that mat[i][j] contains length of LCS of s1[0..i-1] and s2[0..j-1] 18 | for i := 0; i <= m; i++ { 19 | for j := 0; j <= n; j++ { 20 | if i == 0 || j == 0 { 21 | mat[i][j] = 0 22 | } else if s1[i-1] == s2[j-1] { 23 | mat[i][j] = mat[i-1][j-1] + 1 24 | } else { 25 | mat[i][j] = max(mat[i-1][j], mat[i][j-1]) 26 | } 27 | } 28 | } 29 | return mat[m][n] 30 | } 31 | 32 | func max(m int, n int) int { 33 | if m > n { 34 | return m 35 | } 36 | return n 37 | } 38 | 39 | func main() { 40 | fmt.Println(lcs("ABCDGH", "AEDFHR")) 41 | fmt.Println(lcs("AGGTAB", "GXTXAYB")) 42 | } 43 | -------------------------------------------------------------------------------- /dynamic/subset_sum/README.md: -------------------------------------------------------------------------------- 1 | # Subset Sum Problem 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/count-number-of-ways-to-cover-a-distance/) 4 | 5 | Given a set of non-negative integers, and a value sum, determine if there is a subset of the given set with sum equal to given sum. 6 | 7 | ## Example 8 | 9 | > Input: set[] = {3, 34, 4, 12, 5, 2}, sum = 9 10 | > Output: True 11 | > There is a subset (4, 5) with sum 9. 12 | > 13 | > Input: set[] = {3, 34, 4, 12, 5, 2}, sum = 30 14 | > Output: False 15 | > There is no subset that add up to 30. 16 | 17 | ## Algorithm 18 | 19 | * bottom-up approach computes `mat[i][j]` for each `1 <= i <= n` and `1 <= j <= sum` 20 | * is `true` if subset with sum `j` can be found using items up to first `i` items 21 | * it uses values of smaller values `i` and `j` already computed 22 | -------------------------------------------------------------------------------- /dynamic/subset_sum/subsetsum.go: -------------------------------------------------------------------------------- 1 | package subsetsum 2 | 3 | func subsetsum(input []int, sum int) bool { 4 | 5 | n := len(input) 6 | 7 | // T[i][j] stores true if subset with sum j can be attained with 8 | // using items up to first i items 9 | mat := make([][]bool, n+1) 10 | for i := range mat { 11 | mat[i] = make([]bool, sum+1) 12 | } 13 | 14 | // if 0 items in the list and sum is non-zero 15 | for j := 1; j <= sum; j++ { 16 | mat[0][j] = false 17 | } 18 | 19 | // if sum is zero 20 | for i := 0; i <= n; i++ { 21 | mat[i][0] = true 22 | } 23 | 24 | // do for ith item 25 | for i := 1; i <= n; i++ { 26 | // consider all sum from 1 to sum 27 | for j := 1; j <= sum; j++ { 28 | // don't include ith element if j-input[i-1] is negative 29 | if input[i-1] > j { 30 | mat[i][j] = mat[i-1][j] 31 | } else { 32 | // find subset with sum j by excluding or including the ith item 33 | mat[i][j] = mat[i-1][j] || mat[i-1][j-input[i-1]] 34 | } 35 | } 36 | } 37 | 38 | // return maximum value 39 | return mat[n][sum] 40 | 41 | } 42 | -------------------------------------------------------------------------------- /dynamic/subset_sum/subsetsum_test.go: -------------------------------------------------------------------------------- 1 | package subsetsum 2 | 3 | import "testing" 4 | 5 | func TestSubsetSum(t *testing.T) { 6 | for _, tc := range testcases { 7 | t.Run(tc.name, func(t *testing.T) { 8 | output := subsetsum(tc.input, tc.sum) 9 | if output != tc.output { 10 | t.Errorf("got: %v, want: %v", output, tc.output) 11 | } 12 | 13 | }) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dynamic/subset_sum/test_cases.go: -------------------------------------------------------------------------------- 1 | package subsetsum 2 | 3 | var testcases = []struct { 4 | name string 5 | input []int 6 | sum int 7 | output bool 8 | }{ 9 | { 10 | name: "True as 4 + 5 = 9", 11 | input: []int{3, 34, 4, 12, 5, 2}, 12 | sum: 9, 13 | output: true, 14 | }, 15 | { 16 | name: "No sum of 2 elements from the list = 30", 17 | input: []int{3, 34, 4, 12, 5, 2}, 18 | sum: 30, 19 | output: false, 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /graph/README.md: -------------------------------------------------------------------------------- 1 | # Graph 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type)) 4 | 5 | A graph data structure consists of a finite (and possibly mutable) set of vertices (also called nodes or points), together with a set of unordered pairs of these vertices for an undirected graph or a set of ordered pairs for a directed graph. These pairs are known as edges (also called links or lines), and for a directed graph are also known as arrows. The vertices may be part of the graph structure, or may be external entities represented by integer indices or references. 6 | 7 | A graph data structure may also associate to each edge some edge value, such as a symbolic label or a numeric attribute (cost, capacity, length, etc.). 8 | 9 | ## Operation on Graphs 10 | 11 | The basic operations provided by a graph data structure G usually include: 12 | 13 | * adjacent(G, x, y): tests whether there is an edge from the vertex x to the vertex y; 14 | * neighbors(G, x): lists all vertices y such that there is an edge from the vertex x to the vertex y; 15 | * add_vertex(G, x): adds the vertex x, if it is not there; 16 | * remove_vertex(G, x): removes the vertex x, if it is there; 17 | * add_edge(G, x, y): adds the edge from the vertex x to the vertex y, if it is not there; 18 | * remove_edge(G, x, y): removes the edge from the vertex x to the vertex y, if it is there; 19 | * get_vertex_value(G, x): returns the value associated with the vertex x; 20 | * set_vertex_value(G, x, v): sets the value associated with the vertex x to v. 21 | 22 | Structures that associate values to the edges usually also provide: 23 | 24 | * get_edge_value(G, x, y): returns the value associated with the edge (x, y); 25 | * set_edge_value(G, x, y, v): sets the value associated with the edge (x, y) to v. 26 | 27 | ## Graph example 28 | 29 | ![graph example](graph.jpg) 30 | -------------------------------------------------------------------------------- /graph/boggle/README.md: -------------------------------------------------------------------------------- 1 | # Boggle (Find all possible words in a board of characters) 2 | 3 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/boggle-find-possible-words-board-characters/amp/) 4 | 5 | Given a dictionary, a method to do lookup in dictionary and a M x N board where every cell has one character. Find all possible words that can be formed by a sequence of adjacent characters. Note that we can move to any of 8 adjacent characters, but a word should not have multiple instances of same cell. 6 | 7 | ```bash 8 | Input: dictionary[] = {"GEEKS", "FOR", "QUIZ", "GO"}; 9 | boggle[][] = {{'G', 'I', 'Z'}, 10 | {'U', 'E', 'K'}, 11 | {'Q', 'S', 'E'}}; 12 | isWord(str): returns true if str is present in dictionary 13 | else false. 14 | 15 | Output: Following words of dictionary are present 16 | GEEKS 17 | QUIZ 18 | ``` 19 | 20 | ## Algorithm 21 | 22 | * create the graph with the links between the nodes 23 | * iterate over the list of Nodes until we found one with the Value == first letter of the word 24 | * apply a modified breadth for search algorithm on the graph that add to `visited` only the nodes which satisfy the condition that next letter of the word == Node.Value 25 | * run the for loop until either the word was found, by comparing the index with the length of the word, or no `Next` suitable Node was found 26 | 27 | ## Result 28 | 29 | ```bash 30 | $ go run main.go 31 | This word was found: GEEKS 32 | This word was found: QUIZ 33 | ``` 34 | -------------------------------------------------------------------------------- /graph/boggle/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danrusei/algorithms_with_Go/graph" 7 | ) 8 | 9 | type boggle struct { 10 | *graph.Graph 11 | } 12 | 13 | var words = []string{"GEEKS", "FOR", "QUIZ", "GO"} 14 | 15 | func (g *boggle) isWord(word string) bool { 16 | 17 | //find the node value equal with the first letter of the word 18 | first := []*graph.Node{} 19 | for _, node := range g.Nodes { 20 | if node.Value == string(word[0]) { 21 | first = append(first, node) 22 | } 23 | } 24 | 25 | // a modified breadth first search traversal of the graph 26 | // as we note as visited only the Nodes with the values that satisfy the condition: 27 | // Node.Value == string(word[wIndex]) 28 | visited := make(map[*graph.Node]bool) 29 | for _, node := range first { 30 | visited[node] = true 31 | wIndex := 0 32 | nextNode := node 33 | 34 | for { 35 | if wIndex == len(word)-1 { 36 | return true 37 | } 38 | wIndex++ 39 | for _, edge := range g.Edges[nextNode] { 40 | if !visited[edge.ToNode] { 41 | if edge.ToNode.Value == string(word[wIndex]) { 42 | nextNode = edge.ToNode 43 | break 44 | } 45 | } 46 | } 47 | // it means that the nextNode has not changed, therefore not able to find another 48 | // suitable Node in the above iteration 49 | if visited[nextNode] { 50 | return false 51 | } 52 | visited[nextNode] = true 53 | } 54 | } 55 | return false 56 | } 57 | 58 | func main() { 59 | // create nodes 60 | nG := graph.Node{Value: "G"} 61 | nI := graph.Node{Value: "I"} 62 | nZ := graph.Node{Value: "Z"} 63 | nU := graph.Node{Value: "U"} 64 | nE := graph.Node{Value: "E"} 65 | nK := graph.Node{Value: "K"} 66 | nQ := graph.Node{Value: "Q"} 67 | nS := graph.Node{Value: "S"} 68 | nE2 := graph.Node{Value: "E"} 69 | 70 | // create a new graph instance 71 | g := new(graph.Graph) 72 | 73 | // add nodes to graph 74 | g.AddNode(&nG) 75 | g.AddNode(&nI) 76 | g.AddNode(&nZ) 77 | g.AddNode(&nU) 78 | g.AddNode(&nE) 79 | g.AddNode(&nK) 80 | g.AddNode(&nQ) 81 | g.AddNode(&nS) 82 | g.AddNode(&nE2) 83 | 84 | // add the edges(links) between nodes 85 | g.AddEdge(&nG, &nI) 86 | g.AddEdge(&nG, &nE) 87 | g.AddEdge(&nG, &nU) 88 | g.AddEdge(&nI, &nG) 89 | g.AddEdge(&nI, &nU) 90 | g.AddEdge(&nI, &nE) 91 | g.AddEdge(&nI, &nK) 92 | g.AddEdge(&nI, &nZ) 93 | g.AddEdge(&nZ, &nI) 94 | g.AddEdge(&nZ, &nE) 95 | g.AddEdge(&nZ, &nK) 96 | g.AddEdge(&nU, &nG) 97 | g.AddEdge(&nU, &nI) 98 | g.AddEdge(&nU, &nE) 99 | g.AddEdge(&nU, &nS) 100 | g.AddEdge(&nU, &nQ) 101 | g.AddEdge(&nE, &nG) 102 | g.AddEdge(&nE, &nI) 103 | g.AddEdge(&nE, &nZ) 104 | g.AddEdge(&nE, &nU) 105 | g.AddEdge(&nE, &nK) 106 | g.AddEdge(&nE, &nQ) 107 | g.AddEdge(&nE, &nS) 108 | g.AddEdge(&nE, &nE2) 109 | g.AddEdge(&nK, &nZ) 110 | g.AddEdge(&nK, &nI) 111 | g.AddEdge(&nK, &nE) 112 | g.AddEdge(&nK, &nS) 113 | g.AddEdge(&nK, &nE2) 114 | g.AddEdge(&nQ, &nU) 115 | g.AddEdge(&nQ, &nE) 116 | g.AddEdge(&nQ, &nS) 117 | g.AddEdge(&nS, &nQ) 118 | g.AddEdge(&nS, &nU) 119 | g.AddEdge(&nS, &nE) 120 | g.AddEdge(&nS, &nK) 121 | g.AddEdge(&nS, &nE2) 122 | g.AddEdge(&nE2, &nS) 123 | g.AddEdge(&nE2, &nE) 124 | g.AddEdge(&nE2, &nK) 125 | 126 | s := &boggle{g} 127 | 128 | for _, word := range words { 129 | if s.isWord(word) { 130 | fmt.Printf("This word was found: %s\n", word) 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /graph/bridges/README.md: -------------------------------------------------------------------------------- 1 | # Bridges in a graph 2 | 3 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/bridge-in-a-graph/amp/) 4 | 5 | An edge in an undirected connected graph is a bridge if removing it disconnects the graph. For a disconnected undirected graph, definition is similar, a bridge is an edge removing which increases number of disconnected components. 6 | Bridges represent vulnerabilities in a connected network and are useful for designing reliable networks. For example, in a wired computer network, an articulation point indicates the critical computers and a bridge indicates the critical wires or connections. 7 | 8 | ![find the bridges](bridge.png) 9 | 10 | ## Algorithm 11 | 12 | A simple approach is to one by one remove all edges and see if removal of an edge causes disconnected graph. 13 | 14 | * For every edge (u, v), do following 15 | * remove (u, v) from graph 16 | * check if the graph remains connected (We can either use BFS or DFS) 17 | * add (u, v) back to the graph and iterate for other edge 18 | 19 | This is a brute force algorithm with high time complexity, read the alternate solution from geeksforgeeks. 20 | 21 | ## Result 22 | 23 | ```bash 24 | $ go run main.go 25 | Edge 0 --- 3 is a bridge 26 | Edge 3 --- 4 is a bridge 27 | ``` 28 | -------------------------------------------------------------------------------- /graph/bridges/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/graph/bridges/bridge.png -------------------------------------------------------------------------------- /graph/bridges/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danrusei/algorithms_with_Go/graph" 7 | ) 8 | 9 | type bridges struct { 10 | *graph.Graph 11 | } 12 | 13 | func (g *bridges) findBridge() { 14 | 15 | totalNodes := len(g.Nodes) 16 | 17 | for _, node := range g.Nodes { 18 | for _, edge := range g.Edges[node] { 19 | //remove the (u, v) edge from graph 20 | g.RemoveEdge(node, edge.ToNode) 21 | 22 | //check if bfs traversal returns the same number of nodes as expected 23 | if g.BFStraverse(node) != totalNodes { 24 | fmt.Printf("Edge %v --- %v is a bridge\n", edge.ToNode, node) 25 | } 26 | 27 | // add again the (u, v) edge to graph, in order to check the other edges as well 28 | g.AddEdge(node, edge.ToNode) 29 | } 30 | } 31 | } 32 | 33 | // BFS(Breadth First Search) traversal of the Graph 34 | // check out https://github.com/danrusei/algorithms_with_Go/tree/main/graph/traverse_bfs 35 | //for detailed explanation of the algorithm 36 | func (g *bridges) BFStraverse(n *graph.Node) int { 37 | // Create a queue for BFS 38 | queue := make([]*graph.Node, 0, len(g.Nodes)) 39 | 40 | queue = append(queue, n) 41 | visited := make(map[*graph.Node]bool) 42 | 43 | for len(queue) > 0 { 44 | node := queue[0] 45 | //pop out the Node from the queue 46 | queue = queue[1:] 47 | // add the Node to visited map, ensuring that it will not be added again to the queue 48 | // this prevents to loop endlesssly through the nodes 49 | visited[node] = true 50 | 51 | //edges are the links to other Nodes of the searching Node 52 | for _, edge := range g.Edges[node] { 53 | if !visited[edge.ToNode] { 54 | newNode := edge.ToNode 55 | queue = append(queue, newNode) 56 | visited[newNode] = true 57 | } 58 | 59 | } 60 | 61 | } 62 | return len(visited) 63 | } 64 | 65 | func main() { 66 | // create nodes 67 | n0 := graph.Node{Value: "0"} 68 | n1 := graph.Node{Value: "1"} 69 | n2 := graph.Node{Value: "2"} 70 | n3 := graph.Node{Value: "3"} 71 | n4 := graph.Node{Value: "4"} 72 | 73 | // create a new graph instance 74 | g := new(graph.Graph) 75 | 76 | // add nodes to graph 77 | g.AddNode(&n0) 78 | g.AddNode(&n1) 79 | g.AddNode(&n2) 80 | g.AddNode(&n3) 81 | g.AddNode(&n4) 82 | 83 | // add the edges(links) between nodes 84 | g.AddEdge(&n0, &n1) 85 | g.AddEdge(&n0, &n3) 86 | g.AddEdge(&n0, &n2) 87 | g.AddEdge(&n1, &n2) 88 | g.AddEdge(&n3, &n4) 89 | 90 | s := &bridges{g} 91 | s.findBridge() 92 | } 93 | -------------------------------------------------------------------------------- /graph/dijkstra/README.md: -------------------------------------------------------------------------------- 1 | # Dijkstra Algorithm (Shortest Path First algorithm) 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) 4 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/) 5 | In this implementation we create [the graph from the frontpage](https://github.com/danrusei/algorithms_with_Go/tree/main/graph). 6 | 7 | Dijkstra's algorithm (or Dijkstra's Shortest Path First algorithm, SPF algorithm) is an algorithm for finding the shortest paths between `Nodes` in a `graph`, which may represent, for example, road networks. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later. 8 | For a given source node in the graph, the algorithm finds the shortest path between that node and every other. It can also be used for finding the shortest paths from a single node to a single destination node by stopping the algorithm once the shortest path to the destination node has been determined. 9 | A widely used application of shortest path algorithm is network routing protocols, most notably `IS-IS` (Intermediate System to Intermediate System) and `OSPF` Open Shortest Path First. 10 | 11 | ## Algorithm 12 | 13 | Let the node at which we are starting be called the `initial node`. Let the distance of node Y be the distance from the initial node to Y. Dijkstra's algorithm will assign some initial distance values and will try to improve them step by step. 14 | 15 | * Mark all nodes unvisited. Create a set of all the unvisited nodes called the unvisited set. 16 | * Assign to every node a tentative distance value: set it to zero for our initial node and to infinity( or max Int32) for all other nodes. Set the initial node as current. 17 | * For the current node, consider all of its `unvisited neighbours` and calculate their tentative distances through the current node. Compare the newly calculated tentative distance to the current assigned value and assign the smaller one. For example, if the current node A is marked with a distance of 6, and the edge connecting it with a neighbour B has length 2, then the distance to B through A will be 6 + 2 = 8. If B was previously marked with a distance greater than 8 then change it to 8. Otherwise, the current value will be kept. 18 | * When we are done considering all of the unvisited neighbours of the current node, mark the current node as visited and remove it from the unvisited set. A visited node will never be checked again. 19 | * If the destination node has been marked visited (when planning a route between two specific nodes) or if the smallest tentative distance among the nodes in the unvisited set is infinity (when planning a complete traversal; occurs when there is no connection between the initial node and remaining unvisited nodes), then stop. The algorithm has finished. 20 | * Otherwise, `select the unvisited node that is marked with the smallest tentative distance`, set it as the new "current node", and go back to step 3. 21 | 22 | When planning a route, it is actually not necessary to wait until the destination node is "visited" as above: the algorithm can stop once the destination node has the smallest tentative distance among all "unvisited" nodes (and thus could be selected as the next "current"). 23 | -------------------------------------------------------------------------------- /graph/dijkstra/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | 7 | "github.com/danrusei/algorithms_with_Go/graph" 8 | ) 9 | 10 | type spf struct { 11 | *graph.Graph 12 | } 13 | 14 | // this code calculates shortest distance, but doesn’t calculate the path information. 15 | func (g *spf) dijkstra(n *graph.Node) { 16 | 17 | nrNodes := len(g.Nodes) 18 | 19 | // dist[G] holds the shortest distance from source(in our case node n) to node G 20 | dist := make(map[*graph.Node]int) 21 | 22 | // initialize all distances as int Max and the source node with 0 23 | for _, node := range g.Nodes { 24 | dist[node] = math.MaxInt32 25 | } 26 | 27 | dist[n] = 0 28 | 29 | // visited[G] will be true if Node G is included in shortest path tree 30 | // or shortest distance from source to G is finalized 31 | visited := make(map[*graph.Node]bool) 32 | 33 | //find shortest path to all Nodes 34 | for i := 0; i < nrNodes-1; i++ { 35 | 36 | //Pick the minimum distance Node to the source from the set of vertices not yet processed. 37 | nodeX := g.minDistance(dist, visited) 38 | 39 | // Mark the picked vertex as processed 40 | visited[nodeX] = true 41 | 42 | //update dist value of the adjacent Nodes of the picked Node 43 | for _, nodeY := range g.Nodes { 44 | 45 | if visited[nodeY] || dist[nodeX] == math.MaxInt32 { 46 | continue 47 | } 48 | 49 | //if there is an link between nodeX to nodeY, update dist of adjacent nodes value 50 | for _, link := range g.Edges[nodeX] { 51 | if link.ToNode == nodeY && link.Cost+dist[nodeX] < dist[nodeY] { 52 | dist[nodeY] = dist[nodeX] + link.Cost 53 | } 54 | } 55 | } 56 | } 57 | 58 | fmt.Println(dist) 59 | 60 | } 61 | 62 | // A utility function to find the Node with minimum distance value, from 63 | // the set of Nodes not yet included in shortest path tree 64 | func (g *spf) minDistance(dist map[*graph.Node]int, visited map[*graph.Node]bool) *graph.Node { 65 | min := math.MaxInt32 66 | minNode := &graph.Node{} 67 | 68 | for _, node := range g.Nodes { 69 | if !visited[node] && (dist[node] <= min) { 70 | min = dist[node] 71 | minNode = node 72 | } 73 | } 74 | 75 | return minNode 76 | } 77 | 78 | func main() { 79 | // create nodes 80 | nA := graph.Node{Value: "A"} 81 | nB := graph.Node{Value: "B"} 82 | nC := graph.Node{Value: "C"} 83 | nD := graph.Node{Value: "D"} 84 | nE := graph.Node{Value: "E"} 85 | nF := graph.Node{Value: "F"} 86 | nG := graph.Node{Value: "G"} 87 | nH := graph.Node{Value: "H"} 88 | nI := graph.Node{Value: "I"} 89 | 90 | // create a new graph instance 91 | g := new(graph.Graph) 92 | 93 | // add nodes to graph 94 | g.AddNode(&nA) 95 | g.AddNode(&nB) 96 | g.AddNode(&nC) 97 | g.AddNode(&nD) 98 | g.AddNode(&nE) 99 | g.AddNode(&nF) 100 | g.AddNode(&nG) 101 | g.AddNode(&nH) 102 | g.AddNode(&nI) 103 | 104 | // add the edges(links) between nodes 105 | g.AddEdge(&nA, &nB) 106 | g.AddEdge(&nA, &nC) 107 | g.AddEdge(&nB, &nC) 108 | g.AddEdge(&nB, &nD) 109 | g.AddEdge(&nD, &nE) 110 | g.AddEdge(&nC, &nE) 111 | g.AddEdge(&nC, &nF) 112 | g.AddEdge(&nE, &nF) 113 | g.AddEdge(&nD, &nG) 114 | g.AddEdge(&nG, &nH) 115 | g.AddEdge(&nD, &nH) 116 | g.AddEdge(&nF, &nH) 117 | g.AddEdge(&nG, &nI) 118 | g.AddEdge(&nH, &nI) 119 | 120 | // set the Cost of the Edges (Nodes) 121 | g.SetEdgeValue(&nA, &nB, 4) 122 | g.SetEdgeValue(&nA, &nC, 8) 123 | g.SetEdgeValue(&nB, &nC, 11) 124 | g.SetEdgeValue(&nB, &nD, 8) 125 | g.SetEdgeValue(&nD, &nE, 2) 126 | g.SetEdgeValue(&nC, &nE, 7) 127 | g.SetEdgeValue(&nC, &nF, 1) 128 | g.SetEdgeValue(&nE, &nF, 6) 129 | g.SetEdgeValue(&nD, &nG, 7) 130 | g.SetEdgeValue(&nG, &nH, 14) 131 | g.SetEdgeValue(&nD, &nH, 4) 132 | g.SetEdgeValue(&nF, &nH, 2) 133 | g.SetEdgeValue(&nG, &nI, 9) 134 | g.SetEdgeValue(&nH, &nI, 10) 135 | 136 | // run Dijkstra algorithm 137 | s := &spf{g} 138 | s.dijkstra(&nA) 139 | } 140 | -------------------------------------------------------------------------------- /graph/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/danrusei/algorithms_with_Go/graph 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /graph/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/graph/go.sum -------------------------------------------------------------------------------- /graph/graph.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | // Graph represents the graph structure, which has the list of Nodes 9 | // and the Edges(links) between the Nodes 10 | type Graph struct { 11 | Nodes []*Node 12 | Edges map[*Node][]*Edge 13 | } 14 | 15 | // Node represents a Graph Node (vertex) 16 | // where Value is a discretionary value associated to the node 17 | type Node struct { 18 | Value string 19 | } 20 | 21 | // to be able to print the Node 22 | func (n *Node) String() string { 23 | return fmt.Sprintf("%v", n.Value) 24 | } 25 | 26 | // Edge represents a link between two nodes (vertices) 27 | // the Cost field is the weight between nodes, distance etc 28 | // the ToNode field is the other end of the link (as the Edges map key is the first end) 29 | type Edge struct { 30 | Cost int 31 | ToNode *Node 32 | } 33 | 34 | // to be able to print the Edge 35 | func (e *Edge) String() string { 36 | return fmt.Sprintf("%v", e.ToNode.Value) 37 | } 38 | 39 | // Adjancent : tests whether there is an edge from the node x to the node y; 40 | func (g *Graph) Adjancent(x *Node, y *Node) bool { 41 | if _, ok := g.Edges[x]; ok { 42 | for _, link := range g.Edges[x] { 43 | if link.ToNode == y { 44 | return true 45 | } 46 | } 47 | } 48 | return false 49 | } 50 | 51 | // Neighbors : lists all nodes y such that there is an edge from the node x to the node y; 52 | func (g *Graph) Neighbors(node *Node) ([]*Node, bool) { 53 | var resultedNodes []*Node 54 | 55 | if links, ok := g.Edges[node]; ok { 56 | for _, link := range links { 57 | resultedNodes = append(resultedNodes, link.ToNode) 58 | 59 | } 60 | return resultedNodes, true 61 | } 62 | return nil, false 63 | } 64 | 65 | // AddNode : adds a node if it's not there; 66 | func (g *Graph) AddNode(node *Node) error { 67 | //check if the node is already there 68 | for _, foundNode := range g.Nodes { 69 | if foundNode == node { 70 | return errors.New("Node is already present in the list") 71 | } 72 | } 73 | g.Nodes = append(g.Nodes, node) 74 | return nil 75 | } 76 | 77 | // RemoveNode : removes the node by ID, if it is there; 78 | func (g *Graph) RemoveNode(node *Node) bool { 79 | for idx, foundnode := range g.Nodes { 80 | if foundnode == node { 81 | g.Nodes = append(g.Nodes[:idx], g.Nodes[idx+1:]...) 82 | return true 83 | } 84 | } 85 | return false 86 | } 87 | 88 | // AddEdge : adds the edge from the node x to the node y, if it is not there; 89 | func (g *Graph) AddEdge(x, y *Node) error { 90 | foundNode1, foundNode2 := false, false 91 | for _, node := range g.Nodes { 92 | if x == node { 93 | foundNode1 = true 94 | } else if y == node { 95 | foundNode2 = true 96 | } 97 | } 98 | if !foundNode1 || !foundNode2 { 99 | return errors.New("The nodes couldn't be found") 100 | } 101 | 102 | if g.Edges == nil { 103 | g.Edges = make(map[*Node][]*Edge) 104 | } 105 | 106 | g.Edges[x] = append(g.Edges[x], &Edge{ToNode: y}) 107 | g.Edges[y] = append(g.Edges[y], &Edge{ToNode: x}) 108 | 109 | return nil 110 | } 111 | 112 | // RemoveEdge : removes the edge from the node x to the node y, if it is there; 113 | func (g *Graph) RemoveEdge(x, y *Node) error { 114 | for idx, link := range g.Edges[x] { 115 | if link.ToNode == y { 116 | g.Edges[x] = append(g.Edges[x][:idx], g.Edges[x][idx+1:]...) 117 | } 118 | } 119 | for idx, link := range g.Edges[y] { 120 | if link.ToNode == x { 121 | g.Edges[y] = append(g.Edges[y][:idx], g.Edges[y][idx+1:]...) 122 | } 123 | } 124 | return nil 125 | } 126 | 127 | // GetNodeValue : returns the value associated with the node x; 128 | func (g *Graph) GetNodeValue(x *Node) string { 129 | return x.Value 130 | } 131 | 132 | // SetNodeValue : sets the value associated with the node x to v. 133 | func (g *Graph) SetNodeValue(x *Node, value string) { 134 | x.Value = value 135 | } 136 | 137 | // GetEdgeValue : returns the value associated with the edge (x, y); 138 | func (g *Graph) GetEdgeValue(x *Node, y *Node) int { 139 | for _, link := range g.Edges[x] { 140 | if link.ToNode == y { 141 | return link.Cost 142 | } 143 | } 144 | return 0 145 | } 146 | 147 | // SetEdgeValue : sets the value associated with the edge (x, y) to v. 148 | func (g *Graph) SetEdgeValue(x, y *Node, value int) bool { 149 | doneX := false 150 | doneY := false 151 | for _, link := range g.Edges[x] { 152 | if link.ToNode == y { 153 | link.Cost = value 154 | doneX = true 155 | } 156 | } 157 | for _, link := range g.Edges[y] { 158 | if link.ToNode == x { 159 | link.Cost = value 160 | doneY = true 161 | } 162 | } 163 | if doneX && doneY { 164 | return true 165 | } 166 | return false 167 | } 168 | 169 | // to be able to print the graph 170 | func (g *Graph) String() { 171 | s := "" 172 | for i := 0; i < len(g.Nodes); i++ { 173 | s += g.Nodes[i].String() + " -> " 174 | near := g.Edges[g.Nodes[i]] 175 | for j := 0; j < len(near); j++ { 176 | s += near[j].String() + " " 177 | } 178 | s += "\n" 179 | } 180 | fmt.Println(s) 181 | } 182 | -------------------------------------------------------------------------------- /graph/graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/graph/graph.jpg -------------------------------------------------------------------------------- /graph/graph_test.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var g Graph 9 | 10 | func TestGraph(t *testing.T) { 11 | createGraph() 12 | g.String() 13 | 14 | t.Run("Test AddNode()", func(t *testing.T) { 15 | nG := Node{"G"} 16 | g.AddNode(&nG) 17 | 18 | want := []string{"A", "B", "C", "D", "E", "F", "G"} 19 | got := []string{} 20 | 21 | for _, node := range g.Nodes { 22 | got = append(got, node.Value) 23 | } 24 | 25 | if !reflect.DeepEqual(got, want) { 26 | t.Errorf("got: %v, want: %v", got, want) 27 | } 28 | }) 29 | 30 | t.Run("Test AddEdge()", func(t *testing.T) { 31 | g.AddEdge(g.Nodes[5], g.Nodes[6]) 32 | found := false 33 | 34 | for _, link := range g.Edges[g.Nodes[5]] { 35 | if link.ToNode == g.Nodes[6] { 36 | found = true 37 | } 38 | } 39 | if !found { 40 | t.Errorf("Edge creation has failed") 41 | } 42 | }) 43 | 44 | t.Run("Test RemoveEdge()", func(t *testing.T) { 45 | g.RemoveEdge(g.Nodes[5], g.Nodes[6]) 46 | found := false 47 | 48 | for _, link := range g.Edges[g.Nodes[5]] { 49 | if link.ToNode == g.Nodes[6] { 50 | found = true 51 | } 52 | } 53 | if found { 54 | t.Errorf("Edge deletion has failed") 55 | } 56 | }) 57 | 58 | t.Run("Test RemoveNode()", func(t *testing.T) { 59 | g.RemoveNode(g.Nodes[6]) 60 | 61 | want := []string{"A", "B", "C", "D", "E", "F"} 62 | got := []string{} 63 | 64 | for _, node := range g.Nodes { 65 | got = append(got, node.Value) 66 | } 67 | 68 | if !reflect.DeepEqual(got, want) { 69 | t.Errorf("got: %v, want: %v", got, want) 70 | } 71 | }) 72 | } 73 | 74 | func createGraph() { 75 | nA := Node{"A"} 76 | nB := Node{"B"} 77 | nC := Node{"C"} 78 | nD := Node{"D"} 79 | nE := Node{"E"} 80 | nF := Node{"F"} 81 | g.AddNode(&nA) 82 | g.AddNode(&nB) 83 | g.AddNode(&nC) 84 | g.AddNode(&nD) 85 | g.AddNode(&nE) 86 | g.AddNode(&nF) 87 | 88 | g.AddEdge(&nA, &nB) 89 | g.AddEdge(&nA, &nC) 90 | g.AddEdge(&nB, &nE) 91 | g.AddEdge(&nC, &nE) 92 | g.AddEdge(&nE, &nF) 93 | g.AddEdge(&nD, &nA) 94 | } 95 | -------------------------------------------------------------------------------- /graph/traverse_bfs/Animated_BFS.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/graph/traverse_bfs/Animated_BFS.gif -------------------------------------------------------------------------------- /graph/traverse_bfs/README.md: -------------------------------------------------------------------------------- 1 | # Breadth First Search Traversal 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search) 4 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/) 5 | 6 | Breadth-first search (BFS) is an algorithm for traversing or searching tree or graph data structures. It starts at the tree root (or some arbitrary node of a graph, sometimes referred to as a `search key`), and explores all of the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level. 7 | 8 | It uses the opposite strategy of depth-first search, which instead explores the node branch as far as possible before being forced to backtrack and expand other nodes. 9 | 10 | ## Algorithm 11 | 12 | This is a non-recursive implementation. 13 | 14 | * it uses a queue (First In First Out) instead of a stack which contains the frontier along which the algorithm is currently searching. 15 | * it checks whether a Node (vertex) has been discovered before enqueueing it 16 | * Nodes are labelled as discovered by storing them in a set, or by an attribute on each node, depending on the implementation(in the current implementation we use the `map[*Node]bool`). 17 | 18 | ***Note that the word Node is usually interchangeable with the word Vertex.*** 19 | 20 | ## Example 21 | 22 | ![bfs image](Animated_BFS.gif) 23 | -------------------------------------------------------------------------------- /graph/traverse_bfs/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danrusei/algorithms_with_Go/graph" 7 | ) 8 | 9 | type bfs struct { 10 | *graph.Graph 11 | } 12 | 13 | // BFS(Breadth First Search) traversal of the Graph 14 | func (g *bfs) BFStraverse(n *graph.Node) { 15 | // Create a queue for BFS 16 | queue := make([]*graph.Node, 0, len(g.Nodes)) 17 | 18 | queue = append(queue, n) 19 | visited := make(map[*graph.Node]bool) 20 | 21 | for len(queue) > 0 { 22 | node := queue[0] 23 | //print and the pop out the Node from the queue 24 | fmt.Println(node) 25 | queue = queue[1:] 26 | // add the Node to visited map, ensuring that it will not be added again to the queue 27 | // this prevents to loop endlesssly through the nodes 28 | visited[node] = true 29 | 30 | //edges are the links to other Nodes of the searching Node 31 | for _, edge := range g.Edges[node] { 32 | if !visited[edge.ToNode] { 33 | newNode := edge.ToNode 34 | queue = append(queue, newNode) 35 | visited[newNode] = true 36 | } 37 | 38 | } 39 | 40 | } 41 | } 42 | 43 | func main() { 44 | nA := graph.Node{Value: "A"} 45 | nB := graph.Node{Value: "B"} 46 | nC := graph.Node{Value: "C"} 47 | nD := graph.Node{Value: "D"} 48 | nE := graph.Node{Value: "E"} 49 | nF := graph.Node{Value: "F"} 50 | 51 | g := new(graph.Graph) 52 | 53 | g.AddNode(&nA) 54 | g.AddNode(&nB) 55 | g.AddNode(&nC) 56 | g.AddNode(&nD) 57 | g.AddNode(&nE) 58 | g.AddNode(&nF) 59 | g.AddEdge(&nA, &nB) 60 | g.AddEdge(&nA, &nC) 61 | g.AddEdge(&nB, &nE) 62 | g.AddEdge(&nC, &nE) 63 | g.AddEdge(&nE, &nA) 64 | g.AddEdge(&nD, &nA) 65 | 66 | s := &bfs{g} 67 | s.BFStraverse(&nA) 68 | } 69 | -------------------------------------------------------------------------------- /graph/traverse_dfs/Depth-First-Search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/graph/traverse_dfs/Depth-First-Search.gif -------------------------------------------------------------------------------- /graph/traverse_dfs/README.md: -------------------------------------------------------------------------------- 1 | # Depth First Search Traversal 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search) 4 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/) 5 | 6 | Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures. The algorithm starts at the root node (selecting some arbitrary node as the root node in the case of a graph) and explores as far as possible along each branch before backtracking. 7 | 8 | ## Algorithm 9 | 10 | * create a recursive function that takes the index of node and a visited array. 11 | * mark the current node as visited and print the node. 12 | * traverse all the adjacent and unmarked nodes and call the recursive function with index of adjacent node. 13 | 14 | ## Example 15 | 16 | ![depth first search](Depth-First-Search.gif) 17 | -------------------------------------------------------------------------------- /graph/traverse_dfs/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danrusei/algorithms_with_Go/graph" 7 | ) 8 | 9 | type dfs struct { 10 | *graph.Graph 11 | } 12 | 13 | // DFS(Depth First Search) traversal of the Graph 14 | func (g *dfs) DFStraverse(node *graph.Node) { 15 | 16 | // visited map prevents endlesssly loops through the nodes 17 | visited := make(map[*graph.Node]bool) 18 | 19 | // Call the recursive helper function to print DFS traversal 20 | g.DFSUtil(node, visited) 21 | } 22 | 23 | func (g *dfs) DFSUtil(node *graph.Node, visited map[*graph.Node]bool) { 24 | 25 | // add the Node to visited map, ensuring that it will not looked again 26 | visited[node] = true 27 | fmt.Println(node) 28 | 29 | //edges are the current Node links to the other Nodes 30 | for _, edge := range g.Edges[node] { 31 | if !visited[edge.ToNode] { 32 | newNode := edge.ToNode 33 | g.DFSUtil(newNode, visited) 34 | } 35 | 36 | } 37 | 38 | } 39 | 40 | func main() { 41 | nA := graph.Node{Value: "A"} 42 | nB := graph.Node{Value: "B"} 43 | nC := graph.Node{Value: "C"} 44 | nD := graph.Node{Value: "D"} 45 | 46 | g := new(graph.Graph) 47 | 48 | g.AddNode(&nA) 49 | g.AddNode(&nB) 50 | g.AddNode(&nC) 51 | g.AddNode(&nD) 52 | g.AddEdge(&nA, &nB) 53 | g.AddEdge(&nA, &nC) 54 | g.AddEdge(&nB, &nC) 55 | g.AddEdge(&nC, &nA) 56 | g.AddEdge(&nB, &nC) 57 | g.AddEdge(&nC, &nC) 58 | 59 | s := &dfs{g} 60 | s.DFStraverse(&nA) 61 | } 62 | -------------------------------------------------------------------------------- /linkedlist/README.md: -------------------------------------------------------------------------------- 1 | # Single Linked List 2 | 3 | **[Single Linkedlist Definition](https://en.wikipedia.org/wiki/Linked_list)** 4 | 5 | A linked list is a linear collection of data elements whose order is not given by their physical placement in memory. Instead, each element points to the next. It is a data structure consisting of a collection of nodes which together represent a sequence. In its most basic form, each node contains: data, and a reference (in other words, a link) to the next node in the sequence. This structure allows for efficient insertion or removal of elements from any position in the sequence during iteration. 6 | 7 | ![linked list](linked_list.png) 8 | 9 | The principal benefit of a linked list over a conventional array is that the list elements can be easily inserted or removed without reallocation or reorganization of the entire structure because the data items need not be stored contiguously in memory or on disk, while restructuring an array at run-time is a much more expensive operation. Linked lists allow insertion and removal of nodes at any point in the list, and allow doing so with a constant number of operations by keeping the link previous to the link being added or removed in memory during list traversal. 10 | 11 | This module serves as the base for all executable. So we don't have to redefine the Node, Linkedlist and the basic methods while solving the problems. 12 | -------------------------------------------------------------------------------- /linkedlist/compare_strings/README.md: -------------------------------------------------------------------------------- 1 | # Compare two strings represented as linked lists 2 | 3 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/compare-two-strings-represented-as-linked-lists/amp/) 4 | 5 | Given two strings, represented as linked lists (every character is a node in a linked list). Write a function compare() that works similar to strcmp(), i.e., it returns 0 if both strings are same, 1 if first linked list is lexicographically greater, and -1 if the second string is lexicographically greater. 6 | 7 | ## Example 8 | 9 | ```bash 10 | Input: list1 = g->e->e->k->s->a 11 | list2 = g->e->e->k->s->b 12 | Output: -1 13 | 14 | Input: list1 = g->e->e->k->s->a 15 | list2 = g->e->e->k->s 16 | Output: 1 17 | 18 | Input: list1 = g->e->e->k->s 19 | list2 = g->e->e->k->s 20 | Output: 0 21 | ``` 22 | 23 | ## Algorithm 24 | 25 | * define the linkedlist as below: 26 | 27 | ```go 28 | type Node struct { 29 | Val string 30 | Next *Node 31 | } 32 | 33 | type Linkedlist struct { 34 | Length int 35 | Head *Node 36 | } 37 | ``` 38 | 39 | * compare the length of the 2 lists, and return immediately if they are not the same length 40 | * otherwise compare each element and stop when the lists values are different 41 | 42 | ## Result 43 | 44 | ```bash 45 | $ go test -v 46 | === RUN TestComparedStrings 47 | === RUN TestComparedStrings/second_list_greater 48 | === RUN TestComparedStrings/the_same_list 49 | === RUN TestComparedStrings/first_list_greater 50 | --- PASS: TestComparedStrings (0.00s) 51 | --- PASS: TestComparedStrings/second_list_greater (0.00s) 52 | --- PASS: TestComparedStrings/the_same_list (0.00s) 53 | --- PASS: TestComparedStrings/first_list_greater (0.00s) 54 | PASS 55 | ok github.com/danrusei/algorithms_with_go/linkedlist/compare_strings 0.001s 56 | ``` 57 | -------------------------------------------------------------------------------- /linkedlist/compare_strings/compare.go: -------------------------------------------------------------------------------- 1 | package compare 2 | 3 | func compareStrings(list1 *llist, list2 *llist) int { 4 | // remember that the list is defines as: 5 | // type Linkedlist struct { 6 | // Length int 7 | // Head *Node 8 | // } 9 | // so we have the length to check initialy without comparing all elements in the lists 10 | // however if the lists have the same length we have to compare the elements 11 | 12 | if list1.Length > list2.Length { 13 | return 1 14 | } else if list1.Length < list2.Length { 15 | return -1 16 | } 17 | 18 | cur1 := list1.Head 19 | cur2 := list2.Head 20 | // type assertion is required as the Node value = interface{} 21 | for cur1.Val.(string) == cur2.Val.(string) && cur1.Next != nil { 22 | cur1 = cur1.Next 23 | cur2 = cur2.Next 24 | } 25 | 26 | if cur1.Val.(string) > cur2.Val.(string) { 27 | return 1 28 | } else if cur1.Val.(string) < cur2.Val.(string) { 29 | return -1 30 | } 31 | //asumes the list are equal 32 | return 0 33 | } 34 | -------------------------------------------------------------------------------- /linkedlist/compare_strings/compare_test.go: -------------------------------------------------------------------------------- 1 | package compare 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/danrusei/algorithms_with_go/linkedlist" 7 | ) 8 | 9 | type llist struct { 10 | linkedlist.Linkedlist 11 | } 12 | 13 | // this function creates the lists, 14 | // the way the linkedlist is defined it allows us to check the length 15 | func createLinkedList(vals []string) *llist { 16 | list := llist{} 17 | node := linkedlist.NewNode(vals[0]) 18 | list.Head = node 19 | list.Length = 1 20 | cur := list.Head 21 | for i, val := range vals { 22 | if i == 0 { 23 | continue 24 | } 25 | node := linkedlist.NewNode(val) 26 | cur.Next = node 27 | list.Length++ 28 | } 29 | return &list 30 | } 31 | 32 | func TestComparedStrings(t *testing.T) { 33 | for _, tc := range testcases { 34 | t.Run(tc.name, func(t *testing.T) { 35 | list1 := createLinkedList(tc.list1) 36 | list2 := createLinkedList(tc.list2) 37 | result := compareStrings(list1, list2) 38 | if result != tc.result { 39 | t.Errorf("got: %v, want: %v", result, tc.result) 40 | } 41 | }) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /linkedlist/compare_strings/test_cases.go: -------------------------------------------------------------------------------- 1 | package compare 2 | 3 | var testcases = []struct { 4 | name string 5 | list1 []string 6 | list2 []string 7 | result int 8 | }{ 9 | { 10 | name: "second_list_greater", 11 | list1: []string{"g", "e", "e", "k", "s", "a"}, 12 | list2: []string{"g", "e", "e", "k", "s", "b"}, 13 | result: -1, 14 | }, 15 | { 16 | name: "the_same_list", 17 | list1: []string{"g", "e", "e", "k", "s"}, 18 | list2: []string{"g", "e", "e", "k", "s"}, 19 | result: 0, 20 | }, 21 | { 22 | name: "first_list_greater", 23 | list1: []string{"g", "e", "e", "k", "s", "c"}, 24 | list2: []string{"g", "e", "e", "k", "s"}, 25 | result: 1, 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /linkedlist/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/danrusei/algorithms_with_go/linkedlist 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /linkedlist/insert_node/README.md: -------------------------------------------------------------------------------- 1 | # Given a linked list which is sorted, how will you insert in sorted way 2 | 3 | Based on: https://www.geeksforgeeks.org/given-a-linked-list-which-is-sorted-how-will-you-insert-in-sorted-way/ 4 | 5 | ## Example 6 | 7 | Given linkedlist: 8 | 2 -> 5 -> 7 -> 10 -> 15 9 | 10 | Insert value 9 11 | 12 | Resulted linkedlist: 13 | 2 -> 5 -> 7 -> 9 -> 10 -> 15 14 | 15 | ## Algorithm 16 | 17 | * If Linked list is empty then make the node as head and return it. 18 | * If the value of the node to be inserted is smaller than the value of the head node, then insert the node at the start and make it head. 19 | * In a loop, find the appropriate node after which the input node (let 9) is to be inserted. To find the appropriate node start from the head, keep moving until you reach a node GN (10 in the below diagram) who's value is greater than the input node. The node just before GN is the appropriate node (7). 20 | * Insert the node (9) after the appropriate node (7) found in step 3. 21 | -------------------------------------------------------------------------------- /linkedlist/insert_node/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danrusei/algorithms_with_go/linkedlist" 7 | ) 8 | 9 | type llist struct { 10 | linkedlist.Linkedlist 11 | } 12 | 13 | // method to insert nodes, ordered by the values 14 | func (ll *llist) sortedInsert(n *linkedlist.Node) { 15 | 16 | //special case for the head end 17 | // type assertion is required as the Linked List value = interface{} 18 | if ll.Head == nil || ll.Head.Val.(int) >= n.Val.(int) { 19 | n.Next = ll.Head 20 | ll.Head = n 21 | ll.Length++ 22 | return 23 | } 24 | 25 | //locate the node before the point of insertion 26 | cur := ll.Head 27 | for ; cur.Next != nil && cur.Next.Val.(int) < n.Val.(int); cur = cur.Next { 28 | } 29 | n.Next = cur.Next 30 | cur.Next = n 31 | ll.Length++ 32 | } 33 | 34 | func main() { 35 | list := llist{} 36 | node := linkedlist.NewNode(5) 37 | list.sortedInsert(node) 38 | node = linkedlist.NewNode(8) 39 | list.sortedInsert(node) 40 | node = linkedlist.NewNode(10) 41 | list.sortedInsert(node) 42 | node = linkedlist.NewNode(3) 43 | list.sortedInsert(node) 44 | node = linkedlist.NewNode(1) 45 | list.sortedInsert(node) 46 | node = linkedlist.NewNode(9) 47 | list.sortedInsert(node) 48 | 49 | fmt.Println(list.String()) 50 | } 51 | -------------------------------------------------------------------------------- /linkedlist/linked_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/linkedlist/linked_list.png -------------------------------------------------------------------------------- /linkedlist/linkedlist.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package linkedlist implements: 3 | Create a a new Linkedlist and Node 4 | Insert a Node at the beginning of the list 5 | Insert a Node at the end of the list 6 | Delete a Node from the beginning of the list 7 | Delete a Node from the end of the list 8 | Print the Linkedlis 9 | */ 10 | package linkedlist 11 | 12 | import "fmt" 13 | 14 | // Node struct holds a node 15 | // the value of the Node could be anything (int, string or a struncture) 16 | // interface{} - an empty interface may hold values of any type. 17 | // if using interface{} confuse you, change with any type you would like 18 | // initially I started with int value, but some problems require strings as values 19 | // another example: implementing Hash-Table I need even to define a Key-Value struct 20 | type Node struct { 21 | Val interface{} 22 | Next *Node 23 | } 24 | 25 | // Linkedlist struct holds a linked list 26 | type Linkedlist struct { 27 | Length int 28 | Head *Node 29 | } 30 | 31 | // NewLinkedlist creates a new linked list 32 | func NewLinkedlist() *Linkedlist { 33 | return &Linkedlist{} 34 | } 35 | 36 | // NewNode creates a new node 37 | func NewNode(val interface{}) *Node { 38 | return &Node{val, nil} 39 | } 40 | 41 | // utility function to print the linkedlist 42 | func (ll *Linkedlist) String() string { 43 | cur := ll.Head 44 | var printedlist string 45 | for ; cur.Next != nil; cur = cur.Next { 46 | printedlist = printedlist + fmt.Sprintf("%v \t", cur.Val) 47 | } 48 | printedlist = printedlist + fmt.Sprintf("%v", cur.Val) 49 | return printedlist 50 | } 51 | 52 | //AddAtBeg adds a Node at the beginning of the list 53 | func (ll *Linkedlist) AddAtBeg(val interface{}) { 54 | n := NewNode(val) 55 | n.Next = ll.Head 56 | ll.Head = n 57 | ll.Length++ 58 | 59 | } 60 | 61 | //AddAtEnd adds a Node at the end of the list 62 | func (ll *Linkedlist) AddAtEnd(val interface{}) { 63 | n := NewNode(val) 64 | 65 | if ll.Head == nil { 66 | ll.Head = n 67 | ll.Length++ 68 | return 69 | } 70 | 71 | cur := ll.Head 72 | for ; cur.Next != nil; cur = cur.Next { 73 | } 74 | 75 | cur.Next = n 76 | ll.Length++ 77 | } 78 | 79 | //DelAtBeg deletes a node from the beginning of the list 80 | func (ll *Linkedlist) DelAtBeg() interface{} { 81 | if ll.Head == nil { 82 | return -1 83 | } 84 | cur := ll.Head 85 | ll.Head = cur.Next 86 | ll.Length-- 87 | 88 | return cur.Val 89 | } 90 | 91 | //DelAtEnd deletes a node from the end of the list 92 | func (ll *Linkedlist) DelAtEnd() interface{} { 93 | if ll.Head == nil { 94 | return -1 95 | } 96 | 97 | cur := ll.Head 98 | for ; cur.Next.Next != nil; cur = cur.Next { 99 | } 100 | 101 | val := cur.Next.Val 102 | cur.Next = nil 103 | ll.Length-- 104 | 105 | return val 106 | } 107 | 108 | //DeleteWithValute deletes a node which value is equal to the function parameter 109 | func (ll *Linkedlist) DeleteWithValute(val interface{}) interface{} { 110 | if ll.Head == nil { 111 | return -1 112 | } 113 | 114 | cur := ll.Head 115 | for cur.Next.Val != val { 116 | if cur.Next.Next == nil { 117 | return -1 118 | } 119 | cur = cur.Next 120 | } 121 | value := cur.Next.Val 122 | cur.Next = cur.Next.Next 123 | ll.Length-- 124 | 125 | return value 126 | } 127 | -------------------------------------------------------------------------------- /linkedlist/linkedlist_test.go: -------------------------------------------------------------------------------- 1 | package linkedlist 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestLinkedList(t *testing.T) { 9 | list := NewLinkedlist() 10 | list.AddAtBeg(1) 11 | list.AddAtBeg(2) 12 | list.AddAtBeg(3) 13 | 14 | t.Run("Test AddAtBeg()", func(t *testing.T) { 15 | want := []int{3, 2, 1} 16 | got := []int{} 17 | current := list.Head 18 | got = append(got, current.Val.(int)) 19 | for current.Next != nil { 20 | current = current.Next 21 | got = append(got, current.Val.(int)) 22 | } 23 | if !reflect.DeepEqual(got, want) { 24 | t.Errorf("got: %v, want: %v", got, want) 25 | } 26 | }) 27 | 28 | list.AddAtEnd(4) 29 | 30 | t.Run("Test AddAtEnd()", func(t *testing.T) { 31 | want := []int{3, 2, 1, 4} 32 | got := []int{} 33 | current := list.Head 34 | got = append(got, current.Val.(int)) 35 | for current.Next != nil { 36 | current = current.Next 37 | got = append(got, current.Val.(int)) 38 | } 39 | if !reflect.DeepEqual(got, want) { 40 | t.Errorf("got: %v, want: %v", got, want) 41 | } 42 | }) 43 | 44 | t.Run("Test DelAtBeg()", func(t *testing.T) { 45 | want := int(3) 46 | got := list.DelAtBeg() 47 | if got != want { 48 | t.Errorf("got: %v, want: %v", got, want) 49 | } 50 | }) 51 | 52 | t.Run("Test DelAtEnd()", func(t *testing.T) { 53 | want := int(4) 54 | got := list.DelAtEnd() 55 | if got != want { 56 | t.Errorf("got: %v, want: %v", got, want) 57 | } 58 | }) 59 | 60 | t.Run("Test DeleteWithValute", func(t *testing.T) { 61 | want := 1 62 | got := list.DeleteWithValute(1) 63 | if got != want { 64 | t.Errorf("got: %v, want: %v", got, want) 65 | } 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /linkedlist/random_node/README.md: -------------------------------------------------------------------------------- 1 | # Select a Random Node from a Singly Linked List 2 | 3 | Problem description: [GeeksforGeeks](https://www.geeksforgeeks.org/select-a-random-node-from-a-singly-linked-list/amp/) 4 | 5 | Given a singly linked list, select a random node from linked list (the probability of picking a node should be 1/N if there are N nodes in list). You are given a random number generator. 6 | 7 | ## Algorithm 8 | 9 | * initialize result as first node 10 | * initialize n = 2 11 | * traverse the linked list 12 | * generate a random number from 0 to n-1. 13 | * if the number is equal to 0, then replace result with current node. 14 | * n++ 15 | 16 | ## Result 17 | 18 | ```bash 19 | $ go run main.go 20 | 7 21 | $ go run main.go 22 | 1 23 | $ go run main.go 24 | 9 25 | $ go run main.go 26 | 3 27 | $ go run main.go 28 | 10 29 | $ go run main.go 30 | 9 31 | $ go run main.go 32 | 5 33 | ``` 34 | -------------------------------------------------------------------------------- /linkedlist/random_node/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | 8 | "github.com/danrusei/algorithms_with_go/linkedlist" 9 | ) 10 | 11 | type llist struct { 12 | linkedlist.Linkedlist 13 | } 14 | 15 | // we can easily select a random node by using the length field of the linkedlist 16 | // let's assume this time that the length field has not been defined 17 | func (ll *llist) randomNode() int { 18 | if ll.Head == nil { 19 | return 0 20 | } 21 | 22 | //NewSource returns a new pseudo-random Source seeded with the given value. 23 | r1 := rand.NewSource(time.Now().UnixNano()) 24 | //New returns a new Rand that uses random values from x1 to generate other random values. 25 | r2 := rand.New(r1) 26 | 27 | result := ll.Head.Val 28 | cur := ll.Head 29 | 30 | // traverse the list and increase the n, which is the length of the yet discovered list 31 | n := 2 32 | for ; cur.Next != nil; cur = cur.Next { 33 | 34 | if r2.Int()%n == 0 { 35 | result = cur.Val 36 | } 37 | n++ 38 | } 39 | 40 | // type assertion is required because Linked List value = interface{} 41 | return result.(int) 42 | } 43 | 44 | func main() { 45 | list := llist{} 46 | list.AddAtEnd(5) 47 | list.AddAtEnd(8) 48 | list.AddAtEnd(10) 49 | list.AddAtEnd(3) 50 | list.AddAtEnd(1) 51 | list.AddAtEnd(9) 52 | list.AddAtEnd(7) 53 | list.AddAtEnd(2) 54 | 55 | result := list.randomNode() 56 | fmt.Println(result) 57 | } 58 | -------------------------------------------------------------------------------- /linkedlist/remove_loop/README.md: -------------------------------------------------------------------------------- 1 | # Detect and Remove Loop in a Linked List 2 | 3 | From **[GeeksforGeeks](https://www.geeksforgeeks.org/detect-and-remove-loop-in-a-linked-list/amp/)** 4 | 5 | ## Example 6 | 7 | Given linkedlist: 8 | 1 -> 2 -> 3 -> 4 -> 5 9 | ..............|.............| 10 | ..............8 <- 7 <- 6 11 | 12 | Detect and remove the loop. 13 | 14 | Resulted linkedlist: 15 | 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 16 | 17 | ## Algorithm 18 | 19 | * use Floyd’s Cycle detection algorithm that terminates when fast and slow pointers meet at a common point. 20 | * the common point can be one of the loop nodes (3 or 4 or 5 or 6 or 7 or 8 in the above example) 21 | * store the address of this in a pointer variable say `ptr2` 22 | * start from the head of the Linked List (`ptr1`) and check for nodes one by one if they are reachable from `ptr2` 23 | * whenever we find a node that is reachable, we know that this node is the starting node of the loop in Linked List and we can get the pointer to the previous of this node 24 | * set the `ptr2` to nil to break the loop 25 | -------------------------------------------------------------------------------- /linkedlist/remove_loop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danrusei/algorithms_with_go/linkedlist" 7 | ) 8 | 9 | type llist struct { 10 | linkedlist.Linkedlist 11 | } 12 | 13 | //DetectAndRemove detects the loop, if any returns true and runs removeLoop function to remove the loop 14 | func (ll *llist) DetectAndRemove() bool { 15 | slow := ll.Head 16 | fast := ll.Head 17 | 18 | //for loop is running until it reach the end of the list, therefore there is no loop 19 | //or the loop has been identified as the `slow` node is equal to `fast` node 20 | for { 21 | if slow.Next == nil || fast.Next == nil || fast.Next.Next == nil { 22 | break 23 | } 24 | slow = slow.Next 25 | fast = fast.Next.Next 26 | 27 | if slow == fast { 28 | ll.removeLoop(slow) 29 | return true 30 | } 31 | } 32 | 33 | return false 34 | } 35 | 36 | // loopNode --> Pointer to one of the loop nodes 37 | func (ll *llist) removeLoop(loopNode *linkedlist.Node) { 38 | 39 | ptr1 := ll.Head 40 | ptr2 := &linkedlist.Node{} 41 | 42 | //we know that the linkedlist has a loop 43 | //ptr2 is an element inside the loop, can be 3, 4, 5, 6, 7 or 8 44 | //ptr1 advance node by node until ptr2.Next == ptr1 45 | for { 46 | ptr2 = loopNode 47 | for ; ptr2.Next != loopNode && ptr2.Next != ptr1; ptr2 = ptr2.Next { 48 | } 49 | if ptr2.Next == ptr1 { 50 | break 51 | } 52 | 53 | ptr1 = ptr1.Next 54 | } 55 | 56 | // remove the loop by seting the pointer of last element to nil 57 | ptr2.Next = nil 58 | } 59 | 60 | func main() { 61 | list := llist{} 62 | list.AddAtEnd(1) 63 | list.AddAtEnd(2) 64 | list.AddAtEnd(3) 65 | list.AddAtEnd(4) 66 | list.AddAtEnd(5) 67 | list.AddAtEnd(6) 68 | list.AddAtEnd(7) 69 | list.AddAtEnd(8) 70 | 71 | endNode := list.Head 72 | for ; endNode.Next != nil; endNode = endNode.Next { 73 | } 74 | //create the loop 75 | endNode.Next = list.Head.Next.Next 76 | 77 | fmt.Println(list.DetectAndRemove()) 78 | fmt.Println(list.String()) 79 | } 80 | -------------------------------------------------------------------------------- /linkedlist/reverse_by_groups/README.md: -------------------------------------------------------------------------------- 1 | # Reverse a Linked List in groups of given size 2 | 3 | From **[GeeksforGeeks](https://www.geeksforgeeks.org/reverse-a-list-in-groups-of-given-size/amp/)** 4 | 5 | ## Example 6 | 7 | Given a linked list, write a function to reverse every k nodes (where k is an input to the function). 8 | 9 | > Example: 10 | > 11 | > Input: 1->2->3->4->5->6->7->8->NULL, K = 3 12 | > Output: 3->2->1->6->5->4->8->7->NULL 13 | > 14 | > Input: 1->2->3->4->5->6->7->8->NULL, K = 5 15 | > Output: 5->4->3->2->1->8->7->6->NULL 16 | 17 | ## Algorithm 18 | 19 | * Reverse the first sub-list of size k. While reversing keep track of the next node and previous node. Let the pointer to the next node be next and pointer to the previous node be prev. 20 | * head->next = reverse(next, k) ( Recursively call for rest of the list and link the two sub-lists ) 21 | * Return prev ( prev becomes the new head of the list) 22 | -------------------------------------------------------------------------------- /linkedlist/reverse_by_groups/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/danrusei/algorithms_with_go/linkedlist" 7 | ) 8 | 9 | type llist struct { 10 | linkedlist.Linkedlist 11 | } 12 | 13 | // Reverses the linked list in groups of size k and returns the pointer to the new head node. 14 | func (ll *llist) reverseGroups(node *linkedlist.Node, k int) *linkedlist.Node { 15 | curr := node 16 | next := &linkedlist.Node{} 17 | prev := &linkedlist.Node{} 18 | count := 0 19 | 20 | // reverse first k nodes of the linked list 21 | for { 22 | if curr == nil || count > k { 23 | break 24 | } 25 | next = curr.Next 26 | curr.Next = prev 27 | prev = curr 28 | curr = next 29 | count++ 30 | } 31 | 32 | // next is now a pointer to (k+1)th node 33 | // Recursively call for the list starting from current. 34 | // And make rest of the list as next of first node 35 | if next != nil { 36 | ll.Head.Next = ll.reverseGroups(next, k) 37 | } 38 | 39 | // prev is new head of the input list 40 | return prev 41 | } 42 | 43 | func main() { 44 | list := llist{} 45 | list.AddAtEnd(9) 46 | list.AddAtEnd(8) 47 | list.AddAtEnd(7) 48 | list.AddAtEnd(6) 49 | list.AddAtEnd(5) 50 | list.AddAtEnd(4) 51 | list.AddAtEnd(3) 52 | list.AddAtEnd(2) 53 | list.AddAtEnd(1) 54 | fmt.Println(list.String()) 55 | 56 | list.Head = list.reverseGroups(list.Head, 3) 57 | fmt.Println(list.String()) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /numbers/README.md: -------------------------------------------------------------------------------- 1 | # Numbers 2 | 3 | Articles about numbers in Go: 4 | 5 | * [Understanding Data Types in Go](https://www.digitalocean.com/community/tutorials/understanding-data-types-in-go) 6 | 7 | ## Related Go packages 8 | 9 | * Math [pkg.go.dev](https://pkg.go.dev/math@go1.15.6) 10 | * Strconv [pkg.go.dev](https://pkg.go.dev/strconv@go1.15.6) 11 | -------------------------------------------------------------------------------- /numbers/eratosthenes/README.md: -------------------------------------------------------------------------------- 1 | # Sieve of Eratosthenes 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/sieve-of-eratosthenes/amp/) 4 | Source: [Wikipedia - Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) 5 | 6 | Given a number n, print all primes smaller than or equal to n. It is also given that n is a small number. 7 | 8 | ## Example 9 | 10 | > Input : n =10 11 | > Output : 2 3 5 7 12 | > 13 | > Input : n = 20 14 | > Output: 2 3 5 7 11 13 17 19 15 | 16 | ## Algorithm 17 | 18 | A prime number is a natural number that has exactly two distinct natural number divisors: the number 1 and itself. 19 | 20 | To find all the prime numbers less than or equal to a given integer n by Eratosthenes' method: 21 | 22 | * Create a list of consecutive integers from 2 through n: (2, 3, 4, ..., n). 23 | * Initially, let p equal 2, the smallest prime number. 24 | * Enumerate the multiples of p by counting in increments of p from 2p to n, and mark them in the list (these will be 2p, 3p, 4p, ...; the p itself should not be marked). 25 | * Find the smallest number in the list greater than p that is not marked. If there was no such number, stop. Otherwise, let p now equal this new number (which is the next prime), and repeat from step 3. 26 | * When the algorithm terminates, the numbers remaining not marked in the list are all the primes below n. 27 | 28 | The main idea here is that every value given to p will be prime, because if it were composite it would be marked as a multiple of some other, smaller prime. Note that some of the numbers may be marked more than once (e.g., 15 will be marked both for 3 and 5). 29 | 30 | As a refinement, it is sufficient to mark the numbers **in step 3 starting from p * p**, as all the smaller multiples of p will have already been marked at that point. This means that the algorithm is allowed to terminate in step 4 when p2 is greater than n. 31 | 32 | ## Result 33 | 34 | ```bash 35 | $ go test -v 36 | === RUN TestReverse 37 | === RUN TestReverse/10_value 38 | === RUN TestReverse/20_value 39 | === RUN TestReverse/99_value 40 | --- PASS: TestReverse (0.00s) 41 | --- PASS: TestReverse/10_value (0.00s) 42 | --- PASS: TestReverse/20_value (0.00s) 43 | --- PASS: TestReverse/99_value (0.00s) 44 | PASS 45 | ``` 46 | -------------------------------------------------------------------------------- /numbers/eratosthenes/primes.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | func primes(num int) []int { 4 | numbers := make([]bool, num) 5 | 6 | //create the slice of bools and mark initially all true 7 | //a value in numbers[i] will finally be false if i is Not a prime, else true. 8 | for i := 0; i < num; i++ { 9 | numbers[i] = true 10 | } 11 | 12 | for p := 2; p*p < num; p++ { 13 | //if numbers[p] is not changed, then it is a prime 14 | // this selects only the alreade identified prime numbers 15 | if numbers[p] { 16 | // search for multiple of p, and mark them as false 17 | for i := p * p; i < num; i += p { 18 | numbers[i] = false 19 | } 20 | } 21 | } 22 | 23 | //create the list that containts only the prime numbers 24 | primes := []int{} 25 | for i := 2; i < num; i++ { 26 | if numbers[i] { 27 | primes = append(primes, i) 28 | } 29 | } 30 | return primes 31 | } 32 | -------------------------------------------------------------------------------- /numbers/eratosthenes/primes_test.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestReverse(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | result := primes(tc.num) 12 | if !reflect.DeepEqual(result, tc.expected) { 13 | t.Errorf("Expected: %d, got: %d", tc.expected, result) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /numbers/eratosthenes/test_cases.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | var testcases = []struct { 4 | name string 5 | num int 6 | expected []int 7 | }{ 8 | { 9 | name: "10_value", 10 | num: 10, 11 | expected: []int{2, 3, 5, 7}, 12 | }, 13 | { 14 | name: "20_value", 15 | num: 20, 16 | expected: []int{2, 3, 5, 7, 11, 13, 17, 19}, 17 | }, 18 | { 19 | name: "99_value", 20 | num: 99, 21 | expected: []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /numbers/multiplicative/README.md: -------------------------------------------------------------------------------- 1 | # Modular multiplicative inverse 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/amp/) 4 | Source: [Wikipedia - Modular Multiplicative Inverse](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse) 5 | 6 | Given two integers ‘a’ and ‘m’, find modular multiplicative inverse of ‘a’ under modulo ‘m’. 7 | The modular multiplicative inverse is an integer ‘x’ such that. 8 | 9 | a x ≅ 1 (mod m) 10 | 11 | The value of x should be in {0, 1, 2, … m-1}, i.e., in the range of integer modulo m. 12 | The multiplicative inverse of “a modulo m” exists if and only if a and m are relatively prime (i.e., if gcd(a, m) = 1). 13 | 14 | ## Example 15 | 16 | > Input: a = 3, m = 11 17 | > Output: 4 18 | > Since (4*3) mod 11 = 1, 4 is modulo inverse of 3(under 11). 19 | > One might think, 15 also as a valid output as "(15*3) mod 11" 20 | is also 1, but 15 is not in ring {0, 1, 2, ... 10}, so not 21 | valid. 22 | > 23 | > Input: a = 10, m = 17 24 | > Output: 12 25 | > Since (10*12) mod 17 = 1, 12 is modulo inverse of 10(under 17). 26 | -------------------------------------------------------------------------------- /numbers/multiplicative/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func modInverse(a int, m int) int { 6 | m0 := m 7 | x, y := 1, 0 8 | 9 | if m == 1 { 10 | return 0 11 | } 12 | 13 | for a > 1 { 14 | // q is quotient 15 | q := a / m 16 | t := m 17 | 18 | // m is remainder now, process same as Euclid's algo 19 | m = a % m 20 | a = t 21 | t = y 22 | 23 | // update y and x 24 | y = x - q*y 25 | x = t 26 | } 27 | 28 | // make x positive 29 | if x < 0 { 30 | x += m0 31 | } 32 | 33 | return x 34 | } 35 | 36 | func main() { 37 | a, m := 3, 11 38 | fmt.Printf("Modular multiplicative inverse is %d\n", modInverse(a, m)) 39 | } 40 | -------------------------------------------------------------------------------- /numbers/segmented/README.md: -------------------------------------------------------------------------------- 1 | # Segmented Sieve 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/segmented-sieve/amp/) 4 | Source: [Wikipedia - Segmented Sieves](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve) 5 | 6 | Given a number n, print all primes smaller than or equal to n. 7 | 8 | The implemented [Sieve of Eratosthenes](https://github.com/danrusei/algorithms_with_Go/tree/main/numbers/eratosthenes) looks good, but consider the situation when n is large, the Simple Sieve faces following issues: 9 | 10 | * an array of size Θ(n) may not fit in memory 11 | * the simple Sieve is not cache friendly even for slightly bigger n. The algorithm traverses the array without locality of reference 12 | 13 | ## Example 14 | 15 | > Input : n =10 16 | > Output : 2 3 5 7 17 | > 18 | > Input : n = 20 19 | > Output: 2 3 5 7 11 13 17 19 20 | 21 | ## Algorithm 22 | 23 | The idea of segmented sieve is to divide the range [0..n-1] in different segments and compute primes in all segments one by one. This algorithm first uses Simple Sieve to find primes smaller than or equal to √(n). 24 | 25 | * use Simple Sieve to find all primes upto square root of ‘n’ and store these primes in an array “prime[]”. Store the found primes in an array ‘prime[]’. 26 | * divide [0..n-1] range in different segments such that size of every segment is at-most √n 27 | * for every segment [low..high] 28 | * create an array mark[high-low+1]. Here we need only O(x) space where x is number of elements in given range. 29 | * iterate through all primes found in step 1. For every prime, mark its multiples in given range [low..high]. 30 | 31 | In Simple Sieve, we needed O(n) space which may not be feasible for large n. Here we need O(√n) space and we process smaller ranges at a time (locality of reference) 32 | 33 | ## Result 34 | 35 | ```bash 36 | go test -v 37 | === RUN TestPrimes 38 | === RUN TestPrimes/10_value 39 | === RUN TestPrimes/20_value 40 | === RUN TestPrimes/99_value 41 | --- PASS: TestPrimes (0.00s) 42 | --- PASS: TestPrimes/10_value (0.00s) 43 | --- PASS: TestPrimes/20_value (0.00s) 44 | --- PASS: TestPrimes/99_value (0.00s) 45 | PASS 46 | ``` 47 | -------------------------------------------------------------------------------- /numbers/segmented/primes.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | import "math" 4 | 5 | func segmentedSieve(num int) []int { 6 | limit := int(math.Floor(math.Sqrt(float64(num))) + 1) 7 | primes := getPrimes(limit) 8 | 9 | result := []int{} 10 | 11 | low := limit 12 | high := limit * 2 13 | 14 | for low < num { 15 | if high >= num { 16 | high = num 17 | } 18 | 19 | // mark primes in current range. A value in mark[i] 20 | // will finally be false if 'i-low' is Not a prime, else true. 21 | mark := make([]bool, limit+1) 22 | for i := 0; i < limit+1; i++ { 23 | mark[i] = true 24 | } 25 | 26 | for i := 0; i < len(primes); i++ { 27 | 28 | //find the minimum number in [low..high] that is a multiple of prime[i] 29 | loLim := int(math.Floor(float64(low/primes[i])) * float64(primes[i])) 30 | 31 | if loLim < low { 32 | loLim += primes[i] 33 | } 34 | // mark multiples of prime[i] in [low..high]: marking j - low for j 35 | for j := loLim; j < high; j += primes[i] { 36 | mark[j-low] = false 37 | } 38 | } 39 | 40 | for i := low; i < high; i++ { 41 | if mark[i-low] { 42 | result = append(result, i) 43 | } 44 | } 45 | 46 | // update low and high for next segment 47 | low = low + limit 48 | high = high + limit 49 | 50 | } 51 | primes = append(primes, result...) 52 | return primes 53 | } 54 | 55 | func getPrimes(num int) []int { 56 | numbers := make([]bool, num) 57 | 58 | //create the slice of bools and mark initially all true 59 | //a value in numbers[i] will finally be false if i is Not a prime, else true. 60 | for i := 0; i < num; i++ { 61 | numbers[i] = true 62 | } 63 | 64 | for p := 2; p*p < num; p++ { 65 | //if numbers[p] is not changed, then it is a prime 66 | // this selects only the alreade identified prime numbers 67 | if numbers[p] { 68 | // search for multiple of p, and mark them as false 69 | for i := p * p; i < num; i += p { 70 | numbers[i] = false 71 | } 72 | } 73 | } 74 | 75 | //create the list that containts only the prime numbers 76 | primes := []int{} 77 | for i := 2; i < num; i++ { 78 | if numbers[i] { 79 | primes = append(primes, i) 80 | } 81 | } 82 | return primes 83 | } 84 | -------------------------------------------------------------------------------- /numbers/segmented/primes_test.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestPrimes(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | result := segmentedSieve(tc.num) 12 | if !reflect.DeepEqual(result, tc.expected) { 13 | t.Errorf("Expected: %d, got: %d", tc.expected, result) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /numbers/segmented/test_cases.go: -------------------------------------------------------------------------------- 1 | package primes 2 | 3 | var testcases = []struct { 4 | name string 5 | num int 6 | expected []int 7 | }{ 8 | { 9 | name: "10_value", 10 | num: 10, 11 | expected: []int{2, 3, 5, 7}, 12 | }, 13 | { 14 | name: "20_value", 15 | num: 20, 16 | expected: []int{2, 3, 5, 7, 11, 13, 17, 19}, 17 | }, 18 | { 19 | name: "99_value", 20 | num: 99, 21 | expected: []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /other_ds/README.md: -------------------------------------------------------------------------------- 1 | # Other Data Structures 2 | 3 | Other data structures and algorithms that are not mentioned in the article but it worth to be mentioned. 4 | -------------------------------------------------------------------------------- /other_ds/hashtable/README.md: -------------------------------------------------------------------------------- 1 | # HashTable (HashMap) 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) 4 | 5 | A Hash Table (Hash Map) is a data structure that implements an associative array abstract data type, a structure that can `map keys to values`. A hash table uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found. During lookup, the key is hashed and the resulting hash indicates where the corresponding value is stored. 6 | 7 | Ideally, the hash function will assign each key to a unique bucket, but most hash table designs employ an imperfect hash function, which might cause hash collisions where the hash function generates the same index for more than one key. Such collisions are typically accommodated in some way. 8 | 9 | ## Collision resolution with linked list chaining 10 | 11 | The most common hash table implementation uses chaining with linked lists to resolve collisions. This combines the best properties of arrays and linked lists. 12 | 13 | Hash table operations are performed in two steps: 14 | 15 | * a key is converted into an integer index by using a hash function. 16 | * the index decides the bucket (which is a linked list) where the key-value pair record belongs. 17 | 18 | ![hash table](hash_table.png) 19 | 20 | As you can see in the above diagram, two keys have the same calculated bucket, `152`, meaning that there is a collision that can be resolved by chaining the records into a linked list. 21 | Check Out the [Linked List material](https://github.com/danrusei/algorithms_with_Go/tree/main/linkedlist) if you are not familiar with this data structure. 22 | 23 | ## Result 24 | 25 | The underlying array used for my HashTable implementation has a length of 16. I created a utility function String() to print out how the KV elements are distributed across the array. The colision was resolved by chaining the elements from the same bucket into a linked list. 26 | 27 | ```bash 28 | $ go run bin/main.go 29 | Bucket 0 has the following Nodes: {first 1} 30 | Bucket 1 has the following Nodes: {tenth 10} {seventh 7} 31 | Bucket 2 has no Nodes 32 | Bucket 3 has no Nodes 33 | Bucket 4 has the following Nodes: {second 2} 34 | Bucket 5 has the following Nodes: {eleventh 11} 35 | Bucket 6 has the following Nodes: {nineth 9} {sixth 6} 36 | Bucket 7 has the following Nodes: {eigth 8} {fifth 5} 37 | Bucket 8 has no Nodes 38 | Bucket 9 has the following Nodes: {thrid 3} 39 | Bucket 10 has the following Nodes: {fourth 4} 40 | Bucket 11 has no Nodes 41 | Bucket 12 has no Nodes 42 | Bucket 13 has no Nodes 43 | Bucket 14 has no Nodes 44 | Bucket 15 has no Nodes 45 | ``` 46 | -------------------------------------------------------------------------------- /other_ds/hashtable/bin/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/danrusei/algorithms_with_go/other_ds/hashtable" 5 | ) 6 | 7 | func main() { 8 | 9 | hashmap := hashtable.New() 10 | hashmap.AddKeyValue("first", 1) 11 | hashmap.AddKeyValue("second", 2) 12 | hashmap.AddKeyValue("thrid", 3) 13 | hashmap.AddKeyValue("fourth", 4) 14 | hashmap.AddKeyValue("fifth", 5) 15 | hashmap.AddKeyValue("sixth", 6) 16 | hashmap.AddKeyValue("seventh", 7) 17 | hashmap.AddKeyValue("eigth", 8) 18 | hashmap.AddKeyValue("nineth", 9) 19 | hashmap.AddKeyValue("tenth", 10) 20 | hashmap.AddKeyValue("eleventh", 11) 21 | 22 | hashmap.String() 23 | } 24 | -------------------------------------------------------------------------------- /other_ds/hashtable/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/danrusei/algorithms_with_go/other_ds/hashtable 2 | 3 | go 1.15 4 | 5 | require github.com/danrusei/algorithms_with_go/linkedlist v0.0.0-20210125085227-cd4bff82e7da 6 | -------------------------------------------------------------------------------- /other_ds/hashtable/go.sum: -------------------------------------------------------------------------------- 1 | github.com/danrusei/algorithms_with_go/linkedlist v0.0.0-20210125085227-cd4bff82e7da h1:DOPoDxOOM08z89857bKTZ21+8ZfdTcTFYktbqw2Lvas= 2 | github.com/danrusei/algorithms_with_go/linkedlist v0.0.0-20210125085227-cd4bff82e7da/go.mod h1:NvwyzxbWSyZ4nFJnb4zQeKo8BYBRhs/uEAz/epGzG7Y= 3 | -------------------------------------------------------------------------------- /other_ds/hashtable/hash_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/other_ds/hashtable/hash_table.png -------------------------------------------------------------------------------- /other_ds/hashtable/hashtable.go: -------------------------------------------------------------------------------- 1 | package hashtable 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | 7 | "github.com/danrusei/algorithms_with_go/linkedlist" 8 | ) 9 | 10 | // kv stores the HashMap key-value pair 11 | type kv struct { 12 | key string 13 | value interface{} 14 | } 15 | 16 | // the linked list that stores the chained value of each Bucket 17 | //type llist struct { 18 | // linkedlist.Linkedlist 19 | //} 20 | 21 | // number the buckets, it is in fact the length of the array, which is the underlying structure of the hashtable 22 | const bucketCount = 16 23 | 24 | // HashTable data structure is the central structure of the package 25 | type HashTable struct { 26 | data [bucketCount]*linkedlist.Linkedlist 27 | } 28 | 29 | // New is the HashTable constructor 30 | func New() *HashTable { 31 | return &HashTable{ 32 | [bucketCount]*linkedlist.Linkedlist{}, 33 | } 34 | } 35 | 36 | // the hash algorithm to convert the key to an integer of 0 - bucketCount as the index of the array to store/retrieve value. 37 | // the hash algorithm should be as random as possible 38 | // so that the newly added key-value pairs are evenly distributed under each array. 39 | // Java’s implementation of hash functions for strings is a good example: 40 | // key[0]·31n-1 + key[1]·31n-2 + … + key[n-1] -- where n is the length of the key 41 | func hash(key string) int { 42 | hash := 0 43 | for index, char := range key { 44 | hash += int(char) * int(math.Pow(31, float64(len(key)-index+1))) 45 | } 46 | 47 | //the reminder is the selected bucket 48 | bucket := hash % bucketCount 49 | return bucket 50 | } 51 | 52 | // AddKeyValue pairs to HashTable 53 | func (myMap *HashTable) AddKeyValue(key string, value interface{}) { 54 | bucket := hash(key) 55 | 56 | if myMap.data[bucket] == nil { 57 | myMap.data[bucket] = linkedlist.NewLinkedlist() 58 | //AddAtBeg adds a Node at the beginning of the linked list 59 | myMap.data[bucket].AddAtBeg(kv{key, value}) 60 | return 61 | } 62 | myMap.data[bucket].AddAtBeg(kv{key, value}) 63 | } 64 | 65 | // GetValueForKey retrieves the value for a gven key 66 | func (myMap *HashTable) GetValueForKey(key string) (interface{}, bool) { 67 | bucket := hash(key) 68 | 69 | if myMap.data[bucket] == nil { 70 | return 0, false 71 | } 72 | 73 | //check if the key == first node of the linked list 74 | // assertion is required as the Node.Val == interface{} 75 | cur := myMap.data[bucket].Head 76 | if cur.Val.(kv).key == key { 77 | return cur.Val.(kv).value, true 78 | 79 | } 80 | // if not, traverse the linked list, untill the value is found 81 | for ; cur.Next != nil; cur = cur.Next { 82 | node := cur.Val.(kv) 83 | if node.key == key { 84 | return node.value.(int), true 85 | } 86 | 87 | } 88 | // else return false 89 | return 0, false 90 | } 91 | 92 | // utility function to print the HashTable 93 | func (myMap *HashTable) String() { 94 | for i := range myMap.data { 95 | if myMap.data[i] == nil { 96 | fmt.Printf("Bucket %d has no Nodes\n", i) 97 | continue 98 | } 99 | fmt.Printf("Bucket %d has the following Nodes:", i) 100 | fmt.Println(myMap.data[i]) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /other_ds/hashtable/hashtable_test.go: -------------------------------------------------------------------------------- 1 | package hashtable 2 | 3 | import "testing" 4 | 5 | func TestAddKeyValue(t *testing.T) { 6 | var h *HashTable 7 | h = New() 8 | 9 | testcases := []struct { 10 | key string 11 | value int 12 | }{ 13 | {"first", 1}, 14 | {"second", 2}, 15 | {"third", 3}, 16 | {"fourth", 4}, 17 | {"fifth", 5}, 18 | {"sixth", 6}, 19 | {"seventh", 7}, 20 | {"eigth", 8}, 21 | {"nineth", 9}, 22 | {"tenth", 10}, 23 | } 24 | for _, tc := range testcases { 25 | h.AddKeyValue(tc.key, tc.value) 26 | result, ok := h.GetValueForKey(tc.key) 27 | if !ok { 28 | t.Errorf("Could not get the value for key: %s", tc.key) 29 | } 30 | if result.(int) != tc.value { 31 | t.Errorf("Wrong value for key: %s, got: %d, expected: %d", tc.key, result, tc.value) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /other_ds/queue/README.md: -------------------------------------------------------------------------------- 1 | # Queue 2 | 3 | ## Queue definition 4 | 5 | A queue is a collection of entities that are maintained in a sequence and can be modified by the addition of entities at one end of the sequence and the removal of entities from the other end of the sequence. The operation of adding an element to the rear of the queue is known as enqueue, and the operation of removing an element from the front is known as dequeue. Other operations may also be allowed, often including a peek or front operation that returns the value of the next element to be dequeued without dequeuing it. 6 | 7 | The operations of a queue make it a first-in-first-out (FIFO) data structure. In a FIFO data structure, the first element added to the queue will be the first one to be removed. 8 | -------------------------------------------------------------------------------- /other_ds/queue/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/danrusei/algorithms_with_Go/queue 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /other_ds/queue/queue.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package queue implements: 3 | a a new type named Stack, which is a slice of ints 4 | **Enqueue** method to add an element at the end of the Queue 5 | **Dequeue** method to remove the element from the the front of the Queue 6 | */ 7 | package queue 8 | 9 | // Queue represent a stack 10 | type Queue []int 11 | 12 | // Enqueue insert an elememnt at the back of the queue 13 | func (q *Queue) Enqueue(element int) { 14 | *q = append(*q, element) 15 | } 16 | 17 | // Dequeue remove an element at the front of the queue 18 | func (q *Queue) Dequeue() (int, bool) { 19 | if len(*q) == 0 { 20 | return 0, false 21 | } 22 | element := (*q)[0] 23 | *q = (*q)[1:] 24 | return element, true 25 | } 26 | -------------------------------------------------------------------------------- /other_ds/queue/queueString.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package queue implements: 3 | a a new type named Stack, which is a slice of ints 4 | **Enqueue** method to add an element at the end of the Queue 5 | **Dequeue** method to remove the element from the the front of the Queue 6 | */ 7 | package queue 8 | 9 | // Queue represent a stack 10 | type QueueString []string 11 | 12 | // Enqueue insert an elememnt at the back of the queue 13 | func (q *QueueString) Enqueue(element string) { 14 | *q = append(*q, element) 15 | } 16 | 17 | // Dequeue remove an element at the front of the queue 18 | func (q *QueueString) Dequeue() (string, bool) { 19 | if len(*q) == 0 { 20 | return "", false 21 | } 22 | element := (*q)[0] 23 | *q = (*q)[1:] 24 | return element, true 25 | } 26 | -------------------------------------------------------------------------------- /other_ds/queue/queue_test.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestQueue(t *testing.T) { 8 | for _, tc := range testcases { 9 | tc.queue.Enqueue(tc.element) 10 | 11 | if len(tc.queue) != len(tc.enqueue) { 12 | t.Fatalf("Fail, the lengths between current queue and expected are different") 13 | } 14 | 15 | for i := range tc.queue { 16 | if tc.queue[i] != tc.enqueue[i] { 17 | t.Fatalf("Fail, expected: %v, got: %v", tc.enqueue, tc.queue) 18 | } 19 | } 20 | } 21 | } 22 | 23 | func TestDequeue(t *testing.T) { 24 | for _, tc := range testcases { 25 | element, ok := tc.queue.Dequeue() 26 | if ok != tc.ok { 27 | t.Fatalf("Fail, got: %v, expected: %v", ok, tc.ok) 28 | } 29 | 30 | if element != tc.dequeue { 31 | t.Fatalf("Fail got: %d, expected: %d", element, tc.dequeue) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /other_ds/queue/test_cases.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | var testcases = []struct { 4 | description string 5 | queue Queue 6 | element int 7 | enqueue Queue 8 | dequeue int 9 | ok bool 10 | }{ 11 | { 12 | description: "4 elements in queue", 13 | queue: []int{1, 2, 3, 4}, 14 | element: 5, 15 | enqueue: []int{1, 2, 3, 4, 5}, 16 | dequeue: 1, 17 | ok: true, 18 | }, 19 | { 20 | description: "empty queue", 21 | queue: []int{}, 22 | element: 5, 23 | enqueue: []int{5}, 24 | dequeue: 0, 25 | ok: false, 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /other_ds/stack/README.md: -------------------------------------------------------------------------------- 1 | # Stack 2 | 3 | **[Stack Definition](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))** 4 | 5 | A stack is an abstract data type that serves as a collection of elements, with two main principal operations: 6 | 7 | * Push -- adds an element to the collection, and 8 | * Pop -- removes the most recently added element that was not yet removed. 9 | 10 | The order in which elements come off a stack gives rise to its alternative name, LIFO (last in, first out). 11 | -------------------------------------------------------------------------------- /other_ds/stack/go.mod: -------------------------------------------------------------------------------- 1 | module stack 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /other_ds/stack/stack.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package stack implements: 3 | a a new type named Stack, which is a slice of ints 4 | push method to add an element to the Stack 5 | pop method to remove the element from the Stac 6 | */ 7 | package stack 8 | 9 | //Stack represent a stack 10 | type Stack []int 11 | 12 | //Push an elememnt on the top of the stack 13 | func (s *Stack) Push(element int) { 14 | *s = append(*s, element) 15 | } 16 | 17 | //Pop remove the top element from the stack 18 | func (s *Stack) Pop() (int, bool) { 19 | if len(*s) == 0 { 20 | return 0, false 21 | } 22 | lastindex := len(*s) - 1 23 | element := (*s)[lastindex] 24 | *s = (*s)[:lastindex] 25 | return element, true 26 | } 27 | -------------------------------------------------------------------------------- /other_ds/stack/stack_test.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestPush(t *testing.T) { 8 | for _, tc := range testcases { 9 | tc.stack.Push(tc.element) 10 | 11 | if len(tc.stack) != len(tc.push) { 12 | t.Fatalf("Fail, the lengths between current stack and expected are different") 13 | } 14 | 15 | for i := range tc.stack { 16 | if tc.stack[i] != tc.push[i] { 17 | t.Fatalf("Fail, expected: %v, got: %v", tc.push, tc.stack) 18 | } 19 | } 20 | } 21 | } 22 | 23 | func TestPop(t *testing.T) { 24 | for _, tc := range testcases { 25 | element, ok := tc.stack.Pop() 26 | if ok != tc.ok { 27 | t.Fatalf("Fail, got: %v, expected: %v", ok, tc.ok) 28 | } 29 | 30 | if element != tc.pop { 31 | t.Fatalf("Fail got: %d, expected: %d", element, tc.pop) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /other_ds/stack/test_cases.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | var testcases = []struct { 4 | description string 5 | stack Stack 6 | element int 7 | push Stack 8 | pop int 9 | ok bool 10 | }{ 11 | { 12 | description: "4 elements in stack", 13 | stack: []int{1, 2, 3, 4}, 14 | element: 5, 15 | push: []int{1, 2, 3, 4, 5}, 16 | pop: 4, 17 | ok: true, 18 | }, 19 | { 20 | description: "empty stack", 21 | stack: []int{}, 22 | element: 5, 23 | push: []int{5}, 24 | pop: 0, 25 | ok: false, 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /sorting/README.md: -------------------------------------------------------------------------------- 1 | # Sorting and Searching 2 | 3 | In computer science, a sorting algorithm is an algorithm that puts elements of a list in a certain order. The most frequently used orders are numerical order and lexicographical order. Efficient sorting is important for optimizing the efficiency of other algorithms (such as search and merge algorithms) that require input data to be in sorted lists. 4 | 5 | In computer science, a search algorithm is any algorithm which solves the search problem, namely, to retrieve information stored within some data structure, or calculated in the search space of a problem domain, either with discrete or continuous values. 6 | -------------------------------------------------------------------------------- /sorting/bubble_sort/README.md: -------------------------------------------------------------------------------- 1 | # Bubble Sort 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort) 4 | 5 | Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list, compares adjacent elements and swaps them if they are in the wrong order. The pass through the list is repeated until the list is sorted. The algorithm, which is a comparison sort, is named for the way smaller or larger elements "bubble" to the top of the list. 6 | 7 | ## Complexity 8 | 9 | Worst Case Time Complexity [ Big-O ]: **O(n * n)** 10 | Best Case Time Complexity [Big-omega]: **O(n)**- when the list is already sorted 11 | Average Time Complexity [Big-theta]: **O(n * n)** 12 | Space Complexity: **O(1)**- because only a single additional memory space is required for temp variable 13 | 14 | ## Example 15 | 16 | > Take an array of numbers " 5 1 4 2 8", and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in **bold** are being compared. Three passes will be required; 17 | > 18 | > **First Pass** 19 | > ( **5 1** 4 2 8 ) → ( **1 5** 4 2 8 ), Here, algorithm compares the first two elements, and swaps since 5 > 1. 20 | > ( 1 **5 4** 2 8 ) → ( 1 **4 5** 2 8 ), Swap since 5 > 4 21 | > ( 1 4 **5 2** 8 ) → ( 1 4 **2 5** 8 ), Swap since 5 > 2 22 | > ( 1 4 2 **5 8** ) → ( 1 4 2 **5 8** ), Now, since these elements are already in order (8 > 5), algorithm does not swap them. 23 | > 24 | > **Second Pass** 25 | > ( **1 4** 2 5 8 ) → ( **1 4** 2 5 8 ) 26 | > ( 1 **4 2** 5 8 ) → ( 1 **2 4** 5 8 ), Swap since 4 > 2 27 | > ( 1 2 **4 5** 8 ) → ( 1 2 **4 5** 8 ) 28 | > ( 1 2 4 **5 8** ) → ( 1 2 4 **5 8** ) 29 | > Now, the array is already sorted, but the algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted. 30 | > 31 | > **Third Pass** 32 | > ( **1 2** 4 5 8 ) → ( **1 2** 4 5 8 ) 33 | > ( 1 **2 4** 5 8 ) → ( 1 **2 4** 5 8 ) 34 | > ( 1 2 **4 5** 8 ) → ( 1 2 **4 5** 8 ) 35 | > ( 1 2 4 **5 8** ) → ( 1 2 4 **5 8** ) 36 | -------------------------------------------------------------------------------- /sorting/bubble_sort/bubble.go: -------------------------------------------------------------------------------- 1 | package bubblesort 2 | 3 | func bubblesort(target []int) { 4 | for firstnumber := 0; firstnumber < len(target); firstnumber++ { 5 | swapped := false 6 | for i := 0; i < len(target)-1-firstnumber; i++ { 7 | if target[i] > target[i+1] { 8 | target[i], target[i+1] = target[i+1], target[i] 9 | swapped = true 10 | } 11 | } 12 | if !swapped { 13 | break 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sorting/bubble_sort/bubble_test.go: -------------------------------------------------------------------------------- 1 | package bubblesort 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestBubblesort(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | bubblesort(tc.original) 12 | if !reflect.DeepEqual(tc.original, tc.sorted) { 13 | t.Errorf("got: %v, want: %v", tc.original, tc.sorted) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sorting/bubble_sort/test_cases.go: -------------------------------------------------------------------------------- 1 | package bubblesort 2 | 3 | var testcases = []struct { 4 | name string 5 | original []int 6 | sorted []int 7 | }{ 8 | { 9 | name: "4 elements in list", 10 | original: []int{4, 2, 3, 1}, 11 | sorted: []int{1, 2, 3, 4}, 12 | }, 13 | { 14 | name: "empty list", 15 | original: []int{}, 16 | sorted: []int{}, 17 | }, 18 | { 19 | name: "already sorted list", 20 | original: []int{10, 20, 30, 40}, 21 | sorted: []int{10, 20, 30, 40}, 22 | }, 23 | { 24 | name: "9 elements in the list", 25 | original: []int{11, 21, 12, 4, 3, 100, 1000, 1, 123}, 26 | sorted: []int{1, 3, 4, 11, 12, 21, 100, 123, 1000}, 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /sorting/heap_sort/README.md: -------------------------------------------------------------------------------- 1 | # Heap Sort 2 | 3 | Heap sort is a comparison based sorting technique based on Binary Heap data structure. It is similar to selection sort where we first find the maximum element and place the maximum element at the end. We repeat the same process for the remaining elements. 4 | 5 | Source: [Geeksforgeeks](https://www.geeksforgeeks.org/heap-sort/) 6 | 7 | ## Complexity 8 | 9 | Worst Case Time Complexity [ Big-O ]: **O(n log n)** 10 | Best Case Time Complexity [Big-omega]: **O(n log n)** 11 | Average Time Complexity [Big-theta]: **O(n log n)** 12 | Space Complexity: **O(n)** 13 | 14 | ## Algorithm 15 | 16 | * Build a max heap from the input data. 17 | * At this point, the largest item is stored at the root of the heap. Replace it with the last item of the heap followed by reducing the size of heap by 1. Finally, heapify the root of the tree. 18 | * Repeat step 2 while size of heap is greater than 1. 19 | -------------------------------------------------------------------------------- /sorting/heap_sort/heap.go: -------------------------------------------------------------------------------- 1 | package heapsort 2 | 3 | func heapsort(target []int) { 4 | n := len(target) 5 | sortIt(target, n) 6 | } 7 | 8 | func sortIt(target []int, n int) { 9 | 10 | // Build heap (rearrange slice) 11 | for i := n/2 - 1; i >= 0; i-- { 12 | heapify(target, n, i) 13 | } 14 | 15 | // One by one extract an element from heap 16 | for i := n - 1; i > 0; i-- { 17 | // move current root to end 18 | target[0], target[i] = target[i], target[0] 19 | // call max heapify on the reduced heap 20 | heapify(target, i, 0) 21 | } 22 | } 23 | 24 | func heapify(target []int, n int, i int) { 25 | 26 | // If the parent node is stored at index i, 27 | // the left child can be calculated by 2 * i + 1 and 28 | // right child by 2 * i + 2 29 | largest := i 30 | left := 2*i + 1 31 | right := 2*i + 2 32 | 33 | if left < n && target[left] > target[largest] { 34 | largest = left 35 | } 36 | 37 | if right < n && target[right] > target[largest] { 38 | largest = right 39 | } 40 | 41 | if largest != i { 42 | target[i], target[largest] = target[largest], target[i] 43 | // recursively heapify the affected sub-tree 44 | heapify(target, n, largest) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sorting/heap_sort/heap_test.go: -------------------------------------------------------------------------------- 1 | package heapsort 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestMergeSort(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | heapsort(tc.original) 12 | if !reflect.DeepEqual(tc.original, tc.sorted) { 13 | t.Errorf("got: %v, want: %v", tc.original, tc.sorted) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sorting/heap_sort/test_cases.go: -------------------------------------------------------------------------------- 1 | package heapsort 2 | 3 | var testcases = []struct { 4 | name string 5 | original []int 6 | sorted []int 7 | }{ 8 | { 9 | name: "4 elements in list", 10 | original: []int{4, 2, 3, 1}, 11 | sorted: []int{1, 2, 3, 4}, 12 | }, 13 | { 14 | name: "empty list", 15 | original: []int{}, 16 | sorted: []int{}, 17 | }, 18 | { 19 | name: "already sorted list", 20 | original: []int{10, 20, 30, 40}, 21 | sorted: []int{10, 20, 30, 40}, 22 | }, 23 | { 24 | name: "9 elements in the list", 25 | original: []int{11, 21, 12, 4, 3, 100, 1000, 1, 123}, 26 | sorted: []int{1, 3, 4, 11, 12, 21, 100, 123, 1000}, 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /sorting/insertion_sort/README.md: -------------------------------------------------------------------------------- 1 | # Insertion Sort 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort) 4 | 5 | Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. 6 | 7 | ## Complexity 8 | 9 | Worst Case Time Complexity [ Big-O ]: **O(n * n)** 10 | Best Case Time Complexity [Big-omega]: **O(n)** 11 | Average Time Complexity [Big-theta]: **O(n * n)** 12 | Space Complexity: **O(n)** 13 | 14 | ## Algorithm 15 | 16 | Sorting is typically done in-place, by iterating up the array, growing the sorted list behind it. 17 | 18 | * At each array-position, it checks the value there against the largest value in the sorted list (which happens to be next to it, in the previous array-position checked). 19 | * If larger, it leaves the element in place and moves to the next. 20 | * If smaller, it finds the correct position within the sorted list, shifts all the larger values up to make a space, and inserts into that correct position. 21 | 22 | ## Example 23 | 24 | > **12**, 11, 13, 5, 6 25 | > 26 | > Let us loop for i = 1 (second element of the array) to 4 (last element of the array) 27 | > i = 1. Since 11 is smaller than 12, move 12 and insert 11 before 12 28 | > **11**, 12, 13, 5, 6 29 | > 30 | > i = 2. 13 will remain at its position as all elements in A[0..I-1] are smaller than 13 31 | > **11, 12, 13**, 5, 6 32 | > 33 | > i = 3. 5 will move to the beginning and all other elements from 11 to 13 will move one position ahead of their current position. 34 | > **5, 11, 12, 13**, 6 35 | > 36 | > i = 4. 6 will move to position after 5, and elements from 11 to 13 will move one position ahead of their current position. 37 | > **5, 6, 11, 12, 13** 38 | -------------------------------------------------------------------------------- /sorting/insertion_sort/insertion.go: -------------------------------------------------------------------------------- 1 | package insertionsort 2 | 3 | // sorts the slice by traversing and swapping the elements 4 | func insertionsort(target []int) { 5 | for i := 1; i < len(target); i++ { 6 | 7 | // break the loop if the previous element is less than the current element 8 | // or if it reaches the first element of the slice 9 | for i > 0 { 10 | if target[i-1] < target[i] { 11 | break 12 | } 13 | 14 | // swap the elements in the slice 15 | target[i-1], target[i] = target[i], target[i-1] 16 | i-- 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sorting/insertion_sort/insertion_test.go: -------------------------------------------------------------------------------- 1 | package insertionsort 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestBubblesort(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | insertionsort(tc.original) 12 | if !reflect.DeepEqual(tc.original, tc.sorted) { 13 | t.Errorf("got: %v, want: %v", tc.original, tc.sorted) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sorting/insertion_sort/test_cases.go: -------------------------------------------------------------------------------- 1 | package insertionsort 2 | 3 | var testcases = []struct { 4 | name string 5 | original []int 6 | sorted []int 7 | }{ 8 | { 9 | name: "4 elements in list", 10 | original: []int{4, 2, 3, 1}, 11 | sorted: []int{1, 2, 3, 4}, 12 | }, 13 | { 14 | name: "empty list", 15 | original: []int{}, 16 | sorted: []int{}, 17 | }, 18 | { 19 | name: "already sorted list", 20 | original: []int{10, 20, 30, 40}, 21 | sorted: []int{10, 20, 30, 40}, 22 | }, 23 | { 24 | name: "9 elements in the list", 25 | original: []int{11, 21, 12, 4, 3, 100, 1000, 1, 123}, 26 | sorted: []int{1, 3, 4, 11, 12, 21, 100, 123, 1000}, 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /sorting/merge_sort/README.md: -------------------------------------------------------------------------------- 1 | # Merge Sort 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort) 4 | 5 | Like QuickSort, Merge Sort is a Divide and Conquer algorithm. It divides the input array into two halves, calls itself for the two halves, and then merges the two sorted halves. 6 | 7 | ## Complexity 8 | 9 | Worst Case Time Complexity [ Big-O ]: **O(n log n)** 10 | Best Case Time Complexity [Big-omega]: **O(n log n)** 11 | Average Time Complexity [Big-theta]: **O(n log n)** 12 | Space Complexity: **O(n)** 13 | 14 | ## Algorithm 15 | 16 | * Divide the unsorted list into n sublists, each containing one element (a list of one element is considered sorted). 17 | * Repeatedly merge sublists to produce new sorted sublists until there is only one sublist remaining. This will be the sorted list. 18 | 19 | ![merge sort algorithm](merge_sort_algorithm.png) 20 | -------------------------------------------------------------------------------- /sorting/merge_sort/merge.go: -------------------------------------------------------------------------------- 1 | package mergesort 2 | 3 | func mergesort(target []int) { 4 | left := 0 5 | right := len(target) - 1 6 | sortIt(target, left, right) 7 | } 8 | 9 | // run recursively with a modified left and right index of the slice 10 | func sortIt(target []int, left int, right int) { 11 | if left >= right { 12 | return 13 | } 14 | mid := (left + right - 1) / 2 15 | 16 | sortIt(target, left, mid) 17 | sortIt(target, mid+1, right) 18 | 19 | merge(target, left, mid, right) 20 | } 21 | 22 | func merge(target []int, left int, mid int, right int) { 23 | 24 | //find the sizes of the two slices 25 | n1 := mid - left + 1 26 | n2 := right - mid 27 | 28 | //create temp slices 29 | leftSlice := make([]int, n1) 30 | rightSlice := make([]int, n2) 31 | 32 | //copy data to the temp slices 33 | for i := 0; i < n1; i++ { 34 | leftSlice[i] = target[left+i] 35 | } 36 | for j := 0; j < n2; j++ { 37 | rightSlice[j] = target[mid+1+j] 38 | } 39 | 40 | //merge the temp slices 41 | var i, j = 0, 0 42 | k := left 43 | 44 | for i < n1 && j < n2 { 45 | if leftSlice[i] <= rightSlice[j] { 46 | target[k] = leftSlice[i] 47 | i++ 48 | } else { 49 | target[k] = rightSlice[j] 50 | j++ 51 | } 52 | k++ 53 | } 54 | 55 | //copy the remaining elements from leftSlice 56 | for i < n1 { 57 | target[k] = leftSlice[i] 58 | i++ 59 | k++ 60 | } 61 | 62 | //copy the remaining elements from leftSlice 63 | for j < n2 { 64 | target[k] = rightSlice[j] 65 | j++ 66 | k++ 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sorting/merge_sort/merge_sort_algorithm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danrusei/algorithms_with_Go/9d64b2e703d147fb05be645686cdaadebc02c5c4/sorting/merge_sort/merge_sort_algorithm.png -------------------------------------------------------------------------------- /sorting/merge_sort/merge_test.go: -------------------------------------------------------------------------------- 1 | package mergesort 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestMergeSort(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | mergesort(tc.original) 12 | if !reflect.DeepEqual(tc.original, tc.sorted) { 13 | t.Errorf("got: %v, want: %v", tc.original, tc.sorted) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sorting/merge_sort/test_cases.go: -------------------------------------------------------------------------------- 1 | package mergesort 2 | 3 | var testcases = []struct { 4 | name string 5 | original []int 6 | sorted []int 7 | }{ 8 | { 9 | name: "4 elements in list", 10 | original: []int{4, 2, 3, 1}, 11 | sorted: []int{1, 2, 3, 4}, 12 | }, 13 | { 14 | name: "empty list", 15 | original: []int{}, 16 | sorted: []int{}, 17 | }, 18 | { 19 | name: "already sorted list", 20 | original: []int{10, 20, 30, 40}, 21 | sorted: []int{10, 20, 30, 40}, 22 | }, 23 | { 24 | name: "9 elements in the list", 25 | original: []int{11, 21, 12, 4, 3, 100, 1000, 1, 123}, 26 | sorted: []int{1, 3, 4, 11, 12, 21, 100, 123, 1000}, 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /sorting/quick_sort/README.md: -------------------------------------------------------------------------------- 1 | # Quick Sort 2 | 3 | Source: [Wikipedia](https://en.wikipedia.org/wiki/Quicksort) 4 | 5 | Quicksort is a divide-and-conquer algorithm. It works by selecting a 'pivot' element from the array and partitioning the other elements into two sub-arrays, according to whether they are less than or greater than the pivot. The sub-arrays are then sorted recursively. This can be done in-place, requiring small additional amounts of memory to perform the sorting. 6 | 7 | ## Complexity 8 | 9 | Worst Case Time Complexity [ Big-O ]: **O(n * n)** 10 | Best Case Time Complexity [Big-omega]: **O(n log n)** 11 | Average Time Complexity [Big-theta]: **O(n log n)** 12 | Space Complexity: **O(n)** 13 | 14 | ## Algorithm 15 | 16 | It first divides the input array into two smaller sub-arrays: the low elements and the high elements. It then recursively sorts the sub-arrays. The steps for in-place Quicksort are: 17 | 18 | * Pick an element, called a pivot, from the array. 19 | * Partitioning: reorder the array so that all elements with values less than the pivot come before the pivot, while all elements with values greater than the pivot come after it (equal values can go either way). After this partitioning, the pivot is in its final position. This is called the partition operation. 20 | * Recursively apply the above steps to the sub-array of elements with smaller values and separately to the sub-array of elements with greater values. 21 | * The base case of the recursion is arrays of size zero or one, which are in order by definition, so they never need to be sorted. 22 | 23 | The pivot selection and partitioning steps can be done in several different ways; the choice of specific implementation schemes greatly affects the algorithm's performance. 24 | -------------------------------------------------------------------------------- /sorting/quick_sort/quick.go: -------------------------------------------------------------------------------- 1 | package quicksort 2 | 3 | func quicksort(target []int) { 4 | sortIt(target, 0, len(target)-1) 5 | } 6 | 7 | //recursively sort the sub-slices 8 | func sortIt(target []int, left int, right int) { 9 | 10 | // returns when there is nothing left to traverse 11 | if left >= right { 12 | return 13 | } 14 | 15 | //swap the elements and returns the dividing point between right and left side 16 | partIndex := partition(target, left, right) 17 | 18 | sortIt(target, left, partIndex-1) 19 | sortIt(target, partIndex, right) 20 | } 21 | 22 | func partition(target []int, left int, right int) int { 23 | 24 | //select the pivot point, could be randomly selected, in this case I take the middle element 25 | pivot := target[(left+right)/2] 26 | 27 | // loop over the slice untill it finds the elements to be swapped 28 | for left <= right { 29 | for target[left] < pivot { 30 | left++ 31 | } 32 | for target[right] > pivot { 33 | right-- 34 | } 35 | if left <= right { 36 | target[left], target[right] = target[right], target[left] 37 | left++ 38 | right-- 39 | } 40 | } 41 | return left 42 | } 43 | -------------------------------------------------------------------------------- /sorting/quick_sort/quick_test.go: -------------------------------------------------------------------------------- 1 | package quicksort 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestBubblesort(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | quicksort(tc.original) 12 | if !reflect.DeepEqual(tc.original, tc.sorted) { 13 | t.Errorf("got: %v, want: %v", tc.original, tc.sorted) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /sorting/quick_sort/test_cases.go: -------------------------------------------------------------------------------- 1 | package quicksort 2 | 3 | var testcases = []struct { 4 | name string 5 | original []int 6 | sorted []int 7 | }{ 8 | { 9 | name: "4 elements in list", 10 | original: []int{4, 2, 3, 1}, 11 | sorted: []int{1, 2, 3, 4}, 12 | }, 13 | { 14 | name: "empty list", 15 | original: []int{}, 16 | sorted: []int{}, 17 | }, 18 | { 19 | name: "already sorted list", 20 | original: []int{10, 20, 30, 40}, 21 | sorted: []int{10, 20, 30, 40}, 22 | }, 23 | { 24 | name: "9 elements in the list", 25 | original: []int{11, 21, 12, 4, 3, 100, 1000, 1, 123}, 26 | sorted: []int{1, 3, 4, 11, 12, 21, 100, 123, 1000}, 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /strings/README.md: -------------------------------------------------------------------------------- 1 | # Go Strings and Slices 2 | 3 | Articles about Go slices and strings: 4 | 5 | * [Go Slices: usage and internals](https://blog.golang.org/slices-intro) 6 | * [Arrays, slices (and strings): The mechanics of 'append'](https://blog.golang.org/slices) 7 | * [Strings, bytes, runes and characters in Go](https://blog.golang.org/strings) 8 | 9 | ## Related Go packages 10 | 11 | * Strings - [pkg.go.dev](https://pkg.go.dev/strings) 12 | * Bytes - [pkg.go.dev](https://pkg.go.dev/bytes) 13 | -------------------------------------------------------------------------------- /strings/largest_subarray/README.md: -------------------------------------------------------------------------------- 1 | # Length of the largest subarray with contiguous elements 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/length-largest-subarray-contiguous-elements-set-1/amp/) 4 | 5 | Given an array of distinct integers, find length of the longest subarray which contains numbers that can be arranged in a continuous sequence. 6 | 7 | ## Example 8 | 9 | > Input: arr[] = {10, 12, 11}; 10 | > Output: Length of the longest contiguous subarray is 3 11 | > 12 | > Input: arr[] = {14, 12, 11, 20}; 13 | > Output: Length of the longest contiguous subarray is 2 14 | > 15 | > Input: arr[] = {1, 56, 58, 57, 90, 92, 94, 93, 91, 45}; 16 | > Output: Length of the longest contiguous subarray is 5 17 | 18 | ## Algorithm 19 | 20 | If all elements are distinct, then a subarray has contiguous elements if and only if the difference between maximum and minimum elements in subarray is equal to the difference between last and first indexes of subarray. So the idea is to keep track of minimum and maximum element in every subarray. 21 | 22 | ## Result 23 | 24 | ```bash 25 | $ go test -v 26 | === RUN TestReverse 27 | === RUN TestReverse/entire_slice 28 | === RUN TestReverse/middle 29 | === RUN TestReverse/larger_slice 30 | --- PASS: TestReverse (0.00s) 31 | --- PASS: TestReverse/entire_slice (0.00s) 32 | --- PASS: TestReverse/middle (0.00s) 33 | --- PASS: TestReverse/larger_slice (0.00s) 34 | PASS 35 | ok _/home/rdan/projects_public/algorithms_with_Go/strings/largest_subarray 0.001s 36 | ``` 37 | -------------------------------------------------------------------------------- /strings/largest_subarray/largest.go: -------------------------------------------------------------------------------- 1 | package largest 2 | 3 | func largestSlice(input []int) int { 4 | 5 | maxLen := 1 6 | for i := 0; i < len(input)-1; i++ { 7 | // Initialize min and max for all slices starting with i 8 | minN := input[i] 9 | maxN := input[i] 10 | 11 | // Consider all subarrays starting with i and ending with j 12 | for j := i + 1; j < len(input); j++ { 13 | if input[j] < minN { 14 | minN = input[j] 15 | } 16 | if input[j] > maxN { 17 | maxN = input[j] 18 | } 19 | 20 | // calculate if the current slice has all contiguous elements 21 | if maxN-minN == j-i { 22 | if maxLen < maxN-minN+1 { 23 | maxLen = maxN - minN + 1 24 | } 25 | } 26 | } 27 | } 28 | return maxLen 29 | } 30 | -------------------------------------------------------------------------------- /strings/largest_subarray/largest_test.go: -------------------------------------------------------------------------------- 1 | package largest 2 | 3 | import "testing" 4 | 5 | func TestReverse(t *testing.T) { 6 | for _, tc := range testcases { 7 | t.Run(tc.name, func(t *testing.T) { 8 | result := largestSlice(tc.input) 9 | if result != tc.output { 10 | t.Errorf("Expected: %d, got: %d", tc.output, result) 11 | } 12 | 13 | }) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /strings/largest_subarray/test_cases.go: -------------------------------------------------------------------------------- 1 | package largest 2 | 3 | var testcases = []struct { 4 | name string 5 | input []int 6 | output int 7 | }{ 8 | { 9 | name: "entire_slice", 10 | input: []int{10, 12, 11}, 11 | output: 3, 12 | }, 13 | { 14 | name: "middle", 15 | input: []int{14, 12, 11, 20}, 16 | output: 2, 17 | }, 18 | { 19 | name: "larger_slice", 20 | input: []int{1, 56, 58, 57, 90, 92, 94, 93, 91, 45}, 21 | output: 5, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /strings/reverse_alpha/README.md: -------------------------------------------------------------------------------- 1 | # Reverse a string without affecting special characters 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/reverse-a-string-without-affecting-special-characters/amp/) 4 | 5 | Given a string, that contains special character together with alphabets (‘a’ to ‘z’ and ‘A’ to ‘Z’), reverse the string in a way that special characters are not affected. 6 | 7 | ## Example 8 | 9 | > Input: str = "a,b$c" 10 | > Output: str = "c,b$a" 11 | > Note that $ and , are not moved anywhere. 12 | > Only subsequence "abc" is reversed 13 | > 14 | > Input: str = "Ab,c,de!$" 15 | > Output: str = "ed,c,bA!$" 16 | 17 | ## Algorithm 18 | 19 | * Let input string be `str` and length of string be `n` 20 | * l = 0, r = n-1 21 | * for `l` is smaller than `r`, do following 22 | * If `str[l]` is not an alphabetic character, do `l++` 23 | * else if `str[r]` is not an alphabetic character, do `r--` 24 | * else swap `str[l]` and `str[r]` 25 | 26 | ## Result 27 | 28 | ```bash 29 | $ go test -v 30 | === RUN TestReverse 31 | === RUN TestReverse/simple 32 | === RUN TestReverse/with_punctuation 33 | === RUN TestReverse/with_capital 34 | === RUN TestReverse/with_trailing_space 35 | --- PASS: TestReverse (0.00s) 36 | --- PASS: TestReverse/simple (0.00s) 37 | --- PASS: TestReverse/with_punctuation (0.00s) 38 | --- PASS: TestReverse/with_capital (0.00s) 39 | --- PASS: TestReverse/with_trailing_space (0.00s) 40 | PASS 41 | ok _/home/rdan/projects_public/algorithms_with_Go/strings/reverse_alpha 0.001s 42 | ``` 43 | -------------------------------------------------------------------------------- /strings/reverse_alpha/reverse.go: -------------------------------------------------------------------------------- 1 | package reverse 2 | 3 | import ( 4 | "fmt" 5 | "unicode" 6 | ) 7 | 8 | func reverse(input string) string { 9 | toSlice := make([]rune, len(input)) 10 | for i, c := range input { 11 | toSlice[i] = c 12 | } 13 | reverseSlice(toSlice) 14 | 15 | return fmt.Sprint(string(toSlice)) 16 | } 17 | 18 | func reverseSlice(input []rune) { 19 | l := 0 20 | r := len(input) - 1 21 | 22 | for l < r { 23 | if !unicode.IsLetter(input[l]) { 24 | l++ 25 | } else if !unicode.IsLetter(input[r]) { 26 | r-- 27 | } else { 28 | input[l], input[r] = input[r], input[l] 29 | l++ 30 | r-- 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /strings/reverse_alpha/reverse_test.go: -------------------------------------------------------------------------------- 1 | package reverse 2 | 3 | import "testing" 4 | 5 | func TestReverse(t *testing.T) { 6 | for _, tc := range testcases { 7 | t.Run(tc.name, func(t *testing.T) { 8 | result := reverse(tc.input) 9 | if result != tc.output { 10 | t.Errorf("Expected: %s, got: %s", tc.output, result) 11 | } 12 | 13 | }) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /strings/reverse_alpha/test_cases.go: -------------------------------------------------------------------------------- 1 | package reverse 2 | 3 | var testcases = []struct { 4 | name string 5 | input string 6 | output string 7 | }{ 8 | { 9 | name: "simple", 10 | input: "abc", 11 | output: "cba", 12 | }, 13 | { 14 | name: "with_punctuation", 15 | input: "a,b$c", 16 | output: "c,b$a", 17 | }, 18 | { 19 | name: "with_capital", 20 | input: "Ab,c,de!$", 21 | output: "ed,c,bA!$", 22 | }, 23 | { 24 | name: "with_trailing_space", 25 | input: "a,b$c ", 26 | output: "c,b$a ", 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /strings/smallest_subarray/README.md: -------------------------------------------------------------------------------- 1 | # Smallest subarray with sum greater than a given value 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/minimum-length-subarray-sum-greater-given-value/amp/) 4 | 5 | Given an array of integers and a number x, find the smallest subarray with sum greater than the given value. 6 | 7 | ## Example 8 | 9 | > arr[] = {1, 4, 45, 6, 0, 19} 10 | > x = 51 11 | > Output: 3 12 | > Minimum length subarray is {4, 45, 6} 13 | > 14 | > arr[] = {1, 10, 5, 2, 7} 15 | > x = 9 16 | > Output: 1 17 | > Minimum length subarray is {10} 18 | > 19 | > arr[] = {1, 11, 100, 1, 0, 200, 3, 2, 1, 250} 20 | > x = 280 21 | > Output: 4 22 | > Minimum length subarray is {100, 1, 0, 200} 23 | > 24 | > arr[] = {1, 2, 4} 25 | > x = 8 26 | > Output : Not Possible 27 | > Whole array sum is smaller than 8. 28 | 29 | ## Algorithm 30 | 31 | Use two nested loops: 32 | 33 | * the outer loop picks a starting element 34 | * the inner loop considers all elements from the right side of the current start 35 | * Whenever sum of elements between current start and end becomes more than the given number, update the result if current length is smaller than the smallest length so far 36 | 37 | ## Result 38 | 39 | ```bash 40 | $ go test -v 41 | === RUN TestReverse 42 | === RUN TestReverse/51_value 43 | === RUN TestReverse/9_value 44 | === RUN TestReverse/280_value 45 | === RUN TestReverse/8_value 46 | --- PASS: TestReverse (0.00s) 47 | --- PASS: TestReverse/51_value (0.00s) 48 | --- PASS: TestReverse/9_value (0.00s) 49 | --- PASS: TestReverse/280_value (0.00s) 50 | --- PASS: TestReverse/8_value (0.00s) 51 | PASS 52 | ok _/home/rdan/projects_public/algorithms_with_Go/strings/smallest_subarray 0.001s 53 | ``` 54 | -------------------------------------------------------------------------------- /strings/smallest_subarray/smallest.go: -------------------------------------------------------------------------------- 1 | package smallest 2 | 3 | func smallestSlice(num int, input []int) int { 4 | 5 | //Initilize length of smallest slice as len(input) +1, which is not valid 6 | min := len(input) + 1 7 | 8 | for i := 0; i < len(input)-1; i++ { 9 | //initialize the sum with first element 10 | sum := input[i] 11 | 12 | //if first element itself is greater 13 | if sum > num { 14 | return 1 15 | } 16 | 17 | //iterate and add to the sum until the sum is bigger than the input number 18 | for j := i + 1; j < len(input)-1; j++ { 19 | sum += input[j] 20 | 21 | if sum > num { 22 | if j-i+1 < min { 23 | // save the new min 24 | min = j - i + 1 25 | } 26 | break 27 | } 28 | 29 | } 30 | } 31 | return min 32 | } 33 | -------------------------------------------------------------------------------- /strings/smallest_subarray/smallest_test.go: -------------------------------------------------------------------------------- 1 | package smallest 2 | 3 | import "testing" 4 | 5 | func TestReverse(t *testing.T) { 6 | for _, tc := range testcases { 7 | t.Run(tc.name, func(t *testing.T) { 8 | result := smallestSlice(tc.num, tc.input) 9 | if result == len(tc.input)+1 { 10 | result = 0 11 | } 12 | if result != tc.output { 13 | t.Errorf("Expected: %d, got: %d", tc.output, result) 14 | } 15 | }) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /strings/smallest_subarray/test_cases.go: -------------------------------------------------------------------------------- 1 | package smallest 2 | 3 | var testcases = []struct { 4 | name string 5 | num int 6 | input []int 7 | output int 8 | }{ 9 | { 10 | name: "51_value", 11 | num: 51, 12 | input: []int{1, 4, 45, 6, 0, 19}, 13 | output: 3, 14 | }, 15 | { 16 | name: "9_value", 17 | num: 9, 18 | input: []int{1, 10, 5, 2, 7}, 19 | output: 1, 20 | }, 21 | { 22 | name: "280_value", 23 | num: 280, 24 | input: []int{1, 11, 100, 1, 0, 200, 3, 2, 1, 250}, 25 | output: 4, 26 | }, 27 | { 28 | name: "8_value", 29 | num: 8, 30 | input: []int{1, 2, 4}, 31 | output: 0, 32 | }, 33 | } 34 | -------------------------------------------------------------------------------- /strings/zig_zag/README.md: -------------------------------------------------------------------------------- 1 | # Convert array into Zig-Zag fashion 2 | 3 | Source: [GeeksforGeeks](https://www.geeksforgeeks.org/convert-array-into-zig-zag-fashion/amp/) 4 | 5 | Given an array of DISTINCT elements, rearrange the elements of array in zig-zag fashion in O(n) time. The converted array should be in form a < b > c < d > e < f. 6 | 7 | ## Example 8 | 9 | ```bash 10 | Input: arr[] = {4, 3, 7, 8, 6, 2, 1} 11 | Output: arr[] = {3, 7, 4, 8, 2, 6, 1} 12 | 13 | Input: arr[] = {1, 4, 3, 2} 14 | Output: arr[] = {1, 4, 2, 3} 15 | ``` 16 | 17 | ## Algorithm 18 | 19 | * create a flag to denote the "<" or ">" 20 | * if two consecutive numbers do not have the expected relationship, then swap the elements 21 | 22 | ## Result 23 | 24 | ```bash 25 | $ go test -v 26 | === RUN TestReverse 27 | === RUN TestReverse/first_10 28 | === RUN TestReverse/7_values 29 | === RUN TestReverse/4_values 30 | --- PASS: TestReverse (0.00s) 31 | --- PASS: TestReverse/first_10 (0.00s) 32 | --- PASS: TestReverse/7_values (0.00s) 33 | --- PASS: TestReverse/4_values (0.00s) 34 | PASS 35 | ``` 36 | -------------------------------------------------------------------------------- /strings/zig_zag/test_cases.go: -------------------------------------------------------------------------------- 1 | package zigzag 2 | 3 | var testcases = []struct { 4 | name string 5 | input []int 6 | output []int 7 | }{ 8 | { 9 | name: "first_10", 10 | input: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11 | output: []int{1, 3, 2, 5, 4, 7, 6, 9, 8, 10}, 12 | }, 13 | { 14 | name: "7_values", 15 | input: []int{4, 3, 7, 8, 6, 2, 1}, 16 | output: []int{3, 7, 4, 8, 2, 6, 1}, 17 | }, 18 | { 19 | name: "4_values", 20 | input: []int{1, 4, 3, 2}, 21 | output: []int{1, 4, 2, 3}, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /strings/zig_zag/zigzag.go: -------------------------------------------------------------------------------- 1 | package zigzag 2 | 3 | func zigzag(input []int) { 4 | 5 | // if `less` is true indicate "<", else ">" 6 | // initially is true as we start with "<" 7 | // a < b > c < d > e < f 8 | less := true 9 | 10 | for i := 0; i <= len(input)-2; i++ { 11 | if less { 12 | if input[i] > input[i+1] { 13 | input[i], input[i+1] = input[i+1], input[i] 14 | } 15 | } else { 16 | if input[i] < input[i+1] { 17 | input[i], input[i+1] = input[i+1], input[i] 18 | } 19 | } 20 | 21 | // change flag to false, as we should operate on oposite signo 22 | less = !less 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /strings/zig_zag/zigzag_test.go: -------------------------------------------------------------------------------- 1 | package zigzag 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestReverse(t *testing.T) { 9 | for _, tc := range testcases { 10 | t.Run(tc.name, func(t *testing.T) { 11 | zigzag(tc.input) 12 | if !reflect.DeepEqual(tc.input, tc.output) { 13 | t.Errorf("Expected: %d, got: %d", tc.output, tc.input) 14 | } 15 | }) 16 | } 17 | } 18 | --------------------------------------------------------------------------------