├── .gitignore ├── .img └── everything-i-know-about-go.png ├── .vscode └── launch.json ├── README.md ├── bitwise-operations ├── AND │ └── AND-find-network-address.go └── XOR │ └── xor-chiper.go ├── coding-interview-prep └── Crack-the-Coding-Interview.md ├── cracking-the-coding-interview └── ch1-arrays-strings │ ├── go.mod │ └── isUniqueBitwise.go └── dsa ├── grokking algorithms ├── Ch1 - binary-search │ └── main.go ├── Ch2 - selection-sort │ └── main.go ├── Ch3 - recursion │ ├── binary-search.go │ ├── count-slice.go │ ├── factioral.go │ ├── find-max.go │ └── find-sum.go ├── Ch4 - quicksort │ └── main.go ├── Ch6- breadth-first-search │ └── main.go ├── Ch7 - dijkstra │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── temp.go ├── Ch8 - greedy algorithms │ └── main.go └── Grokking algorithms in Go.md └── grokkingDataStructures ├── arrays ├── ch3-sorted-arrays.go ├── dynamicArray.go ├── go.mod ├── main.go ├── sortedArray.go ├── sorted_array_test.go └── unsortedArray.go └── linkedLists └── linkedLists.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | .DS_Store 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | *.html 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | # Dependency directories (remove the comment below to include it) 17 | # vendor/ 18 | -------------------------------------------------------------------------------- /.img/everything-i-know-about-go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duffney/golang-notebook/9a071562a3588ed2a4bc25ffc2310b748846b301/.img/everything-i-know-about-go.png -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Package", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${workspaceFolder}" 13 | }, 14 | { 15 | "name": "Launch file", 16 | "type": "go", 17 | "request": "launch", 18 | "mode": "debug", 19 | "program": "${file}" 20 | }, 21 | { 22 | "name": "Launch file", 23 | "type": "go", 24 | "request": "launch", 25 | "mode": "debug", 26 | "program": "${file}" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang Resources 2 | 3 | Start-here (pick just 1) 4 | - [Introducing Go](https://www.oreilly.com/library/view/introducing-go/9781491941997/) 5 | - [Learn How To Code: Google's Go (golang) Programming Language](https://www.udemy.com/course/learn-how-to-code/) 6 | - [Exercism Go language track](https://exercism.org/tracks/go) 7 | - [Learning Go](https://www.oreilly.com/library/view/learning-go/9781492077206/) 8 | 9 | Dive deeper 10 | - [Go in Action, Second Edition](https://www.manning.com/books/go-in-action-second-edition) 11 | 12 | Turn Pro 13 | - [Ultimate Go](https://www.ardanlabs.com/training/ultimate-go/advanced-concepts/) 14 | - [The Power of Go: Advanced Software Engineering in Go](https://bitfieldconsulting.com/books/tools) 15 | 16 | Dabble in Web development 17 | - [Web Development w/ Google’s Go (golang) Programming Language](https://www.udemy.com/course/go-programming-language/) 18 | - [Let's Go!](https://lets-go.alexedwards.net/#packages) 19 | 20 | Reference docs: 21 | - https://go.dev/doc/effective_go 22 | 23 | Cool clips about Golang: 24 | - [Best Programming Language | John Carmack and Lex Fridman](https://youtu.be/RfWGJS7rckk?t=322) 25 | - ["The two twins of doom" Go and Rust](https://youtu.be/H9jMs-Lcyhc?t=479) 26 | 27 | Articles worth reading: 28 | - [The Best Go framework: no framework?](https://threedots.tech/post/best-go-framework/) 29 | 30 | quotes: 31 | 32 | > "Go suffers no fools" - Todd McLeod 33 | -------------------------------------------------------------------------------- /bitwise-operations/AND/AND-find-network-address.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | "fmt" 6 | "strconv" 7 | ) 8 | 9 | func main() { 10 | ipBytes := []byte{192,168,1,18} 11 | subnetBytes := []byte{255,255,255,0} 12 | 13 | binaryIp := "" 14 | for _, byte := range ipBytes { 15 | binaryIp += fmt.Sprintf("%08b", byte) 16 | } 17 | 18 | fmt.Println("IP address:", binaryIp) 19 | 20 | binaryMask := "" 21 | for _, byte := range subnetBytes { 22 | binaryMask += fmt.Sprintf("%08b", byte) 23 | } 24 | 25 | fmt.Println("Subnet Mask:", binaryMask) 26 | 27 | binaryNetwork := "" 28 | for i := 0; i < 32; i++ { 29 | if binaryIp[i] == '1' && binaryMask[i] == '1' { 30 | binaryNetwork += "1" 31 | } else { 32 | binaryNetwork += "0" 33 | } 34 | } 35 | 36 | 37 | fmt.Println("NetworkAddress:" , binaryNetwork) 38 | 39 | left := 0 40 | right := 8 41 | var octets[]byte 42 | 43 | for left < right { 44 | oct, _ := strconv.ParseInt(binaryNetwork[left:right], 2, 64) 45 | octets = append(octets, byte(oct)) 46 | left = right 47 | if right < 24 { 48 | right = right+8 49 | } else { 50 | oct,_ := strconv.ParseInt(binaryNetwork[right:], 2, 64) 51 | octets = append(octets, byte(oct)) 52 | } 53 | } 54 | 55 | netAddr := net.IP(octets) 56 | fmt.Println("Network with Net:", netAddr.String()) 57 | } 58 | -------------------------------------------------------------------------------- /bitwise-operations/XOR/xor-chiper.go: -------------------------------------------------------------------------------- 1 | // https://www.educative.io/blog/bit-manipulation-algorithms#xor 2 | // TODO: Write a simple XOR cipher block algorithm 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func main () { 10 | // cipher 1 as 3 with XOR 11 | plaintext := 1 // 00000001 12 | key := 2 // 00000010 13 | 14 | fmt.Println("simple...") 15 | ciphertext := plaintext ^ key// 00000011 16 | //compares two bits and returns 1 if those bits are different. 17 | //If both bits are the same, then XOR returns a 0. 18 | //allows you to compre two bits and generate a completely different bit 19 | fmt.Printf("encrypt: %d ^ %d = %d\n", plaintext, key, ciphertext) 20 | 21 | xorOne := ciphertext^ key 22 | fmt.Printf("decrypt: %d ^ %d = %d\n", ciphertext, key, xorOne) 23 | fmt.Println(fmt.Sprintf("%08b",xorOne)) 24 | 25 | a := "a" 26 | binA := fmt.Sprintf("%08b", a[0]) 27 | fmt.Println(binA) 28 | fmt.Printf("Character: %s, Byte(ascii): %d, Binary: %s\n", a, a[0], binA) 29 | } 30 | 31 | func encrypt (plaintext, key string) string { 32 | cipherText := make([]byte, len(plaintext)) 33 | keyLen := len(key) 34 | 35 | for i := range plaintext { 36 | cipherText[i] = plaintext[i] ^ key[i % keyLen] 37 | fmt.Println(key[i % keyLen]) 38 | } 39 | 40 | return string(cipherText) 41 | } 42 | 43 | func decrypt (s string) string { 44 | return "" 45 | } 46 | -------------------------------------------------------------------------------- /coding-interview-prep/Crack-the-Coding-Interview.md: -------------------------------------------------------------------------------- 1 | # Crack the Coding Interview 2 | 3 | ## Arrays and Strings 4 | 5 | > **Is Unique**: Implement an algorithm to determine if a string has all unique characters. 6 | 7 | Soulution: https://play.golang.com/p/zfqzmMoZ1VR 8 | 9 | --- 10 | 11 | > **Check permutations**: Given two strings, write a method to detect if one is a permutation of the other. 12 | 13 | solution: https://play.golang.com/p/cwbgH2FmJzg 14 | 15 | --- 16 | 17 | > **URLify**: Write a method to replace all spaces in a string with `%20`. You may assume that the string has sufficient space at the end to hold the additional characters, and that you are given the "true" length of the string. 18 | 19 | Input: "Mr John Smith " (13 chars) 20 | 21 | Output: `Mr%20John%20Smith` 22 | 23 | Brue-force: 24 | - Use strings.trim to remove whitespace at the end and strings.replace to replace whitespace with `%20`. 25 | 26 | solution: https://play.golang.com/p/DBUrbwT6Hcq 27 | 28 | --- 29 | 30 | > **Palindrome Permutation**: Given a string, write a function to check if it is a permutation of a palindrome. 31 | 32 | Example 33 | - Input: Tact Coa 34 | - Output: True (permutations: "taco cat", atco cta", etc.) 35 | 36 | Partial Solution: https://play.golang.com/p/zaZAx_wz6-J 37 | 38 | --- 39 | 40 | > **One Away**: There are three types of edits that can be performed on strings: insert a character, remove a character, or replace a character. Given two strings, write a function to check if they are one edit (or zero edits) away. 41 | 42 | Example: 43 | - pale, ple -> true 44 | - pales, pale -> true 45 | - pale, bale -> true 46 | - pale, bake -> false 47 | 48 | Partial solution: https://play.golang.com/p/Tus2QIvwtK- -------------------------------------------------------------------------------- /cracking-the-coding-interview/ch1-arrays-strings/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/duffney/cracking-coding-interview 2 | 3 | go 1.22.3 4 | -------------------------------------------------------------------------------- /cracking-the-coding-interview/ch1-arrays-strings/isUniqueBitwise.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | s := "aabc" 9 | 10 | for k,v := range s { 11 | fmt.Printf("key: %x, value:%x", k, v) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch1 - binary-search/main.go: -------------------------------------------------------------------------------- 1 | // binary search 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | list := [5]int{1, 3, 5, 7, 9} 8 | fmt.Println(binary_search(list, 5)) 9 | } 10 | 11 | func binary_search(list [5]int, item int) int { 12 | low := 0 13 | high := len(list) - 1 14 | 15 | for low <= len(list) { 16 | mid := (low + high) / 2 17 | guess := list[mid] 18 | if guess == item { 19 | return mid 20 | } 21 | if guess > item { 22 | high = mid - 1 23 | } else { 24 | low = mid + 1 25 | } 26 | } 27 | return 0 28 | } 29 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch2 - selection-sort/main.go: -------------------------------------------------------------------------------- 1 | // Select sort algorithm 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | arr := []int{10, 33, 5, 7, 9} 8 | fmt.Println(selectionSort(arr)) 9 | } 10 | 11 | func findSmallest(arr []int) int { 12 | smallest := arr[0] 13 | smallestIndex := 0 14 | for i := 0; i < len(arr); i++ { 15 | if arr[i] < smallest { 16 | smallest = arr[i] 17 | smallestIndex = i 18 | } 19 | } 20 | return smallestIndex 21 | } 22 | 23 | func selectionSort(arr []int) []int { 24 | var newArr []int 25 | copyArr := arr 26 | 27 | for i := 0; i < len(arr); i++ { 28 | smallest := findSmallest(copyArr) 29 | newArr = append(newArr, copyArr[smallest]) 30 | copyArr = removeIndex(copyArr, smallest) 31 | } 32 | return newArr 33 | } 34 | 35 | func removeIndex(s []int, index int) []int { 36 | ret := make([]int, 0) 37 | ret = append(ret, s[:index]...) 38 | return append(ret, s[index+1:]...) 39 | } 40 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch3 - recursion/binary-search.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | slice := []int{1, 3, 5, 7, 9, 10} 7 | //slice := []int{2, 1} 8 | fmt.Println(search(slice, 5)) 9 | } 10 | 11 | func search(list []int, item int) int { 12 | // what's the base case? 13 | low := 0 14 | high := len(list) - 1 15 | guess := (low + high) / 2 16 | 17 | if guess == item { 18 | return guess 19 | } 20 | if guess > item { 21 | high = guess - 1 22 | } 23 | if guess < item { 24 | low = guess + 1 25 | } 26 | return search(list, guess) 27 | } 28 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch3 - recursion/count-slice.go: -------------------------------------------------------------------------------- 1 | // count items in a slice (recursion) 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | list := []string{"first", "second", "third", "forth"} 8 | fmt.Println(count(list)) 9 | } 10 | 11 | func count(list []string) int { 12 | if len(list) == 0 { 13 | return 0 14 | } 15 | return 1 + count(list[1:]) 16 | } 17 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch3 - recursion/factioral.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | fmt.Println(fact(3)) 9 | } 10 | 11 | func fact(x int) int { 12 | if x == 1 { // base case 13 | return 1 14 | } else { 15 | return x * fact(x-1) // recursive case 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch3 - recursion/find-max.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | list := []int{1, 2, 3, 20} 7 | fmt.Println(max(list)) 8 | } 9 | 10 | func max(list []int) int { 11 | if len(list) == 2 { 12 | if list[0] > list[1] { 13 | return list[0] 14 | } 15 | return list[1] 16 | } 17 | if list[0] > max(list[1:]) { 18 | return list[0] 19 | } else { 20 | return max(list[1:]) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch3 - recursion/find-sum.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | list := []int{1, 2, 3} 7 | fmt.Println(Sum(list)) 8 | } 9 | 10 | func Sum(list []int) int { 11 | if len(list) == 0 { 12 | return 0 13 | } 14 | return list[0] + Sum(list[1:]) 15 | } 16 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch4 - quicksort/main.go: -------------------------------------------------------------------------------- 1 | // Quicksort (divide and conquer) 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | list := []int{33, 10, 15, 45, 65, 16, 5} 8 | 9 | fmt.Println(quicksort(list)) 10 | } 11 | 12 | func quicksort(list []int) []int { 13 | if len(list) < 2 { 14 | return list 15 | } 16 | if len(list) == 2 { 17 | left, right := 0, len(list)-1 18 | if list[0] > list[1] { 19 | list[left], list[right] = list[right], list[left] 20 | } 21 | return list 22 | } 23 | 24 | pivot := list[0] 25 | var less []int 26 | var greater []int 27 | 28 | for i := range list { 29 | if list[i] < pivot { 30 | less = append(less, list[i]) 31 | } 32 | if list[i] > pivot { 33 | greater = append(greater, list[i]) 34 | } 35 | } 36 | 37 | return append(append(quicksort(less), pivot), quicksort(greater)...) 38 | } 39 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch6- breadth-first-search/main.go: -------------------------------------------------------------------------------- 1 | // Credit: Grokking Algorithms: An illustrated guide for programmers and other curious people 2 | package main 3 | 4 | import "fmt" 5 | 6 | func main() { 7 | // create a graph 8 | graph := make(map[string][]string) 9 | graph["you"] = []string{"alice", "bob", "claire"} 10 | graph["bob"] = []string{"anuj", "peggy"} 11 | graph["alice"] = []string{"peggy"} 12 | graph["claire"] = []string{"thom", "jonny"} 13 | graph["anuj"] = []string{} 14 | graph["peggy"] = []string{} 15 | graph["thom"] = []string{} 16 | graph["jonny"] = []string{} 17 | 18 | fmt.Println(breathFirstSearch(graph)) 19 | } 20 | 21 | func breathFirstSearch(graph map[string][]string) string { 22 | // create a queue 23 | var queue []string 24 | var person string 25 | queue = graph["you"] 26 | 27 | i := 0 28 | for i < len(queue) { // while loop 29 | person, queue = dequeue(queue) 30 | if isSalesman(person) { 31 | return person 32 | } else { 33 | for _, contact := range graph[person] { 34 | queue = enqueue(queue, contact) 35 | } 36 | } 37 | } 38 | return "" 39 | } 40 | 41 | func isSalesman(p string) bool { 42 | // does the last letter == m? 43 | if p[len(p)-1:] == "m" { 44 | return true 45 | } 46 | return false 47 | } 48 | 49 | // https://codesource.io/how-to-implement-the-queue-in-golang 50 | func enqueue(queue []string, element string) []string { 51 | queue = append(queue, element) 52 | return queue 53 | } 54 | 55 | func dequeue(queue []string) (string, []string) { 56 | return queue[0], queue[1:] 57 | } 58 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch7 - dijkstra/go.mod: -------------------------------------------------------------------------------- 1 | module dijkstra 2 | 3 | go 1.19 4 | 5 | require golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 // indirect 6 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch7 - dijkstra/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 h1:yZNXmy+j/JpX19vZkVktWqAo7Gny4PBWYYK3zskGpx4= 2 | golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 3 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch7 - dijkstra/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | 7 | "golang.org/x/exp/slices" 8 | ) 9 | 10 | func main() { 11 | //https://nilpointer.net/programming-language/golang/nested-maps-in-golang/ 12 | graph := make(map[string]map[string]interface{}) 13 | 14 | graph["start"] = make(map[string]interface{}) 15 | graph["start"]["a"] = 6 16 | graph["start"]["b"] = 2 17 | 18 | graph["a"] = make(map[string]interface{}) 19 | graph["a"]["fin"] = 1 20 | 21 | graph["b"] = make(map[string]interface{}) 22 | graph["b"]["a"] = 3 23 | graph["b"]["fin"] = 5 24 | 25 | graph["fin"] = make(map[string]interface{}) 26 | 27 | //costs 28 | infinity := math.Inf(1) 29 | costs := make(map[string]int) 30 | costs["a"] = 6 31 | costs["b"] = 2 32 | costs["fin"] = int(infinity) 33 | 34 | // parents 35 | parents := make(map[string]string) 36 | parents["a"] = "start" 37 | parents["b"] = "start" 38 | parents["fin"] = "" 39 | 40 | // array of processed nodes 41 | var processed []string 42 | 43 | node := findLowestCostNode(costs, processed) 44 | for node != "" { 45 | cost := costs[node] 46 | neighbors := graph[node] 47 | for n := range neighbors { 48 | newCost := cost + neighbors[n].(int) 49 | if costs[n] > newCost { 50 | costs[n] = newCost 51 | parents[n] = node 52 | } 53 | } 54 | processed = append(processed, node) 55 | node = findLowestCostNode(costs, processed) 56 | } 57 | 58 | fmt.Println(parents) 59 | } 60 | 61 | func findLowestCostNode(costs map[string]int, process []string) string { 62 | lowestCost := 1000 63 | var lowestCostNode string 64 | 65 | for node := range costs { 66 | cost := costs[node] 67 | processed := slices.Contains(process, node) 68 | 69 | if (cost < lowestCost) && (!processed) { 70 | lowestCostNode = node 71 | lowestCost = cost 72 | } 73 | } 74 | return lowestCostNode 75 | } 76 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch7 - dijkstra/temp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "golang.org/x/exp/slices" 7 | ) 8 | 9 | func main() { 10 | names := []string{"Ana", "Bob", "Clair", "Daniel", "Fred", "Hush", "Timmy"} 11 | 12 | // some string to check 13 | nameCheck := "Bob" 14 | isPresent1 := slices.Contains(names, nameCheck) 15 | 16 | if isPresent1 { 17 | fmt.Println(nameCheck, "is in the names array") 18 | } else { 19 | fmt.Println(nameCheck, "is not in the names array") 20 | } 21 | 22 | scores := []float64{14.2, 26.5, 9.6, 36.4, 52.6} 23 | scoreCheck := 9.6 24 | 25 | isPresent2 := slices.Contains(scores, scoreCheck) 26 | if isPresent2 { 27 | fmt.Println(scoreCheck, "is in the scores array") 28 | } else { 29 | fmt.Println(scoreCheck, "is not in the scores array") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Ch8 - greedy algorithms/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | set := make(map[string]struct{}) 7 | var exists = struct{}{} 8 | statesNeeded := []string{"mt", "wa", "or", "id", "nv", "ut", "ca", "az"} 9 | for _, v := range statesNeeded { 10 | set[v] = exists 11 | } 12 | 13 | for state := range set { 14 | fmt.Println(state) 15 | } 16 | 17 | //stations = {} 18 | //stations["kone"] = set(["id", "nv", "ut"]) 19 | //stations["ktwo"] = set(["wa", "id", "mt"]) 20 | //stations["kthree"] = set(["or", "nv", "ca"]) 21 | //stations["kfour"] = set(["nv", "ut"]) 22 | //stations["kfive"] = set(["ca", "az"]) 23 | } 24 | -------------------------------------------------------------------------------- /dsa/grokking algorithms/Grokking algorithms in Go.md: -------------------------------------------------------------------------------- 1 | # Grokking algorithms exercises 2 | 3 | ## Intro to algorithms 4 | 5 | Key terms: 6 | - Big-O notation 7 | - linear time 8 | - log time 9 | - constant time 10 | 11 | Common Big-O run times 12 | 13 | When determining how fast an algorithm is it isn't enough to know how long an algorithm took to run. You need to figure out how the run time increases as the size increases, which is what Big-O notation is used for. Big-O notation tells you how fast an algorithm is by letting you compare the number of operations an algorithm will take by expressing them with a mathematical expression. 14 | 15 | - `O(1)`, also known as *constant time* 16 | - `O(log n)`, also known as *log time*. Example: [Binary search](https://go.dev/play/p/_8l_9M-JHbo). 17 | - `O(n)`, also known as linear time. Example: Simple search. 18 | - `O(log n)` is faster than O(n), but it gets a lot faster as the list of items you’re searching grows 19 | - `O(n * log n)`. Example: A fast sorting algorithm, like quicksort 20 | - `O(n2)`. Example: A slow sorting algorithm, like *[selection sort](https://go.dev/play/p/qIKqlckz-gZ)* 21 | - `O(n!)`, also known as factorial time. Example: A really slow algorithm, like the traveling salesperson 22 | 23 | ## Select sort 24 | 25 | - [Binary search](https://go.dev/play/p/FCC3NEn5SQ-) 26 | - [Selection sort](https://go.dev/play/p/tH96VhF7ync) 27 | 28 | ## Recursion 29 | 30 | Key terms: 31 | - base case 32 | - recursive case 33 | - call stack 34 | 35 | Algorithms: 36 | - [Factioral Recursion](https://play.golang.com/p/Ta9vPb-SC0N) 37 | - [Count items in a slice (recursion)](https://go.dev/play/p/BcpvpAq1MKP) 38 | - [Find maximum number (recursion)](https://go.dev/play/p/KLy0MyZ9K5W) 39 | - [Binary search (recursion)](https://go.dev/play/p/7qM0WKge6O_x) 40 | - [Sum (recursion)](https://go.dev/play/p/Nnvc4BXF9de) 41 | 42 | ## Quicksort 43 | 44 | Key terms: 45 | - Divide & Conquer 46 | - Pivot 47 | - Partitioning 48 | 49 | Algorithms: 50 | - [Quicksort divide and conquer](https://go.dev/play/p/Cx7Mq9svxTa) 51 | 52 | 53 | ## Breadth-first Search 54 | 55 | Key terms: 56 | - queue 57 | - enqueue 58 | - dequeue 59 | - FIFO data structure 60 | - LIFO data structure (stack) 61 | - graph (data structure) 62 | - direct graph 63 | - indirect graph 64 | 65 | Useful links 66 | - https://codesource.io/how-to-implement-the-queue-in-golang 67 | 68 | Algorithms: 69 | - [Graph](https://go.dev/play/p/NMssEtyBWbX) 70 | 71 | https://go.dev/play/p/bCz8OzwRAFp 72 | 73 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/arrays/ch3-sorted-arrays.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | ) 7 | 8 | //TODO: unsorted 9 | 10 | type sortedArray struct { 11 | data [5]int 12 | count int 13 | } 14 | 15 | // get better at sorting algos bro 16 | func (a *sortedArray) Insert(value int) { 17 | if a.count == len(a.data) { 18 | log.Fatal("array is full") 19 | } 20 | for i:= a.count; i > 0; i-- { 21 | if a.data[i-1] <= value { 22 | a.data[i] = value 23 | a.count++ 24 | return 25 | } else { 26 | a.data[i] = a.data[i-1] 27 | } 28 | } 29 | a.data[0] = value 30 | a.count++ 31 | } 32 | 33 | func main() { 34 | a := &sortedArray{} 35 | a.data = [5]int{1,3,0,0,0} 36 | a.count = 2 37 | a.Insert(2) 38 | fmt.Println(a.data) 39 | } 40 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/arrays/dynamicArray.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/arrays/go.mod: -------------------------------------------------------------------------------- 1 | module arrays 2 | 3 | go 1.24.1 4 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/arrays/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // ints := []int{1, 2, 3} 5 | // // unsorted 6 | // ua := NewUnsortedArray[int](3) 7 | 8 | // // fill array 9 | // for _, i := range ints { 10 | // ua.Insert(i) 11 | // } 12 | // // rm 1 from array 13 | // ua.DeleteByIndex(0) 14 | 15 | // // add 6 to array, making it full again 16 | // if !ua.Insert(4) { 17 | // fmt.Println("insert failed, array full") 18 | // } 19 | 20 | // if !ua.Insert(5) { 21 | // fmt.Println("insert failed, array full") 22 | // } 23 | 24 | // ua.Print() 25 | 26 | // ua.Find(3) 27 | 28 | // max := ua.Max() 29 | // fmt.Println(max) 30 | // sa := NewSortedArray(4) 31 | 32 | // sa.Insert(1) 33 | // sa.Insert(3) 34 | // sa.Insert(2) 35 | // sa.Insert(4) 36 | 37 | // sa.Delete(2) 38 | // sa.Insert(5) 39 | // fmt.Println(sa) 40 | // sa.LinearSearch(3) 41 | 42 | bSearch := NewSortedArray(100) 43 | ints := make([]int, 100) 44 | for i := range 100 { 45 | ints[i] = i + 1 46 | bSearch.Insert(ints[i]) 47 | } 48 | // fmt.Println(bSearch) 49 | bSearch.Find(30) 50 | bSearch.BinarySearchNonRecursive(30) 51 | 52 | } 53 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/arrays/sortedArray.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | /* 6 | type, just ust int this time... 7 | new func 8 | methods 9 | - insert 10 | - delete 11 | - max 12 | - find 13 | - print/traverse 14 | */ 15 | 16 | type SortedArray struct { 17 | Elements []int 18 | Length int 19 | Capacity int 20 | } 21 | 22 | func NewSortedArray(capacity int) SortedArray { 23 | return SortedArray{ 24 | Elements: make([]int, capacity), 25 | Length: 0, 26 | Capacity: capacity, 27 | } 28 | } 29 | 30 | // insertion sort 31 | func (a *SortedArray) Insert(value int) bool { 32 | if a.Length >= a.Capacity { 33 | return false // Return false if the array is full 34 | } 35 | 36 | // Start from the last occupied index 37 | i := a.Length - 1 38 | 39 | // Shift elements to the right until the correct position for 'e' is found 40 | for i >= 0 && a.Elements[i] > value { 41 | a.Elements[i+1] = a.Elements[i] // Move the current element one position to the right 42 | i-- // Move left to check the next element 43 | } 44 | 45 | // Insert 'e' at the found position (i+1) 46 | a.Elements[i+1] = value 47 | a.Length++ 48 | 49 | return true // Return true to indicate successful insertion 50 | } 51 | 52 | // To remove an element from a sorted array, 53 | // first we find its index, 54 | // then we shift all the elements to its right left one position, overwriting the deleted element. 55 | func (a *SortedArray) Delete(target int) bool { 56 | var index int 57 | for i, e := range a.Elements { 58 | if e == target { 59 | index = i 60 | } 61 | } 62 | 63 | // Loop through starting at the index 64 | for i := index; i < a.Length-1; i++ { 65 | //Shift elements left one position 66 | a.Elements[i] = a.Elements[i+1] 67 | } 68 | // Blank out last element in the array 69 | a.Elements[a.Length-1] = 0 70 | a.Length-- 71 | 72 | return true 73 | } 74 | 75 | func (a *SortedArray) LinearSearch(target int) bool { 76 | for i := 0; i < a.Length; i++ { 77 | if a.Elements[i] == target { 78 | fmt.Printf("found, %d at index %d\n", a.Elements[i], i) 79 | return true 80 | } 81 | } 82 | return false 83 | } 84 | 85 | func (a *SortedArray) Find(target int) bool { 86 | left := 0 87 | right := a.Length - 1 88 | return a.BinarySearch(target, left, right) 89 | } 90 | 91 | // BinarySearch performs a recursive binary search 92 | func (a *SortedArray) BinarySearch(target, left, right int) bool { 93 | // Base case 1: Search space exhausted (element not found) 94 | if left > right { 95 | return false 96 | } 97 | 98 | // Correct midpoint calculation 99 | mid := left + (right-left)/2 100 | 101 | // Base case 2: Target found 102 | if a.Elements[mid] == target { 103 | fmt.Printf("found %d at index %d\n", a.Elements[mid], mid) 104 | return true 105 | } 106 | 107 | // Recursive cases 108 | if a.Elements[mid] > target { 109 | // Search left half and return the result 110 | return a.BinarySearch(target, left, mid-1) 111 | } 112 | // Note: No else needed; if > fails, it must be < 113 | // Search right half and return the result 114 | return a.BinarySearch(target, mid+1, right) 115 | } 116 | 117 | func (a *SortedArray) BinarySearchNonRecursive(target int) bool { 118 | left := 0 119 | right := a.Length - 1 120 | 121 | for left <= right { 122 | mid := left + (right-left)/2 123 | 124 | if a.Elements[mid] == target { 125 | fmt.Printf("found %d at index %d\n", a.Elements[mid], mid) 126 | return true 127 | } 128 | 129 | if a.Elements[mid] > target { 130 | right = mid + 1 131 | } else { 132 | left = mid + 1 133 | } 134 | } 135 | return false 136 | } 137 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/arrays/sorted_array_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestInsert(t *testing.T) { 9 | // Test case 1: Insert into an empty sorted array 10 | t.Run("Insert into empty array", func(t *testing.T) { 11 | arr := NewSortedArray(3) 12 | success := arr.Insert(10) 13 | 14 | if !success { 15 | t.Errorf("Insert failed when the array is empty") 16 | } 17 | 18 | if arr.Length != 1 { 19 | t.Errorf("Expected Length to be 1, got %d", arr.Length) 20 | } 21 | 22 | if arr.Elements[0] != 10 { 23 | t.Errorf("Expected first element to be 10, got %d", arr.Elements[0]) 24 | } 25 | }) 26 | t.Run("Insert into empty unsorted array", func(t *testing.T) { 27 | ua := NewUnsortedArray[int](3) 28 | success := ua.Insert(2) 29 | 30 | if !success { 31 | t.Errorf("Insert faield when the array is empty") 32 | } 33 | }) 34 | } 35 | 36 | func TestDelete(t *testing.T) { 37 | t.Run("Insert into empty array", func(t *testing.T) { 38 | sa := NewSortedArray(4) 39 | ints := []int{1, 2, 3, 4} 40 | for i := range ints { 41 | sa.Insert(i) 42 | } 43 | 44 | sucess := sa.Delete(2) 45 | 46 | if !sucess { 47 | t.Errorf("Delete failed") 48 | } 49 | }) 50 | } 51 | 52 | func TestInsertAlgorithms(t *testing.T) { 53 | tests := []struct { 54 | name string 55 | initial []int 56 | insert int 57 | expected []int 58 | }{ 59 | { 60 | name: "Insert into empty array", 61 | initial: []int{}, 62 | insert: 1, 63 | expected: []int{1}, 64 | }, 65 | { 66 | name: "Insert 2 between 1,3", 67 | initial: []int{1, 3}, 68 | insert: 2, 69 | expected: []int{1, 2, 3}, 70 | }, 71 | } 72 | 73 | for _, tt := range tests { 74 | // Test the original algorithm 75 | t.Run("Original: "+tt.name, func(t *testing.T) { 76 | // Create and initialize array 77 | a := NewSortedArray(10) 78 | a.Length = len(tt.initial) 79 | for val := range tt.initial { 80 | a.Insert(val) 81 | } 82 | 83 | // Insert the value 84 | a.Insert(tt.insert) 85 | 86 | // Check the result 87 | result := a.Elements[:a.Length] 88 | if !reflect.DeepEqual(result, tt.expected) { 89 | t.Errorf("InsertOriginal() = %v, want %v", result, tt.expected) 90 | } 91 | }) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/arrays/unsortedArray.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type UnsortedArray[T ~int | ~string] struct { 6 | Elements []T 7 | Length int 8 | Capacity int 9 | } 10 | 11 | func NewUnsortedArray[T ~int | ~string](capactiy int) UnsortedArray[T] { 12 | return UnsortedArray[T]{ 13 | Elements: make([]T, capactiy), 14 | Length: 0, 15 | Capacity: capactiy, 16 | } 17 | } 18 | 19 | func (a *UnsortedArray[T]) Insert(e T) bool { 20 | if a.Length >= a.Capacity { 21 | return false 22 | } 23 | a.Elements[a.Length] = e 24 | a.Length++ 25 | return true 26 | } 27 | 28 | // Move selected element to the end, then delete 29 | func (a *UnsortedArray[T]) DeleteByIndex(index int) bool { 30 | if a.Length == 0 { 31 | return false 32 | } 33 | 34 | if index < 0 || index >= a.Capacity { 35 | return false 36 | } 37 | a.Elements[index] = a.Elements[a.Length-1] 38 | a.Length-- 39 | return true 40 | } 41 | 42 | func (a *UnsortedArray[T]) Find(target T) bool { 43 | for i := range a.Length { 44 | if a.Elements[i] == target { 45 | fmt.Printf("target: %v found at index: %d\n", target, i) 46 | return true 47 | } 48 | } 49 | return false 50 | } 51 | 52 | func (a *UnsortedArray[T]) Print() { 53 | fmt.Println(a.Elements[:a.Length]) 54 | } 55 | 56 | // can you make a generic method work for only 1 of the types? ex int not string 57 | func (a *UnsortedArray[T]) Max() T { 58 | var max T 59 | for i := range a.Length { 60 | fmt.Printf("current: %v i: %v\n", max, a.Elements[i]) 61 | if max < a.Elements[i] { 62 | max = a.Elements[i] 63 | } 64 | } 65 | return max 66 | } 67 | -------------------------------------------------------------------------------- /dsa/grokkingDataStructures/linkedLists/linkedLists.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Song struct { 9 | Name string 10 | Artist string 11 | Album string 12 | } 13 | 14 | type node struct { 15 | value Song 16 | next *node 17 | } 18 | 19 | type LinkedList struct { 20 | head *node 21 | size int 22 | } 23 | 24 | func NewLinkedList() *LinkedList { 25 | return &LinkedList{head: nil, size: 0} 26 | } 27 | 28 | func (l *LinkedList) Append(value Song) { 29 | newNode := &node{ 30 | value: value, 31 | next: l.head, 32 | } 33 | l.head = newNode 34 | l.size++ 35 | } 36 | 37 | func (l *LinkedList) Display() { 38 | current := l.head 39 | 40 | for current != nil { 41 | fmt.Printf("Name: %s, Artist: %s, Album: %s\n", current.value.Name, current.value.Artist, current.value.Album) 42 | current = current.next 43 | } 44 | } 45 | func (l *LinkedList) Search(value, field string) Song { 46 | current := l.head 47 | 48 | for current != nil { 49 | v := reflect.ValueOf(current.value) 50 | f := v.FieldByName(field) 51 | 52 | // Check if the field exists and is a string 53 | if f.IsValid() && f.Kind() == reflect.String && f.String() == value { 54 | return current.value 55 | } 56 | current = current.next 57 | } 58 | return Song{} 59 | } 60 | 61 | // TODO: Delete, handle edge cases 62 | // If you delete the last node, then you have to make the previous node the new tail (in our implementation, its link is set to None). 63 | // If you delete the first node, the head of the list, then there is no predecessor! In this case, we just have to update the list’s head pointer. 64 | func (l *LinkedList) DeleteSong(value string) bool { 65 | current := l.head 66 | var prev *node 67 | 68 | for current != nil { 69 | if current.value.Name == value { 70 | if prev == nil { 71 | l.head = current.next 72 | } else { 73 | // set previous.Next to current.next 74 | prev.next = current.next 75 | } 76 | l.size-- 77 | return true 78 | } 79 | prev = current 80 | current = current.next 81 | } 82 | return false 83 | } 84 | 85 | func main() { 86 | list := NewLinkedList() 87 | 88 | list.Append(Song{Name: "My Own Prison", Artist: "Creed", Album: "My Own Prison"}) 89 | list.Append(Song{Name: "Higher", Artist: "Creed", Album: "Human Clay"}) 90 | list.Append(Song{Name: "With Arms Wide Open", Artist: "Creed", Album: "Human Clay"}) 91 | 92 | // list.Display() 93 | 94 | // s := list.Search("Higher", "Name") 95 | // fmt.Println(s) 96 | list.DeleteSong("With Arms Wide Open") 97 | list.Display() 98 | } 99 | --------------------------------------------------------------------------------