├── .gitignore ├── 1-BigO ├── BigONotation.playground │ ├── Contents.swift │ └── contents.xcplayground ├── README.md └── images │ └── cheat.png ├── 10-Graphs ├── Graphs.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-PathExists-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Q1-PathExists-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 11-CommonlyAsked ├── Q1-UniqueCharacters-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-UniqueCharacters-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-Permutations-Answer.playground │ ├── Pages │ │ ├── Untitled Page 2.xcplaygroundpage │ │ │ └── Contents.swift │ │ └── Untitled Page.xcplaygroundpage │ │ │ └── Contents.swift │ └── contents.xcplayground ├── Q2-Permutations-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-URLify-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-URLify-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q4-Oneaway-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q4-Oneaway-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q5-Compressor-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q5-Compressor-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q6-RemoveDuplicates-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q6-RemoveDuplicates-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q7-SubtreeChecker-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q7-SubtreeChecker-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q8-MinStack-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Q8-MinStack-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 12-GreatestHits ├── Q1-FizzBuzz-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-FizzBuzz-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-Palindromes-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-Palindromes-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-RansomNote-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-RansomNote-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q4-CaesarCipher-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q4-CaesarCipher-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q6-StringReversal-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q6-StringReversal-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q7-IntegerReversal-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q7-IntegerReversal-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q8-Anagrams-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Q8-Anagrams-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 13-Google ├── Q1-Google-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Q1-Google-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 14-TheFacebook ├── Q1-Facebook-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-Facebook-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-Facebook-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-Facebook-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-Facebook-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-Facebook-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q4-Facebook-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Q4-Facebook-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 15-Amazon ├── Amazon-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Amazon-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 16-Spotify └── Q4-Spotify.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 2-Arrays ├── 0-Arrays.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-CyclicRotation-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-CyclicRotation-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-DashPhoneNumber-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-DashPhoneNumber-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-ContactMatch-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Q3-ContactMatch-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 3-LinkedLists ├── LinkedList-Skeleton.playground │ ├── Contents.swift │ └── contents.xcplayground ├── LinkedList.playground │ ├── Contents.swift │ └── contents.xcplayground └── Questions │ ├── Q1-LengthOfLinkedList-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground │ ├── Q1-LengthOfLinkedList-Question.playground │ ├── Contents.swift │ └── contents.xcplayground │ ├── Q2-MergePointTwoLists-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground │ ├── Q2-MergePointTwoLists-Question.playground │ ├── Contents.swift │ └── contents.xcplayground │ ├── Q3-DetectACycle-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground │ └── Q3-DetectACycle-Quesion.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 4-BigOReduced └── BigOReduced.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 5-StacksQueues ├── Q1-CyclicRotation-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-CyclicRotation-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-ReverseAString-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-ReverseAString-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-BalancedBrackets-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-BalancedBrackets-Question.playground │ ├── Contents.swift │ └── contents.xcplayground └── StacksAndQueues.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 6-HashTables └── HashTable.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 7-BinaryTrees ├── BST-Empty.playground │ ├── Contents.swift │ └── contents.xcplayground ├── BST-Solution.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-IsBST-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q1-IsBST-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-Height-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q2-Height-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Q3-LowestCommonAncestor-Answer.playground │ ├── Contents.swift │ └── contents.xcplayground └── Q3-LowestCommonAncestor-Question.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 8-Memoization └── Fibanocci.playground │ ├── Contents.swift │ └── contents.xcplayground ├── 9-Sorting └── BubbleSort.playground │ ├── Contents.swift │ └── contents.xcplayground ├── LICENSE ├── README.md └── images ├── banner.png └── construction.gif /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Xcode 4 | # 5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 6 | 7 | ## User settings 8 | xcuserdata/ 9 | 10 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 11 | *.xcscmblueprint 12 | *.xccheckout 13 | 14 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 15 | build/ 16 | DerivedData/ 17 | *.moved-aside 18 | *.pbxuser 19 | !default.pbxuser 20 | *.mode1v3 21 | !default.mode1v3 22 | *.mode2v3 23 | !default.mode2v3 24 | *.perspectivev3 25 | !default.perspectivev3 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | 30 | ## App packaging 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | ## Playgrounds 36 | timeline.xctimeline 37 | playground.xcworkspace 38 | 39 | # Swift Package Manager 40 | # 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | # *.xcodeproj 46 | # 47 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 48 | # hence it is not needed unless you have added a package configuration file to your project 49 | # .swiftpm 50 | 51 | .build/ 52 | 53 | # CocoaPods 54 | # 55 | # We recommend against adding the Pods directory to your .gitignore. However 56 | # you should judge for yourself, the pros and cons are mentioned at: 57 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 58 | # 59 | # Pods/ 60 | # 61 | # Add this line if you want to avoid checking in source code from the Xcode workspace 62 | # *.xcworkspace 63 | 64 | # Carthage 65 | # 66 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 67 | # Carthage/Checkouts 68 | 69 | Carthage/Build/ 70 | 71 | # Accio dependency management 72 | Dependencies/ 73 | .accio/ 74 | 75 | # fastlane 76 | # 77 | # It is recommended to not store the screenshots in the git repo. 78 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 79 | # For more information about the recommended setup visit: 80 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 81 | 82 | fastlane/report.xml 83 | fastlane/Preview.html 84 | fastlane/screenshots/**/*.png 85 | fastlane/test_output 86 | 87 | # Code Injection 88 | # 89 | # After new code Injection tools there's a generated folder /iOSInjectionProject 90 | # https://github.com/johnno1962/injectionforxcode 91 | 92 | iOSInjectionProject/ 93 | -------------------------------------------------------------------------------- /1-BigO/BigONotation.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | /* 2 | ___ _ ___ _ _ _ _ _ 3 | | _ |_)__ _ / _ \ | \| |___| |_ __ _| |_(_)___ _ _ 4 | | _ \ / _` | | (_) | | .` / _ \ _/ _` | _| / _ \ ' \ 5 | |___/_\__, | \___/ |_|\_\___/\__\__,_|\__|_\___/_||_| 6 | |___/ 7 | */ 8 | 9 | import Foundation 10 | 11 | func findNemo(_ arr: [String]) { 12 | let before = Date() 13 | 14 | for i in 0..(repeating: "", count: 100000) 28 | findNemo(nemo) 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | // Constant time O(1) 50 | func constantTime(_ n: Int) -> Int { 51 | let result = n * n 52 | return result 53 | } 54 | 55 | // Linear time O(n) 56 | func linearTime(_ A: [Int]) -> Int { 57 | for i in 0.. Int { 69 | var n = N 70 | var result = 0 71 | while n > 1 { 72 | n /= 2 73 | // print(n) 74 | result += 1 75 | } 76 | return result 77 | } 78 | logarithmicTime(128) 79 | 80 | // Quadratic time O(n^2) 81 | func quadratic(_ n: Int) -> Int { 82 | var result = 0 83 | for i in 0..() 97 | set.count 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | /* 119 | Given two arrays, create a function that let's a user know whether these two arrays contain any common items. 120 | */ 121 | 122 | // Naive brute force O(n^2) 123 | func commonItemsBrute(_ A: [Int], _ B: [Int]) -> Bool { 124 | for i in 0.. Bool { 139 | 140 | // Still looping...but not nested - O(2n) vs O(n^2) 141 | var hashA = [Int: Bool]() 142 | for a in A { // O(n) 143 | hashA[a] = true 144 | } 145 | 146 | // Now lookup in the hash to see if elements of B exist 147 | for b in B { 148 | if hashA[b] == true { 149 | return true 150 | } 151 | } 152 | return false 153 | } 154 | commonItemsHash([1, 2, 3], [4, 5, 6]) 155 | commonItemsHash([1, 2, 3], [3, 5, 6]) 156 | -------------------------------------------------------------------------------- /1-BigO/BigONotation.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /1-BigO/README.md: -------------------------------------------------------------------------------- 1 | # What is Big O Notation? 2 | 3 | Big O notation (aka Big O) is a way assessing the relative performance of a data structure or algorithm usually along two axis: time and space. 4 | 5 | ## Dominant Operations 6 | 7 | The way we determine an algorithms Big O, is to look at the worse case performance of it's dominant operations. 8 | 9 | ### Constant time - O(1) 10 | 11 | ```swift 12 | func constantTime(_ n: Int) -> Int { 13 | let result = n * n 14 | return result 15 | } 16 | ``` 17 | 18 | Algorithms that don't do a lot of looping, or simply return the result of some simple calculation are said to have *constant time* or *O(1)*. Meaning these operations are very quick. 19 | 20 | ### Linear time - O(n) 21 | 22 | ```swift 23 | func linearTime(_ A: [Int]) -> Int { 24 | for i in 0.. Note: Even though the loop could return immediately if the first value of the array is `0`, when evaluating Big O we always look for worst case performance. That's when this is still O(n) with a best case of O(1). 38 | 39 | ### Logarithmic time - O(log n) 40 | 41 | ```swift 42 | func logarithmicTime(_ N: Int) -> Int { 43 | var n = N 44 | var result = 0 45 | while n > 1 { 46 | n /= 2 47 | result += 1 48 | } 49 | return result 50 | } 51 | ``` 52 | 53 | Algorithms like BSTs (Binary Search Trees) are extremely fast because they half their results each time they look for a result. This halfing is logarithmic which we refer to as *O(log n)*. 54 | 55 | ### Quadratic time - O(n^2) 56 | 57 | ```swift 58 | func quadratic(_ n: Int) -> Int { 59 | var result = 0 60 | for i in 0.. Given two arrays, create a function that let's a user know whether these two arrays contain any common items. 93 | 94 | A brute force way to answer this question would be to loop through every element in both arrays until a match is found. Very efficient in terms of space. Slow in terms of time O(n^2). 95 | 96 | ```swift 97 | // Naive brute force O(n^2) 98 | func commonItemsBrute(_ A: [Int], _ B: [Int]) -> Bool { 99 | for i in 0.. Bool { 117 | 118 | // Still looping...but not nested - O(2n) vs O(n^2) 119 | var hashA = [Int: Bool]() 120 | for a in A { // O(n) 121 | hashA[a] = true 122 | } 123 | 124 | // Now lookup in the hash to see if elements of B exist 125 | for b in B { 126 | if hashA[b] == true { 127 | return true 128 | } 129 | } 130 | return false 131 | } 132 | commonItemsHash([1, 2, 3], [4, 5, 6]) 133 | commonItemsHash([1, 2, 3], [3, 5, 6]) 134 | ``` 135 | 136 | This is an example of trading of space for time. The brute force way required no extra space. Here is was very good. But in terms of time it was very slow. Not performant. 137 | 138 | By taking some space however (the extra Hash Map), we gained a lot of time, and got a much faster algorith (O(n)) as a result. 139 | 140 | This is just one trick we can use to improve the performance of our algorithms. And this is what the Googles, Facebooks, and Amazons will be looking for in their interviews. -------------------------------------------------------------------------------- /1-BigO/images/cheat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrasmusson/datastructures-algorithms/805b5739a333b143147360adb976be48230616db/1-BigO/images/cheat.png -------------------------------------------------------------------------------- /10-Graphs/Graphs.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /* 4 | ___ _ 5 | / __|_ _ __ _ _ __| |_ ___ 6 | | (_ | '_/ _` | '_ \ ' \(_-< 7 | \___|_| \__,_| .__/_||_/__/ 8 | |_| 9 | */ 10 | 11 | struct Queue { 12 | private var array: [T] 13 | 14 | init() { 15 | array = [] 16 | } 17 | 18 | var isEmpty: Bool { 19 | return array.isEmpty 20 | } 21 | 22 | var count: Int { 23 | return array.count 24 | } 25 | 26 | mutating func add(_ element: T) { 27 | array.append(element) 28 | } 29 | 30 | mutating func remove() -> T? { 31 | if isEmpty { 32 | return nil 33 | } else { 34 | return array.removeFirst() 35 | } 36 | } 37 | 38 | func peek() -> T? { 39 | return array.first 40 | } 41 | } 42 | 43 | struct Stack { 44 | fileprivate var array = [T]() 45 | 46 | var isEmpty: Bool { 47 | return array.isEmpty 48 | } 49 | 50 | var count: Int { 51 | return array.count 52 | } 53 | 54 | mutating func push(_ element: T) { 55 | array.append(element) 56 | } 57 | 58 | mutating func pop() -> T? { 59 | return array.popLast() 60 | } 61 | 62 | var top: T? { 63 | return array.last 64 | } 65 | } 66 | 67 | class Graph { 68 | var V = 0 // number of vertices 69 | var adj = [[Int]]() // adjacency list 70 | 71 | init(_ V: Int) { 72 | self.V = V 73 | for _ in 0.. [Int] { 84 | 85 | var result = [Int]() 86 | 87 | // Mark all vertices as not visited 88 | var visited = adj.map { _ in false } 89 | 90 | // Create BFS Queue 91 | var queue = Queue() 92 | 93 | // Mark first vertex as visited and enqueue 94 | visited[s] = true 95 | print("Starting at \(s)") 96 | queue.add(s) 97 | result.append(s) 98 | 99 | while queue.count > 0 { 100 | let current = queue.remove()! 101 | print("De-queueing \(current)") 102 | 103 | // Get all the adjacent vertices of the current vertex 104 | // If adjacent has not being visited, mark visited and enqueue 105 | 106 | for n in adj[current] { 107 | if visited[n] == false { 108 | visited[n] = true 109 | print("Queuing \(n)") 110 | queue.add(n) 111 | result.append(n) 112 | } 113 | } 114 | } 115 | 116 | return result 117 | } 118 | 119 | // DFS traversal from a given source s 120 | func DFS(s: Int) -> [Int] { 121 | 122 | var result = [Int]() 123 | 124 | // Mark all vertices as not visited 125 | var visited = adj.map { _ in false } 126 | 127 | // Create DFS Stack 128 | var stack = Stack() 129 | 130 | // Mark first vertex as visited and enqueue 131 | // print("Starting at \(s)") 132 | visited[s] = true 133 | stack.push(s) 134 | 135 | while stack.count > 0 { 136 | let current = stack.pop()! 137 | // print("Popping \(current)") 138 | result.append(current) 139 | 140 | // Iterate over all neighbours adding to queue and popping deep as we go 141 | for n in adj[current] { 142 | if visited[n] == false { 143 | visited[n] = true 144 | // print("Pushing - \(n)") 145 | stack.push(n) 146 | } 147 | } 148 | } 149 | 150 | return result 151 | } 152 | } 153 | 154 | // Need to have as many vertices as you have edges 155 | let g = Graph(8) 156 | g.addEdge(v: 0, w: 1) 157 | g.addEdge(v: 1, w: 4) 158 | g.addEdge(v: 4, w: 6) 159 | g.addEdge(v: 6, w: 0) 160 | g.addEdge(v: 1, w: 5) 161 | g.addEdge(v: 5, w: 3) 162 | g.addEdge(v: 3, w: 0) 163 | g.addEdge(v: 5, w: 2) 164 | g.addEdge(v: 2, w: 7) 165 | 166 | //g.BFS(s: 0) 167 | print(g.DFS(s: 0)) 168 | 169 | /* 170 | Graph 171 | ┌────┐ ┌────┐ ┌────┐ 172 | ┌────────────▶│ 5 │◀──────────▶ 2 │◀─────▶ 7 │ 173 | │ └────┘ └────┘ └────┘ 174 | │ ▲ 175 | │ └─────────┐ 176 | │ │ 177 | ▼ ▼ 178 | ┌────┐ ┌────┐ ┌────┐ 179 | │ 1 │◀────────▶│ 0 │◀────▶ 3 │ 180 | └────┘ └────┘ └────┘ 181 | ▲ │ 182 | ▼ ▼ 183 | ┌────┐ ┌────┐ 184 | │ 4 │◀─────────▶ 6 │ 185 | └────┘ └────┘ 186 | 187 | */ 188 | -------------------------------------------------------------------------------- /10-Graphs/Graphs.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /10-Graphs/Q1-PathExists-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /* 4 | You are given in undirected graph consisting of N vertices, numbered from 1 to N, and M edges. 5 | 6 | The graph is described by two arrays, A and B, both of length M. A pair A[K] and B[K] for K from 0 to M-1, describe the edge between vertex A[K] and vertex B[K]. 7 | 8 | Your task is to check whether the given graph contains a path from vertex 1 to vertex N going through all the vertices, one-by-one, in increasing order of the numbers. All connections on the path should be direct. 9 | 10 | Write a function, that given an integer N and two arrays A and B of M integers each, returns true if there exists a path from vertex 1 to N going through all vertices, one-by-one, in increasing order, or false other wise. 11 | 12 | Example 1: 13 | 14 | ┌─────┐ 15 | ┌──────│ 3 │──────┐ 16 | │ └─────┘ │ 17 | │ │ │ 18 | ┌─────┐ │ ┌─────┐ 19 | │ 2 │ │ │ 4 │ 20 | └───── │ └─────┘ 21 | │ ┌─────┐ │ 22 | └──────│ 1 │──────┘ 23 | └─────┘ 24 | 25 | Given N = 4 26 | A = [1, 2, 4, 4, 3] 27 | B = [2, 3, 1, 3, 1] 28 | Function should return true. 29 | 30 | There is a path (1 > 2 > 3 > 4) using edges (1, 2), (2, 3), (4, 3). 31 | 32 | Example 2: 33 | 34 | ┌─────┐ 35 | ┌──────│ 4 │──────┐ 36 | │ └─────┘ │ 37 | │ │ │ 38 | ┌─────┐ │ ┌─────┐ 39 | │ 2 │ │ │ 3 │ 40 | └───── │ └─────┘ 41 | │ ┌─────┐ │ 42 | └──────│ 1 │──────┘ 43 | └─────┘ 44 | 45 | Given N = 4 46 | A = [1, 2, 1, 3] 47 | B = [2, 4, 3, 4] 48 | Function should return false. 49 | 50 | There is no path (1 > 2 > 3 > 4) as there is no direct connection from vertex 2 to vertex 3. 51 | 52 | Example 3: 53 | 54 | ┌─────┐ 55 | │ 1 │ 56 | └─────┘ 57 | 58 | ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ 59 | │ 2 │────┤ 3 │────│ 4 │───│ 5 │────│ 6 │ 60 | └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ 61 | 62 | Given N = 6 63 | A = [2, 4, 5, 3] 64 | B = [3, 5, 6, 4] 65 | Function should return false. 66 | 67 | Example 4: 68 | 69 | ┌─────┐ ┌─────┐ ┌─────┐ 70 | │ 1 │────┤ 2 │────│ 3 │ 71 | └─────┘ └─────┘ └─────┘ 72 | 73 | Given N = 3 74 | A = [1, 3] 75 | B = [2, 2] 76 | Function should return true. 77 | 78 | 79 | Example 5: 80 | 81 | ┌─────┐ ┌─────┐ ┌─────┐ 82 | │ 2 │────┤ 3 │────│ 4 │ 83 | └─────┘ └─────┘ └─────┘ 84 | 85 | Given N = 3 86 | A = [2, 3] 87 | B = [3, 4] 88 | Function should return false. 89 | 90 | */ 91 | 92 | struct Edge: Equatable { 93 | let from: Int 94 | let to: Int 95 | 96 | init(_ from: Int, _ to: Int) { 97 | self.from = from 98 | self.to = to 99 | } 100 | } 101 | 102 | func solution(_ A: [Int], _ B: [Int]) -> Bool { 103 | guard A.count > 0 && B.count > 0 else { return false } 104 | let maxValue = max(A.max()!, B.max()!) 105 | 106 | // make edges 107 | var edges: [Edge] = [] 108 | for n in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /10-Graphs/Q1-PathExists-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /* 4 | You are given in undirected graph consisting of N vertices, numbered from 1 to N, and M edges. 5 | 6 | The graph is described by two arrays, A and B, both of length M. A pair A[K] and B[K] for K from 0 to M-1, describe the edge between vertex A[K] and vertex B[K]. 7 | 8 | Your task is to check whether the given graph contains a path from vertex 1 to vertex N going through all the vertices, one-by-one, in increasing order of the numbers. All connections on the path should be direct. 9 | 10 | Write a function, that given an integer N and two arrays A and B of M integers each, returns true if there exists a path from vertex 1 to N going through all vertices, one-by-one, in increasing order, or false other wise. 11 | 12 | Example 1: 13 | 14 | ┌─────┐ 15 | ┌──────│ 3 │──────┐ 16 | │ └─────┘ │ 17 | │ │ │ 18 | ┌─────┐ │ ┌─────┐ 19 | │ 2 │ │ │ 4 │ 20 | └───── │ └─────┘ 21 | │ ┌─────┐ │ 22 | └──────│ 1 │──────┘ 23 | └─────┘ 24 | 25 | Given N = 4 26 | A = [1, 2, 4, 4, 3] 27 | B = [2, 3, 1, 3, 1] 28 | Function should return true. 29 | 30 | There is a path (1 > 2 > 3 > 4) using edges (1, 2), (2, 3), (4, 3). 31 | 32 | Example 2: 33 | 34 | ┌─────┐ 35 | ┌──────│ 4 │──────┐ 36 | │ └─────┘ │ 37 | │ │ │ 38 | ┌─────┐ │ ┌─────┐ 39 | │ 2 │ │ │ 3 │ 40 | └───── │ └─────┘ 41 | │ ┌─────┐ │ 42 | └──────│ 1 │──────┘ 43 | └─────┘ 44 | 45 | Given N = 4 46 | A = [1, 2, 1, 3] 47 | B = [2, 4, 3, 4] 48 | Function should return false. 49 | 50 | There is no path (1 > 2 > 3 > 4) as there is no direct connection from vertex 2 to vertex 3. 51 | 52 | Example 3: 53 | 54 | ┌─────┐ 55 | │ 1 │ 56 | └─────┘ 57 | 58 | ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ 59 | │ 2 │────┤ 3 │────│ 4 │───│ 5 │────│ 6 │ 60 | └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ 61 | 62 | Given N = 6 63 | A = [2, 4, 5, 3] 64 | B = [3, 5, 6, 4] 65 | Function should return false. 66 | 67 | Example 4: 68 | 69 | ┌─────┐ ┌─────┐ ┌─────┐ 70 | │ 1 │────┤ 2 │────│ 3 │ 71 | └─────┘ └─────┘ └─────┘ 72 | 73 | Given N = 3 74 | A = [1, 3] 75 | B = [2, 2] 76 | Function should return true. 77 | 78 | 79 | Example 5: 80 | 81 | ┌─────┐ ┌─────┐ ┌─────┐ 82 | │ 2 │────┤ 3 │────│ 4 │ 83 | └─────┘ └─────┘ └─────┘ 84 | 85 | Given N = 3 86 | A = [2, 3] 87 | B = [3, 4] 88 | Function should return false. 89 | 90 | */ 91 | 92 | func solution(_ A: [Int], _ B: [Int]) -> Bool { 93 | return false 94 | } 95 | 96 | solution([], []) // false 97 | solution([1], [2]) // true 98 | solution([1, 3], [2, 2]) // true 99 | solution([1, 3], [2, 99]) // false 100 | solution([2, 3], [3, 4]) // false 101 | solution([1, 2, 4, 4, 3], [2, 3, 1, 3, 1]) // true 102 | solution([1, 2, 1, 3], [2, 4, 3, 4]) // false 103 | solution([2, 4, 5, 3], [3, 5, 6, 4]) // false 104 | -------------------------------------------------------------------------------- /10-Graphs/Q1-PathExists-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q1-UniqueCharacters-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ _ _ ___ _ 5 | | | | |_ _ (_)__ _ _ _ ___ / __| |_ __ _ _ _ ___ 6 | | |_| | ' \| / _` | || / -_) (__| ' \/ _` | '_(_-< 7 | \___/|_||_|_\__, |\_,_\___|\___|_||_\__,_|_| /__/ 8 | |_| 9 | 10 | Challenge: Given a string, see if you can detect whether it contains only unique chars. 11 | 12 | */ 13 | 14 | /* 15 | Solution: 16 | 17 | There are lots of ways we could solve this: 18 | - HashMap where we store every character and a boolean on whether found 19 | - An array that counts the number of times a character occurs 20 | */ 21 | 22 | func isUnique(_ text: String) -> Bool { 23 | var foundChars = [Character:Bool]() 24 | let chars = Array(text) 25 | 26 | for c in chars { 27 | if foundChars[c] != nil { // Already found 28 | return false 29 | } 30 | foundChars[c] = true 31 | } 32 | return true 33 | } 34 | 35 | isUnique("ab") 36 | isUnique("aa") 37 | isUnique("abcdefghijklmnopqrstuvwxyz") 38 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q1-UniqueCharacters-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q1-UniqueCharacters-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ _ _ ___ _ 5 | | | | |_ _ (_)__ _ _ _ ___ / __| |_ __ _ _ _ ___ 6 | | |_| | ' \| / _` | || / -_) (__| ' \/ _` | '_(_-< 7 | \___/|_||_|_\__, |\_,_\___|\___|_||_\__,_|_| /__/ 8 | |_| 9 | 10 | Challenge: Given a string, see if you can detect whether it contains only unique chars. 11 | 12 | */ 13 | 14 | func isUnique(_ text: String) -> Bool { 15 | return true 16 | } 17 | 18 | isUnique("ab") 19 | isUnique("aa") 20 | isUnique("abcdefghijklmnopqrstuvwxyz") 21 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q1-UniqueCharacters-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q2-Permutations-Answer.playground/Pages/Untitled Page 2.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | var str = "Hello, playground" 6 | 7 | //: [Next](@next) 8 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q2-Permutations-Answer.playground/Pages/Untitled Page.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ 5 | | _ \___ _ _ _ __ _ _| |_ __ _| |_(_)___ _ _ ___ 6 | | _/ -_) '_| ' \ || | _/ _` | _| / _ \ ' \(_-< 7 | |_| \___|_| |_|_|_\_,_|\__\__,_|\__|_\___/_||_/__/ 8 | 9 | Challenge: Given two strings, check if one is a permutation of the other. 10 | 11 | */ 12 | 13 | func isPermutation(_ text: String, _ perm: String) -> Bool { 14 | if text.count != perm.count { 15 | return false 16 | } 17 | 18 | return text.sorted() == perm.sorted() 19 | } 20 | 21 | isPermutation("abc", "cba") // true 22 | isPermutation("abc", "xyz") // false 23 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q2-Permutations-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q2-Permutations-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ 5 | | _ \___ _ _ _ __ _ _| |_ __ _| |_(_)___ _ _ ___ 6 | | _/ -_) '_| ' \ || | _/ _` | _| / _ \ ' \(_-< 7 | |_| \___|_| |_|_|_\_,_|\__\__,_|\__|_\___/_||_/__/ 8 | 9 | Challenge: Given two strings, check if one is a permutation of the other. 10 | 11 | */ 12 | 13 | func isPermutation(_ text: String, _ perm: String) -> Bool { 14 | return false 15 | } 16 | 17 | isPermutation("abc", "cba") // true 18 | isPermutation("abc", "xyz") // false 19 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q2-Permutations-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q3-URLify-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ _ ___ _ _ __ 5 | | | | | _ \ | (_)/ _|_ _ 6 | | |_| | / |__| | _| || | 7 | \___/|_|_\____|_|_| \_, | 8 | |__/ 9 | 10 | Challenge: See if you can replaces all the spaces in a a string with the 11 | ASCII symbol for space '%20'. Assume you are given the length of the final 12 | string. Hint: Use array of char[]. 13 | 14 | */ 15 | 16 | func urlify(_ url: String, length: Int) -> String { 17 | // Create a bucket to hold our final result 18 | var result = Array(repeating: " ", count: length) 19 | 20 | // Strip off any space at beginning or end 21 | let url = url.trimmingCharacters(in: .whitespacesAndNewlines) 22 | 23 | // Loop through url, and insert an ASCII space '%20' whenever we hit a space 24 | let urlChars = Array(url) 25 | 26 | // Also create a pointer to keep track of where we are in our results array 27 | var pointer = 0 28 | 29 | for i in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q3-URLify-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ _ ___ _ _ __ 5 | | | | | _ \ | (_)/ _|_ _ 6 | | |_| | / |__| | _| || | 7 | \___/|_|_\____|_|_| \_, | 8 | |__/ 9 | 10 | Challenge: See if you can replace all the spaces in a a string with the 11 | ASCII symbol for space '%20'. Assume you are given the length of the final 12 | string. Hint: Use array of char[]. 13 | 14 | */ 15 | 16 | func urlify(_ url: String, length: Int) -> String { 17 | return "" 18 | } 19 | 20 | urlify("My Home Page ", length: 16) // "My%20Home%20Page" 21 | 22 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q3-URLify-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q4-Oneaway-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | 5 | ___ 6 | / _ \ _ _ ___ __ ___ __ ____ _ _ _ 7 | |(_) | ' \/ -_) _` \ V V / _` | || | 8 | \___/|_||_\___\__,_|\_/\_/\__,_|\_, | 9 | |__/ 10 | 11 | Challenge: There are three types of edits that can be performed on strings: 12 | - insert a character 13 | - remove a character, or 14 | - replace a character. 15 | 16 | Given two strings, write a function to check if they are one or zero edits away. 17 | 18 | */ 19 | 20 | func oneAway(_ first: String, _ second: String) -> Bool { 21 | // Let's break this down. 22 | // If the strings differ by > 1 length, they are not one replacement away 23 | // If the strings are the same length, they are one replacement away 24 | // If the strings differ by one, they may be one edit or insert away 25 | // If the strings differ by one less, they may be one edit or insert away 26 | 27 | if abs(first.count - second.count) > 1 { 28 | return false 29 | } else if first.count == second.count { 30 | return oneEditReplace(first, second) 31 | } else if first.count + 1 == second.count { 32 | return oneEditInsert(first, second) 33 | } else if first.count - 1 == second.count { 34 | return oneEditInsert(second, first) 35 | } 36 | 37 | return true 38 | } 39 | 40 | // Check if you can insert a character into s1 to make s2 41 | // Do this by comparing characters and pointers. 42 | // 43 | // For example: 44 | // pale 45 | // i 46 | // pble 47 | // j 48 | // 49 | // As soon as you detect that one of the characters doesn't match, 50 | // compare the indexes. If they are the same, that's OK. That means 51 | // this is your first check that doesn't match. Increment the other pointer. 52 | // If the characters don't match again, and the pointers don't match, 53 | // you know they are more than one away. 54 | 55 | func oneEditInsert(_ s1: String, _ s2: String) -> Bool { 56 | var i = 0 57 | var j = 0 58 | 59 | let s1Chars = Array(s1) 60 | let s2Chars = Array(s2) 61 | 62 | while i < s1.count && j < s2.count { 63 | if s1Chars[i] != s2Chars[j] { 64 | if i != j { 65 | return false 66 | } 67 | j += 1 68 | } else { 69 | i += 1 70 | j += 1 71 | } 72 | } 73 | return true 74 | } 75 | 76 | // If we detect one difference - fine. 77 | // If we detect another - more than one edit away. 78 | func oneEditReplace(_ s1: String, _ s2: String) -> Bool { 79 | var foundDifference = false 80 | 81 | let s1Chars = Array(s1) 82 | let s2Chars = Array(s2) 83 | 84 | for i in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q4-Oneaway-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ 5 | / _ \ _ _ ___ __ ___ __ ____ _ _ _ 6 | |(_) | ' \/ -_) _` \ V V / _` | || | 7 | \___/|_||_\___\__,_|\_/\_/\__,_|\_, | 8 | |__/ 9 | 10 | Challenge: There are three types of edits that can be performed on strings: 11 | - insert a character 12 | - remove a character, or 13 | - replace a character. 14 | 15 | Given two strings, write a function to check if they are one or zero edits away. 16 | 17 | */ 18 | 19 | func oneAway(_ first: String, _ second: String) -> Bool { 20 | return false 21 | } 22 | 23 | oneAway("pale", "paleXXXX") // false 24 | oneAway("pale", "ple") // true 25 | oneAway("pales", "pale") // true 26 | oneAway("pale", "bale") // true 27 | oneAway("pale", "bake") // false 28 | oneAway("pale", "bakeerer") // false 29 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q4-Oneaway-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q5-Compressor-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ 5 | / __|___ _ __ _ __ _ _ ___ ______ ___ _ _ 6 | |(__/ _ \ ' \| '_ \ '_/ -_|_-<_- String { 18 | var compressed = "" 19 | var count = 0 20 | let chars = Array(str) 21 | 22 | for i in 0..= str.count || chars[i] != chars[i + 1] { 27 | compressed.append(chars[i]) 28 | compressed.append(String(count)) 29 | count = 0 30 | } 31 | } 32 | 33 | // Return the original string if shorter, or the compressed if longer 34 | return compressed.count < str.count ? compressed : str 35 | } 36 | 37 | compress("aaabb") // a3b2 38 | compress("aabb") // aabb 39 | compress("ab") // ab 40 | compress("abc") // abc 41 | compress("zzz") // z3 42 | compress("aabbaabb") // aabbaabb (not shorter) 43 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q5-Compressor-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q5-Compressor-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ 5 | / __|___ _ __ _ __ _ _ ___ ______ ___ _ _ 6 | |(__/ _ \ ' \| '_ \ '_/ -_|_-<_- String { 18 | return "" 19 | } 20 | 21 | compress("aaabb") // a3b2 22 | compress("aabb") // aabb 23 | compress("ab") // ab 24 | compress("abc") // abc 25 | compress("zzz") // z3 26 | compress("aabbaabb") // aabbaabb (not shorter) 27 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q5-Compressor-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q6-RemoveDuplicates-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ 5 | | \ _ _ _ __| (_)__ __ _| |_ ___ ___ 6 | | |) | || | '_ \ | / _/ _` | _/ -_|_-< 7 | |___/ \_,_| .__/_|_\__\__,_|\__\___/__/ 8 | |_| 9 | 10 | // Challenge: Write a method that removes any duplicates from our Linked List. 11 | 12 | */ 13 | 14 | func printLinkedListSimple(_ head: Node?) { 15 | if head == nil { return } 16 | 17 | var node = head 18 | print(node!.data) 19 | 20 | while node?.next != nil { 21 | print(node!.next!.data) 22 | node = node?.next 23 | } 24 | } 25 | 26 | class Node { 27 | var data: Int 28 | var next: Node? 29 | 30 | init(_ data: Int, _ next: Node? = nil) { 31 | self.data = data 32 | self.next = next 33 | } 34 | } 35 | 36 | func removeDuplictates(_ head: Node?) { 37 | // Create a hash table or set to store the unique values. 38 | // Then delete the duplicate as soon as we detect it while walking the list. 39 | // Algorithm is O(n). 40 | 41 | var uniques = Set() 42 | var previous: Node? = nil 43 | var current = head 44 | 45 | while current != nil { 46 | if uniques.contains(current!.data) { 47 | previous!.next = current!.next // skip this duplicate 48 | } else { 49 | uniques.insert(current!.data) 50 | previous = current 51 | } 52 | current = current!.next 53 | } 54 | } 55 | 56 | let node3 = Node(3) 57 | let node2 = Node(2, node3) 58 | let node1 = Node(1, node2) 59 | node3.next = Node(1) // duplicate 60 | printLinkedListSimple(node1) 61 | print("===") 62 | removeDuplictates(node1) 63 | printLinkedListSimple(node1) 64 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q6-RemoveDuplicates-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q6-RemoveDuplicates-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ 5 | | \ _ _ _ __| (_)__ __ _| |_ ___ ___ 6 | | |) | || | '_ \ | / _/ _` | _/ -_|_-< 7 | |___/ \_,_| .__/_|_\__\__,_|\__\___/__/ 8 | |_| 9 | 10 | // Challenge: Write a method that removes any duplicates from our Linked List. 11 | 12 | */ 13 | 14 | func printLinkedListSimple(_ head: Node?) { 15 | if head == nil { return } 16 | 17 | var node = head 18 | print(node!.data) 19 | 20 | while node?.next != nil { 21 | print(node!.next!.data) 22 | node = node?.next 23 | } 24 | } 25 | 26 | class Node { 27 | var data: Int 28 | var next: Node? 29 | 30 | init(_ data: Int, _ next: Node? = nil) { 31 | self.data = data 32 | self.next = next 33 | } 34 | } 35 | 36 | func removeDuplictates(_ head: Node?) -> Node? { 37 | return nil 38 | } 39 | 40 | let node3 = Node(3) 41 | let node2 = Node(2, node3) 42 | let node1 = Node(1, node2) 43 | node3.next = Node(1) // duplicate 44 | printLinkedListSimple(node1) 45 | print("===") 46 | removeDuplictates(node1) 47 | printLinkedListSimple(node1) 48 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q6-RemoveDuplicates-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q7-SubtreeChecker-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | / __|_ _| |__| |_ _ _ ___ ___ 6 | \__ \ || | '_ \ _| '_/ -_) -_) 7 | |___/\_,_|_.__/\__|_| \___\___| 8 | 9 | // Challenge: T1 is a large binary tree and T2 is a smaller one. Write an 10 | // algorithm to determine if T2 is a subtree of T1. 11 | 12 | Root 13 | 5 14 | 3 7 15 | 2 4 6 8 16 | 17 | Subtree 18 | 7 19 | 6 8 20 | 21 | */ 22 | 23 | class Node { 24 | var key: Int 25 | var left: Node? 26 | var right: Node? 27 | 28 | init(_ data: Int) { 29 | self.key = data 30 | } 31 | } 32 | 33 | func getOrder(_ root: Node) -> String { 34 | var result = "" 35 | preOrderTraversal(root, &result); 36 | return result 37 | } 38 | 39 | func preOrderTraversal(_ node: Node?, _ result: inout String) { 40 | guard let node = node else { return } 41 | result.append(String(node.key)) // root 42 | preOrderTraversal(node.left, &result) 43 | preOrderTraversal(node.right, &result) 44 | } 45 | 46 | let root = Node(5) 47 | root.left = Node(3) 48 | root.right = Node(7) 49 | root.left?.left = Node(2) 50 | root.left?.right = Node(4) 51 | root.right?.left = Node(6) 52 | root.right?.right = Node(8) 53 | 54 | let rootOrder = getOrder(root) // 5324768 55 | 56 | let subTree = Node(7) 57 | subTree.left = Node(6) 58 | subTree.right = Node(8) 59 | 60 | let subTreeOrder = getOrder(subTree) // 768 61 | 62 | func isSubTree(_ tree: Node, _ subTree: Node) -> Bool { 63 | let rootOrder = getOrder(root) // 5324768 64 | let subTreeOrder = getOrder(subTree) // 768 65 | 66 | return rootOrder.contains(subTreeOrder) 67 | } 68 | 69 | isSubTree(root, subTree) 70 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q7-SubtreeChecker-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q7-SubtreeChecker-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | / __|_ _| |__| |_ _ _ ___ ___ 6 | \__ \ || | '_ \ _| '_/ -_) -_) 7 | |___/\_,_|_.__/\__|_| \___\___| 8 | 9 | // Challenge: T1 is a large binary tree and T2 is a smaller one. Write an 10 | // algorithm to determine if T2 is a subtree of T1. 11 | 12 | Root 13 | 5 14 | 3 7 15 | 2 4 6 8 16 | 17 | Subtree 18 | 7 19 | 6 8 20 | 21 | */ 22 | 23 | class Node { 24 | var key: Int 25 | var left: Node? 26 | var right: Node? 27 | 28 | init(_ data: Int) { 29 | self.key = data 30 | } 31 | } 32 | 33 | func isSubTree(_ tree: Node, _ subTree: Node) -> Bool { 34 | return false 35 | } 36 | 37 | //isSubTree(root, subTree) 38 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q7-SubtreeChecker-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q8-MinStack-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | __ __ _ _ _ 5 | | \/ (_)_ _ __| |_ __ _ __| |__ 6 | | |\/| | | ' \ (_-< _/ _` / _| / / 7 | |_| |_|_|_||_| /__/\__\__,_\__|_\_\ 8 | 9 | // Challenge: Design a stack which, in addition to push and pop, has a function 10 | // 'min' which returns the minimum element? Push, pop and min should all operate in 11 | // O(1) time. 12 | 13 | */ 14 | 15 | // Doing it with a Linked List 16 | // 17 | // Stacks can be implemented as either arrays or via a linked list. 18 | // If we do it with a linked list, we can store the current minimum value 19 | // with each new node as we pop it onto the list. 20 | // 21 | // That way we have a running record of what the current min was, and the time 22 | // the node was added. 23 | // 24 | // Genious! 25 | 26 | class MinStack { 27 | private class Node { 28 | var data: Int 29 | var min: Int // track here 30 | var next: Node? 31 | 32 | init(_ data: Int, _ min: Int, _ next: Node? = nil) { 33 | self.data = data 34 | self.min = min 35 | self.next = next 36 | } 37 | } 38 | 39 | private var head: Node? 40 | 41 | func push(_ data: Int) { 42 | var currentMin = data 43 | 44 | // Check for min with each push 45 | if head != nil { 46 | currentMin = Swift.min(data, min()!) 47 | } 48 | 49 | let newNode = Node(data, currentMin) 50 | newNode.next = head 51 | head = newNode 52 | } 53 | 54 | func pop() -> Int? { 55 | let data = head?.data 56 | head = head?.next 57 | return data 58 | } 59 | 60 | func min() -> Int? { return head?.min } 61 | } 62 | 63 | let stack = MinStack() 64 | 65 | stack.push(5) 66 | stack.push(6) 67 | stack.push(3) 68 | stack.push(7) 69 | stack.min() // 3 70 | stack.pop() 71 | stack.min() // 3 72 | stack.pop() 73 | stack.min() // 5 74 | 75 | 76 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q8-MinStack-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q8-MinStack-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | __ __ _ _ _ 5 | | \/ (_)_ _ __| |_ __ _ __| |__ 6 | | |\/| | | ' \ (_-< _/ _` / _| / / 7 | |_| |_|_|_||_| /__/\__\__,_\__|_\_\ 8 | 9 | // Challenge: Design a stack which, in addition to push and pop, has a function 10 | // 'min' which returns the minimum element? Push, pop and min should all operate in 11 | // O(1) time. 12 | 13 | */ 14 | 15 | let stack = MinStack() // Create this how ever you want... 16 | 17 | stack.push(5) 18 | stack.push(6) 19 | stack.push(3) 20 | stack.push(7) 21 | stack.min() // 3 22 | stack.pop() 23 | stack.min() // 3 24 | stack.pop() 25 | stack.min() // 5 26 | 27 | 28 | -------------------------------------------------------------------------------- /11-CommonlyAsked/Q8-MinStack-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q1-FizzBuzz-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ ___ 5 | | __(_)_____| _ )_ _ ______ 6 | | _|| |_ /_ / _ \ || |_ /_ / 7 | |_| |_/__/__|___/\_,_/__/__| 8 | 9 | // Challenge: Write a program that prints 1 to 100. 10 | // But for multiples of three print 'Fizz' instead of the number. 11 | // And for multiples of five print 'Buzz'. 12 | // For numbers which are multiples of both three and five print 'FizzBuzz'. 13 | // 14 | // Example 15 | 1 16 | 2 17 | Fizz 18 | 4 19 | Buzz 20 | ... 21 | 14 22 | FizzBuzz 23 | */ 24 | 25 | func fizzBuzz() { 26 | for i in 1..<101 { 27 | if i % 3 == 0 && i % 5 == 0 { 28 | print("FizzBuzz") 29 | } else if i % 3 == 0 { 30 | print("Fizz") 31 | } else if i % 5 == 0 { 32 | print("Buzz") 33 | } else { 34 | print(i) 35 | } 36 | } 37 | } 38 | 39 | fizzBuzz() 40 | -------------------------------------------------------------------------------- /12-GreatestHits/Q1-FizzBuzz-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q1-FizzBuzz-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ ___ 5 | | __(_)_____| _ )_ _ ______ 6 | | _|| |_ /_ / _ \ || |_ /_ / 7 | |_| |_/__/__|___/\_,_/__/__| 8 | 9 | // Challenge: Write a program that prints 1 to 100. 10 | // But for multiples of three print 'Fizz' instead of the number. 11 | // And for multiples of five print 'Buzz'. 12 | // For numbers which are multiples of both three and five print 'FizzBuzz'. 13 | // 14 | // Example 15 | 1 16 | 2 17 | Fizz 18 | 4 19 | Buzz 20 | ... 21 | 14 22 | FizzBuzz 23 | */ 24 | 25 | func fizzBuzz() { 26 | // You are here... 27 | } 28 | 29 | fizzBuzz() 30 | -------------------------------------------------------------------------------- /12-GreatestHits/Q1-FizzBuzz-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q2-Palindromes-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ _ 5 | | _ \ |__ _| (_)_ _ __| |_ _ ___ _ __ ___ ___ 6 | | _/ / _` | | | ' \/ _` | '_/ _ \ ' \/ -_|_-< 7 | |_| |_\__,_|_|_|_||_\__,_|_| \___/_|_|_\___/__/ 8 | 9 | // Challenge: Detect if a given string is a palindrome. 10 | // A palindrome is a word that can be spelt the same way forwards and backwards. 11 | 12 | */ 13 | 14 | func isPalindrome(_ text: String) -> Bool { 15 | let chars = Array(text) 16 | let length = chars.count 17 | 18 | for i in 0.. Bool { 36 | return value == String(value.reversed()) 37 | } 38 | 39 | -------------------------------------------------------------------------------- /12-GreatestHits/Q2-Palindromes-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q2-Palindromes-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ _ 5 | | _ \ |__ _| (_)_ _ __| |_ _ ___ _ __ ___ ___ 6 | | _/ / _` | | | ' \/ _` | '_/ _ \ ' \/ -_|_-< 7 | |_| |_\__,_|_|_|_||_\__,_|_| \___/_|_|_\___/__/ 8 | 9 | // Challenge: Detect if a given string is a palindrome. 10 | // A palindrome is a word that can be spelt the same way forwards and backwards. 11 | 12 | */ 13 | 14 | func isPalindrome(_ text: String) -> Bool { 15 | return false 16 | } 17 | 18 | isPalindrome("abba") // true 19 | isPalindrome("mom") // true 20 | isPalindrome("dad") // true 21 | isPalindrome("radar") // true 22 | isPalindrome("rush") // false 23 | isPalindrome("yes") // false 24 | -------------------------------------------------------------------------------- /12-GreatestHits/Q2-Palindromes-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q3-RansomNote-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ _ 5 | | _ \__ _ _ _ ___ ___ _ __ ___ | \| |___| |_ ___| | 6 | | / _` | ' \(_- Bool { 29 | 30 | // Create a map of all values 31 | let noteMap = map(note.replacingOccurrences(of: " ", with: "")) 32 | let letterMap = map(letters) 33 | 34 | // Compare 35 | for (key, _) in noteMap { 36 | if letterMap[key] == nil { 37 | return false 38 | } 39 | 40 | let noteCount = noteMap[key]! 41 | let letterCount = letterMap[key]! 42 | 43 | if letterCount < noteCount { 44 | return false 45 | } 46 | } 47 | return true 48 | } 49 | 50 | func map(_ text: String) -> [Character: Int] { 51 | var map = [Character: Int]() 52 | let chars = Array(text) 53 | 54 | for char in chars { 55 | if map[char] != nil { 56 | map[char] = map[char]! + 1 57 | } else { 58 | map[char] = 1 59 | } 60 | } 61 | return map 62 | } 63 | 64 | canWrite(note: "Pay", letters: "yaP") 65 | canWrite(note: "Pay", letters: "yaP a") 66 | canWrite(note: "Pay me $1000", letters: "ayPem0001$") 67 | canWrite(note: "Pay", letters: "Pa") 68 | -------------------------------------------------------------------------------- /12-GreatestHits/Q3-RansomNote-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q3-RansomNote-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ _ 5 | | _ \__ _ _ _ ___ ___ _ __ ___ | \| |___| |_ ___| | 6 | | / _` | ' \(_- Bool { 21 | return false 22 | } 23 | 24 | canWrite(note: "Pay", letters: "yaP") 25 | canWrite(note: "Pay", letters: "yaP a") 26 | canWrite(note: "Pay me $1000", letters: "ayPem0001$") 27 | canWrite(note: "Pay", letters: "Pa") 28 | -------------------------------------------------------------------------------- /12-GreatestHits/Q3-RansomNote-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q4-CaesarCipher-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ ___ _ _ 5 | / __|__ _ ___ ___ __ _ _ _ / __(_)_ __| |_ ___ _ _ 6 | |(__/ _` / -_|_- String { 94 | var result = "" 95 | let chars = Array(plainText) 96 | 97 | for char in chars { 98 | var encryptedLetter = " " 99 | if char != " " { 100 | encryptedLetter = encryptMap[char]! 101 | } 102 | result.append(encryptedLetter) 103 | } 104 | return result 105 | } 106 | 107 | func decrypt(_ cipherText: String) -> String { 108 | var result = "" 109 | let chars = Array(cipherText) 110 | 111 | for char in chars { 112 | var decryptedLetter = " " 113 | if char != " " { 114 | decryptedLetter = decryptMap[char]! 115 | } 116 | result.append(decryptedLetter) 117 | } 118 | return result 119 | } 120 | 121 | } 122 | 123 | let cipher = CaesarCipherSimple() 124 | 125 | cipher.encrypt("ABC") // XYZ 126 | cipher.encrypt("ATTACK AT FIRST LIGHT") // XQQXZH XQ CFOPQ IFDEQ 127 | cipher.encrypt("MEET AT THE RUBICON") // JBBQ XQ QEB ORYFZLK 128 | 129 | cipher.decrypt("XYZ") // ABC 130 | cipher.decrypt("XQQXZH XQ CFOPQ IFDEQ") // ATTACK AT FIRST LIGHT 131 | cipher.decrypt("JBBQ XQ QEB ORYFZLK") // MEET AT THE RUBICON 132 | 133 | // 134 | // This is a more algorithmic way of solving the Caesar Cipher using the following equations 135 | // 136 | // E(x) = (x + n) mod 26 137 | // D(x) = (x - n) mod 26 138 | // 139 | // x = letter 140 | // n = offset 141 | 142 | // What these equations basically say is, you can take any given letter, shift it by it's offset, and then 143 | // modulus 26 that result (25 letters in the alphabet). 144 | // 145 | // By applying this equation, we can come up with a more generic cipher algorithm, that encrypts and decrypts 146 | // for any generic offset (n). 147 | // 148 | // https://en.wikipedia.org/wiki/Caesar_cipher 149 | // http://www.sanfoundry.com/java-program-implement-caesar-cypher/ (based on) 150 | 151 | // Assumption: Upper case only 152 | 153 | class CaesarCipherAdvanced { 154 | 155 | let ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 156 | 157 | func encrypt(_ plainText: String, _ n: Int = 3) -> String { 158 | var result = "" 159 | let charsToEncrypt = Array(plainText) 160 | let lookupMap = Array(ALPHABET) 161 | 162 | for charToEncrypt in charsToEncrypt { 163 | var encryptedChar: Character = " " 164 | if charToEncrypt != " " { 165 | let x = lookupMap.firstIndex(of: charToEncrypt)! 166 | let key = (n + x) % 26 167 | encryptedChar = lookupMap[key] 168 | } 169 | result.append(encryptedChar) 170 | } 171 | return result 172 | } 173 | 174 | func decrypt(_ cipherText: String, _ n: Int = 3) -> String { 175 | var result = "" 176 | let charsToDecrypt = Array(cipherText) 177 | let lookupMap = Array(ALPHABET) 178 | 179 | for charToDecrypt in charsToDecrypt { 180 | var decryptedChar: Character = " " 181 | if charToDecrypt != " " { 182 | let x = lookupMap.firstIndex(of: charToDecrypt)! 183 | let key = (x - n) % 26 184 | decryptedChar = lookupMap[key] 185 | } 186 | result.append(decryptedChar) 187 | } 188 | return result 189 | } 190 | } 191 | 192 | let cipherAdvanced = CaesarCipherAdvanced() 193 | 194 | // Note: This algorithm shifts left (while the problem asks for right). 195 | // Keep it left to match solution in Wikipedia and make easier to follow. 196 | 197 | cipherAdvanced.encrypt("ABC") // DEF 198 | cipherAdvanced.encrypt("ATTACK AT FIRST LIGHT") // DWWDFN DW ILUVW OLJKW 199 | cipherAdvanced.encrypt("MEET AT THE RUBICON") // PHHW DW WKH UXELFRQ 200 | 201 | cipherAdvanced.decrypt("DEF") // ABC 202 | cipherAdvanced.decrypt("DWWDFN DW ILUVW OLJKW") // ATTACK AT FIRST LIGHT 203 | cipherAdvanced.decrypt("PHHW DW WKH UXELFRQ") // MEET AT THE RUBICON 204 | -------------------------------------------------------------------------------- /12-GreatestHits/Q4-CaesarCipher-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q4-CaesarCipher-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ ___ _ _ 5 | / __|__ _ ___ ___ __ _ _ _ / __(_)_ __| |_ ___ _ _ 6 | |(__/ _` / -_|_- String { 31 | return "" 32 | } 33 | } 34 | 35 | let cipher = CaesarCipher() 36 | 37 | cipher.encrypt("ABC") // XYZ 38 | cipher.encrypt("ATTACK AT FIRST LIGHT") // XQQXZH XQ CFOPQ IFDEQ 39 | cipher.encrypt("MEET AT THE RUBICON") // JBBQ XQ QEB ORYFZLK 40 | 41 | -------------------------------------------------------------------------------- /12-GreatestHits/Q4-CaesarCipher-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q6-StringReversal-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ ___ _ 5 | / __| |_ _ _(_)_ _ __ _ | _ \_____ _____ _ _ ___ __ _| | 6 | \__ \ _| '_| | ' \/ _` | | / -_) V / -_) '_(_- "cba" 12 | 13 | */ 14 | 15 | func reverse(_ text: String) -> String { 16 | var chars = Array(text) 17 | 18 | // Initialize pointers 19 | var left = 0 20 | var right = text.count - 1; 21 | 22 | // Loop through swapping left and right until we hit the middle 23 | for _ in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q6-StringReversal-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ ___ _ 5 | / __| |_ _ _(_)_ _ __ _ | _ \_____ _____ _ _ ___ __ _| | 6 | \__ \ _| '_| | ' \/ _` | | / -_) V / -_) '_(_- "cba" 12 | 13 | */ 14 | 15 | func reverse(_ text: String) -> String { 16 | return "" 17 | } 18 | 19 | reverse("Hello") // olleH 20 | reverse("Sam") // maS 21 | -------------------------------------------------------------------------------- /12-GreatestHits/Q6-StringReversal-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q7-IntegerReversal-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ ___ _ 5 | |_ _|_ _| |_ ___ __ _ ___ _ _ | _ \_____ _____ _ _ ___ __ _| | 6 | | || ' \ _/ -_) _` / -_) '_| | / -_) V / -_) '_(_- Int { 17 | var x = x 18 | let isNegative = x < 0 19 | 20 | if isNegative { 21 | x = abs(x) 22 | } 23 | 24 | var reverse = 0 25 | var lastDigit = 0 26 | 27 | while x >= 1 { 28 | lastDigit = x % 10 // get the last digit 29 | reverse = reverse * 10 + lastDigit // shift by order of magnitude each time 30 | print("x: \(x) lastDigit: \(lastDigit) reverse: \(reverse)") 31 | x = x / 10 // drop last digit 32 | } 33 | return isNegative ? reverse * -1 : reverse 34 | } 35 | 36 | reverse(123) // 321 37 | reverse(-123) // -321 38 | -------------------------------------------------------------------------------- /12-GreatestHits/Q7-IntegerReversal-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q7-IntegerReversal-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ ___ _ 5 | |_ _|_ _| |_ ___ __ _ ___ _ _ | _ \_____ _____ _ _ ___ __ _| | 6 | | || ' \ _/ -_) _` / -_) '_| | / -_) V / -_) '_(_- Int { 17 | return 0 18 | } 19 | 20 | reverse(123) // 321 21 | reverse(-123) // -321 22 | -------------------------------------------------------------------------------- /12-GreatestHits/Q7-IntegerReversal-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q8-Anagrams-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ 5 | /_\ _ _ __ _ __ _ _ _ __ _ _ __ ___ 6 | / _ \| ' \/ _` / _` | '_/ _` | ' \(_-< 7 | /_/ \_\_||_\__,_\__, |_| \__,_|_|_|_/__/ 8 | |___/ 9 | 10 | // Challenge: Given two strings, write an algorithm to detect whether one word is an anagram of the other. 11 | // An anagram is a word that can be made by changing the order of the letters in another word. 12 | // 13 | // For example: 14 | // tar => rat 15 | // state => taste 16 | 17 | */ 18 | 19 | /* 20 | We could create a Dictionary of each word, and do a count comparison 21 | like we did in ransom note. Or, we could note that two sorted String 22 | equal to each other would also be anagrams. 23 | */ 24 | 25 | func isAnagram(_ text: String, _ anagram: String) -> Bool { 26 | let chars1 = Array(text).sorted() 27 | let chars2 = Array(anagram).sorted() 28 | 29 | return chars1 == chars2 30 | } 31 | 32 | isAnagram("arc", "car") // true 33 | isAnagram("night", "thing") // true 34 | isAnagram("cat", "dog") // false 35 | -------------------------------------------------------------------------------- /12-GreatestHits/Q8-Anagrams-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /12-GreatestHits/Q8-Anagrams-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ 5 | /_\ _ _ __ _ __ _ _ _ __ _ _ __ ___ 6 | / _ \| ' \/ _` / _` | '_/ _` | ' \(_-< 7 | /_/ \_\_||_\__,_\__, |_| \__,_|_|_|_/__/ 8 | |___/ 9 | 10 | // Challenge: Given two strings, write an algorithm to detect whether one word is an anagram of the other. 11 | // An anagram is a word that can be made by changing the order of the letters in another word. 12 | // 13 | // For example: 14 | // tar => rat 15 | // state => taste 16 | 17 | */ 18 | 19 | func isAnagram(_ text: String, _ anagram: String) -> Bool { 20 | return false 21 | } 22 | 23 | isAnagram("arc", "car") // true 24 | isAnagram("night", "thing") // true 25 | isAnagram("cat", "dog") // false 26 | -------------------------------------------------------------------------------- /12-GreatestHits/Q8-Anagrams-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /13-Google/Q1-Google-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ 5 | / __|___ ___ __ _| |___ 6 | |(_ / _ \/ _ \/ _` | / -_) 7 | \___\___/\___/\__, |_\___| 8 | |___/ 9 | 10 | // https://www.youtube.com/watch?v=XKu_SEDAykw&ab_channel=LifeatGoogle 11 | 12 | Given a set of numbers, determine if there is a pair that equals a given sum. 13 | 14 | */ 15 | 16 | func hasPairWithSumBrute(_ data: [Int], _ sum: Int) -> Bool { 17 | // progressively walk - O(n^2) 18 | for i in 0.. Bool { 34 | 35 | // Store the complement in a Set 36 | var comp = Set() 37 | 38 | for value in data { // O(n) 39 | // And then add it if we haven't seen it 40 | print("Have we seen \(value)'s complement \(sum - value) before?") 41 | if comp.contains(value) { 42 | print("Yes we have - match ✅.") 43 | return true 44 | } 45 | print("No we have not. Add it.") 46 | comp.insert(sum - value) 47 | } 48 | return false 49 | } 50 | 51 | //hasPairWithSum([1, 2, 4, 9], 8) // false 52 | hasPairWithSum([1, 2, 4, 4], 8) // true 53 | //hasPairWithSum([1, 2, 4], 8) // false 54 | -------------------------------------------------------------------------------- /13-Google/Q1-Google-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /13-Google/Q1-Google-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ 5 | / __|___ ___ __ _| |___ 6 | |(_ / _ \/ _ \/ _` | / -_) 7 | \___\___/\___/\__, |_\___| 8 | |___/ 9 | 10 | Given a set of numbers, determine if there is a pair that equals a given sum. 11 | 12 | */ 13 | 14 | func hasPairWithSum(_ arr: [Int], _ sum: Int) -> Bool { 15 | return false 16 | } 17 | 18 | hasPairWithSum([1, 2, 4, 9], 8) // false 19 | hasPairWithSum([1, 2, 4, 4], 8) // true 20 | -------------------------------------------------------------------------------- /13-Google/Q1-Google-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q1-Facebook-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | | __|_ _ __ ___| |__ ___ ___| |__ 6 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 7 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 8 | 9 | Determine which elements intersect between two given arrays. 10 | 11 | */ 12 | 13 | func intersectBrute(_ A: [Int], _ B: [Int]) -> [Int] { 14 | var result = [Int]() 15 | 16 | // O(n) 17 | for a in A { 18 | // O(m) 19 | for b in B { 20 | if a == b { 21 | result.append(a) 22 | } 23 | } 24 | } 25 | return result 26 | } 27 | 28 | intersectBrute([1, 2, 4, 5, 6], [2, 3, 5, 7]) // [2, 5] 29 | 30 | func intersect(_ A: [Int], _ B: [Int]) -> [Int] { 31 | 32 | // create two pointers and loop through both arrays 33 | // if one element is less than the other... 34 | // increment the lower pointer 35 | // if elements are equal collect 36 | // then increment either of the pointers 37 | 38 | var result = [Int]() 39 | 40 | var i = 0; let m = A.count 41 | var j = 0; let n = B.count 42 | 43 | // O(n + m) 44 | while i < m && j < n { 45 | if A[i] < B[j] { 46 | i += 1 47 | } else if B[j] < A[i] { 48 | j += 1 49 | } else { 50 | result.append(A[i]) 51 | i += 1 52 | } 53 | } 54 | 55 | return result 56 | } 57 | 58 | intersect([1, 2, 4, 5, 6], [2, 3, 5, 7]) // [2, 5] 59 | -------------------------------------------------------------------------------- /14-TheFacebook/Q1-Facebook-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q1-Facebook-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | | __|_ _ __ ___| |__ ___ ___| |__ 6 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 7 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 8 | 9 | Determine which elements intersect between two given arrays. 10 | 11 | */ 12 | 13 | func intersect(_ A: [Int], _ B: [Int]) -> [Int] { 14 | return [Int]() 15 | } 16 | 17 | intersect([1, 2, 4, 5, 6], [2, 3, 5, 7]) // [2, 5] 18 | -------------------------------------------------------------------------------- /14-TheFacebook/Q1-Facebook-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q2-Facebook-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | | __|_ _ __ ___| |__ ___ ___| |__ 6 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 7 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 8 | 9 | Write, in code, how one could represent the node of a binary tree. 10 | 11 | */ 12 | 13 | class Node { 14 | var data: Int 15 | var left: Node? 16 | var right: Node? 17 | 18 | init(_ data: Int) { 19 | self.data = data 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /14-TheFacebook/Q2-Facebook-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q2-Facebook-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | | __|_ _ __ ___| |__ ___ ___| |__ 6 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 7 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 8 | 9 | Write, in code, how one could represent the node of a binary tree. 10 | 11 | */ 12 | 13 | // Create your node here... 14 | -------------------------------------------------------------------------------- /14-TheFacebook/Q2-Facebook-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q3-Facebook-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | ___ _ _ 6 | | __|_ _ __ ___| |__ ___ ___| |__ 7 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 8 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 9 | 10 | Give a binary tree node, write a copy function that duplicates 11 | the right and left branches of the node. 12 | */ 13 | 14 | class Node { 15 | var data: Int 16 | var left: Node? 17 | var right: Node? 18 | 19 | init(_ data: Int) { 20 | self.data = data 21 | } 22 | 23 | func copy() -> Node { 24 | let newNode = Node(data) 25 | if let left = left { 26 | newNode.left = left.copy() 27 | } 28 | if let right = right { 29 | newNode.right = right.copy() 30 | } 31 | return newNode 32 | } 33 | } 34 | 35 | class Tests: XCTestCase { 36 | 37 | func testCopy() { 38 | // 1 39 | // / \ 40 | // 2 3 41 | let node1 = Node(1) 42 | let node2 = Node(2) 43 | let node3 = Node(3) 44 | node1.left = node2 45 | node1.right = node3 46 | 47 | let newCopy = node1.copy() 48 | XCTAssertEqual(newCopy.data, node1.data) 49 | XCTAssertEqual(newCopy.left!.data, node1.left!.data) 50 | XCTAssertEqual(newCopy.right!.data, node1.right!.data) 51 | } 52 | 53 | func testDeepCopy() { 54 | // 5 55 | // / \ 56 | // 3 7 57 | // / \ /\ 58 | // 2 4 6 8 59 | let node5 = Node(5) 60 | let node3 = Node(3) 61 | let node7 = Node(7) 62 | let node2 = Node(2) 63 | let node4 = Node(4) 64 | let node6 = Node(6) 65 | let node8 = Node(8) 66 | 67 | node5.left = node3 68 | node5.right = node7 69 | 70 | node3.left = node2 71 | node3.right = node4 72 | 73 | node7.left = node6 74 | node7.right = node8 75 | 76 | let newCopy = node5.copy() 77 | XCTAssertEqual(newCopy.data, node5.data) 78 | XCTAssertEqual(newCopy.left!.data, node5.left!.data) 79 | XCTAssertEqual(newCopy.right!.data, node5.right!.data) 80 | 81 | // Modify 7 to point to 9 instead of 8 82 | let node9 = Node(9) 83 | node7.right = node9 84 | 85 | // Copy should still point to old value - 8 86 | XCTAssertEqual(newCopy.right!.right!.data, 8) 87 | } 88 | } 89 | 90 | // Infrastructure 91 | class TestObserver: NSObject, XCTestObservation { 92 | func testCase(_ testCase: XCTestCase, 93 | didFailWithDescription description: String, 94 | inFile filePath: String?, 95 | atLine lineNumber: Int) { 96 | assertionFailure(description, line: UInt(lineNumber)) 97 | } 98 | } 99 | let testObserver = TestObserver() 100 | XCTestObservationCenter.shared.addTestObserver(testObserver) 101 | Tests.defaultTestSuite.run() 102 | -------------------------------------------------------------------------------- /14-TheFacebook/Q3-Facebook-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q3-Facebook-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | | __|_ _ __ ___| |__ ___ ___| |__ 6 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 7 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 8 | 9 | Give a binary tree node, write a copy function that duplicates 10 | the right and left branches of the node. 11 | */ 12 | 13 | class Node { 14 | var data: Int 15 | var left: Node? 16 | var right: Node? 17 | 18 | init(_ data: Int) { 19 | self.data = data 20 | } 21 | 22 | func copy() -> Node { 23 | // Do your work here... 24 | return Node(0) 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /14-TheFacebook/Q3-Facebook-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q4-Facebook-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | ___ _ _ 6 | | __|_ _ __ ___| |__ ___ ___| |__ 7 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 8 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 9 | 10 | Give a binary tree node, write a copy function that duplicates 11 | the right and left branches of the node. 12 | */ 13 | 14 | class Node { 15 | var data: Int 16 | var left: Node? 17 | var right: Node? 18 | 19 | init(_ data: Int) { 20 | self.data = data 21 | } 22 | 23 | func copy() -> Node { 24 | let newNode = Node(data) 25 | if let left = left { 26 | newNode.left = left.copy() 27 | } 28 | if let right = right { 29 | newNode.right = right.copy() 30 | } 31 | return newNode 32 | } 33 | 34 | func inOrderTraversal(node: Node?) { 35 | // L 36 | // Root 37 | // R 38 | guard let node = node else { return } 39 | inOrderTraversal(node: node.left) // L 40 | print(node.data) // root // Root 41 | inOrderTraversal(node: node.right)// R 42 | } 43 | } 44 | 45 | class Tests: XCTestCase { 46 | 47 | func testCopy() { 48 | // 1 49 | // / \ 50 | // 2 3 51 | let node1 = Node(1) 52 | let node2 = Node(2) 53 | let node3 = Node(3) 54 | node1.left = node2 55 | node1.right = node3 56 | 57 | let newCopy = node1.copy() 58 | XCTAssertEqual(newCopy.data, node1.data) 59 | XCTAssertEqual(newCopy.left!.data, node1.left!.data) 60 | XCTAssertEqual(newCopy.right!.data, node1.right!.data) 61 | 62 | // print nodes inorder traversal 63 | newCopy.inOrderTraversal(node: newCopy) 64 | } 65 | 66 | func testDeepCopy() { 67 | // 5 68 | // / \ 69 | // 3 7 70 | // / \ /\ 71 | // 2 4 6 8 72 | let node5 = Node(5) 73 | let node3 = Node(3) 74 | let node7 = Node(7) 75 | let node2 = Node(2) 76 | let node4 = Node(4) 77 | let node6 = Node(6) 78 | let node8 = Node(8) 79 | 80 | node5.left = node3 81 | node5.right = node7 82 | 83 | node3.left = node2 84 | node3.right = node4 85 | 86 | node7.left = node6 87 | node7.right = node8 88 | 89 | let newCopy = node5.copy() 90 | XCTAssertEqual(newCopy.data, node5.data) 91 | XCTAssertEqual(newCopy.left!.data, node5.left!.data) 92 | XCTAssertEqual(newCopy.right!.data, node5.right!.data) 93 | 94 | // Modify 7 to point to 9 instead of 8 95 | let node9 = Node(9) 96 | node7.right = node9 97 | 98 | // Copy should still point to old value - 8 99 | XCTAssertEqual(newCopy.right!.right!.data, 8) 100 | 101 | // print nodes inorder traversal 102 | newCopy.inOrderTraversal(node: newCopy) 103 | } 104 | } 105 | 106 | // Infrastructure 107 | class TestObserver: NSObject, XCTestObservation { 108 | func testCase(_ testCase: XCTestCase, 109 | didFailWithDescription description: String, 110 | inFile filePath: String?, 111 | atLine lineNumber: Int) { 112 | assertionFailure(description, line: UInt(lineNumber)) 113 | } 114 | } 115 | let testObserver = TestObserver() 116 | XCTestObservationCenter.shared.addTestObserver(testObserver) 117 | Tests.defaultTestSuite.run() 118 | 119 | -------------------------------------------------------------------------------- /14-TheFacebook/Q4-Facebook-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /14-TheFacebook/Q4-Facebook-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | ___ _ _ 6 | | __|_ _ __ ___| |__ ___ ___| |__ 7 | | _/ _` / _/ -_) '_ \/ _ \/ _ \ / / 8 | |_|\__,_\__\___|_.__/\___/\___/_\_\ 9 | 10 | Give a binary tree node, write a copy function that duplicates 11 | the right and left branches of the node. 12 | */ 13 | 14 | class Node { 15 | var data: Int 16 | var left: Node? 17 | var right: Node? 18 | 19 | init(_ data: Int) { 20 | self.data = data 21 | } 22 | 23 | func copy() -> Node { 24 | let newNode = Node(data) 25 | if let left = left { 26 | newNode.left = left.copy() 27 | } 28 | if let right = right { 29 | newNode.right = right.copy() 30 | } 31 | return newNode 32 | } 33 | 34 | func inOrderTraversal(node: Node?) { 35 | // Do your work here... 36 | } 37 | 38 | } 39 | 40 | class Tests: XCTestCase { 41 | 42 | func testCopy() { 43 | // 1 44 | // / \ 45 | // 2 3 46 | let node1 = Node(1) 47 | let node2 = Node(2) 48 | let node3 = Node(3) 49 | node1.left = node2 50 | node1.right = node3 51 | 52 | let newCopy = node1.copy() 53 | XCTAssertEqual(newCopy.data, node1.data) 54 | XCTAssertEqual(newCopy.left!.data, node1.left!.data) 55 | XCTAssertEqual(newCopy.right!.data, node1.right!.data) 56 | 57 | // print nodes inorder traversal 58 | 59 | } 60 | 61 | func testDeepCopy() { 62 | // 5 63 | // / \ 64 | // 3 7 65 | // / \ /\ 66 | // 2 4 6 8 67 | let node5 = Node(5) 68 | let node3 = Node(3) 69 | let node7 = Node(7) 70 | let node2 = Node(2) 71 | let node4 = Node(4) 72 | let node6 = Node(6) 73 | let node8 = Node(8) 74 | 75 | node5.left = node3 76 | node5.right = node7 77 | 78 | node3.left = node2 79 | node3.right = node4 80 | 81 | node7.left = node6 82 | node7.right = node8 83 | 84 | let newCopy = node5.copy() 85 | XCTAssertEqual(newCopy.data, node5.data) 86 | XCTAssertEqual(newCopy.left!.data, node5.left!.data) 87 | XCTAssertEqual(newCopy.right!.data, node5.right!.data) 88 | 89 | // Modify 7 to point to 9 instead of 8 90 | let node9 = Node(9) 91 | node7.right = node9 92 | 93 | // Copy should still point to old value - 8 94 | XCTAssertEqual(newCopy.right!.right!.data, 8) 95 | 96 | // print nodes inorder traversal 97 | 98 | } 99 | } 100 | 101 | // Infrastructure 102 | class TestObserver: NSObject, XCTestObservation { 103 | func testCase(_ testCase: XCTestCase, 104 | didFailWithDescription description: String, 105 | inFile filePath: String?, 106 | atLine lineNumber: Int) { 107 | assertionFailure(description, line: UInt(lineNumber)) 108 | } 109 | } 110 | let testObserver = TestObserver() 111 | XCTestObservationCenter.shared.addTestObserver(testObserver) 112 | Tests.defaultTestSuite.run() 113 | 114 | -------------------------------------------------------------------------------- /14-TheFacebook/Q4-Facebook-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /15-Amazon/Amazon-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | _ 6 | /_\ _ __ __ _ ______ _ _ 7 | / _ \| ' \/ _` |_ / _ \ ' \ 8 | /_/ \_\_|_|_\__,_/__\___/_||_| 9 | 10 | Write an algorithm that merges these two arrays into one. 11 | 12 | */ 13 | 14 | func merge(_ L1: [Int], _ L2: [Int]) -> [Int] { 15 | var result = [Int]() 16 | 17 | var i = 0 18 | var j = 0 19 | 20 | // Merge the full length of on list 21 | while i < L1.count && j < L2.count { 22 | if L1[i] <= L2[j] { 23 | result.append(L1[i]) 24 | i += 1 25 | } else { 26 | result.append(L2[j]) 27 | j += 1 28 | } 29 | } 30 | 31 | // Copy remaining elements of L1 32 | while i < L1.count { 33 | result.append(L1[i]) 34 | i += 1 35 | } 36 | 37 | // Copy remaining elements of L2 38 | while j < L2.count { 39 | result.append(L2[j]) 40 | j += 1 41 | } 42 | 43 | return result 44 | } 45 | 46 | 47 | 48 | class Tests: XCTestCase { 49 | 50 | func testMerge() { 51 | let expected = [1, 2, 3, 5, 5, 7, 8, 11, 14] 52 | let actual = merge([1, 3, 5, 7], [2, 5, 8, 11, 14]) 53 | XCTAssertEqual(expected, actual) 54 | } 55 | 56 | func testL1Empty() { 57 | let expected = [2, 5, 8, 11, 14] 58 | let actual = merge([], [2, 5, 8, 11, 14]) 59 | XCTAssertEqual(expected, actual) 60 | } 61 | 62 | func testL2Empty() { 63 | let expected = [1, 3, 5, 7] 64 | let actual = merge([1, 3, 5, 7], []) 65 | XCTAssertEqual(expected, actual) 66 | } 67 | 68 | func testNoOverlap() { 69 | let expected = [1, 2, 3, 4, 5, 6] 70 | let actual = merge([1, 2, 3], [4, 5, 6]) 71 | XCTAssertEqual(expected, actual) 72 | } 73 | } 74 | 75 | // Infrastructure 76 | class TestObserver: NSObject, XCTestObservation { 77 | func testCase(_ testCase: XCTestCase, 78 | didFailWithDescription description: String, 79 | inFile filePath: String?, 80 | atLine lineNumber: Int) { 81 | assertionFailure(description, line: UInt(lineNumber)) 82 | } 83 | } 84 | let testObserver = TestObserver() 85 | XCTestObservationCenter.shared.addTestObserver(testObserver) 86 | Tests.defaultTestSuite.run() 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /15-Amazon/Amazon-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /15-Amazon/Amazon-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ 5 | /_\ _ __ __ _ ______ _ _ 6 | / _ \| ' \/ _` |_ / _ \ ' \ 7 | /_/ \_\_|_|_\__,_/__\___/_||_| 8 | 9 | Write an algorithm that merges these two arrays into one. 10 | 11 | */ 12 | 13 | func merge(_ A: [Int], _ B: [Int]) -> [Int] { 14 | // Do your work here... 15 | return [Int]() 16 | } 17 | 18 | merge([1, 3, 5, 7], [2, 5, 8, 11, 14]) // [1, 2, 3, 5, 5, 7, 8, 11, 14] 19 | 20 | 21 | -------------------------------------------------------------------------------- /15-Amazon/Amazon-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /16-Spotify/Q4-Spotify.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ __ 5 | / __|_ __ ___| |_(_)/ _|_ _ 6 | \__ \ '_ \/ _ \ _| | _| || | 7 | |___/ .__/\___/\__|_|_| \_, | 8 | |_| |__/ 9 | */ 10 | var str = "Hello, playground" 11 | -------------------------------------------------------------------------------- /16-Spotify/Q4-Spotify.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /2-Arrays/0-Arrays.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | _ 5 | /_\ _ _ _ _ __ _ _ _ ___ 6 | / _ \| '_| '_/ _` | || (_-< 7 | /_/ \_\_| |_| \__,_|\_, /__/ 8 | |__/ 9 | */ 10 | 11 | struct Person {} 12 | 13 | let ints = [1, 2, 3] 14 | let strings = ["a", "b", "c"] 15 | let people = [Person(), Person(), Person()] 16 | 17 | //let ints = [Int]() 18 | //let strings = [String]() 19 | //let people = [Person]() 20 | 21 | let arrayOfSpecificSize = Array(repeating: 1, count: 10) 22 | 23 | var array = ["a", "b", "c", "d"] 24 | array.remove(at: 1) 25 | array.insert("b", at: 1) 26 | array.append("e") 27 | 28 | -------------------------------------------------------------------------------- /2-Arrays/0-Arrays.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /2-Arrays/Q1-CyclicRotation-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Rotate array to right N times. 5 | https://app.codility.com/programmers/lessons/2-arrays/cyclic_rotation/ 6 | 7 | For example, given 8 | 9 | A = [3, 8, 9, 7, 6] 10 | K = 3 11 | the function should return [9, 7, 6, 3, 8]. Three rotations were made: 12 | 13 | [3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7] 14 | [6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9] 15 | [7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8] 16 | 17 | */ 18 | 19 | func solution(A: [Int], K: Int) -> [Int] { 20 | guard !A.isEmpty else { return [] } 21 | guard K > 0 else { return A } 22 | 23 | var result = A 24 | for _ in 1...K { // O(n) 25 | result = rotateRightOnce(A: result) 26 | } 27 | return result 28 | } 29 | 30 | func rotateRightOnce(A: [Int]) -> [Int] { 31 | var newArray = Array(repeating: 0, count: A.count) 32 | for i in 0.. [Int] { 60 | guard !A.isEmpty else { return [] } 61 | guard K > 0 else { return A } 62 | 63 | var result = A 64 | 65 | // treat like a stack and pop off first and add to end 66 | for _ in 1...K { 67 | let last = result.last! // O(1) 68 | result.insert(last, at: 0) // O(n) 69 | result.remove(at: A.count) // O(n) 70 | } 71 | 72 | return result 73 | } 74 | 75 | solutionStackRight(A: [1, 2, 3, 4, 5], K: 1) 76 | solutionStackRight(A: [1, 2, 3, 4, 5], K: 2) 77 | solutionStackRight(A: [1, 2, 3, 4, 5], K: 3) 78 | solutionStackRight(A: [1, 2, 3, 4, 5], K: 4) 79 | 80 | func solutionStackLeft(A: [Int], K: Int) -> [Int] { 81 | guard !A.isEmpty else { return [] } 82 | guard K > 0 else { return A } 83 | 84 | var result = A 85 | 86 | // treat like a stack and pop off first and add to end 87 | for _ in 1...K { 88 | let first = result.first! 89 | result.append(first) 90 | result.remove(at: 0) 91 | } 92 | 93 | return result 94 | } 95 | 96 | solutionStackLeft(A: [1, 2, 3, 4, 5], K: 1) 97 | solutionStackLeft(A: [1, 2, 3, 4, 5], K: 4) 98 | 99 | -------------------------------------------------------------------------------- /2-Arrays/Q1-CyclicRotation-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /2-Arrays/Q1-CyclicRotation-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Rotate array to right N times. 5 | https://app.codility.com/programmers/lessons/2-arrays/cyclic_rotation/ 6 | 7 | For example, given 8 | 9 | A = [3, 8, 9, 7, 6] 10 | K = 3 11 | the function should return [9, 7, 6, 3, 8]. Three rotations were made: 12 | 13 | [3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7] 14 | [6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9] 15 | [7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8] 16 | 17 | */ 18 | 19 | func solution(A: [Int], K: Int) -> [Int] { 20 | // do your work here... 21 | return [Int]() 22 | } 23 | 24 | solution(A: [1, 2, 3, 4, 5], K: 1) // 5 1 2 3 4 25 | solution(A: [1, 2, 3, 4, 5], K: 2) // 4 5 1 2 3 26 | solution(A: [1, 2, 3, 4, 5], K: 3) // 3 4 5 1 2 27 | 28 | solution(A: [3, 8, 9, 7, 6], K: 3) // [9, 7, 6, 3, 8] 29 | 30 | -------------------------------------------------------------------------------- /2-Arrays/Q1-CyclicRotation-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /2-Arrays/Q2-DashPhoneNumber-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | We are given a string S representing a phone number, which we would like to reformat. String S consists of N characters: digits, spaces, and/or dashes. It contains at least two digits. 5 | 6 | Spaces and dashes in string S can be ignored. We want to reformat the given phone number is such a way that the digits are grouped in blocks of length three, separated by single dashes. If necessary, the final block or the last two blocks can be of length two. 7 | 8 | For example: 9 | 10 | S = "00-44 48 5555 8361" should become 11 | "004-448-555-583-61" 12 | 13 | Assume: 14 | - S consists only of digits (0-9), spaces, and/or dashses (-) 15 | - S containts at least two digits 16 | 17 | Translate: 18 | 19 | Would like to reformat a phone number string so that: 20 | - every third char is a "-" 21 | - spaces and dashes don't matter 22 | - if the block ends in anything other than -xxx or -xx reformat to a block of two like xx-xx (not obvious) 23 | 24 | */ 25 | func solution(_ S : String) -> String { 26 | 27 | let noSpace = S.replacingOccurrences(of: " ", with: "") 28 | let noSpaceNoDash = noSpace.replacingOccurrences(of: "-", with: "") 29 | 30 | // loop through char-by-char appending dashes 31 | var result = "" 32 | 33 | var count = -2 34 | for c in noSpaceNoDash { 35 | result.append(c) 36 | if count % 3 == 0 { 37 | result.append("-") 38 | } 39 | count += 1 40 | } 41 | 42 | // strip off lingering dash 43 | if result.last == "-" { 44 | result = String(result.dropLast()) 45 | } 46 | 47 | // if second last char has a dash (-x) 48 | // reformat last three chars to (-xx) 49 | var chars = Array(result) 50 | let secondLastPtr = chars.count - 2 51 | if chars[secondLastPtr] == "-" { 52 | // *-x > -*x 53 | chars[secondLastPtr] = chars[secondLastPtr - 1] 54 | chars[secondLastPtr - 1] = "-" 55 | } 56 | 57 | return String(chars) 58 | } 59 | 60 | solution("123456789") // 123-456-789 61 | solution("555372654") // 555-372-654 62 | solution("0 - 22 1985--324") // 022-198-53-24 63 | 64 | // Edge cases 65 | solution("01") // 01 66 | solution("012") // 012 67 | solution("0123") // 01-23 68 | solution("0123 444") // 012-34-44 69 | solution("------0123 444") // 012-34-44 70 | -------------------------------------------------------------------------------- /2-Arrays/Q2-DashPhoneNumber-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /2-Arrays/Q2-DashPhoneNumber-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | We are given a string S representing a phone number, which we would like to reformat. String S consists of N characters: digits, spaces, and/or dashes. It contains at least two digits. 5 | 6 | Spaces and dashes in string S can be ignored. We want to reformat the given phone number is such a way that the digits are grouped in blocks of length three, separated by single dashes. If necessary, the final block or the last two blocks can be of length two. 7 | 8 | For example: 9 | 10 | S = "00-44 48 5555 8361" should become 11 | "004-448-555-583-61" 12 | 13 | Assume: 14 | - S consists only of digits (0-9), spaces, and/or dashses (-) 15 | - S containts at least two digits 16 | 17 | Translate: 18 | 19 | Would like to reformat a phone number string so that: 20 | - every third char is a "-" 21 | - spaces and dashes don't matter 22 | - if the block ends in anything other than -xxx or -xx reformat to a block of two like xx-xx (not obvious) 23 | 24 | */ 25 | func solution(_ S : String) -> String { 26 | // do your work here 27 | return "" 28 | } 29 | 30 | solution("123456789") // 123-456-789 31 | solution("555372654") // 555-372-654 32 | solution("0 - 22 1985--324") // 022-198-53-24 33 | 34 | // Edge cases 35 | solution("01") // 01 36 | solution("012") // 012 37 | solution("0123") // 01-23 38 | solution("0123 444") // 012-34-44 39 | solution("------0123 444") // 012-34-44 40 | -------------------------------------------------------------------------------- /2-Arrays/Q2-DashPhoneNumber-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /2-Arrays/Q3-ContactMatch-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /* 4 | When someone searches their contacts based on a phone number, it's nice when a list 5 | of contact pops up. 6 | 7 | Write an algorithm that searches you contacts for phone number strings, and returns: 8 | - NO CONTACT if contact can't be found 9 | - A contact if a contact is found 10 | - The first alphabetized contact if there are multiple 11 | 12 | A = ["pim", "pom"] // Contacts (return one of these) 13 | B = ["999999999", "777888999"] // Phone numbers for each contact A[i] = B[i] 14 | P = "88999" // Search phrase 15 | 16 | Answer should be correct. Don't worry about performance. 17 | */ 18 | public func solution(_ A : [String], _ B : [String], _ P : String) -> String { 19 | var result = [String]() 20 | 21 | // loop through looking for match - when found add to result 22 | for i in 0.. String { 51 | 52 | // Create a dictionary of name / numbers 53 | var dict = [String: String]() 54 | 55 | for i in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /2-Arrays/Q3-ContactMatch-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /* 4 | When someone searches their contacts based on a phone number, it's nice when a list 5 | of contact pops up. 6 | 7 | Write an algorithm that searches you contacts for phone number strings, and returns: 8 | - NO CONTACT if contact can't be found 9 | - A contact if a contact is found 10 | - The first alphabetized contact if there are multiple 11 | 12 | A = ["pim", "pom"] // Contacts (return one of these) 13 | B = ["999999999", "777888999"] // Phone numbers for each contact A[i] = B[i] 14 | P = "88999" // Search phrase 15 | 16 | Answer should be correct. Don't worry about performance. 17 | */ 18 | 19 | public func solution(_ A : [String], _ B : [String], _ P : String) -> String { 20 | // do your work here 21 | return "" 22 | } 23 | 24 | let A = ["pim", "pom"] 25 | let B = ["999999999", "777888999"] 26 | let P = "88999" 27 | 28 | solution(A, B, P) // pom 29 | solution(["sander", "amy", "ann"], ["12345", "23456", "123"], "1") // ann 30 | solution(["ada,", "eva", "leo"], ["1212", "1111", "4444"], "112") // NO CONTACT 31 | 32 | // edge cases 33 | solution([String](), [String](), "") 34 | solution(A, B, "") 35 | 36 | public func solutionDict(_ A : [String], _ B : [String], _ P : String) -> String { 37 | // 🕹 Game on here 38 | return "" 39 | } 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /2-Arrays/Q3-ContactMatch-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/LinkedList-Skeleton.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Node { 4 | var data: Int 5 | var next: Node? 6 | 7 | init(_ data: Int, _ next: Node? = nil) { 8 | self.data = data 9 | self.next = next 10 | } 11 | } 12 | 13 | class LinkList { 14 | private var head: Node? 15 | 16 | func addFront(_ data: Int) { 17 | } 18 | 19 | func getFirst() -> Int? { 20 | return 0 21 | } 22 | 23 | func addBack(_ data: Int) { 24 | } 25 | 26 | func getLast() -> Int? { 27 | return nil 28 | } 29 | 30 | func insert(position: Int, data: Int) { 31 | } 32 | 33 | func deleteFirst() { 34 | } 35 | 36 | func deleteLast() { 37 | } 38 | 39 | func delete(at position: Int) { 40 | } 41 | 42 | var isEmpty: Bool { 43 | return false 44 | } 45 | 46 | func clear() { 47 | } 48 | 49 | func printLinkedList() { 50 | if head == nil { return } 51 | 52 | var result = [Int]() 53 | var node = head 54 | result.append(node!.data) 55 | 56 | while node?.next != nil { 57 | result.append(node!.next!.data) 58 | node = node?.next 59 | } 60 | 61 | print(result) 62 | } 63 | } 64 | 65 | let linkedList = LinkList() 66 | 67 | -------------------------------------------------------------------------------- /3-LinkedLists/LinkedList-Skeleton.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/LinkedList.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Node { 4 | var data: Int 5 | var next: Node? 6 | 7 | init(_ data: Int, _ next: Node? = nil) { 8 | self.data = data 9 | self.next = next 10 | } 11 | } 12 | 13 | class LinkList { 14 | private var head: Node? 15 | 16 | func addFront(_ data: Int) { 17 | let newNode = Node(data) 18 | newNode.next = head 19 | head = newNode 20 | } 21 | 22 | func getFirst() -> Int? { 23 | if head == nil { 24 | return nil 25 | } 26 | return head!.data 27 | } 28 | 29 | func addBack(_ data: Int) { 30 | let newNode = Node(data) 31 | 32 | if head == nil { 33 | head = newNode 34 | return 35 | } 36 | 37 | var node = head! 38 | while(node.next != nil) { 39 | node = node.next! 40 | } 41 | node.next = newNode 42 | } 43 | 44 | func getLast() -> Int? { 45 | if head == nil { 46 | return nil 47 | } 48 | 49 | var node = head! 50 | while(node.next != nil) { 51 | node = node.next! 52 | } 53 | return node.data 54 | } 55 | 56 | func insert(position: Int, data: Int) { 57 | if position == 0 { 58 | addFront(data) 59 | return 60 | } 61 | 62 | let newNode = Node(data) 63 | var currentNode = head 64 | 65 | for _ in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q1-LengthOfLinkedList-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Write a function that determines the length of any linked list. 5 | */ 6 | 7 | class Node { 8 | var data: Int 9 | var next: Node? 10 | 11 | init(_ data: Int, _ next: Node? = nil) { 12 | self.data = data 13 | self.next = next 14 | } 15 | } 16 | 17 | func length(_ head: Node?) -> Int { 18 | if head == nil { 19 | return 0 20 | } 21 | 22 | var len = 0 23 | var current = head 24 | while current != nil { 25 | len += 1 26 | current = current?.next 27 | } 28 | return len 29 | } 30 | 31 | // 1 2 3 4 5 6 32 | let node6 = Node(6) 33 | let node5 = Node(5, node6) 34 | let node4 = Node(4, node5) 35 | let node3 = Node(3, node4) 36 | let node2 = Node(2, node3) 37 | let node1 = Node(1, node2) 38 | 39 | length(nil) 40 | length(node1) 41 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q1-LengthOfLinkedList-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q1-LengthOfLinkedList-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Write a function that determines the length of any linked list. 5 | */ 6 | 7 | class Node { 8 | var data: Int 9 | var next: Node? 10 | 11 | init(_ data: Int, _ next: Node? = nil) { 12 | self.data = data 13 | self.next = next 14 | } 15 | } 16 | 17 | func length(_ head: Node?) -> Int { 18 | // Do your work here... 19 | return 0 20 | } 21 | 22 | // 1 2 3 4 5 6 23 | let node6 = Node(6) 24 | let node5 = Node(5, node6) 25 | let node4 = Node(4, node5) 26 | let node3 = Node(3, node4) 27 | let node2 = Node(2, node3) 28 | let node1 = Node(1, node2) 29 | 30 | length(nil) // 0 31 | length(node1) // 6 32 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q1-LengthOfLinkedList-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q2-MergePointTwoLists-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | // https://www.youtube.com/watch?v=gE0GopCq378&ab_channel=mycodeschool 4 | 5 | /* 6 | Find Merge Point of Two Lists 7 | 8 | Given pointers to the head nodes of 2 linked lists that merge together at some point, find the node where the two lists merge. The merge point is where both lists point to the same node, i.e. they reference the same memory location. It is guaranteed that the two head nodes will be different, and neither will be NULL. If the lists share a common node, return that node's data value. 9 | 10 | Note: After the merge point, both lists will share the same node pointers. 11 | 12 | */ 13 | 14 | class Node { 15 | var data: Int 16 | var next: Node? 17 | 18 | init(_ data: Int, _ next: Node? = nil) { 19 | self.data = data 20 | self.next = next 21 | } 22 | } 23 | 24 | func length(_ head: Node?) -> Int { 25 | if head == nil { 26 | return 0 27 | } 28 | 29 | var len = 0 30 | var current = head 31 | while current != nil { 32 | len += 1 33 | current = current?.next 34 | } 35 | return len 36 | } 37 | 38 | func printLinkedList(_ head: Node?) { 39 | if head == nil { return } 40 | 41 | var result = [Int]() 42 | var node = head 43 | result.append(node!.data) 44 | 45 | while node?.next != nil { 46 | result.append(node!.next!.data) 47 | node = node?.next 48 | } 49 | 50 | print(result) 51 | } 52 | 53 | // Loop through every element of A while checking every element of B 54 | func findMergeBrute(headA: Node?, headB: Node?) -> Int? { // O(m*n) 55 | let m = length(headA) // O(m) 56 | let n = length(headB) // O(n) 57 | 58 | var currentA = headA 59 | 60 | for _ in 0...m-1 { // O(m) 61 | var currentB = headB 62 | for _ in 0...n-1 { // O(n) 63 | let A = currentA?.data 64 | let B = currentB?.data 65 | print("A: \(A ?? 0) B: \(B ?? 0)") 66 | if A == B { 67 | return currentA?.data 68 | } 69 | currentB = currentB?.next 70 | } 71 | currentA = currentA?.next 72 | } 73 | return nil 74 | } 75 | 76 | // Trade-off time for space 77 | func findMergeSpaceTime(headA: Node?, headB: Node?) -> Int? { // O(2m + 2n) > O(m + n) 78 | // Create a Dict of all nodes of B 79 | // Use it to loop up each element of A 80 | let m = length(headA) // O(m) 81 | let n = length(headB) // O(n) 82 | 83 | var dict = [Int?: Bool]() 84 | var currentB = headB 85 | for _ in 0...n-1 { // O(n) 86 | let B = currentB?.data 87 | dict[B] = true 88 | currentB = currentB?.next 89 | } 90 | 91 | var currentA = headA 92 | for _ in 0...m-1 { // O(m) 93 | let A = currentA?.data 94 | if dict[A] == true { 95 | return A 96 | } 97 | currentA = currentA?.next 98 | } 99 | return nil 100 | } 101 | 102 | // Insight: If we can line up the arrays, we can walk them once 103 | func findMergeInsight(headA: Node?, headB: Node?) -> Int? { // O(n + m) 104 | // Figure out which is longer 105 | // Swap if necessary 106 | 107 | // Calculate d 108 | // Walk d for longer 109 | // Walk remainder for both 110 | let m = length(headA) // O(m) 111 | let n = length(headB) // O(n) 112 | 113 | var currentA = headA 114 | var currentB = headB 115 | 116 | if n > m { 117 | let temp = currentA 118 | currentA = currentB 119 | currentB = temp 120 | } 121 | 122 | let d = abs(m - n) 123 | 124 | for _ in 1...d { // O(n) 125 | currentA = currentA?.next 126 | } 127 | 128 | for _ in 0...n-1 { // O(n) 129 | print(4) 130 | let A = currentA?.data 131 | let B = currentB?.data 132 | if A == B { 133 | return A 134 | } 135 | currentA = currentA?.next 136 | currentB = currentB?.next 137 | } 138 | return nil 139 | } 140 | 141 | // 1 2 3 4 5 6 142 | let node6 = Node(6) 143 | let node5 = Node(5, node6) 144 | let node4 = Node(4, node5) 145 | let node3 = Node(3, node4) 146 | let node2 = Node(2, node3) 147 | let node1 = Node(1, node2) 148 | 149 | // 10 11 12 13 4 5 6 150 | let node11 = Node(11, node4) 151 | let node10 = Node(10, node11) 152 | 153 | printLinkedList(node1) 154 | printLinkedList(node10) 155 | 156 | //findMergeBrute(headA: node1, headB: node10) 157 | //findMergeSpaceTime(headA: node1, headB: node10) 158 | findMergeInsight(headA: node1, headB: node10) 159 | 160 | 161 | // Insight: Simple (no swap) 162 | //func findMergeInsight(headA: Node?, headB: Node?) -> Int? { // O(n) 163 | // // Figure out which is longer 164 | // // Swap if necessary 165 | // 166 | // // Calculate d 167 | // // Walk d for longer 168 | // // Walk remainder for both 169 | // let m = length(headA) // O(n) 170 | // let n = length(headB) // O(n) 171 | // 172 | // let d = m - n 173 | // var currentA = headA 174 | // for _ in 1...d { // O(n) 175 | // currentA = currentA?.next 176 | // } 177 | // 178 | // var currentB = headB 179 | // for _ in 0...n-1 { // O(n) 180 | // let A = currentA?.data 181 | // let B = currentB?.data 182 | // if A == B { 183 | // return A 184 | // } 185 | // currentA = currentA?.next 186 | // currentB = currentB?.next 187 | // } 188 | // return nil 189 | //} 190 | 191 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q2-MergePointTwoLists-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q2-MergePointTwoLists-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Find Merge Point of Two Lists 5 | 6 | Given pointers to the head nodes of 2 linked lists that merge together at some point, find the node where the two lists merge. The merge point is where both lists point to the same node, i.e. they reference the same memory location. It is guaranteed that the two head nodes will be different, and neither will be NULL. If the lists share a common node, return that node's data value. 7 | 8 | Note: After the merge point, both lists will share the same node pointers. 9 | 10 | */ 11 | 12 | class Node { 13 | var data: Int 14 | var next: Node? 15 | 16 | init(_ data: Int, _ next: Node? = nil) { 17 | self.data = data 18 | self.next = next 19 | } 20 | } 21 | 22 | func length(_ head: Node?) -> Int { 23 | if head == nil { 24 | return 0 25 | } 26 | 27 | var len = 0 28 | var current = head 29 | while current != nil { 30 | len += 1 31 | current = current?.next 32 | } 33 | return len 34 | } 35 | 36 | func printLinkedList(_ head: Node?) { 37 | if head == nil { return } 38 | 39 | var result = [Int]() 40 | var node = head 41 | result.append(node!.data) 42 | 43 | while node?.next != nil { 44 | result.append(node!.next!.data) 45 | node = node?.next 46 | } 47 | 48 | print(result) 49 | } 50 | 51 | func findMerge(headA: Node?, headB: Node?) -> Int? { 52 | // Here... 53 | return nil 54 | } 55 | 56 | // 1 2 3 4 5 6 57 | let node6 = Node(6) 58 | let node5 = Node(5, node6) 59 | let node4 = Node(4, node5) 60 | let node3 = Node(3, node4) 61 | let node2 = Node(2, node3) 62 | let node1 = Node(1, node2) 63 | 64 | // 10 11 12 13 4 5 6 65 | let node11 = Node(11, node4) 66 | let node10 = Node(10, node11) 67 | 68 | printLinkedList(node1) 69 | printLinkedList(node10) 70 | 71 | findMerge(headA: node1, headB: node10) 72 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q2-MergePointTwoLists-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q3-DetectACycle-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Detect A Cycle 5 | https://www.hackerrank.com/challenges/ctci-linked-list-cycle/problem 6 | https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_Tortoise_and_Hare 7 | 8 | A linked list is said to contain a cycle if any node is visited more than once while traversing the list. For example, in the following graph there is a cycle formed when node 5 points back to node 3. 9 | 10 | 4 11 | / \ 12 | 1 2 3 5 13 | \_____/ 14 | 15 | */ 16 | 17 | class Node { 18 | var data: Int 19 | weak var next: Node? 20 | 21 | init(_ data: Int, _ next: Node? = nil) { 22 | self.data = data 23 | self.next = next 24 | } 25 | } 26 | 27 | func hasCycle(first: Node) -> Bool { 28 | var slow: Node? = first 29 | var fast: Node? = first 30 | 31 | while fast != nil && fast!.next != nil { 32 | slow = slow?.next 33 | fast = fast?.next?.next 34 | 35 | if slow?.data == fast?.data { 36 | return true 37 | } 38 | } 39 | return false 40 | } 41 | 42 | let node5 = Node(5) 43 | let node4 = Node(4) 44 | let node3 = Node(3) 45 | let node2 = Node(2) 46 | let head = Node(1) 47 | 48 | head.next = node2 49 | node2.next = node3 50 | node3.next = node4 51 | node4.next = node5 52 | node5.next = node3 53 | 54 | hasCycle(first: head) 55 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q3-DetectACycle-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q3-DetectACycle-Quesion.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Detect A Cycle 5 | https://www.hackerrank.com/challenges/ctci-linked-list-cycle/problem 6 | https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_Tortoise_and_Hare 7 | 8 | A linked list is said to contain a cycle if any node is visited more than once while traversing the list. For example, in the following graph there is a cycle formed when node 5 points back to node 3. 9 | 10 | 4 11 | / \ 12 | 1 2 3 5 13 | \_____/ 14 | 15 | */ 16 | 17 | class Node { 18 | var data: Int 19 | weak var next: Node? 20 | 21 | init(_ data: Int, _ next: Node? = nil) { 22 | self.data = data 23 | self.next = next 24 | } 25 | } 26 | 27 | func hasCycle(first: Node) -> Bool { 28 | // here... 29 | return false 30 | } 31 | 32 | let node5 = Node(5) 33 | let node4 = Node(4) 34 | let node3 = Node(3) 35 | let node2 = Node(2) 36 | let head = Node(1) 37 | 38 | head.next = node2 39 | node2.next = node3 40 | node3.next = node4 41 | node4.next = node5 42 | node5.next = node3 43 | 44 | hasCycle(first: head) 45 | -------------------------------------------------------------------------------- /3-LinkedLists/Questions/Q3-DetectACycle-Quesion.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /4-BigOReduced/BigOReduced.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ ___ ___ _ _ 5 | | _ |_)__ _ / _ \ | _ \___ __| |_ _ __ ___ __| | 6 | | _ \ / _` | (_) | | / -_) _` | || / _/ -_) _` | 7 | |___/_\__, |\___/ |_|_\___\__,_|\_,_\__\___\__,_| 8 | |___/ 9 | 10 | */ 11 | 12 | func someFunc(_ n: Int) { 13 | var a = 0 14 | a = 5 15 | a += 1 16 | 17 | for _ in 0.. O(2n) > O(n) 156 | // bar > O(n*m) 157 | // baz > O(n^2) 158 | // bep > O(n^2) 159 | -------------------------------------------------------------------------------- /4-BigOReduced/BigOReduced.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /5-StacksQueues/Q1-CyclicRotation-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Rotate array to right N times. 5 | https://app.codility.com/programmers/lessons/2-arrays/cyclic_rotation/ 6 | 7 | For example, given 8 | 9 | A = [3, 8, 9, 7, 6] 10 | K = 3 11 | the function should return [9, 7, 6, 3, 8]. Three rotations were made: 12 | 13 | [3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7] 14 | [6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9] 15 | [7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8] 16 | 17 | Shoot for correctness. Not performance. 18 | */ 19 | 20 | func solutionQueueRight(A: [Int], K: Int) -> [Int] { 21 | guard !A.isEmpty else { return [] } 22 | guard K > 0 else { return A } 23 | 24 | var result = A 25 | 26 | // treat like a queue enqueuing and dequeuing off the end 27 | for _ in 1...K { 28 | let last = result.last! 29 | result.insert(last, at: 0) 30 | result.remove(at: A.count) 31 | } 32 | 33 | return result 34 | } 35 | 36 | solutionQueueRight(A: [1, 2, 3, 4, 5], K: 1) // [5, 1, 2, 3, 4] 37 | solutionQueueRight(A: [1, 2, 3, 4, 5], K: 2) // [4, 5, 1, 2, 3] 38 | solutionQueueRight(A: [1, 2, 3, 4, 5], K: 3) // [3, 4, 5, 1, 2] 39 | 40 | solutionQueueRight(A: [3, 8, 9, 7, 6], K: 3) // [9, 7, 6, 3, 8] 41 | 42 | /* 43 | Rotate array to right N times. 44 | https://app.codility.com/programmers/lessons/2-arrays/cyclic_rotation/ 45 | 46 | For example, given 47 | 48 | A = [3, 8, 9, 7, 6] 49 | K = 3 50 | the function should return [9, 7, 6, 3, 8]. Three rotations were made: 51 | 52 | [3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7] 53 | [6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9] 54 | [7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8] 55 | 56 | Shoot for correctness. Not performance. 57 | */ 58 | 59 | func solutionQueueLeft(A: [Int], K: Int) -> [Int] { 60 | guard !A.isEmpty else { return [] } 61 | guard K > 0 else { return A } 62 | 63 | var result = A 64 | 65 | // treat like a queue enqueuing and dequeuing off the end 66 | for _ in 1...K { 67 | let first = result.first! 68 | result.append(first) 69 | result.remove(at: 0) 70 | } 71 | 72 | return result 73 | } 74 | 75 | solutionQueueLeft(A: [1, 2, 3, 4, 5], K: 1) // [2, 3, 4, 5, 1] 76 | solutionQueueLeft(A: [1, 2, 3, 4, 5], K: 2) // [3, 4, 5, 1, 2] 77 | solutionQueueLeft(A: [1, 2, 3, 4, 5], K: 3) // [4, 5, 1, 2, 3] 78 | 79 | solutionQueueLeft(A: [3, 8, 9, 7, 6], K: 3) // [7, 6, 3, 8, 9] 80 | 81 | 82 | -------------------------------------------------------------------------------- /5-StacksQueues/Q1-CyclicRotation-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /5-StacksQueues/Q1-CyclicRotation-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Rotate array to right N times. 5 | https://app.codility.com/programmers/lessons/2-arrays/cyclic_rotation/ 6 | 7 | For example, given 8 | 9 | A = [3, 8, 9, 7, 6] 10 | K = 3 11 | the function should return [9, 7, 6, 3, 8]. Three rotations were made: 12 | 13 | [3, 8, 9, 7, 6] -> [6, 3, 8, 9, 7] 14 | [6, 3, 8, 9, 7] -> [7, 6, 3, 8, 9] 15 | [7, 6, 3, 8, 9] -> [9, 7, 6, 3, 8] 16 | 17 | Shoot for correctness. Not performance. 18 | */ 19 | 20 | func solutionQueueRight(A: [Int], K: Int) -> [Int] { 21 | guard !A.isEmpty else { return [] } 22 | guard K > 0 else { return A } 23 | 24 | var result = A 25 | 26 | // treat like a queue enqueuing and dequeuing off the end 27 | for _ in 1...K { 28 | let last = result.last! 29 | result.insert(last, at: 0) 30 | result.remove(at: A.count) 31 | } 32 | 33 | return result 34 | } 35 | 36 | solutionQueueRight(A: [1, 2, 3, 4, 5], K: 1) // [5, 1, 2, 3, 4] 37 | solutionQueueRight(A: [1, 2, 3, 4, 5], K: 2) // [4, 5, 1, 2, 3] 38 | solutionQueueRight(A: [1, 2, 3, 4, 5], K: 3) // [3, 4, 5, 1, 2] 39 | 40 | solutionQueueRight(A: [3, 8, 9, 7, 6], K: 3) // [9, 7, 6, 3, 8] 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | /* 50 | Rotate array to left N times. 51 | 52 | For example, given 53 | 54 | A = [3, 8, 9, 7, 6] 55 | K = 3 56 | the function should return [9, 7, 6, 3, 8]. Three rotations were made: 57 | 58 | [3, 8, 9, 7, 6] -> [8, 9, 7, 6, 3] 59 | [8, 9, 7, 6, 3] -> [9, 7, 6, 3, 8] 60 | [9, 7, 6, 3, 8] -> [7, 6, 3, 8, 9] 61 | 62 | Shoot for correctness. Not performance. 63 | */ 64 | 65 | func solutionQueueLeft(A: [Int], K: Int) -> [Int] { 66 | guard !A.isEmpty else { return [] } 67 | guard K > 0 else { return A } 68 | 69 | var result = A 70 | 71 | // treat like a queue enqueuing and dequeuing off the end 72 | for _ in 1...K { 73 | // Do your work here... 74 | } 75 | 76 | return result 77 | } 78 | 79 | solutionQueueLeft(A: [1, 2, 3, 4, 5], K: 1) // [2, 3, 4, 5, 1] 80 | solutionQueueLeft(A: [1, 2, 3, 4, 5], K: 2) // [3, 4, 5, 1, 2] 81 | solutionQueueLeft(A: [1, 2, 3, 4, 5], K: 3) // [4, 5, 1, 2, 3] 82 | 83 | solutionQueueLeft(A: [3, 8, 9, 7, 6], K: 3) // [7, 6, 3, 8, 9] 84 | 85 | 86 | -------------------------------------------------------------------------------- /5-StacksQueues/Q1-CyclicRotation-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /5-StacksQueues/Q2-ReverseAString-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | // https://www.fullstack.cafe/interview-questions/stacks 4 | 5 | /* 6 | Giving a String, write a function that reverses the String 7 | using a stack. 8 | */ 9 | 10 | func solution(_ text: String) -> String { 11 | var chars = Array(text) 12 | 13 | // Create stack 14 | var result = [String]() 15 | 16 | // Push chars 17 | for c in chars { 18 | result.append(String(c)) 19 | } 20 | 21 | // Pop chars 22 | for i in 0.. 2 | 3 | 4 | -------------------------------------------------------------------------------- /5-StacksQueues/Q2-ReverseAString-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | // https://www.fullstack.cafe/interview-questions/stacks 4 | 5 | /* 6 | Giving a String, write a function that reverses the String 7 | using a stack. 8 | */ 9 | 10 | func solution(_ text: String) -> String { 11 | // Do your work here... 12 | return "" 13 | } 14 | 15 | solution("abc") // bca 16 | solution("Would you like to play a game?") 17 | -------------------------------------------------------------------------------- /5-StacksQueues/Q2-ReverseAString-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /5-StacksQueues/Q3-BalancedBrackets-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Balanced brackets 5 | https://www.hackerrank.com/challenges/balanced-brackets/problem 6 | 7 | A bracket is considered to be any one of the following characters: (, ), {, }, [, or ]. 8 | 9 | Two brackets are considered to be a matched pair if the an opening bracket (i.e., (, [, or {) occurs to the left of a closing bracket (i.e., ), ], or }) of the exact same type. There are three types of matched pairs of brackets: [], {}, and (). 10 | 11 | A matching pair of brackets is not balanced if the set of brackets it encloses are not matched. For example, {[(])} is not balanced because the contents in between { and } are not balanced. The pair of square brackets encloses a single, unbalanced opening bracket, (, and the pair of parentheses encloses a single, unbalanced closing square bracket, ]. 12 | 13 | By this logic, we say a sequence of brackets is balanced if the following conditions are met: 14 | 15 | It contains no unmatched brackets. 16 | The subset of brackets enclosed within the confines of a matched pair of brackets is also a matched pair of brackets. 17 | Given strings of brackets, determine whether each sequence of brackets is balanced. If a string is balanced, return YES. Otherwise, return NO. 18 | 19 | */ 20 | 21 | 22 | 23 | func isBalanced(s: String) -> String { 24 | 25 | var st = [Character]() 26 | 27 | for c in s { 28 | switch c { 29 | case "{", "(", "[": 30 | st.append(c) 31 | case "}": 32 | if (st.isEmpty || (st.last != "{")) { 33 | return "NO" 34 | } 35 | st.popLast() 36 | case ")": 37 | if (st.isEmpty || (st.last != "(")) { 38 | return "NO"; 39 | } 40 | st.popLast() 41 | case "]": 42 | if (st.isEmpty || (st.last != "[")) { 43 | return "NO"; 44 | } 45 | st.popLast() 46 | default: 47 | print("breaking \(c)") 48 | } 49 | } 50 | 51 | return st.isEmpty ? "YES" : "NO" 52 | } 53 | 54 | isBalanced(s: "{[()]}") // Yes 55 | isBalanced(s: "[()]}") // No 56 | isBalanced(s: "{}()(){}((){})({[[({({(){}{}}){}})]{({()}((())))}()]})(({}(()){[][]}){()}(({}{}))())()[](){{((){})}}()([[]])[][]()({}((([()]{})())[][[()]]())){{}}[]{()}()[][]{}([])[]{({})}{}{{}{[[]]}[]{}}{[()]}[]{(([{{[{[]}]}[{}]}]))}(){}{{}}[]((([])([{(){}[(()[]((()(){})({([]({{{[]{}}[({})()({}{([()])()()[]{}})][{[]}]{{}([]({{{(()(({}[[[{{}}]]{{[()]([[{{}([[]][([{{}}(([])[][({()}())()({}[])]{}[])]())[]]){}}[]]])([]({{[[][]{[]}[]]}}{}(){[]}))}()[]((){{}()[{[[()]]}()]}[()]{})}][]{}))())}(())}{{[]}{}}({[([{[{[[[]]]{()}[]}]{}}()((({{{{({{(){}}}[[()]()[]]())({{{[]}{{[[{{[{}]}}[][]]]([][](()(()[]){{}}))([])}}}}[{}{}])[(){{()()}{(())}()}]{(){{}[]{}[][{[]([[]()]{(){[{}[()]][{}{}]{(){}}}{[]}}{[]}[]){[]}[]}][((){}{}[[[[{{}()[([({{[[][{{()}(([[]][[[[[[[{}]][{}]]]()](())[()[][]({({[][][[]{}][]}{})}{({})([[][]({}{[]})])[([([])][[]{([])(({}))}](()[]){[[]]}({}))]}[])()]]]))([{}()()([([[{}][()]][])])][[[{}][][]({[]})][(({{()}}))]])}]]}})])]}]]]])]}}}}}})))])]})}))}}}))})))]}])))") // Yes 57 | -------------------------------------------------------------------------------- /5-StacksQueues/Q3-BalancedBrackets-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /5-StacksQueues/Q3-BalancedBrackets-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Balanced brackets 5 | https://www.hackerrank.com/challenges/balanced-brackets/problem 6 | 7 | A bracket is considered to be any one of the following characters: (, ), {, }, [, or ]. 8 | 9 | Two brackets are considered to be a matched pair if the an opening bracket (i.e., (, [, or {) occurs to the left of a closing bracket (i.e., ), ], or }) of the exact same type. There are three types of matched pairs of brackets: [], {}, and (). 10 | 11 | A matching pair of brackets is not balanced if the set of brackets it encloses are not matched. For example, {[(])} is not balanced because the contents in between { and } are not balanced. The pair of square brackets encloses a single, unbalanced opening bracket, (, and the pair of parentheses encloses a single, unbalanced closing square bracket, ]. 12 | 13 | By this logic, we say a sequence of brackets is balanced if the following conditions are met: 14 | 15 | It contains no unmatched brackets. 16 | The subset of brackets enclosed within the confines of a matched pair of brackets is also a matched pair of brackets. 17 | Given strings of brackets, determine whether each sequence of brackets is balanced. If a string is balanced, return YES. Otherwise, return NO. 18 | 19 | */ 20 | 21 | func isBalanced(s: String) -> String { // "{[()]}" 22 | // 🕹 Game on here 23 | return "NO" 24 | } 25 | 26 | isBalanced(s: "{[()]}") // Yes 27 | isBalanced(s: "[()]}") // No 28 | isBalanced(s: "{}()(){}((){})({[[({({(){}{}}){}})]{({()}((())))}()]})(({}(()){[][]}){()}(({}{}))())()[](){{((){})}}()([[]])[][]()({}((([()]{})())[][[()]]())){{}}[]{()}()[][]{}([])[]{({})}{}{{}{[[]]}[]{}}{[()]}[]{(([{{[{[]}]}[{}]}]))}(){}{{}}[]((([])([{(){}[(()[]((()(){})({([]({{{[]{}}[({})()({}{([()])()()[]{}})][{[]}]{{}([]({{{(()(({}[[[{{}}]]{{[()]([[{{}([[]][([{{}}(([])[][({()}())()({}[])]{}[])]())[]]){}}[]]])([]({{[[][]{[]}[]]}}{}(){[]}))}()[]((){{}()[{[[()]]}()]}[()]{})}][]{}))())}(())}{{[]}{}}({[([{[{[[[]]]{()}[]}]{}}()((({{{{({{(){}}}[[()]()[]]())({{{[]}{{[[{{[{}]}}[][]]]([][](()(()[]){{}}))([])}}}}[{}{}])[(){{()()}{(())}()}]{(){{}[]{}[][{[]([[]()]{(){[{}[()]][{}{}]{(){}}}{[]}}{[]}[]){[]}[]}][((){}{}[[[[{{}()[([({{[[][{{()}(([[]][[[[[[[{}]][{}]]]()](())[()[][]({({[][][[]{}][]}{})}{({})([[][]({}{[]})])[([([])][[]{([])(({}))}](()[]){[[]]}({}))]}[])()]]]))([{}()()([([[{}][()]][])])][[[{}][][]({[]})][(({{()}}))]])}]]}})])]}]]]])]}}}}}})))])]})}))}}}))})))]}])))") // Yes 29 | -------------------------------------------------------------------------------- /5-StacksQueues/Q3-BalancedBrackets-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /5-StacksQueues/StacksAndQueues.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ 5 | / __| |_ __ _ __| |__ ___ 6 | \__ \ _/ _` / _| / /(_-< 7 | |___/\__\__,_\__|_\_\/__/ 8 | 9 | */ 10 | 11 | /* 12 | Last-in first-out (LIFO) 13 | Push and pop are O(1) operations. 14 | */ 15 | 16 | class Stack { 17 | private var array: [T] = [] 18 | 19 | func push(_ item: T) { 20 | array.append(item) 21 | } 22 | 23 | func pop() -> T? { 24 | array.popLast() 25 | } 26 | 27 | func peek() -> T? { 28 | array.last 29 | } 30 | 31 | var isEmpty: Bool { 32 | array.isEmpty 33 | } 34 | 35 | var count: Int { 36 | array.count 37 | } 38 | } 39 | 40 | struct StackStruct { 41 | fileprivate var array = [T]() 42 | 43 | mutating func push(_ item: T) { 44 | array.append(item) 45 | } 46 | 47 | mutating func pop() -> T? { 48 | array.popLast() 49 | } 50 | 51 | var peek: T? { 52 | array.last 53 | } 54 | 55 | var isEmpty: Bool { 56 | array.isEmpty 57 | } 58 | 59 | var count: Int { 60 | array.count 61 | } 62 | } 63 | 64 | 65 | 66 | 67 | /* 68 | ___ 69 | / _ \ _ _ ___ _ _ ___ ___ 70 | | (_) | || / -_) || / -_|_-< 71 | \__\_\\_,_\___|\_,_\___/__/ 72 | 73 | */ 74 | 75 | /* 76 | First-in first-out (FIFO) 77 | enqueue O(1) dequeue O(n) 78 | */ 79 | 80 | class Queue { 81 | private var array: [T] = [] 82 | 83 | func enqueue(_ item: T) { 84 | array.append(item) 85 | } 86 | 87 | func dequeue() -> T? { 88 | if isEmpty { 89 | return nil 90 | } else { 91 | return array.removeFirst() 92 | } 93 | } 94 | 95 | var isEmpty: Bool { 96 | return array.isEmpty 97 | } 98 | 99 | var count: Int { 100 | return array.count 101 | } 102 | 103 | func peek() -> T? { 104 | return array.first 105 | } 106 | } 107 | 108 | struct QueueStruct { 109 | private var array: [T] = [] 110 | 111 | mutating func enqueue(_ item: T) { 112 | array.append(item) 113 | } 114 | 115 | mutating func dequeue() -> T? { 116 | if isEmpty { 117 | return nil 118 | } else { 119 | return array.removeFirst() 120 | } 121 | } 122 | 123 | var isEmpty: Bool { 124 | return array.isEmpty 125 | } 126 | 127 | var count: Int { 128 | return array.count 129 | } 130 | 131 | func peek() -> T? { 132 | return array.first 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /5-StacksQueues/StacksAndQueues.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /6-HashTables/HashTable.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /* 4 | _ _ _ _____ _ _ 5 | | || |__ _ __| |_ |_ _|_ _| |__| |___ ___ 6 | | __ / _` (_-< ' \ | |/ _` | '_ \ / -_|_-< 7 | |_||_\__,_/__/_||_| |_|\__,_|_.__/_\___/__/ 8 | 9 | */ 10 | 11 | // Strings, Integers, Floating point numbers and Booleans 12 | // are all hashable by default. 13 | let stringsAreHashable = "abc".hashValue 14 | 15 | struct GridPoint { 16 | var x: Int 17 | var y: Int 18 | 19 | var hashValue: Int { 20 | // XOR properties together seeded with a prime number 21 | return x.hashValue ^ y.hashValue &* 16777619 22 | } 23 | } 24 | 25 | let mainBase = GridPoint(x: 131, y: 541) 26 | let hashCode = mainBase.hashValue 27 | 28 | // Modulus operator 29 | let even = 2 % 2 30 | let odd = 3 % 2 // remainder 1 31 | 32 | let initialSize = 16 33 | let index = hashCode % initialSize // guaranteed fit 34 | 35 | let indexPositive = abs(index) 36 | 37 | 38 | // Linked List 39 | class HashEntry { 40 | var key: String 41 | var value: String 42 | var next: HashEntry? 43 | 44 | init(_ key: String, _ value: String) { 45 | self.key = key 46 | self.value = value 47 | } 48 | } 49 | 50 | class HashTable { 51 | private static let initialSize = 256 52 | private var entries = Array(repeating: nil, count: initialSize) 53 | 54 | func put(_ key: String, _ value: String) { 55 | // Get the index 56 | let index = getIndex(key) 57 | 58 | // Create entry 59 | let entry = HashEntry(key, value) 60 | 61 | // If entry is not already there - store it 62 | if entries[index] == nil { 63 | entries[index] = entry 64 | } 65 | // else handle collision by appending to our linked list 66 | else { 67 | var collisions = entries[index] 68 | 69 | // Walk to the end 70 | while collisions?.next != nil { 71 | collisions = collisions?.next 72 | } 73 | 74 | // Add collision there 75 | collisions?.next = entry 76 | } 77 | } 78 | 79 | func get(_ key: String) -> String? { 80 | // Get the index 81 | let index = getIndex(key) 82 | 83 | // Get current list of entries for this index 84 | let possibleCollisions = entries[index] 85 | 86 | // Walk our linked list looking for a possible match on the key (that will be unique) 87 | var currentEntry = possibleCollisions 88 | while currentEntry != nil { 89 | if currentEntry?.key == key { 90 | return currentEntry?.value 91 | } 92 | currentEntry = currentEntry?.next 93 | } 94 | 95 | return nil 96 | } 97 | 98 | private func getIndex(_ key: String) -> Int { 99 | // Get the key's hash code 100 | let hashCode = abs(key.hashValue) 101 | 102 | // Normalize it into an acceptable index 103 | let index = hashCode % HashTable.initialSize 104 | print("\(key) \(hashCode) \(index)") 105 | 106 | // Forced collision for demonstration purposes 107 | if key == "John Smith" || key == "Sandra Dee" { 108 | return 152 109 | } 110 | 111 | return index 112 | } 113 | 114 | func prettyPrint() { 115 | for entry in entries { 116 | if entry == nil { 117 | continue 118 | } 119 | if entry?.next == nil { 120 | // nothing else there 121 | print("key: \(String(describing: entry?.key)) value: \(String(describing: entry?.value))") 122 | } else { 123 | // collisions 124 | var currentEntry = entry 125 | while currentEntry?.next != nil { 126 | print("💥 key: \(String(describing: currentEntry?.key)) value: \(String(describing: currentEntry?.value))") 127 | currentEntry = currentEntry?.next 128 | } 129 | print("💥 key: \(String(describing: currentEntry?.key)) value: \(String(describing: currentEntry?.value))") 130 | } 131 | } 132 | } 133 | 134 | subscript(key: String) -> String? { 135 | get { 136 | get(key) 137 | } 138 | set(newValue) { 139 | guard let value = newValue else { return } 140 | put(key, value) 141 | } 142 | } 143 | } 144 | 145 | let hashTable = HashTable() 146 | hashTable.put("John Smith", "521-1234") 147 | hashTable.put("Lisa Smith", "521-8976") 148 | hashTable.put("Sam Doe", "521-5030") 149 | hashTable.put("Sandra Dee", "521-9655") 150 | hashTable.put("Ted Baker", "418-4165") 151 | 152 | hashTable.prettyPrint() 153 | 154 | hashTable.get("John Smith") 155 | hashTable.get("Lisa Smith") 156 | hashTable.get("Sam Doe") 157 | hashTable.get("Sandra Dee") 158 | hashTable.get("Ted Baker") 159 | hashTable.get("Tim Lee") 160 | 161 | hashTable["Kevin Flynn"] = "The grid" 162 | hashTable["Kevin Flynn"] 163 | -------------------------------------------------------------------------------- /6-HashTables/HashTable.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/BST-Empty.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | ___ _ ___ _ _____ 6 | | _ |_)_ _ __ _ _ _ _ _ / __| ___ __ _ _ _ __| |_ |_ _| _ ___ ___ 7 | | _ \ | ' \/ _` | '_| || | \__ \/ -_) _` | '_/ _| ' \ | || '_/ -_) -_) 8 | |___/_|_||_\__,_|_| \_, | |___/\___\__,_|_| \__|_||_| |_||_| \___\___| 9 | |__/ 10 | */ 11 | 12 | class Node { 13 | var key: Int = 0 14 | var left: Node? 15 | var right: Node? 16 | 17 | init(_ key: Int) { 18 | self.key = key 19 | } 20 | } 21 | 22 | class BST { 23 | var root: Node? 24 | 25 | func insert(key: Int) { 26 | } 27 | 28 | private func insertItem(_ node: Node?, _ key: Int) -> Node { 29 | return Node(key) 30 | } 31 | 32 | func find(key: Int) -> Int? { 33 | guard let root = root else { return nil } 34 | guard let node = find(root, key) else { return nil } 35 | 36 | return node.key 37 | } 38 | 39 | private func find(_ node: Node?, _ key: Int) -> Node? { 40 | guard let node = node else { return nil } 41 | 42 | if node.key == key { 43 | return node 44 | } else if key < node.key { 45 | return find(node.left, key) 46 | } else if key > node.key { 47 | return find(node.right, key) 48 | } 49 | return nil 50 | // Note: duplicate keys not allowed so don't need to check 51 | } 52 | 53 | func findMin() -> Int { 54 | return 0 55 | } 56 | 57 | private func findMin(_ node: Node) -> Node { 58 | return Node(0) 59 | } 60 | 61 | func delete(key: Int) { 62 | } 63 | 64 | private func delete(_ node: inout Node?, _ key: Int) -> Node? { 65 | return nil 66 | } 67 | 68 | func prettyPrint() { 69 | // Hard code print for tree depth = 3 70 | let rootLeftKey = root?.left == nil ? 0 : root?.left?.key 71 | let rootRightKey = root?.right == nil ? 0 : root?.right?.key 72 | 73 | var rootLeftLeftKey = 0 74 | var rootLeftRightKey = 0 75 | 76 | if root?.left != nil { 77 | rootLeftLeftKey = root?.left?.left == nil ? 0 : root?.left?.left?.key as! Int 78 | rootLeftRightKey = root?.left?.right == nil ? 0 : root?.left?.right?.key as! Int 79 | } 80 | 81 | var rootRightLeftKey = 0 82 | var rootRightRightKey = 0 83 | 84 | if root?.right != nil { 85 | rootRightLeftKey = root?.right?.left == nil ? 0 : root?.right?.left?.key as! Int 86 | rootRightRightKey = root?.right?.right == nil ? 0 : root?.right?.right?.key as! Int 87 | } 88 | 89 | let str = """ 90 | \(root!.key) 91 | / \\ 92 | \(rootLeftKey!) \(rootRightKey!) 93 | / \\ / \\ 94 | \(rootLeftLeftKey) \(rootLeftRightKey) \(rootRightLeftKey) \(rootRightRightKey) 95 | """ 96 | 97 | print(str) 98 | } 99 | } 100 | 101 | class BSTTests: XCTestCase { 102 | var bst: BST! 103 | override func setUp() { 104 | super.setUp() 105 | bst = BST() 106 | } 107 | 108 | func testInsert() { 109 | bst.insert(key: 5) 110 | bst.insert(key: 3) 111 | bst.insert(key: 2) 112 | bst.insert(key: 4) 113 | bst.insert(key: 7) 114 | bst.insert(key: 6) 115 | bst.insert(key: 8) 116 | 117 | bst.prettyPrint() 118 | 119 | XCTAssertNotNil(bst.find(key: 5)) 120 | } 121 | 122 | func testDeleteNoChild() { 123 | bst.insert(key: 5) 124 | bst.insert(key: 3) 125 | bst.insert(key: 2) 126 | bst.insert(key: 4) 127 | bst.insert(key: 7) 128 | bst.insert(key: 6) 129 | bst.insert(key: 8) 130 | 131 | XCTAssertNotNil(bst.find(key: 2)) 132 | bst.delete(key: 2) 133 | XCTAssertNil(bst.find(key: 2)) 134 | } 135 | 136 | func testDeleteOneChild() { 137 | bst.insert(key: 5) 138 | bst.insert(key: 3) 139 | bst.insert(key: 2) 140 | bst.insert(key: 4) 141 | bst.insert(key: 7) 142 | bst.insert(key: 6) 143 | // bst.insert(key: 8) 144 | 145 | bst.delete(key: 7) 146 | XCTAssertNil(bst.find(key: 7)) 147 | } 148 | 149 | func testDeleteTwoChildren() { 150 | bst.insert(key: 5) 151 | bst.insert(key: 3) 152 | bst.insert(key: 2) 153 | bst.insert(key: 4) 154 | bst.insert(key: 7) 155 | bst.insert(key: 6) 156 | bst.insert(key: 8) 157 | 158 | bst.delete(key: 7) 159 | XCTAssertNil(bst.find(key: 7)) 160 | XCTAssertNotNil(6) 161 | XCTAssertNotNil(8) 162 | } 163 | } 164 | 165 | 166 | // Infrastructure for running unit tests in playground 167 | 168 | class TestObserver: NSObject, XCTestObservation { 169 | func testCase(_ testCase: XCTestCase, 170 | didFailWithDescription description: String, 171 | inFile filePath: String?, 172 | atLine lineNumber: Int) { 173 | assertionFailure(description, line: UInt(lineNumber)) 174 | } 175 | } 176 | let testObserver = TestObserver() 177 | XCTestObservationCenter.shared.addTestObserver(testObserver) 178 | BSTTests.defaultTestSuite.run() 179 | 180 | -------------------------------------------------------------------------------- /7-BinaryTrees/BST-Empty.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/BST-Solution.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | ___ _ ___ _ _____ 6 | | _ |_)_ _ __ _ _ _ _ _ / __| ___ __ _ _ _ __| |_ |_ _| _ ___ ___ 7 | | _ \ | ' \/ _` | '_| || | \__ \/ -_) _` | '_/ _| ' \ | || '_/ -_) -_) 8 | |___/_|_||_\__,_|_| \_, | |___/\___\__,_|_| \__|_||_| |_||_| \___\___| 9 | |__/ 10 | */ 11 | 12 | class Node { 13 | var key: Int = 0 14 | var left: Node? 15 | var right: Node? 16 | 17 | init(_ key: Int) { 18 | self.key = key 19 | } 20 | 21 | var min: Node { 22 | if left == nil { 23 | return self 24 | } else { 25 | return left!.min 26 | } 27 | } 28 | } 29 | 30 | class BST { 31 | var root: Node? 32 | 33 | func insert(key: Int) { 34 | root = insertItem(root, key) 35 | } 36 | 37 | private func insertItem(_ node: Node?, _ key: Int) -> Node { 38 | 39 | // If node is nil - set it here. We are done. 40 | guard let node = node else { 41 | let node = Node(key) 42 | return node 43 | } 44 | 45 | if key < node.key { 46 | node.left = insertItem(node.left, key) 47 | } 48 | if key > node.key { 49 | node.right = insertItem(node.right, key) 50 | } 51 | 52 | // If we get here we have have hit the bottom of our tree with a duplicate. 53 | // Since duplicates are not allowed in BSTs, simply ignore the duplicate, 54 | // and return our fully constructed tree. We are done! 55 | return node; 56 | } 57 | 58 | func find(key: Int) -> Int? { 59 | guard let root = root else { return nil } 60 | guard let node = find(root, key) else { return nil } 61 | 62 | return node.key 63 | } 64 | 65 | private func find(_ node: Node?, _ key: Int) -> Node? { 66 | guard let node = node else { return nil } 67 | 68 | if node.key == key { 69 | return node 70 | } else if key < node.key { 71 | return find(node.left, key) 72 | } else if key > node.key { 73 | return find(node.right, key) 74 | } 75 | return nil 76 | // Note: duplicate keys not allowed so don't need to check 77 | } 78 | 79 | func findMin() -> Int { 80 | guard let root = root else { return 0 } 81 | return findMin(root).key; 82 | } 83 | 84 | private func findMin(_ node: Node) -> Node { 85 | return node.min; 86 | } 87 | 88 | // Delete: Three cases 89 | // 1. No child 90 | // 2. One child 91 | // 3. Two children 92 | 93 | // First two are simple. Third is more complex. 94 | 95 | // Case 1: No child - simply remove from tree by nulling it. 96 | // 97 | // Case 2: One child - copy the child to the node to be deleted and delete the child 98 | 99 | // Case 3: Two children - re-gig the tree to turn into a Case 1 or a Case 2 100 | 101 | // For third case we first need to 102 | // 1. Find the right side min 103 | // 2. Copy it to the node we want to delete (creating a duplicate) 104 | // 3. Then delete the min value way down on the branch we just copied 105 | // 106 | // This works because you can represent a binary tree in more than one way. 107 | // Here we are taking advantage of that fact to make our more complicated 108 | // 3rd case delete more simple by transforming it into case 1. 109 | 110 | 111 | func delete(key: Int) { 112 | guard let _ = root else { return } 113 | root = delete(&root, key); 114 | } 115 | 116 | private func delete(_ node: inout Node?, _ key: Int) -> Node? { 117 | guard let nd = node else { return nil } 118 | 119 | if key < nd.key { 120 | nd.left = delete(&nd.left, key) 121 | } else if key > nd.key { 122 | nd.right = delete(&nd.right, key) 123 | } else { 124 | // Woohoo! Found you. This is the node we want to delete. 125 | 126 | // Case 1: No child 127 | if nd.left == nil && nd.right == nil { 128 | return nil 129 | } 130 | 131 | // Case 2: One child 132 | else if nd.left == nil { 133 | return nd.right // check delete(&insideNode.right, key) not necessary because we have already found 134 | } 135 | else if nd.right == nil { 136 | return nd.left // delete(&insideNode.left, key) 137 | } 138 | 139 | // Case 3: Two children 140 | else { 141 | // Find the minimum node on the right (could also find max on the left) 142 | let minRight = findMin(nd.right!) 143 | 144 | // Duplicate it by copying its value here 145 | nd.key = minRight.key 146 | 147 | // Now go ahead and delete the node we just duplicated (same key) 148 | nd.right = delete(&nd.right, nd.key) 149 | } 150 | } 151 | 152 | return nd 153 | } 154 | 155 | func prettyPrint() { 156 | // Hard code print for tree depth = 3 157 | let rootLeftKey = root?.left == nil ? 0 : root?.left?.key 158 | let rootRightKey = root?.right == nil ? 0 : root?.right?.key 159 | 160 | var rootLeftLeftKey = 0 161 | var rootLeftRightKey = 0 162 | 163 | if root?.left != nil { 164 | rootLeftLeftKey = root?.left?.left == nil ? 0 : root?.left?.left?.key as! Int 165 | rootLeftRightKey = root?.left?.right == nil ? 0 : root?.left?.right?.key as! Int 166 | } 167 | 168 | var rootRightLeftKey = 0 169 | var rootRightRightKey = 0 170 | 171 | if root?.right != nil { 172 | rootRightLeftKey = root?.right?.left == nil ? 0 : root?.right?.left?.key as! Int 173 | rootRightRightKey = root?.right?.right == nil ? 0 : root?.right?.right?.key as! Int 174 | } 175 | 176 | let str = """ 177 | \(root!.key) 178 | / \\ 179 | \(rootLeftKey!) \(rootRightKey!) 180 | / \\ / \\ 181 | \(rootLeftLeftKey) \(rootLeftRightKey) \(rootRightLeftKey) \(rootRightRightKey) 182 | """ 183 | 184 | print(str) 185 | } 186 | 187 | /* 188 | 1 189 | / \ 190 | 2 3 191 | 192 | Three ways to walk depth first: 193 | - inorder (L > Root > R) 213 Good if there is inherit order smallest > largest (Left > Right) 194 | - preorder (Root > L > R) 123 Good for copying and expression tress (Top > Bottom) 195 | - postorder (L > R > Root) 231 Bottom up used in deletes (Bottom > Up) 196 | 197 | */ 198 | 199 | func printInOrderTravseral() { inOrderTraversal(node: root) } 200 | 201 | func inOrderTraversal(node: Node?) { 202 | guard let node = node else { return } 203 | inOrderTraversal(node: node.left) 204 | print(node.key) // root 205 | inOrderTraversal(node: node.right) 206 | } 207 | 208 | func printPreOrderTravseral() { preOrderTraversal(node: root) } 209 | 210 | func preOrderTraversal(node: Node?) { 211 | guard let node = node else { return } 212 | print(node.key) // root 213 | preOrderTraversal(node: node.left) 214 | preOrderTraversal(node: node.right) 215 | } 216 | 217 | func printPostOrderTravseral() { postOrderTraversal(node: root) } 218 | 219 | func postOrderTraversal(node: Node?) { 220 | guard let node = node else { return } 221 | postOrderTraversal(node: node.left) 222 | postOrderTraversal(node: node.right) 223 | print(node.key) // root 224 | } 225 | } 226 | 227 | class BSTTests: XCTestCase { 228 | var bst: BST! 229 | override func setUp() { 230 | super.setUp() 231 | bst = BST() 232 | } 233 | 234 | func testInsert() { 235 | bst.insert(key: 5) 236 | bst.insert(key: 3) 237 | bst.insert(key: 2) 238 | bst.insert(key: 4) 239 | bst.insert(key: 7) 240 | bst.insert(key: 6) 241 | bst.insert(key: 8) 242 | 243 | bst.prettyPrint() 244 | 245 | XCTAssertNotNil(bst.find(key: 5)) 246 | XCTAssertNotNil(bst.find(key: 3)) 247 | XCTAssertNotNil(bst.find(key: 2)) 248 | XCTAssertNotNil(bst.find(key: 4)) 249 | XCTAssertNotNil(bst.find(key: 7)) 250 | XCTAssertNotNil(bst.find(key: 6)) 251 | XCTAssertNotNil(bst.find(key: 8)) 252 | } 253 | 254 | func testDeleteNoChild() { 255 | bst.insert(key: 5) 256 | bst.insert(key: 3) 257 | bst.insert(key: 2) 258 | bst.insert(key: 4) 259 | bst.insert(key: 7) 260 | bst.insert(key: 6) 261 | bst.insert(key: 8) 262 | 263 | XCTAssertNotNil(bst.find(key: 2)) 264 | bst.delete(key: 2) 265 | XCTAssertNil(bst.find(key: 2)) 266 | 267 | XCTAssertNotNil(bst.find(key: 5)) 268 | XCTAssertNotNil(bst.find(key: 3)) 269 | XCTAssertNotNil(bst.find(key: 4)) 270 | XCTAssertNotNil(bst.find(key: 7)) 271 | XCTAssertNotNil(bst.find(key: 6)) 272 | XCTAssertNotNil(bst.find(key: 8)) 273 | } 274 | 275 | func testDeleteOneChild() { 276 | bst.insert(key: 5) 277 | bst.insert(key: 3) 278 | bst.insert(key: 2) 279 | bst.insert(key: 4) 280 | bst.insert(key: 7) 281 | bst.insert(key: 6) 282 | // bst.insert(key: 8) 283 | 284 | XCTAssertNotNil(bst.find(key: 2)) 285 | bst.delete(key: 7) 286 | XCTAssertNil(bst.find(key: 7)) 287 | 288 | XCTAssertNotNil(bst.find(key: 5)) 289 | XCTAssertNotNil(bst.find(key: 3)) 290 | XCTAssertNotNil(bst.find(key: 4)) 291 | XCTAssertNotNil(bst.find(key: 6)) 292 | } 293 | 294 | func testDeleteTwoChildren() { 295 | bst.insert(key: 5) 296 | bst.insert(key: 3) 297 | bst.insert(key: 2) 298 | bst.insert(key: 4) 299 | bst.insert(key: 7) 300 | bst.insert(key: 6) 301 | bst.insert(key: 8) 302 | 303 | XCTAssertNotNil(bst.find(key: 2)) 304 | bst.delete(key: 7) 305 | XCTAssertNil(bst.find(key: 7)) 306 | 307 | XCTAssertNotNil(bst.find(key: 5)) 308 | XCTAssertNotNil(bst.find(key: 3)) 309 | XCTAssertNotNil(bst.find(key: 4)) 310 | XCTAssertNotNil(bst.find(key: 6)) 311 | XCTAssertNotNil(bst.find(key: 8)) 312 | } 313 | } 314 | 315 | 316 | // Infrastructure for running unit tests 317 | 318 | class TestObserver: NSObject, XCTestObservation { 319 | func testCase(_ testCase: XCTestCase, 320 | didFailWithDescription description: String, 321 | inFile filePath: String?, 322 | atLine lineNumber: Int) { 323 | assertionFailure(description, line: UInt(lineNumber)) 324 | } 325 | } 326 | let testObserver = TestObserver() 327 | XCTestObservationCenter.shared.addTestObserver(testObserver) 328 | BSTTests.defaultTestSuite.run() 329 | 330 | -------------------------------------------------------------------------------- /7-BinaryTrees/BST-Solution.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q1-IsBST-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | CheckBST 6 | https://www.hackerrank.com/challenges/ctci-is-binary-search-tree/problem 7 | 8 | Given the root node of a binary tree, determine if it is a binary search tree. 9 | 10 | The Node class is defined as follows: 11 | class Node { 12 | int data; 13 | Node left; 14 | Node right; 15 | } 16 | */ 17 | 18 | class Node { 19 | var key: Int 20 | var left: Node? 21 | var right: Node? 22 | 23 | init(_ data: Int) { 24 | self.key = data 25 | } 26 | } 27 | 28 | func checkBST(root: Node?) -> Bool { 29 | return isBST(root, nil, nil) 30 | } 31 | 32 | private func isBST(_ node: Node?, _ min: Int?, _ max: Int?) -> Bool { 33 | print("Comparing: \(node?.key) min: \(min) max: \(max)") 34 | 35 | // if nil we hit the end of our branch - OK 36 | guard let node = node else { 37 | return true 38 | } 39 | 40 | // else check if min < parent 41 | if let min = min, node.key <= min { 42 | print("min: \(min) key: \(node.key)") 43 | return false 44 | } 45 | 46 | // check if max > parent 47 | if let max = max, node.key >= max { 48 | print("max: \(max) key: \(node.key)") 49 | return false 50 | } 51 | 52 | // if min max OK, go to next level passing in min/max and parent 53 | return isBST(node.left, min, node.key) && isBST(node.right, node.key, max) 54 | } 55 | 56 | class Tests: XCTestCase { 57 | 58 | func testIsValid1() { 59 | let root = Node(4) 60 | root.left = Node(2) 61 | root.right = Node(6) 62 | root.left?.left = Node(1) 63 | root.left?.right = Node(3) 64 | root.right?.left = Node(5) 65 | root.right?.right = Node(7) 66 | 67 | XCTAssertTrue(checkBST(root: root)) 68 | } 69 | 70 | func testIsNotValid1() { 71 | let root = Node(3) 72 | root.left = Node(2) 73 | root.right = Node(4) 74 | root.left?.left = Node(1) 75 | root.right?.left = Node(5) 76 | root.right?.right = Node(6) 77 | 78 | XCTAssertFalse(checkBST(root: root)) 79 | } 80 | 81 | func testIsNotValidDuplicate1() { 82 | let root = Node(3) 83 | root.left = Node(2) 84 | root.right = Node(5) 85 | root.left?.left = Node(1) 86 | root.right?.left = Node(6) 87 | root.right?.right = Node(1) 88 | 89 | XCTAssertFalse(checkBST(root: root)) 90 | } 91 | } 92 | 93 | // Infrastructure 94 | class TestObserver: NSObject, XCTestObservation { 95 | func testCase(_ testCase: XCTestCase, 96 | didFailWithDescription description: String, 97 | inFile filePath: String?, 98 | atLine lineNumber: Int) { 99 | assertionFailure(description, line: UInt(lineNumber)) 100 | } 101 | } 102 | let testObserver = TestObserver() 103 | XCTestObservationCenter.shared.addTestObserver(testObserver) 104 | Tests.defaultTestSuite.run() 105 | 106 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q1-IsBST-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q1-IsBST-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | CheckBST 6 | https://www.hackerrank.com/challenges/ctci-is-binary-search-tree/problem 7 | 8 | Given the root node of a binary tree, determine if it is a binary search tree. 9 | 10 | The Node class is defined as follows: 11 | class Node { 12 | int data; 13 | Node left; 14 | Node right; 15 | } 16 | */ 17 | 18 | class Node { 19 | var key: Int 20 | var left: Node? 21 | var right: Node? 22 | 23 | init(_ data: Int) { 24 | self.key = data 25 | } 26 | } 27 | 28 | func checkBST(root: Node?) -> Bool { 29 | return false 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q1-IsBST-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q2-Height-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | TreeHeight 6 | https://app.codility.com/programmers/trainings/4/tree_height/ 7 | https://github.com/raywenderlich/swift-algorithm-club/tree/master/Binary%20Search%20Tree 8 | 9 | Height is the number of steps to the lowest leaf. 10 | Length of the longest path. 11 | Tree with one node has height of zero. 12 | 13 | 20 14 | / \ 15 | 8 22 16 | / \ 17 | 4 12 18 | / \ 19 | 10 14 20 | */ 21 | class Node { 22 | var data: Int = 0 23 | var left: Node? 24 | var right: Node? 25 | 26 | init(_ key: Int) { 27 | self.data = key 28 | } 29 | 30 | func height() -> Int { 31 | if isLeaf { 32 | return 0 33 | } else { 34 | return 1 + max(left?.height() ?? 0, right?.height() ?? 0) 35 | } 36 | } 37 | 38 | var isLeaf: Bool { 39 | return left == nil && right == nil 40 | } 41 | } 42 | 43 | let root = Node(20) 44 | root.left = Node(8) 45 | root.right = Node(22) 46 | root.left?.left = Node(4) 47 | root.left?.right = Node(12) 48 | root.left?.right?.left = Node(10) 49 | root.left?.right?.right = Node(14) 50 | 51 | root.height() 52 | 53 | class Tree { 54 | var x: Int = 0 55 | var l: Tree? 56 | var r: Tree? 57 | 58 | init(_ key: Int) { 59 | self.x = key 60 | } 61 | } 62 | 63 | func solution(_ T: Tree?) -> Int { 64 | return height(T!) 65 | } 66 | 67 | func isLeaf(_ tree: Tree?) -> Bool { 68 | return tree?.l == nil && tree?.r == nil 69 | } 70 | 71 | func height(_ tree: Tree?) -> Int { 72 | if isLeaf(tree) { 73 | return 0 74 | } else { 75 | return 1 + max(height(tree?.l ?? nil), height(tree?.r ?? nil)) 76 | } 77 | } 78 | 79 | class Tests: XCTestCase { 80 | 81 | func testHeightOfZero() { 82 | let root = Node(5) 83 | XCTAssertEqual(0, root.height()) 84 | } 85 | 86 | func testHeightOfTwo() { 87 | let root = Node(5) 88 | root.left = Node(3) 89 | root.right = Node(10) 90 | root.left?.left = Node(20) 91 | root.left?.right = Node(21) 92 | root.right?.left = Node(1) 93 | 94 | XCTAssertEqual(2, root.height()) 95 | } 96 | 97 | func testHeightOfThree() { 98 | let tree = Tree(20) 99 | tree.l = Tree(8) 100 | tree.r = Tree(22) 101 | tree.l?.l = Tree(4) 102 | tree.l?.r = Tree(12) 103 | tree.l?.r?.l = Tree(10) 104 | tree.l?.r?.r = Tree(14) 105 | 106 | XCTAssertEqual(3, solution(tree)) 107 | } 108 | } 109 | 110 | // Infrastructure 111 | class TestObserver: NSObject, XCTestObservation { 112 | func testCase(_ testCase: XCTestCase, 113 | didFailWithDescription description: String, 114 | inFile filePath: String?, 115 | atLine lineNumber: Int) { 116 | assertionFailure(description, line: UInt(lineNumber)) 117 | } 118 | } 119 | let testObserver = TestObserver() 120 | XCTestObservationCenter.shared.addTestObserver(testObserver) 121 | Tests.defaultTestSuite.run() 122 | 123 | 124 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q2-Height-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q2-Height-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /* 5 | TreeHeight 6 | https://app.codility.com/programmers/trainings/4/tree_height/ 7 | 8 | Height is the number of steps to the lowest leaf. 9 | Length of the longest path. 10 | Tree with one node has height of zero. 11 | 12 | 20 13 | / \ 14 | 8 22 15 | / \ 16 | 4 12 17 | / \ 18 | 10 14 19 | */ 20 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q2-Height-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q3-LowestCommonAncestor-Answer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Lowest common ancestor (LCA) in BST. 5 | https://www.geeksforgeeks.org/lowest-common-ancestor-in-a-binary-search-tree/ 6 | 7 | O(h) - height of the tree 8 | 9 | 1. If the value of the current node is less than both n1 and n2, then LCA lies in the right. 10 | 2. If the value of the current node is greater than both n1 and n2, then LCA lies in the left. 11 | 3. If both the above cases are false then return the current node as LCA. 12 | 13 | 20 14 | / \ 15 | 8 22 16 | / \ 17 | 4 12 18 | / \ 19 | 10 14 20 | */ 21 | class Node { 22 | var data: Int = 0 23 | var left: Node? 24 | var right: Node? 25 | 26 | init(_ key: Int) { 27 | self.data = key 28 | } 29 | } 30 | 31 | class BinaryTree { 32 | var root: Node? 33 | 34 | func lca(_ node: Node?, _ n1: Int, _ n2: Int) -> Node? { 35 | if node == nil { return nil } 36 | 37 | // If both n1 and n2 are smaller than root, then LCA lies in left 38 | if node!.data > n1 && node!.data > n2 { 39 | return lca(node?.left, n1, n2) 40 | } 41 | 42 | // If both n1 and n2 are larger than root, then LCA lies in right 43 | if node!.data < n1 && node!.data < n2 { 44 | return lca(node?.right, n1, n2) 45 | } 46 | 47 | // Else we are at the node which is the LCA 48 | return node 49 | } 50 | } 51 | 52 | let tree = BinaryTree() 53 | tree.root = Node(20) 54 | tree.root?.left = Node(8) 55 | tree.root?.right = Node(22) 56 | tree.root?.left?.left = Node(4) 57 | tree.root?.left?.right = Node(12) 58 | tree.root?.left?.right?.left = Node(10) 59 | tree.root?.left?.right?.right = Node(14) 60 | 61 | var n1 = 10, n2 = 14 62 | var t = tree.lca(tree.root, n1, n2) 63 | print("LCA of \(n1) and \(n2) is \(String(describing: t?.data))") // 12 64 | 65 | n1 = 14; n2 = 8 66 | t = tree.lca(tree.root, n1, n2) 67 | print("LCA of \(n1) and \(n2) is \(String(describing: t?.data))") // 8 68 | 69 | n1 = 10; n2 = 22 70 | t = tree.lca(tree.root, n1, n2) 71 | print("LCA of \(n1) and \(n2) is \(String(describing: t?.data))") // 20 72 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q3-LowestCommonAncestor-Answer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q3-LowestCommonAncestor-Question.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | Lowest common ancestor (LCA) in BST. 5 | https://www.geeksforgeeks.org/lowest-common-ancestor-in-a-binary-search-tree/ 6 | 7 | O(h) - height of the tree 8 | 9 | 1. If the value of the current node is less than both n1 and n2, then LCA lies in the right. 10 | 2. If the value of the current node is greater than both n1 and n2, then LCA lies in the left. 11 | 3. If both the above cases are false then return the current node as LCA. 12 | 13 | 20 14 | / \ 15 | 8 22 16 | / \ 17 | 4 12 18 | / \ 19 | 10 14 20 | */ 21 | class Node { 22 | var data: Int = 0 23 | var left: Node? 24 | var right: Node? 25 | 26 | init(_ key: Int) { 27 | self.data = key 28 | } 29 | } 30 | 31 | class BinaryTree { 32 | var root: Node? 33 | 34 | func lca(_ node: Node?, _ n1: Int, _ n2: Int) -> Node? { 35 | // Magic happens here... 36 | return nil 37 | } 38 | } 39 | 40 | let tree = BinaryTree() 41 | // Step 1: Build the BST 42 | 43 | // Step 2: Make it pass these test cases 44 | var n1 = 10, n2 = 14 45 | var t = tree.lca(tree.root, n1, n2) 46 | print("LCA of \(n1) and \(n2) is \(String(describing: t?.data))") // 12 47 | 48 | n1 = 14; n2 = 8 49 | t = tree.lca(tree.root, n1, n2) 50 | print("LCA of \(n1) and \(n2) is \(String(describing: t?.data))") // 8 51 | 52 | n1 = 10; n2 = 22 53 | t = tree.lca(tree.root, n1, n2) 54 | print("LCA of \(n1) and \(n2) is \(String(describing: t?.data))") // 20 55 | -------------------------------------------------------------------------------- /7-BinaryTrees/Q3-LowestCommonAncestor-Question.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /8-Memoization/Fibanocci.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ 5 | | __(_) |__ __ _ _ _ ___ __ __(_) 6 | | _|| | '_ \/ _` | ' \/ _ \/ _/ _| | 7 | |_| |_|_.__/\__,_|_||_\___/\__\__|_| 8 | 9 | */ 10 | 11 | func fibNaive(_ n: Int) -> Int { 12 | print(n) 13 | if n == 0 { 14 | return 0 15 | } else if n == 1 { 16 | return 1 17 | } else { 18 | return fibNaive(n - 1) + fibNaive(n - 2) 19 | } 20 | } 21 | 22 | fibNaive(20) // 20 = 13s / 22 = 54 s 23 | 24 | var memo = [Int: Int]() 25 | 26 | func fib(_ n: Int) -> Int { 27 | if n == 0 { return 0} 28 | else if n == 1 { return 1 } 29 | 30 | if let result = memo[n] { return result } 31 | 32 | memo[n] = fib(n - 1) + fib(n - 2) 33 | 34 | return memo[n]! 35 | } 36 | 37 | fib(22) // 70 max 38 | -------------------------------------------------------------------------------- /8-Memoization/Fibanocci.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /9-Sorting/BubbleSort.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ _ _ ___ _ 5 | | _ )_ _| |__| |__| |___ / __| ___ _ _| |_ 6 | | _ \ || | '_ \ '_ \ / -_) \__ \/ _ \ '_| _| 7 | |___/\_,_|_.__/_.__/_\___| |___/\___/_| \__| 8 | 9 | */ 10 | 11 | 12 | 13 | 14 | class BubbleSort { 15 | func sort(_ array: [Int]) -> [Int] { 16 | var arr = array 17 | let n = arr.count 18 | for i in 0.. arr[j+1] { 21 | // swap 22 | let temp = arr[j] 23 | arr[j] = arr[j+1] 24 | arr[j+1] = temp 25 | } 26 | } 27 | } 28 | 29 | return arr 30 | } 31 | } 32 | 33 | let bubbleSort = BubbleSort() 34 | bubbleSort.sort([5, 4, 3, 2, 1]) 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /9-Sorting/BubbleSort.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jonathan Rasmusson 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 | ![](images/banner.png) 2 | 3 | This is the repository for the Swift Arcade data structures and algorithms course hosted on Udemy. Here you will find all the playgrounds used in the couse. 4 | 5 | 6 | - [What is Big O Notation?](1-BigO/README.md) 7 | -------------------------------------------------------------------------------- /images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrasmusson/datastructures-algorithms/805b5739a333b143147360adb976be48230616db/images/banner.png -------------------------------------------------------------------------------- /images/construction.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrasmusson/datastructures-algorithms/805b5739a333b143147360adb976be48230616db/images/construction.gif --------------------------------------------------------------------------------