├── .gitignore ├── .sourcery.yml ├── .swift-version ├── .travis.yml ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Sources ├── ArrayAndStringQuestions │ ├── 1.1_IsUnique.swift │ ├── 1.2_CheckPermutation.swift │ ├── 1.3_Urlify.swift │ ├── 1.4_PalindromPermutation.swift │ ├── 1.5_OneAway.swift │ ├── 1.6_StringCompression.swift │ ├── 1.7_RotateMatrix.swift │ ├── 1.8_ZeroMatrix.swift │ └── 1.9_StringRotation.swift ├── BitManipulationQuestions │ ├── 5.1_Insertion.swift │ └── 5.2_Conversion.swift ├── HardQuestions │ ├── 17.21_VolumeOfHistogram.swift │ └── 17.7_BabyNames.swift ├── LinkedListsQuestions │ ├── 2.1_RemoveDups.swift │ ├── 2.2_KthToLast.swift │ ├── 2.5_SumLists.swift │ ├── 2.6_IsPalindrome.swift │ ├── 2.7_Intersection.swift │ └── 2.8_LoopDetection.swift ├── ModerateQuestions │ ├── 16.11_DivingBoard.swift │ ├── 16.13_EncodeXML.swift │ ├── 16.15_MasterMind.swift │ ├── 16.17_ContiguousSequence.swift │ ├── 16.19_PondSizes.swift │ ├── 16.1_NumberSwap.swift │ ├── 16.21_SumSwap.swift │ ├── 16.22_LangtonsAnt.swift │ ├── 16.2_WordFrequency.swift │ ├── 16.5_FactorialZeros.swift │ ├── 16.6_SmallestDifference.swift │ └── 16.8_EnglishInt.swift ├── RecursionAndDynamicProgrammingQuestions │ ├── 8.11_Coins.swift │ ├── 8.1_TripleStep.swift │ ├── 8.2_RobotInAGrid.swift │ ├── 8.4_PowerSet.swift │ ├── 8.5_RecursiveMultiply.swift │ └── 8.9_Parens.swift ├── SortingAndSearchingQuestions │ └── 10.1_SortedMerge.swift ├── StacksAndQueuesQuestions │ ├── 3.2_StackMin.swift │ ├── 3.4_QueueViaStacks.swift │ └── 3.5_SortStack.swift └── TreesAndGraphsQuestions │ ├── 4.1_RouteBetweenNodes.swift │ ├── 4.2_MinimalTree.swift │ ├── 4.3_ListOfDepth.swift │ ├── 4.5_ValidateBST.swift │ ├── 4.7_BuildOrder.swift │ └── 4.8_FirstCommonAncestor.swift ├── Tests ├── CrackingTests │ ├── ArrayAndStringTests.swift │ ├── BitManipulationTests.swift │ ├── HardTests.swift │ ├── LinkedListsTests.swift │ ├── ModerateTests.swift │ ├── RecursionAndDynamicProgrammingTests.swift │ ├── SortingAndSearchingTests.swift │ ├── StacksAndQueueTests.swift │ ├── TreesAndGraphsTests.swift │ └── XCTestCase+CustomAssertion.swift └── LinuxMain.swift └── templates ├── LinuxMain.stencil └── Readme.stencil /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | /bin 6 | /.vscode 7 | -------------------------------------------------------------------------------- /.sourcery.yml: -------------------------------------------------------------------------------- 1 | sources: 2 | - Tests/ 3 | templates: 4 | - templates/LinuxMain.stencil 5 | - templates/Readme.stencil 6 | output: 7 | '.' 8 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.1 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | language: generic 3 | sudo: required 4 | dist: trusty 5 | install: 6 | - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" 7 | script: 8 | - swift test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ikhsan Assaat 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 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "DataStructure", 6 | "repositoryURL": "https://github.com/ikhsan/DataStructure", 7 | "state": { 8 | "branch": "master", 9 | "revision": "afb64183a1c9d60c3ca370836d60cf170fe80af1", 10 | "version": null 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "ctci-swift", 7 | dependencies: [ 8 | .package(url: "https://github.com/ikhsan/DataStructure", from: "0.0.1") 9 | ], 10 | targets: [ 11 | .target(name: "ArrayAndStringQuestions"), 12 | .target( 13 | name: "LinkedListsQuestions", 14 | dependencies: [ "DataStructure" ] 15 | ), 16 | .target( 17 | name: "StacksAndQueuesQuestions", 18 | dependencies: [ "DataStructure" ] 19 | ), 20 | .target( 21 | name: "TreesAndGraphsQuestions", 22 | dependencies: [ "DataStructure" ] 23 | ), 24 | .target(name: "BitManipulationQuestions"), 25 | .target(name: "RecursionAndDynamicProgrammingQuestions"), 26 | .target(name: "SortingAndSearchingQuestions"), 27 | .target(name: "ModerateQuestions"), 28 | .target( 29 | name: "HardQuestions", 30 | dependencies: [ "DataStructure" ] 31 | ), 32 | 33 | .testTarget( 34 | name: "CrackingTests", 35 | dependencies: [ 36 | "ArrayAndStringQuestions", 37 | "LinkedListsQuestions", 38 | "StacksAndQueuesQuestions", 39 | "TreesAndGraphsQuestions", 40 | "BitManipulationQuestions", 41 | "RecursionAndDynamicProgrammingQuestions", 42 | "SortingAndSearchingQuestions", 43 | "ModerateQuestions", 44 | "HardQuestions", 45 | ] 46 | ) 47 | ] 48 | ) 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cracking The Coding Interview 2 | 3 | [![Build Status](https://travis-ci.org/ikhsan/ctci-swift.svg?branch=master)](https://travis-ci.org/ikhsan/ctci-swift) 4 | ![Swift 4](https://img.shields.io/badge/Swift-4.0-orange.svg) 5 | 6 | Solutions of Cracking The Coding Interview written in Swift. 7 | 8 | ## Tests 9 | 10 | Tests are updated by using [Sourcery](https://github.com/krzysztofzablocki/Sourcery). When editing tests (add, remove, disable, enable tests) run `sourcery` from the root folder. You can unzip `sourcery`'s [latest binary](https://github.com/krzysztofzablocki/Sourcery/releases) and put the `bin` directory in the root directory, then run `bin/sourcery` from the root directory. 11 | 12 | Run the test by using SPM's test command: 13 | 14 | ```bash 15 | $ swift test 16 | ``` 17 | 18 | You can also run individual tests by using its number. 19 | 20 | ```bash 21 | $ swift test --filter 2.1 22 | ``` 23 | 24 | ## Solved Problems 25 | 26 | - ArrayAndString 27 | - 1.1.AllUnique 28 | - 1.2.CheckPermutation 29 | - 1.3.Urlify 30 | - 1.4.PalindromPermutation 31 | - 1.5.OneAway 32 | - 1.6.StringCompression 33 | - 1.7.RotateMatrix 34 | - 1.8.ZeroMatrix 35 | - 1.9.StringRotation 36 | - BitManipulation 37 | - 5.1.Insertion 38 | - 5.6.Conversion 39 | - HardQuestions 40 | - 17.7.BabyNames 41 | - 17.21.VolumeOfHistogram 42 | - LinkedLists 43 | - 2.1.RemoveDups 44 | - 2.2.ReturnKthToLast 45 | - 2.5.SumLists 46 | - 2.6.Palindrome 47 | - 2.7.Intersection 48 | - 2.8.LoopDetection 49 | - Moderate 50 | - 16.1.NumberSwap 51 | - 16.2.WordFrequencies 52 | - 16.3.CountZeroFactorial 53 | - 16.4.FindMinDiff 54 | - 16.8.EnglishInt 55 | - 16.11.DivingBoard 56 | - 16.13.XMLEncoding 57 | - 16.15.MasterMind 58 | - 16.17.ContiguousSequence 59 | - 16.19.PondSize 60 | - 16.21.SumSwap 61 | - 16.22.LangtonsAnt 62 | - RecursionAndDynamicProgramming 63 | - 8.1.TripleSteps 64 | - 8.2.RobotInAGrid 65 | - 8.4.PowerSet 66 | - 8.5.RecursiveMultiply 67 | - 8.9.Parens 68 | - 8.11.Coins 69 | - SortingAndSearching 70 | - 10.1.SortedMerge 71 | - StacksAndQueues 72 | - 3.2.StackMin 73 | - 3.4.QueueViaStacks 74 | - 3.5.SortStack 75 | - TreesAndGraphs 76 | - 4.1.RouteBetweenNodes 77 | - 4.2.MinimalTree 78 | - 4.3.ListOfDepth 79 | - 4.5.ValidateBST 80 | - 4.7.BuildOrder 81 | - 4.8.FirstCommonAncestor 82 | 83 | ## License 84 | 85 | MIT 86 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.1_IsUnique.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | private func clean(_ string: String) -> String { 4 | let charSet = CharacterSet.lowercaseLetters.inverted.union(.whitespacesAndNewlines) 5 | return string.components(separatedBy: charSet).joined() 6 | } 7 | 8 | private func asciiIndex(_ char: Character) -> Int { 9 | let s = String(char).unicodeScalars 10 | return Int(s[s.startIndex].value) 11 | } 12 | 13 | /// Solution #1: Use dictionary 14 | /// 15 | /// Complexity: O(n) time, O(n) space where n is number of unique char 16 | public func isUnique1(_ string: String) -> Bool { 17 | var chars: [Character : Int] = [:] 18 | 19 | for char in clean(string) { 20 | if chars[char] != nil { return false } 21 | chars[char, default: 0] += 1 22 | } 23 | 24 | return true 25 | } 26 | 27 | /// Solution #2: Use bits 28 | /// 29 | /// Complexity: O(n) time, O(1) space 30 | /// Int can either be Int32 or Int64 based on its platform, to make a safe assumption, 31 | /// we only support lowercase letter in ascii which only needs 26 bit 32 | public func isUnique2(_ string: String) -> Bool { 33 | let words = clean(string) 34 | var letter = 0 35 | 36 | for char in words { 37 | let offset = asciiIndex(char) - asciiIndex("a") 38 | if (letter & (1 << offset) > 0) { 39 | return false 40 | } 41 | letter = letter | (1 << offset) 42 | } 43 | 44 | return true 45 | } 46 | 47 | 48 | /* 49 | Learnings: 50 | - Don't forget about whitespaces 51 | - Make assumption on character encoding, above just assumes that it only supports lowercase letters 52 | - Bit manipulation: switch with OR (&), check with AND(|), and shift 1 to the left using offset (BITWISE SHIFT <<) 53 | */ 54 | 55 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.2_CheckPermutation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func isPermutation(_ str1: String, _ str2: String) -> Bool { 4 | if (str1.count != str2.count) { 5 | return false 6 | } 7 | 8 | var charCount: [Character : Int] = [:] 9 | 10 | for char in str1 { 11 | charCount[char, default: 0] += 1 12 | } 13 | for char in str2 { 14 | guard let count = charCount[char] else { 15 | return false 16 | } 17 | charCount[char] = count - 1 18 | if (charCount[char] == 0) { 19 | charCount.removeValue(forKey: char) 20 | } 21 | } 22 | 23 | return charCount.isEmpty 24 | } 25 | 26 | 27 | /* 28 | Learnings: 29 | - Forgot to clarify about whitespaces and case sensivity 30 | */ 31 | 32 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.3_Urlify.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func urlify(_ str: String, _ size: Int) -> String { 4 | let word = str.trimmingCharacters(in: .whitespacesAndNewlines) 5 | 6 | var stringSize = size 7 | for char in word { 8 | if char == " " { stringSize += 2 } 9 | } 10 | 11 | var chars: [Character] = Array(repeating: Character("_"), count: stringSize) 12 | var index = 0 13 | 14 | for char in word { 15 | if char != " " { 16 | chars[index] = char 17 | index += 1 18 | } else { 19 | chars[index] = "%" 20 | chars[index+1] = "2" 21 | chars[index+2] = "0" 22 | index += 3 23 | } 24 | } 25 | 26 | return String(chars) 27 | } 28 | 29 | /* 30 | Learnings: 31 | - Misunderstood the true size in the question 32 | - Don't forget trimming whitespaces 33 | */ 34 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.4_PalindromPermutation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Only accept letters and returns all lowercase letters 4 | private func clean(_ str: String) -> String { 5 | let charSet = CharacterSet.lowercaseLetters.inverted.union(.whitespacesAndNewlines) 6 | return str.lowercased().components(separatedBy: charSet).joined() 7 | } 8 | 9 | private func isOdd(_ number: Int) -> Bool { return number % 2 == 1 } 10 | 11 | /// Complexity: O(n) time and space 12 | public func isPalindromePermutation(_ str: String) -> Bool { 13 | let cleaned = clean(str) 14 | 15 | var counter: [Character : Int] = [:] 16 | for char in cleaned { 17 | counter[char, default: 0] += 1 18 | } 19 | 20 | let oddCharCount = counter.values.filter(isOdd).count 21 | 22 | return oddCharCount < 2 23 | } 24 | 25 | private func asciiIndex(_ char: Character) -> Int { 26 | let s = String(char).unicodeScalars 27 | return Int(s[s.startIndex].value) 28 | } 29 | 30 | private func toggle(_ vector: Int, _ offset: Int) -> Int { 31 | guard offset >= 0 else { return vector } 32 | 33 | let mask = (1 << offset) 34 | return (vector & mask == 0) 35 | ? vector | mask 36 | : vector & ~mask 37 | } 38 | 39 | /// Complexity: O(n) time and O(1) space 40 | /// Use bit vector 41 | public func isPalindromePermutation2(_ str: String) -> Bool { 42 | let cleaned = clean(str) 43 | 44 | var counter: Int = 0 45 | for char in cleaned { 46 | let offset = asciiIndex(char) - asciiIndex("a") 47 | counter = toggle(counter, offset) 48 | } 49 | 50 | let isOnlyOneBitSet = (counter - 1) & counter == 0 51 | return counter == 0 || isOnlyOneBitSet 52 | } 53 | 54 | 55 | 56 | /** 57 | Learnings: 58 | - Hash table is really powerful! 59 | - Don't forget to clean up the input 60 | - Think again about the information needed in the hash table, if we only need a flag-y value, then bit vector (Int32) should work 61 | */ 62 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.5_OneAway.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func isOneAway(_ lhs: String, _ rhs: String) -> Bool { 4 | if (lhs.count == rhs.count) { 5 | return isOneEdit(lhs, rhs) 6 | } else if (lhs.count + 1 == rhs.count) { 7 | return isOneInsertion(rhs, lhs) 8 | } else if (lhs.count == rhs.count + 1) { 9 | return isOneInsertion(lhs, rhs) 10 | } 11 | return false 12 | } 13 | 14 | private func isOneInsertion(_ lhs: String, _ rhs: String) -> Bool { 15 | var leftIndex = 0 16 | var rightIndex = 0 17 | 18 | while leftIndex < lhs.count && rightIndex < rhs.count { 19 | let leftChar = lhs[lhs.index(lhs.startIndex, offsetBy: leftIndex)] 20 | let rightChar = rhs[rhs.index(rhs.startIndex, offsetBy: rightIndex)] 21 | 22 | if leftChar == rightChar { 23 | leftIndex += 1 24 | rightIndex += 1 25 | } else { 26 | if (leftIndex != rightIndex) { 27 | return false 28 | } 29 | leftIndex += 1 30 | } 31 | } 32 | return true 33 | } 34 | 35 | private func isOneEdit(_ lhs: String, _ rhs: String) -> Bool { 36 | var foundEdit = false 37 | for (i, leftChar) in lhs.enumerated() { 38 | let index = rhs.index(rhs.startIndex, offsetBy: i) 39 | if (leftChar != rhs[index]) { 40 | if foundEdit { 41 | return false 42 | } 43 | foundEdit = true 44 | } 45 | } 46 | return true 47 | } 48 | 49 | /** 50 | Learnings: 51 | - Dictionary won't work, because order is important 52 | - Breakdown the problem and solve it one by one 53 | */ 54 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.6_StringCompression.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Complexity: O(n) time and space 4 | public func compress(_ str: String) -> String { 5 | let strCount = str.utf8.count 6 | var chars: [Character] = Array(repeating: "_", count: strCount) 7 | var current: Character? = nil 8 | var counter = 0 9 | var index = 0 10 | 11 | for char in str { 12 | if char != current { 13 | if counter > 0 { 14 | chars[index] = Character("\(counter)") 15 | index += 1 16 | if index >= strCount { return str } 17 | } 18 | 19 | chars[index] = char 20 | index += 1 21 | if index >= strCount { return str } 22 | 23 | current = char 24 | counter = 0 25 | } 26 | counter += 1 27 | } 28 | 29 | if counter > 0 { 30 | chars[index] = Character("\(counter)") 31 | } 32 | 33 | return String(chars.prefix(index + 1)) 34 | } 35 | 36 | /* 37 | Learnings: 38 | - Making many String concats is not efficient 39 | - In C/Java, terminating String is easier, in Swift we just cut the string until index 40 | */ 41 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.7_RotateMatrix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Complexity: O(n^2) 4 | public func rotate(matrix: [[T]]) -> [[T]] { 5 | var m = matrix 6 | 7 | var size = matrix.count 8 | var (row, col) = (0,0) 9 | 10 | while size > 1 { 11 | for i in 0..<(size-1) { 12 | let (r1, c1) = (row, col + i) 13 | let (r2, c2) = (row + i, col + (size - 1)) 14 | let (r3, c3) = (row + (size-1), col + (size - 1) - i) 15 | let (r4, c4) = (row + (size-1) - i, col) 16 | 17 | let temp = m[r4][c4] 18 | m[r4][c4] = m[r3][c3] 19 | m[r3][c3] = m[r2][c2] 20 | m[r2][c2] = m[r1][c1] 21 | m[r1][c1] = temp 22 | } 23 | 24 | size -= 2 25 | (row, col) = (row + 1, col + 1) 26 | } 27 | 28 | return m 29 | } 30 | 31 | /** 32 | Learnings: 33 | - Realise how I struggle to convert my algo from visual to text 34 | */ 35 | -------------------------------------------------------------------------------- /Sources/ArrayAndStringQuestions/1.8_ZeroMatrix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func zero(matrix: inout [[Int]]) { 4 | guard !matrix.isEmpty else { return } 5 | 6 | let height = matrix.count 7 | let width = matrix.first!.count 8 | var isFirstRowZero = false 9 | var isFirstColZero = false 10 | 11 | for row in 0.. Bool { 6 | isSubstringCallCount += 1 7 | return haystack.range(of: needle) != nil 8 | } 9 | 10 | public func isRotation(_ s1: String, _ s2: String) -> Bool { 11 | return isSubstring(s1, s2 + s2) 12 | } 13 | -------------------------------------------------------------------------------- /Sources/BitManipulationQuestions/5.1_Insertion.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func insertBit(n: Int, m: Int, i: Int, j: Int) -> Int { 4 | let mask = createMask(from: i, to: j) 5 | let nCleared = n & mask 6 | let mShifted = m << i 7 | return nCleared | mShifted 8 | } 9 | 10 | private func createMask(from start: Int, to end: Int) -> Int { 11 | return createMask(to: start) | createMask(from: start + end) 12 | } 13 | 14 | private func createMask(to i: Int) -> Int { 15 | return (1 << i) - 1 16 | } 17 | 18 | private func createMask(from i: Int) -> Int { 19 | return ~0 << (i - 1) 20 | } 21 | 22 | /** 23 | 24 | Learnings: 25 | - Get, set, clear bits 26 | - Print and assign integer in binary: `0b1111` and `String(s, radix: 2)` 27 | 28 | */ 29 | -------------------------------------------------------------------------------- /Sources/BitManipulationQuestions/5.2_Conversion.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func bitsToFlip(_ x: Int, _ y: Int) -> Int { 4 | return countSetBits(x ^ y) 5 | } 6 | 7 | private func countSetBits(_ x: Int) -> Int { 8 | var counter = 0 9 | var n = x 10 | while n > 0 { 11 | counter += n & 1 12 | n >>= 1 13 | } 14 | return counter 15 | } 16 | -------------------------------------------------------------------------------- /Sources/HardQuestions/17.21_VolumeOfHistogram.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func calculateVolume(histogram: [Int]) -> Int { 4 | var maxBars: [Int] = [] 5 | var maxBar = 0 6 | for i in (0.. 0 { 20 | res += vol 21 | } 22 | 23 | leftBar = max(leftBar, bar) 24 | } 25 | 26 | return res 27 | } -------------------------------------------------------------------------------- /Sources/HardQuestions/17.7_BabyNames.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import DataStructure 3 | 4 | class NameVertex: Vertex { 5 | var value: String 6 | var count = 0 7 | var isVisited = false 8 | 9 | required init(_ value: String) { self.value = value } 10 | var description: String { return value } 11 | static func ==(lhs: NameVertex, rhs: NameVertex) -> Bool { return lhs.value == rhs.value } 12 | } 13 | 14 | func getCount(for name: String, in graph: Graph) -> Int { 15 | guard let vertex = graph.getVertex(name), !vertex.isVisited else { return 0 } 16 | var count = 0 17 | var q = [vertex] 18 | while (!q.isEmpty) { 19 | let node = q.removeFirst() 20 | count += node.count 21 | node.isVisited = true 22 | for edge in graph.getEdges(node) where !edge.isVisited { 23 | q.append(edge) 24 | } 25 | } 26 | return count 27 | } 28 | 29 | public func countBabyNames(names: [(String, Int)], synonyms: [(String, String)]) -> [String : Int] { 30 | let graph = Graph(vertices: [], edges: []) 31 | for (name, count) in names { 32 | let v = NameVertex(name) 33 | v.count = count 34 | graph.addVertex(v) 35 | } 36 | for (node1, node2) in synonyms { 37 | graph.addEdge(from: node1, to: node2) 38 | graph.addEdge(from: node2, to: node1) 39 | } 40 | 41 | var res: [String : Int] = [:] 42 | for (name, _) in names { 43 | let count = getCount(for: name, in: graph) 44 | if count > 0 { res[name] = count } 45 | } 46 | return res 47 | } -------------------------------------------------------------------------------- /Sources/LinkedListsQuestions/2.1_RemoveDups.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import DataStructure 3 | 4 | /// Complexity: O(n) time & space 5 | public func removeDups(_ list: LinkedList) { 6 | var node = list.head 7 | var previous: LinkedList.Node? = nil 8 | 9 | var founds: Set = [] 10 | 11 | while node != nil { 12 | let val = node!.value 13 | if founds.contains(val) { 14 | previous?.next = node?.next 15 | } else { 16 | founds.insert(val) 17 | previous = node 18 | } 19 | 20 | node = node?.next 21 | } 22 | } 23 | 24 | /// Complexity: O(n^2) time and O(1) space 25 | public func removeDups2(_ list: LinkedList) { 26 | var node = list.head 27 | 28 | while node != nil { 29 | var runner = node?.next 30 | 31 | var previous = node 32 | while runner != nil { 33 | if runner?.value == node!.value { 34 | previous?.next = runner?.next 35 | } else { 36 | previous = runner 37 | } 38 | runner = runner?.next 39 | } 40 | 41 | node = node?.next 42 | } 43 | } 44 | 45 | /* 46 | Learnings: 47 | - Use set instead of dictionary 48 | */ 49 | -------------------------------------------------------------------------------- /Sources/LinkedListsQuestions/2.2_KthToLast.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import DataStructure 3 | 4 | /// Complexity: O(n) space, O(1) time 5 | public func kthToLast(_ k: Int, _ list: LinkedList) -> T? { 6 | guard k > 0 else { return nil } 7 | 8 | var runner1 = list.head 9 | var runner2: LinkedList.Node? = nil 10 | var index = 0 11 | 12 | while runner1?.next != nil { 13 | index += 1 14 | 15 | if k == index { 16 | runner2 = list.head 17 | } 18 | 19 | runner1 = runner1?.next 20 | runner2 = runner2?.next 21 | } 22 | 23 | return runner2?.value 24 | } 25 | 26 | /* 27 | Learnings: 28 | - First thought is using hash table and make a copy as array 29 | - Thought of the multiple runner solution after reading the hints 30 | */ 31 | -------------------------------------------------------------------------------- /Sources/LinkedListsQuestions/2.5_SumLists.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | /// Complexity: O(n) time & space 4 | public func sumList(_ lhs: LinkedList, _ rhs: LinkedList) -> LinkedList { 5 | let result = LinkedList() 6 | 7 | var leftCurrent = lhs.head 8 | var rightCurrent = rhs.head 9 | var node: LinkedList.Node? = nil 10 | 11 | var carry = 0 12 | while leftCurrent != nil || rightCurrent != nil { 13 | let sum = (leftCurrent?.value ?? 0) + (rightCurrent?.value ?? 0) + carry 14 | 15 | carry = sum / 10 16 | let number = sum % 10 17 | 18 | let newNode = LinkedList.Node(number) 19 | if result.head == nil { 20 | result.head = newNode 21 | } else { 22 | node?.next = newNode 23 | } 24 | 25 | node = newNode 26 | leftCurrent = leftCurrent?.next 27 | rightCurrent = rightCurrent?.next 28 | } 29 | 30 | if carry > 0 { 31 | node?.next = .init(carry) 32 | } 33 | 34 | return result 35 | } 36 | 37 | /// Complexity: O(n) time & space 38 | public func sumListReverse(_ lhs: LinkedList, _ rhs: LinkedList) -> LinkedList { 39 | return intToList(listToInt(lhs) + listToInt(rhs)) 40 | } 41 | 42 | private func listToInt(_ list: LinkedList) -> Int { 43 | return list.reduce(into: 0) { (result, node) in 44 | result = (result * 10) + node.value 45 | } 46 | } 47 | 48 | private func intToList(_ number: Int) -> LinkedList { 49 | let list = LinkedList() 50 | var num = number 51 | while num > 0 { 52 | let node = LinkedList.Node(num % 10) 53 | node.next = list.head 54 | 55 | list.head = node 56 | num /= 10 57 | } 58 | return list 59 | } 60 | 61 | // TODO: Recursion 62 | 63 | /* 64 | Learnings: 65 | - Reduce into is awesome 66 | - Didn't think of recursion as the solution 67 | */ 68 | -------------------------------------------------------------------------------- /Sources/LinkedListsQuestions/2.6_IsPalindrome.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | private func isPalindromeWrapper(_ left: inout LinkedList.Node?, _ right: LinkedList.Node?) -> Bool { 4 | if right == nil { return true } 5 | 6 | if !isPalindromeWrapper(&left, right?.next) { 7 | return false 8 | } 9 | 10 | let isSymmetrical = left?.value == right?.value 11 | left = left?.next 12 | return isSymmetrical 13 | } 14 | 15 | /// Complexity: O(n) 16 | public func isPalindrome(_ list: LinkedList) -> Bool { 17 | return isPalindromeWrapper(&list.head, list.head) 18 | } 19 | 20 | /* 21 | Learnings: 22 | - Only thought as far as O(2n) where first traversal to determine its size, then put it on a stack 23 | - If we need stack to put our variables, call stack can be your stack! :mindblown: 24 | - inout params, use c-like ampersand 25 | */ 26 | -------------------------------------------------------------------------------- /Sources/LinkedListsQuestions/2.7_Intersection.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | public func listIntersection(_ lhs: LinkedList, _ rhs: LinkedList) -> LinkedList.Node? { 4 | let (leftTail, leftCount) = countAndTail(list: lhs) 5 | let (rightTail, rightCount) = countAndTail(list: rhs) 6 | 7 | guard leftTail === rightTail else { return nil } 8 | 9 | var left = lhs.head 10 | var right = rhs.head 11 | 12 | let moveCount = abs(leftCount - rightCount) 13 | var moveNode = leftCount > rightCount ? left : right 14 | move(node: &moveNode, by: moveCount) 15 | 16 | while left != nil && right != nil { 17 | if left === right { return left } 18 | 19 | left = left?.next 20 | right = right?.next 21 | } 22 | 23 | return nil 24 | } 25 | 26 | private func move(node: inout LinkedList.Node?, by offset: Int) { 27 | var offset = offset 28 | while offset > 0 { 29 | node = node?.next 30 | offset -= 1 31 | } 32 | } 33 | 34 | private func countAndTail(list: LinkedList) -> (LinkedList.Node?, Int) { 35 | var node = list.head 36 | var count = 0 37 | 38 | while node != nil { 39 | count += 1 40 | node = node?.next 41 | } 42 | 43 | return (node, count) 44 | } 45 | -------------------------------------------------------------------------------- /Sources/LinkedListsQuestions/2.8_LoopDetection.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | public func detectLoop(_ list: LinkedList) -> Bool { 4 | guard !list.isEmpty else { return false } 5 | 6 | var hare = list.head 7 | var tortoise = list.head 8 | 9 | repeat { 10 | hare = hare?.next?.next 11 | tortoise = tortoise?.next 12 | 13 | if (hare === tortoise) { return true } 14 | } while (hare != nil && tortoise != nil) 15 | 16 | return false 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.11_DivingBoard.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func allLengthsForBoard(length1: Int, length2: Int, k: Int) -> Set { 4 | var result: Set = [] 5 | for i in 0...k { 6 | let j = k - i 7 | result.insert(i * length1 + j * length2) 8 | } 9 | return result 10 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.13_EncodeXML.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func encode(xml: String) -> String { 4 | guard let doc = try? XMLDocument(xmlString: xml), 5 | let root = doc.rootElement() 6 | else { return "" } 7 | return encode(node: root) 8 | } 9 | 10 | private let tags: [String : String] = [ 11 | "family" : "1", 12 | "person" : "2", 13 | "firstName" : "3", 14 | "lastName" : "4", 15 | "state" : "5", 16 | ] 17 | 18 | private func encode(node: XMLNode) -> String { 19 | guard let element = node as? XMLElement else { 20 | return node.stringValue ?? "" 21 | } 22 | 23 | guard let name = element.name, let tag = tags[name] else { return "" } 24 | 25 | let attributes = (element.attributes ?? []).reduce(into: "") { memo, attr in 26 | let key = attr.name ?? "" 27 | let value = attr.stringValue ?? "" 28 | 29 | if let tag = tags[key] { 30 | memo += "\(tag) \(value) " 31 | } 32 | } 33 | 34 | let children = element.children ?? [] 35 | 36 | var result = "\(tag) \(attributes)0" 37 | for child in children { 38 | result += " " + encode(node: child) 39 | } 40 | result += " 0" 41 | 42 | return result 43 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.15_MasterMind.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func masterMind(solution: String, guess: String) -> (Int, Int) { 4 | let sol = Array(solution) 5 | let gss = Array(guess) 6 | 7 | guard sol.count == 4 && gss.count == 4 else { return (-1, -1) } 8 | 9 | var hits = 0 10 | var pseudoHits = 0 11 | var solDict: [Character : Int] = [:] 12 | var gssDict: [Character : Int] = [:] 13 | 14 | for i in 0.. Int { 4 | guard !arr.isEmpty else { return 0 } 5 | guard arr.count > 1 else { return arr.first! } 6 | 7 | var current = arr.first! 8 | var maxSum = arr.first! 9 | for val in arr.dropFirst() { 10 | current = max(val, current + val) 11 | maxSum = max(maxSum, current) 12 | } 13 | return maxSum 14 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.19_PondSizes.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /* 4 | [0, 2, 1, 0], 5 | [0, 1, 0, 1], 6 | [1, 1, 0, 1], 7 | [0, 1, 0, 1] 8 | */ 9 | 10 | public func getPondSizes(_ ponds: inout [[Int]]) -> [Int] { 11 | guard !ponds.isEmpty else { return [] } 12 | 13 | var sizes: [Int] = [] 14 | let size = ponds.count 15 | for row in 0.. Int { 29 | let isBound = (row >= 0 && col >= 0 && row < ponds.count && col < ponds.count) 30 | guard isBound else { return 0 } 31 | 32 | let isPond = (ponds[row][col] == 0) 33 | guard isPond else { return 0 } 34 | 35 | ponds[row][col] = -1 36 | 37 | var count = 1 38 | for i in row-1...row+1 { 39 | for j in col-1...col+1 { 40 | count += getSize(&ponds, i, j) 41 | } 42 | } 43 | 44 | return count 45 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.1_NumberSwap.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func numberSwap(_ a: inout Int, _ b: inout Int) { 4 | a = b - a 5 | b = b - a 6 | a = a + b 7 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.21_SumSwap.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func sumSwap(_ a: [Int], _ b: [Int]) -> (Int, Int)? { 4 | guard !a.isEmpty && !b.isEmpty else { return nil } 5 | 6 | let sumA = a.reduce(0, +) 7 | let sumB = b.reduce(0, +) 8 | guard abs(sumA - sumB) % 2 == 0 else { return nil } 9 | 10 | let diff = (sumA - sumB) / 2 11 | 12 | return findDiffWithSorting(diff, a.sorted(), b.sorted()) 13 | // OR 14 | // return findDiffWithHash(diff, a, b) 15 | } 16 | 17 | private func findDiffWithSorting(_ diff: Int, _ a: [Int], _ b: [Int]) -> (Int, Int)? { 18 | var i = 0 19 | var j = 0 20 | 21 | while (i < a.count && j < b.count) { 22 | let valA = a[i] 23 | let valB = b[j] 24 | let d = valA - valB 25 | if d < diff { 26 | i += 1 27 | } else if d > diff { 28 | j += 1 29 | } else { 30 | return (valA, valB) 31 | } 32 | } 33 | 34 | return nil 35 | } 36 | 37 | private func findDiffWithHash(_ diff: Int, _ a: [Int], _ b: [Int]) -> (Int, Int)? { 38 | let setB : Set = Set(b) 39 | for val in a { 40 | let target = val - diff 41 | if setB.contains(target) { 42 | return (val, target) 43 | } 44 | } 45 | return nil 46 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.22_LangtonsAnt.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Grid { 4 | var grid: [[Int]] = [[0]] 5 | var height: Int { return grid.count } 6 | var width: Int { return grid.first!.count } 7 | 8 | func flip(_ row: Int, _ col: Int) { 9 | grid[row][col] = (grid[row][col] == 0) ? 1 : 0 10 | } 11 | 12 | func resize(for ant: Ant) { 13 | let h = height 14 | let w = width 15 | switch (ant.row, ant.col) { 16 | case (-1, _): // top 17 | grid.insert(Array(repeating: 0, count: w), at: 0) 18 | ant.row += 1 19 | case (_, -1): // left 20 | for row in 0.. String { 32 | let rows = grid.map { $0.map(String.init).joined(separator: "") } 33 | return rows.joined(separator: "\n") 34 | } 35 | } 36 | 37 | class Ant { 38 | var row = 0 39 | var col = 0 40 | var dir = Direction.right 41 | 42 | func move() { 43 | switch dir { 44 | case .up: 45 | row -= 1 46 | case .down: 47 | row += 1 48 | case .right: 49 | col += 1 50 | case .left: 51 | col -= 1 52 | } 53 | } 54 | 55 | func turnRight() { dir = dir.turnRight() } 56 | func turnLeft() { dir = dir.turnLeft() } 57 | } 58 | 59 | enum Direction { 60 | case up, right, down, left 61 | 62 | func turnRight() -> Direction { 63 | switch self { 64 | case .up: return .right 65 | case .right: return .down 66 | case .down: return .left 67 | case .left: return .up 68 | } 69 | } 70 | 71 | func turnLeft() -> Direction { 72 | switch self { 73 | case .up: return .left 74 | case .right: return .up 75 | case .down: return .right 76 | case .left: return .down 77 | } 78 | } 79 | } 80 | 81 | public func printAnt(moves: Int) -> String { 82 | let grid = Grid() 83 | let ant = Ant() 84 | 85 | for _ in 0.. Int { 4 | let dict = createDictionary(book: book) 5 | let key = normalizeKey(word) 6 | return dict[key] ?? 0 7 | } 8 | 9 | private func normalizeKey(_ word: String) -> String { 10 | return word.lowercased() 11 | } 12 | 13 | private func createDictionary(book: [String]) -> [String : Int] { 14 | var dict: [String : Int] = [:] 15 | 16 | for word in book where !word.isEmpty { 17 | let key = normalizeKey(word) 18 | dict[key, default: 0] += 1 19 | } 20 | 21 | return dict 22 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.5_FactorialZeros.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func countZeroFactorial(_ num: Int) -> Int { 4 | var count = 0 5 | var i = 5 6 | while ((num / i) > 0) { 7 | count += num / i 8 | i *= 5 9 | } 10 | return count 11 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.6_SmallestDifference.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func minDiff(_ a: [Int], _ b: [Int]) -> Int? { 4 | guard !a.isEmpty && !b.isEmpty else { return nil } 5 | 6 | let sortedA = a.sorted() 7 | let sortedB = b.sorted() 8 | 9 | var indexA = 0 10 | var indexB = 0 11 | var result = Int.max 12 | 13 | while indexA < sortedA.count && indexB < sortedB.count { 14 | let valA = sortedA[indexA] 15 | let valB = sortedB[indexB] 16 | 17 | result = min(result, abs(valA - valB)) 18 | if valA < valB { 19 | indexA += 1 20 | } else if valA > valB { 21 | indexB += 1 22 | } else { 23 | return 0 24 | } 25 | } 26 | 27 | return result 28 | } -------------------------------------------------------------------------------- /Sources/ModerateQuestions/16.8_EnglishInt.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func english(for number: Int) -> String { 4 | guard number != 0 else { return "Zero" } 5 | 6 | let digits = ["", "Thousand", "Million", "Billion", "Trillion"] 7 | 8 | var result = "" 9 | var itr = 0 10 | var n = number 11 | 12 | while n > 0 { 13 | let threes = n % 1000 14 | let english = translate(for: threes) 15 | 16 | if itr == 0 { 17 | result = english 18 | } else { 19 | result = "\(english) \(digits[itr]), \(result)" 20 | } 21 | 22 | n = n / 1000 23 | itr += 1 24 | } 25 | 26 | return result 27 | } 28 | 29 | // translate 3 digit 30 | private func translate(for number: Int) -> String { 31 | let digits = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", 32 | "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"] 33 | let digits2 = ["", "", "Twenty", "Thirty", "Fourty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"] 34 | 35 | var result = "" 36 | let hundred = number / 100 37 | if hundred > 0 { 38 | result += "\(digits[hundred]) Hundred " 39 | } 40 | 41 | let remainder = number % 100 42 | if remainder < 20 { 43 | result += digits[remainder] 44 | } else { 45 | let digit2 = remainder / 10 46 | let digit1 = remainder % 10 47 | result += "\(digits2[digit2]) \(digits[digit1])" 48 | } 49 | 50 | return result 51 | } -------------------------------------------------------------------------------- /Sources/RecursionAndDynamicProgrammingQuestions/8.11_Coins.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func countWaysForChange(_ cents: Int) -> Int { 4 | var memo: [String : Int] = [:] 5 | return _countWaysForChange(cents, [25, 10, 5, 1], &memo) 6 | } 7 | 8 | private func _countWaysForChange(_ cents: Int, _ denoms: [Int], _ memo: inout [String : Int]) -> Int { 9 | guard cents > 0 && denoms.count > 1 else { return 1 } 10 | 11 | let key = createKey(cents, denoms) 12 | if memo[key] == nil { 13 | var ways = 0 14 | 15 | var mDenoms = denoms 16 | let denom = mDenoms.removeFirst() 17 | 18 | for i in stride(from: 0, through: cents, by: denom) { 19 | let remain = cents - i 20 | ways += _countWaysForChange(remain, mDenoms, &memo) 21 | } 22 | 23 | memo[key] = ways 24 | } 25 | 26 | return memo[key]! 27 | } 28 | 29 | private func createKey(_ cents: Int, _ denoms: [Int]) -> String { 30 | return "\(cents)_\(denoms.first!)" 31 | } 32 | -------------------------------------------------------------------------------- /Sources/RecursionAndDynamicProgrammingQuestions/8.1_TripleStep.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func possibleWaysToStep(n: Int) -> Int { 4 | var memo = [1: 1, 2: 2, 3: 4] 5 | return _possibleWaysToStep(n: n, memo: &memo) 6 | } 7 | 8 | private func _possibleWaysToStep(n: Int, memo: inout [Int : Int]) -> Int { 9 | guard n > 0 else { return 0 } 10 | 11 | if memo[n] == nil { 12 | memo[n] = _possibleWaysToStep(n: n - 3, memo: &memo) + _possibleWaysToStep(n: n - 2, memo: &memo) + _possibleWaysToStep(n: n - 1, memo: &memo) 13 | } 14 | return memo[n]! 15 | } 16 | -------------------------------------------------------------------------------- /Sources/RecursionAndDynamicProgrammingQuestions/8.2_RobotInAGrid.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias Grid = [[Int]] 4 | 5 | public struct Point: Equatable { 6 | let row: Int 7 | let col: Int 8 | 9 | public init(_ row: Int, _ col: Int) { 10 | self.row = row 11 | self.col = col 12 | } 13 | } 14 | 15 | public typealias PathCache = [Int : [Point]] 16 | 17 | public func getPath(grid: Grid) -> [Point] { 18 | guard !grid.isEmpty && !grid.first!.isEmpty else { fatalError("grid can't be empty") } 19 | 20 | var memo: PathCache = [ 0: [Point(0,0)] ] 21 | let destination = Point(height(for: grid) - 1, width(for: grid) - 1) 22 | return _getPath(grid: grid, point: destination, memo: &memo) 23 | } 24 | 25 | private func _getPath(grid: Grid, point: Point, memo: inout PathCache) -> [Point] { 26 | guard isGridValid(grid: grid, point: point) else { return [] } 27 | 28 | let cacheKey = getKey(point: point, width: width(for: grid)) 29 | if memo[cacheKey] == nil { 30 | let upper = _getPath(grid: grid, point: Point(point.row - 1, point.col), memo: &memo) 31 | let lefty = _getPath(grid: grid, point: Point(point.row, point.col - 1), memo: &memo) 32 | 33 | let result: [Point] 34 | if !upper.isEmpty { 35 | result = upper + [point] 36 | } else if !lefty.isEmpty { 37 | result = lefty + [point] 38 | } else { 39 | result = [] 40 | } 41 | memo[cacheKey] = result 42 | } 43 | return memo[cacheKey]! 44 | } 45 | 46 | private func isGridValid(grid: Grid, point: Point) -> Bool { 47 | let (row, column) = (point.row, point.col) 48 | 49 | if 0 > row || row >= height(for: grid) { return false } 50 | if 0 > column || column >= width(for: grid) { return false } 51 | if grid[row][column] != 0 { return false } 52 | return true 53 | } 54 | 55 | // MARK: - Helper 56 | 57 | private func getKey(point p: Point, width: Int) -> Int { return (p.row * width) + p.col } 58 | private func height(for grid: Grid) -> Int { return grid.count } 59 | private func width(for grid: Grid) -> Int { return grid[0].count } 60 | -------------------------------------------------------------------------------- /Sources/RecursionAndDynamicProgrammingQuestions/8.4_PowerSet.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func allSubset(_ theSet: [T]) -> [[T]] { 4 | let all = theSet 5 | 6 | if all.isEmpty { 7 | return [Array()] 8 | } 9 | 10 | let lastElement = all.last! 11 | let previousSet = allSubset(Array(all.dropLast())) 12 | 13 | let newSet: [[T]] = previousSet.map { 14 | var currentSet = $0 15 | currentSet.append(lastElement) 16 | return currentSet 17 | } 18 | 19 | return previousSet + newSet 20 | } 21 | -------------------------------------------------------------------------------- /Sources/RecursionAndDynamicProgrammingQuestions/8.5_RecursiveMultiply.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func recursiveMultiply(_ x: Int, _ y: Int) -> Int { 4 | let s = min(x, y) 5 | let b = max(x, y) 6 | return _recursiveMultiply2(s, b) 7 | } 8 | 9 | private func _recursiveMultiply1(_ s: Int, _ b: Int) -> Int { 10 | switch s { 11 | case 0: return 0 12 | case 1: return b 13 | default: return _recursiveMultiply1(s - 1, b) + b 14 | } 15 | } 16 | 17 | public func recursiveMultiply2(_ x: Int, _ y: Int) -> Int { 18 | let s = min(x, y) 19 | let b = max(x, y) 20 | return _recursiveMultiply2(s, b) 21 | } 22 | 23 | private func _recursiveMultiply2(_ s: Int, _ b: Int) -> Int { 24 | switch s { 25 | case 0: return 0 26 | case 1: return b 27 | default: 28 | let halfS = s >> 1 29 | let half = _recursiveMultiply2(halfS, b) 30 | let offset = (s % 2 == 0) ? 0 : b 31 | return half + half + offset 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/RecursionAndDynamicProgrammingQuestions/8.9_Parens.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func generateParentheses(_ n: Int) -> Set { 4 | switch n { 5 | case ..<1: 6 | return [] 7 | case 1: 8 | return ["()"] 9 | default: 10 | let previousSet = generateParentheses(n - 1) 11 | return previousSet.reduce(into: []) { result, element in 12 | result.insert("()\(element)") 13 | result.insert("(\(element))") 14 | result.insert("\(element)()") 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SortingAndSearchingQuestions/10.1_SortedMerge.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func mergeSortedArray(_ a: inout [Int], _ countA: Int, _ b: [Int]) { 4 | var indexA = countA - 1 // -1 5 | var indexB = b.count - 1 // 0 6 | var indexMerge = countA + b.count - 1 // 0 7 | 8 | while indexB >= 0 { 9 | if indexA < 0 || b[indexB] > a[indexA] { 10 | a[indexMerge] = b[indexB] 11 | indexB -= 1 12 | } else { 13 | a[indexMerge] = a[indexA] 14 | indexA -= 1 15 | } 16 | indexMerge -= 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/StacksAndQueuesQuestions/3.2_StackMin.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | public class MinStack { 4 | private var mainStack: [T] 5 | private var minStack: [T] 6 | 7 | public init() { 8 | mainStack = .init() 9 | minStack = .init() 10 | } 11 | 12 | public func peek() -> T? { 13 | return mainStack.last 14 | } 15 | 16 | public func min() -> T? { 17 | return minStack.last 18 | } 19 | 20 | public func push(_ value: T) { 21 | mainStack.append(value) 22 | 23 | if !minStack.isEmpty && value > min()! { return } 24 | minStack.append(value) 25 | } 26 | 27 | public func pop() -> T? { 28 | guard !mainStack.isEmpty else { return nil } 29 | 30 | let lastValue = mainStack.removeLast() 31 | if lastValue == min() { 32 | minStack.removeLast() 33 | } 34 | return lastValue 35 | } 36 | } 37 | 38 | /** 39 | Learnings: 40 | - Realise another easy solution is to have the value as pair (value, minValue) but it might waste more space than this current solution 41 | */ 42 | -------------------------------------------------------------------------------- /Sources/StacksAndQueuesQuestions/3.4_QueueViaStacks.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | public class MyQueue { 4 | 5 | private let enqueueStack: Stack 6 | private let dequeueStack: Stack 7 | 8 | public var isEmpty: Bool { 9 | return enqueueStack.isEmpty && dequeueStack.isEmpty 10 | } 11 | 12 | public init() { 13 | self.enqueueStack = .init() 14 | self.dequeueStack = .init() 15 | } 16 | 17 | public func enqueue(_ value: T) { 18 | enqueueStack.push(value) 19 | } 20 | 21 | public func dequeue() -> T? { 22 | if dequeueStack.isEmpty { 23 | backFill() 24 | } 25 | return dequeueStack.pop() 26 | } 27 | 28 | public func peek() -> T? { 29 | if dequeueStack.isEmpty { 30 | backFill() 31 | } 32 | return dequeueStack.peek() 33 | } 34 | 35 | private func backFill() { 36 | while let val = enqueueStack.pop() { 37 | dequeueStack.push(val) 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Sources/StacksAndQueuesQuestions/3.5_SortStack.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | /// Complexity: O(N^2) time, O(N) space 4 | public func sortStack(_ s: Stack) -> Stack { 5 | let r = Stack() 6 | while !s.isEmpty { 7 | let val = s.pop()! 8 | while let p = r.peek(), p < val { 9 | s.push(r.pop()!) 10 | } 11 | r.push(val) 12 | } 13 | return r 14 | } 15 | 16 | /** 17 | Learnings: 18 | - Realise that you don't need the 3rd stack 19 | */ 20 | -------------------------------------------------------------------------------- /Sources/TreesAndGraphsQuestions/4.1_RouteBetweenNodes.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | /// Complexity: O(n) time & O(1) space 4 | public func isDfsRouted(from source: MarkedVertex, to target: MarkedVertex, in graph: Graph) -> Bool { 5 | if source == target { return true } 6 | for child in graph.getEdges(source) { 7 | if child.marked { continue } 8 | if isDfsRouted(from: child, to: target, in: graph) { return true } 9 | child.marked = true 10 | } 11 | return false 12 | } 13 | 14 | /// Complexity: O(n) time & O(1) space 15 | public func isBfsRouted(from source: MarkedVertex, to target: MarkedVertex, in graph: Graph) -> Bool { 16 | let queue = Queue() 17 | 18 | queue.enqueue(source) 19 | source.marked = true 20 | 21 | while let node = queue.dequeue() { 22 | if node == target { return true } 23 | 24 | for child in graph.getEdges(node) where !child.marked { 25 | queue.enqueue(child) 26 | child.marked = true 27 | } 28 | } 29 | 30 | return false 31 | } 32 | 33 | // MARK: - Data Structure 34 | public class MarkedVertex: Vertex { 35 | var value: String 36 | var marked: Bool 37 | 38 | public required init(_ value: String) { 39 | self.value = value 40 | self.marked = false 41 | } 42 | 43 | public var description: String { return value } 44 | public static func ==(lhs: MarkedVertex, rhs: MarkedVertex) -> Bool { return lhs.value == rhs.value } 45 | } 46 | 47 | extension Graph where T == MarkedVertex { 48 | public func reset() { 49 | for vertex in vertices { vertex.marked = false } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/TreesAndGraphsQuestions/4.2_MinimalTree.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | public func minimalTree(_ list: [T]) -> BinaryTree { 4 | guard !list.isEmpty else { return .empty } 5 | 6 | let size = list.count 7 | if size == 1 { return BinaryTree.node(.empty, list.first!, .empty) } 8 | 9 | let center = size / 2 10 | let rootValue = list[center] 11 | 12 | let leftSide = Array(list[0..? { 10 | guard case .node(let leftChild, _, _) = self else { return nil } 11 | return leftChild 12 | } 13 | 14 | var right: BinaryTree? { 15 | guard case .node(_, _, let rightChild) = self else { return nil } 16 | return rightChild 17 | } 18 | } 19 | 20 | public typealias DepthList = LinkedList> 21 | 22 | public func listOfDepth(_ tree: BinaryTree) -> DepthList { 23 | let list = DepthList() 24 | 25 | var q = [BinaryTree]() 26 | q.append(tree) 27 | 28 | var levelSize = 0 29 | var previous: DepthList.Node? = nil 30 | 31 | while !q.isEmpty { 32 | if levelSize == 0 { 33 | // backfill 34 | levelSize = q.count 35 | let levelList = backfill(q.compactMap { $0.value }) 36 | 37 | let node = DepthList.Node(levelList) 38 | if list.head == nil { 39 | list.head = node 40 | } else { 41 | previous?.next = node 42 | } 43 | previous = node 44 | } 45 | 46 | // dequeue 47 | let t = q.removeFirst() 48 | if let leftChild = t.left, leftChild != .empty { q.append(leftChild) } 49 | if let rightChild = t.right, rightChild != .empty { q.append(rightChild) } 50 | levelSize -= 1 51 | } 52 | 53 | return list 54 | } 55 | 56 | private func backfill(_ items: [T]) -> LinkedList { 57 | let list = LinkedList() 58 | 59 | var previous: LinkedList.Node? = nil 60 | for item in items { 61 | let node = LinkedList.Node(item) 62 | if list.head == nil { 63 | list.head = node 64 | } else { 65 | previous?.next = node 66 | } 67 | previous = node 68 | } 69 | 70 | return list 71 | } 72 | -------------------------------------------------------------------------------- /Sources/TreesAndGraphsQuestions/4.5_ValidateBST.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | public func validateBST(tree: BinaryTree) -> Bool { 4 | guard case .node(let leftChild, let value, let rightChild) = tree else { return false } 5 | 6 | if case .node(_, let leftValue, _) = leftChild { 7 | let isLeftValid = (leftValue <= value) && validateBST(tree: leftChild) 8 | if !isLeftValid { return false } 9 | } 10 | 11 | if case .node(_, let rightValue, _) = rightChild { 12 | let isRightValid = (value <= rightValue) && validateBST(tree: rightChild) 13 | if !isRightValid { return false } 14 | } 15 | 16 | return true 17 | } 18 | -------------------------------------------------------------------------------- /Sources/TreesAndGraphsQuestions/4.7_BuildOrder.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | // MARK: - Solution #1 4 | 5 | /// Complexity: O(P + D), P: # of projects, D: # of dependencies 6 | public func order(_ graph: Graph) -> [Project] { 7 | var result: [Project?] = Array(repeating: nil, count: graph.vertices.count) 8 | 9 | var offset = 0 10 | var buildIndex = 0 11 | 12 | graph.vertices 13 | .filter { $0.dependsOn == 0 } 14 | .enumerated() 15 | .forEach { (index, node) in 16 | result[index] = node 17 | offset += 1 18 | } 19 | 20 | // return early, can't start build any projects 21 | if offset == 0 { return [] } 22 | 23 | while buildIndex < result.count { 24 | guard let proj = result[buildIndex] else { continue } 25 | for dependent in graph.getEdges(proj) { 26 | dependent.dependsOn -= 1 27 | if (dependent.dependsOn == 0) { 28 | result[offset] = dependent 29 | offset += 1 30 | } 31 | } 32 | buildIndex += 1 33 | } 34 | 35 | return result.compactMap { $0 } 36 | } 37 | 38 | // MARK: - Solution #2 39 | 40 | /// Using DFS. Complexity: O(P + D), P: # of projects, D: # of dependencies 41 | public func order2(_ graph: Graph) -> [Project] { 42 | var result = [Project]() 43 | for node in graph.vertices { 44 | if !shouldComplete(graph: graph, project: node, result: &result) { 45 | return [] 46 | } 47 | } 48 | return result 49 | } 50 | 51 | private func shouldComplete(graph: Graph, project: Project, result: inout [Project]) -> Bool { 52 | switch project.state { 53 | case .processing: 54 | return false 55 | case .complete: 56 | return true 57 | case .uninitialized: 58 | project.state = .processing 59 | 60 | for dependent in graph.getEdges(project) { 61 | if !shouldComplete(graph: graph, project: dependent, result: &result) { 62 | return false 63 | } 64 | } 65 | 66 | project.state = .complete 67 | result.insert(project, at: 0) 68 | return true 69 | } 70 | } 71 | 72 | // MARK: - Data Structure 73 | 74 | public class Project: Vertex { 75 | public enum State { case uninitialized, processing, complete } 76 | 77 | public let name: String 78 | public var dependsOn: Int 79 | public var state: State 80 | 81 | public required init(_ name: String) { 82 | self.name = name 83 | self.dependsOn = 0 84 | self.state = .uninitialized 85 | } 86 | 87 | public var description: String { return name } 88 | 89 | public static func ==(lhs: Project, rhs: Project) -> Bool { 90 | return lhs.name == rhs.name 91 | } 92 | } 93 | 94 | extension Graph where T == Project { 95 | 96 | public func reset() { 97 | for vertex in vertices { 98 | for child in getEdges(vertex) { 99 | child.dependsOn += 1 100 | } 101 | } 102 | } 103 | 104 | } 105 | 106 | /** 107 | Learnings: 108 | - Learned how to breakdown small problems with graph 109 | - Reminded that graph is just collection of nodes 110 | - Made aware of the term topological sort 111 | */ 112 | -------------------------------------------------------------------------------- /Sources/TreesAndGraphsQuestions/4.8_FirstCommonAncestor.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | 3 | private enum Result { 4 | case notFound 5 | case found(T) 6 | case ancestor(T) 7 | } 8 | 9 | private func _commonAncestor(root: BinaryTree, p: BinaryTree, q: BinaryTree) -> Result> { 10 | guard case .node(let left, _, let right) = root else { return .notFound } 11 | 12 | if root == p && root == q { return .ancestor(root) } 13 | 14 | let x = _commonAncestor(root: left, p: p, q: q) 15 | if case .ancestor = x { return x } 16 | 17 | let y = _commonAncestor(root: right, p: p, q: q) 18 | if case .ancestor = y { return y } 19 | 20 | let isFoundInRoot = (root == p || root == q) 21 | switch (x, y) { 22 | case (.found, .found): 23 | return .ancestor(root) 24 | case (.found, .notFound): 25 | return isFoundInRoot ? .ancestor(root) : x 26 | case (.notFound, .found): 27 | return isFoundInRoot ? .ancestor(root) : y 28 | default: 29 | return isFoundInRoot ? .found(root) : .notFound 30 | } 31 | } 32 | 33 | public func commonAncestor(root: BinaryTree, p: BinaryTree, q: BinaryTree) -> BinaryTree? { 34 | let result = _commonAncestor(root: root, p: p, q: q) 35 | guard case .ancestor(let tree) = result else { return nil } 36 | return tree 37 | } 38 | 39 | /** 40 | Learnings: 41 | - I spent too long trying to understand how the recursion solution works 42 | - What confused me most is how many cases the return type of the recursion can be 43 | - Try to think all of the different cases and try to summarise it to a type, I tried with enum and I can get my head around it 44 | - The solution from the book explained all the cases but the code's structure scatters the all possibilities which made it hard to digest 45 | */ 46 | -------------------------------------------------------------------------------- /Tests/CrackingTests/ArrayAndStringTests.swift: -------------------------------------------------------------------------------- 1 | import ArrayAndStringQuestions 2 | import XCTest 3 | 4 | class ArrayAndStringTests: XCTestCase { 5 | 6 | /** 7 | 1.1: Is Unique 8 | 9 | Implement an algorihtm to determine if a string has all unique characters. What if you cannot use additional data structures? 10 | */ 11 | func test_1_1_AllUnique() { 12 | let abcd = "abcdefABCDEF" 13 | XCTAssert(isUnique1(abcd)) 14 | XCTAssert(isUnique2(abcd)) 15 | 16 | let hello = "hello" 17 | XCTAssertFalse(isUnique1(hello)) 18 | XCTAssertFalse(isUnique2(hello)) 19 | } 20 | 21 | /** 22 | 1.2: Check Permutation 23 | 24 | Given two strings, write a method to decide if one is permutation of the other. 25 | */ 26 | func test_1_2_CheckPermutation() { 27 | XCTAssert(isPermutation("abcde", "ebacd")) 28 | XCTAssert(isPermutation("abbba", "babab")) 29 | 30 | XCTAssertFalse(isPermutation("hello", "world")) 31 | XCTAssertFalse(isPermutation("hello", "world!")) 32 | } 33 | 34 | /** 35 | 1.3: URLify 36 | 37 | Write a method to replace all spaces in a string with '%20'. You may assume that the string has sufficient space at the end to hold the additional characters, and that you are given the "true" length of the string. 38 | */ 39 | func test_1_3_Urlify() { 40 | XCTAssertEqual(urlify("Mr John Smith ", 13), "Mr%20John%20Smith") 41 | 42 | // with whitespace 43 | XCTAssertEqual(urlify(" Mr John Smith ", 13), "Mr%20John%20Smith") 44 | } 45 | 46 | /** 47 | 1.4: Palindrom Permutation 48 | 49 | Given a string, write a function to check if it is a permutation of a palindrome. A palindrome is a word or phrase that is the same forwards and backwards. A permutation is a rearrangement of letters. The palindrom does not need to be limited to just dictionary words. 50 | */ 51 | func test_1_4_PalindromPermutation() { 52 | XCTAssert(isPalindromePermutation("Tact Coa")) 53 | XCTAssert(isPalindromePermutation2("abba")) 54 | XCTAssert(isPalindromePermutation("Kasur Nababan rusak")) 55 | XCTAssertFalse(isPalindromePermutation("hello world")) 56 | 57 | XCTAssert(isPalindromePermutation2("Tact Coa")) 58 | XCTAssert(isPalindromePermutation2("ABBA")) 59 | XCTAssert(isPalindromePermutation2("Kasur Nababan rusak")) 60 | XCTAssertFalse(isPalindromePermutation2("hello world")) 61 | } 62 | 63 | /** 64 | 1.5: One Away 65 | 66 | There are three types of edits that can be performed on strings: insert a character, remove a character, or replace a character. Given two strings, write a function to check if they are one edit (or zero edits) away. 67 | */ 68 | func test_1_5_OneAway() { 69 | XCTAssert(isOneAway("test", "test")) 70 | XCTAssert(isOneAway("pale", "ple")) 71 | XCTAssert(isOneAway("pales", "pale")) 72 | XCTAssert(isOneAway("bake", "cake")) 73 | XCTAssertFalse(isOneAway("pales", "bake")) 74 | XCTAssertFalse(isOneAway("hell", "ohello")) 75 | } 76 | 77 | /** 78 | 1.6: String Compression 79 | 80 | Implement a method to perform basic string compression using the counts of repeated characters. For example, the string `aabccccaaa` would become `a2b1c5a3`. If the 'compressed' string would not become smaller than the original string, your method should return the original string. You can assume the string has only uppercase and lowercase letters (a -z) 81 | */ 82 | func test_1_6_StringCompression() { 83 | XCTAssertEqual(compress("aabccccaaa"), "a2b1c4a3") 84 | XCTAssertEqual(compress("aa"), "a2") 85 | XCTAssertEqual(compress("abcde"), "abcde") 86 | } 87 | 88 | /** 89 | 1.7: Rotate Matrix 90 | 91 | Given an image represented by an NxN matric, where each pixel in the image is 4 bytes, write a method to rotate the image by 90 degrees. Can you do this in place? 92 | */ 93 | func test_1_7_RotateMatrix() { 94 | let matrix1 = [ [1] ] 95 | let expected1 = [ [1] ] 96 | 97 | XCTAssertEqual(rotate(matrix: matrix1), expected1) 98 | 99 | let matrix2 = [ 100 | [1, 2], 101 | [3, 4], 102 | ] 103 | let expected2 = [ 104 | [3, 1], 105 | [4, 2], 106 | ] 107 | XCTAssertEqual(rotate(matrix: matrix2), expected2) 108 | 109 | let matrix3 = [ 110 | [1, 2, 3], 111 | [4, 5, 6], 112 | [7, 8, 9], 113 | ] 114 | let expected3 = [ 115 | [7, 4, 1], 116 | [8, 5, 2], 117 | [9, 6, 3], 118 | ] 119 | XCTAssertEqual(rotate(matrix: matrix3), expected3) 120 | 121 | let matrix4 = [ 122 | [1, 2, 3, 4], 123 | [5, 6, 7, 8], 124 | [9, 10, 11, 12], 125 | [13, 14, 15, 16], 126 | ] 127 | let expected4 = [ 128 | [13, 9, 5, 1], 129 | [14, 10, 6, 2], 130 | [15, 11, 7, 3], 131 | [16, 12, 8, 4], 132 | ] 133 | XCTAssertEqual(rotate(matrix: matrix4), expected4) 134 | } 135 | 136 | /** 137 | 1.8: Zero Matrix 138 | 139 | Write an algorithm such that if an element in a n MxN matrix is 0, its entire row and column are set to 0. 140 | */ 141 | func test_1_8_ZeroMatrix() { 142 | var matrix = [ 143 | [1, 2, 3, 4], 144 | [0, 6, 0, 8], 145 | [9, 10, 11, 12], 146 | ] 147 | zero(matrix: &matrix) 148 | 149 | XCTAssertEqual(matrix, [ 150 | [0, 2, 0, 4], 151 | [0, 0, 0, 0], 152 | [0, 10, 0, 12], 153 | ]) 154 | 155 | var matrix2 = [ 156 | [1, 2, 0, 4], 157 | [0, 6, 7, 8], 158 | [9, 10, 11, 12], 159 | ] 160 | zero(matrix: &matrix2) 161 | XCTAssertEqual(matrix2, [ 162 | [0, 0, 0, 0], 163 | [0, 0, 0, 0], 164 | [0, 10, 0, 12], 165 | ]) 166 | } 167 | 168 | /** 169 | 1.9: String Rotation 170 | 171 | Assume you have a method `isSubstring` which checks if one word is a substring of another. Given two strings, `s1` and `s2`, write code to check if `s2` is a rotation of s1 using only one call to `isSubstring`. 172 | */ 173 | func test_1_9_StringRotation() { 174 | isSubstringCallCount = 0 175 | XCTAssert(isRotation("test", "test")) 176 | XCTAssertEqual(isSubstringCallCount, 1) 177 | 178 | isSubstringCallCount = 0 179 | XCTAssert(isRotation("waterbottle", "erbottlewat")) 180 | XCTAssertEqual(isSubstringCallCount, 1) 181 | 182 | isSubstringCallCount = 0 183 | XCTAssert(isRotation("helloworld", "worldhello")) 184 | XCTAssertEqual(isSubstringCallCount, 1) 185 | 186 | isSubstringCallCount = 0 187 | XCTAssertFalse(isRotation("hello", "heyo")) 188 | XCTAssertEqual(isSubstringCallCount, 1) 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Tests/CrackingTests/BitManipulationTests.swift: -------------------------------------------------------------------------------- 1 | import BitManipulationQuestions 2 | import XCTest 3 | 4 | class BitManipulationTests: XCTestCase { 5 | 6 | /** 7 | 5.1: Insertion 8 | 9 | You are given two 32-bit numbers, N and M, and two bit positions, i and j. Write a method to insert M into N such that M starts at bit j and ends at bit i. You can assume that the bits j through i have enough space to fit all of M. That is, if M = 10011, you can assume that there are at least 5 bits between j and i. You would not, for example, have j = 3 and i = 2, because M could not fully fit between bit 3 and bit 2. 10 | 11 | EXAMPLE 12 | 13 | Input: N = 10000000000, M = 10011, i = 2, j = 6 14 | 15 | Output: N = 10001001100 16 | */ 17 | func test_5_1_Insertion() { 18 | let subject = insertBit(n: 0b10000000000, m: 0b10011, i: 2, j: 6) 19 | XCTAssertEqual(subject, 0b10001001100) 20 | } 21 | 22 | /** 23 | 5.6: Conversion 24 | 25 | Write a function to determine the number of bits you would need to flip to covert integer A to integer B. 26 | 27 | EXAMPLE 28 | 11111111 29 | 30 | Input: 29 (or: 11101), 15 (or: 01111) 31 | Output: 2 32 | */ 33 | func test_5_6_Conversion() { 34 | XCTAssertEqual(bitsToFlip(29, 15), 2) 35 | XCTAssertEqual(bitsToFlip(255, 0), 8) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Tests/CrackingTests/HardTests.swift: -------------------------------------------------------------------------------- 1 | import HardQuestions 2 | import XCTest 3 | 4 | class HardQuestions: XCTestCase { 5 | 6 | /** 7 | 17.7: Baby Names 8 | 9 | Each year, the government releases a list of the 10000 most common baby names and their frequencies (the number of babies with that name). The only problem with this is that some names have multiple spellings. For example, "John" and "Jon" are essentially the same name but would be listed separately in the list. Given two lists, one of names/frequencies and the other of pairs of equivalent names, write an algorithm to print a new list of the true frequency of each name. Note that if John and Jon are synonyms, and Jon and Johnny are synonyms, then John and Johnny are sysnonyms. (Is it both transitive and symmetric.) In the final list, any name can be used as the "real" name. 10 | */ 11 | func test_17_7_BabyNames() { 12 | let result = countBabyNames( 13 | names: [("John", 15), ("Jon", 12), ("Chris", 13), ("Kris", 4), ("Christopher", 19)], 14 | synonyms: [("Jon", "John"), ("John", "Johnny"), ("Chris", "Kris"), ("Chris", "Christopher")] 15 | ) 16 | XCTAssertEqual(result["John"], 27) 17 | XCTAssertEqual(result["Chris"], 36) 18 | } 19 | 20 | /** 21 | 17.21: Volume of Histogram 22 | 23 | Imagine a histogram (bar graph). Design an algorithm to compute the volume of water it could hold if someone poured water acress the top. You can assume that each histogram bar has width 1. 24 | */ 25 | 26 | func test_17_21_VolumeOfHistogram() { 27 | XCTAssertEqual(calculateVolume(histogram: [2, 0, 2]), 2) 28 | XCTAssertEqual(calculateVolume(histogram: [3, 0, 0, 2, 0, 4]), 10) 29 | XCTAssertEqual(calculateVolume(histogram: [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]), 6) 30 | XCTAssertEqual(calculateVolume(histogram: [0, 0, 4, 0, 0, 6, 0, 0, 3, 0, 5, 0, 1, 0, 0, 0]), 26) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/CrackingTests/LinkedListsTests.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | import LinkedListsQuestions 3 | import XCTest 4 | 5 | extension LinkedList { 6 | fileprivate func append(node: LinkedList.Node?) { 7 | guard head != nil else { 8 | head = node 9 | return 10 | } 11 | 12 | var current = head 13 | while (current?.next != nil) { 14 | current = current?.next 15 | } 16 | current?.next = node 17 | } 18 | } 19 | 20 | class LinkedListsTests: XCTestCase { 21 | 22 | /** 23 | 2.1: Remove Dups 24 | 25 | Write code to remove duplicates from an unsorted linked list. **Follow Up**: How would you solve this problem if a temporary buffer is not allowed? 26 | */ 27 | func test_2_1_RemoveDups() { 28 | let list1: LinkedList = [1, 2, 3, 4, 5, 3, 5] 29 | removeDups(list1) 30 | XCTAssertEqual(list1, [1, 2, 3, 4, 5]) 31 | 32 | let list2: LinkedList = [1, 1, 1, 1, 1, 1] 33 | removeDups(list2) 34 | XCTAssertEqual(list2, [1]) 35 | 36 | let list3: LinkedList = [1, 3, 5] 37 | removeDups(list3) 38 | XCTAssertEqual(list3, [1, 3, 5]) 39 | 40 | let list4: LinkedList = [1, 2, 3, 4, 5, 3, 5] 41 | removeDups2(list4) 42 | XCTAssertEqual(list4, [1, 2, 3, 4, 5]) 43 | 44 | let list5: LinkedList = [1, 1, 1, 1, 1, 1] 45 | removeDups2(list5) 46 | XCTAssertEqual(list5, [1]) 47 | 48 | let list6: LinkedList = [1, 3, 5] 49 | removeDups2(list6) 50 | XCTAssertEqual(list6, [1, 3, 5]) 51 | } 52 | 53 | /** 54 | 2.2: Return Kth to Last 55 | 56 | Implement an algorithm to find the kth to last element of a singly linked list. 57 | */ 58 | func test_2_2_ReturnKthToLast() { 59 | XCTAssertNil(kthToLast(-2, [1, 2, 3])) 60 | XCTAssertNil(kthToLast(10, [1, 2, 3, 4, 5, 6, 7, 8])) 61 | XCTAssertEqual(kthToLast(1, [1, 2, 3, 4, 5, 6, 7, 8]), 8) 62 | XCTAssertEqual(kthToLast(4, [1, 2, 3, 4, 5, 6, 7, 8]), 5) 63 | } 64 | 65 | /** 66 | 2.3: Delete Middle Node 67 | 68 | Implement an algorithm to delete a node in the middle (i.r.m any node but the first and last node, not necessarily the exact middle) of a singly linked list, given only access to that node. 69 | 70 | Input: the ode c from the linked list a->b->c->d->e->f 71 | Result: nothing is returned, bit the new lnked list looks like a->b->d->e->f 72 | */ 73 | func _test_2_3_DeleteMiddleNode() {} 74 | 75 | 76 | /** 77 | 2.4: Partition 78 | 79 | Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. If x is contained within the list, the values of x only need to be after the elements less than x (see below). The partition element x can appear anywhere in the "right partition"; it does not to appear between the left and right partitions. 80 | 81 | Input: 3 -> 5 -> 8 -> 5 -> 10 -> 2 -> 1 [partition = 5] 82 | Output: 3 -> 1 -> 2 -> 10 -> 5 -> 5 -> 8 83 | */ 84 | func _test_2_4_Partition() {} 85 | 86 | /** 87 | 2.5: Sum Lists 88 | 89 | You have two numbers represented by a linked list, where each node contains a single digit. The digits are stored in reverse order, such that the 1's digit is at the head of the list. Write a function that adds the two numbers and returns the sum as a linked list. 90 | 91 | 92 | Input: (7 -> 1 -> 6) + (5 -> 9 -> 2). That is, 617 + 295 93 | Output: 2 -> 1 -> 9. That is, 912. 94 | 95 | **Follow up**: Suppose the digits are store in forward order. Repeat the above problem. 96 | Input: (6 -> 1 -> 7) + (2 -> 9 -> 5). That is, 617 + 295 97 | Output: 9 -> 1 -> 2. That is, 912. 98 | */ 99 | func test_2_5_SumLists() { 100 | XCTAssertEqual(sumList([7, 1, 6], [5, 9 ,2]), [2, 1, 9]) 101 | XCTAssertEqual(sumList([9, 9, 9], [1]), [0, 0, 0, 1]) 102 | 103 | XCTAssertEqual(sumListReverse([6, 1, 7], [2, 9, 5]), [9, 1, 2]) 104 | XCTAssertEqual(sumListReverse([9, 9, 9], [1]), [1, 0, 0, 0]) 105 | } 106 | 107 | /** 108 | 2.6: Palindrome 109 | 110 | Implement a function to check if a linked list is a palindrome. 111 | */ 112 | func test_2_6_Palindrome() { 113 | XCTAssert(isPalindrome(LinkedList())) 114 | XCTAssert(isPalindrome([1])) 115 | 116 | XCTAssert(isPalindrome([1, 1])) 117 | XCTAssert(isPalindrome(["K","A","S","U","R","E","B","E","R","U","S","A","K"])) 118 | 119 | XCTAssertFalse(isPalindrome([1,2,3])) 120 | XCTAssertFalse(isPalindrome(["H", "E", "L", "L", "O"])) 121 | } 122 | 123 | /** 124 | 2.7: Intersection 125 | 126 | Given two (singly) linked lists, determine if the two lists intersect. Return the intersecting node. Note that the intersection is definced based on reference, not value. That is, if the `kth` node of the first linked list is the exact same node (by reference) as the `jth` node of the second linked list, then they are intersecting. 127 | */ 128 | func test_2_7_Intersection() { 129 | let list1: LinkedList = [1, 4, 5, 3] 130 | let list2: LinkedList = [7, 2, 8, 6] 131 | XCTAssertNil(listIntersection(list1, list2)) 132 | 133 | let shared: LinkedList = [9, 10, 11] 134 | let nine = shared.head 135 | list1.append(node: nine) 136 | list2.append(node: nine) 137 | XCTAssert(listIntersection(list1, list2) === nine) 138 | } 139 | 140 | /** 141 | 2.8: Loop Detection 142 | 143 | Given a circular linked list, implement an algoroightm that returns the node at the beginning of the loop. 144 | 145 | DEFINITION, Circular linked list: A (corrupt) linked list in which a node's next pointer points to an earlier node, so as to make a loop in the linked list. 146 | 147 | Input: A -> B -> C -> D -> E 148 | Output: C 149 | */ 150 | func test_2_8_LoopDetection() { 151 | let emptyList: LinkedList = [] 152 | XCTAssertFalse(detectLoop(emptyList)) 153 | 154 | let list: LinkedList = [1, 4, 5, 3] 155 | XCTAssertFalse(detectLoop(list)) 156 | 157 | let cyclic: LinkedList = [7, 2, 8, 6] 158 | let seven = cyclic.head! 159 | cyclic.append(node: seven) 160 | XCTAssert(detectLoop(cyclic)) 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /Tests/CrackingTests/ModerateTests.swift: -------------------------------------------------------------------------------- 1 | import ModerateQuestions 2 | import XCTest 3 | 4 | class ModerateTests: XCTestCase { 5 | 6 | /** 7 | 16.1: Number Swapper 8 | 9 | Wite a function to swap a number in place (that is, without temporary variable). 10 | */ 11 | func test_16_1_NumberSwap() { 12 | var a = 1 13 | var b = 5 14 | numberSwap(&a, &b) 15 | XCTAssertEqual(a, 5) 16 | XCTAssertEqual(b, 1) 17 | 18 | a = -3 19 | b = -10 20 | numberSwap(&a, &b) 21 | XCTAssertEqual(a, -10) 22 | XCTAssertEqual(b, -3) 23 | } 24 | 25 | /** 26 | 16.2: Word Frequencies 27 | 28 | Design a method to find the frequency of occurrences of any given word in a book. What if we were running this algorithm multiple times? 29 | */ 30 | func test_16_2_WordFrequencies() { 31 | let book = """ 32 | Lorem ipsum dolor sit amet, etiam et consectetuer et, ipsum consequat mauris sed parturient, in nec nibh velit adipiscing penatibus sed, integer faucibus bibendum turpis ut proin, mauris nulla elit dui ultrices justo. Ultricies sed vitae vel. Amet tempus consectetuer nam fusce mattis, duis ligula fusce accusamus curabitur semper fusce, sodales ultrices vehicula natoque nisl quis, nec magna urna dis sit, volutpat suspendisse venenatis mi amet eu vehicula. Id nunc, morbi ratione a sit, placerat sollicitudin nunc, ut mi vehicula in eu blandit vitae. Id mollis felis ipsum nulla, magna maecenas sagittis vestibulum, eu in donec justo, est amet volutpat quisque suspendisse, nec luctus integer libero vitae lorem molestie. Pellentesque turpis assumenda ut ipsum nullam ut, habitant imperdiet tincidunt nisl. Dolor ac, arcu cupiditate id ultrices sociis velit in. Risus pharetra eleifend. Dictum enim tortor in vestibulum, donec libero. 33 | """.components(separatedBy: [" ", ".", ","]) 34 | XCTAssertEqual(wordFreq("in", from: book), 5) 35 | XCTAssertEqual(wordFreq("ipsum", from: book), 4) 36 | XCTAssertEqual(wordFreq("lorem", from: book), 2) 37 | } 38 | 39 | /** 40 | 16.5: Factorial Zeros 41 | 42 | Write an algorithm which computes the number of trailing zeros in n factorial 43 | */ 44 | func test_16_3_CountZeroFactorial() { 45 | XCTAssertEqual(countZeroFactorial(1), 0) 46 | XCTAssertEqual(countZeroFactorial(6), 1) 47 | XCTAssertEqual(countZeroFactorial(28), 6) 48 | XCTAssertEqual(countZeroFactorial(129), 31) 49 | } 50 | 51 | /** 52 | 16.6: Smallest Difference 53 | 54 | Given two arrays of integers, compute the pair of values (one value in each array) with the smallest (non-negative) difference. Return the difference. 55 | */ 56 | func test_16_4_FindMinDiff() { 57 | XCTAssertNil(minDiff([], [])) 58 | XCTAssertEqual(minDiff([1, 3, 15, 11, 2], [23, 127, 235, 19, 8]), 3) 59 | XCTAssertEqual(minDiff([1, 3, 15, 11], [23, 235, 15, 19, 8]), 0) 60 | } 61 | 62 | /** 63 | 16.8: English Int 64 | 65 | Given any integer, print an English phrase that describes the integer 66 | */ 67 | func test_16_8_EnglishInt() { 68 | XCTAssertEqual(english(for: 0), "Zero") 69 | XCTAssertEqual(english(for: 12), "Twelve") 70 | XCTAssertEqual(english(for: 1_234), "One Thousand, Two Hundred Thirty Four") 71 | XCTAssertEqual(english(for: 14_101_023), "Fourteen Million, One Hundred One Thousand, Twenty Three") 72 | } 73 | 74 | /** 75 | 16.11: Diving Board 76 | 77 | You are building a diving board by placing a bunch of planks of weed end-to-end. There are two types of planks, one of length `shorter` and one of length `longer`. You must use exactly K planks of wood. Write a method to generate all possible lengths for the diving board. 78 | */ 79 | func test_16_11_DivingBoard() { 80 | XCTAssertEqual(allLengthsForBoard(length1: 3, length2: 5, k: 1), [3, 5]) 81 | XCTAssertEqual(allLengthsForBoard(length1: 3, length2: 5, k: 3), [9, 11, 13, 15]) 82 | } 83 | 84 | /** 85 | 16.12: XML Encoding 86 | 87 | Since XML is very verbose, you are given a way of encoding it where each tag gets mapped to a pre-defined integer value. The language/grammar is as follows: 88 | 89 | Element --> Tag Attributes END Children END 90 | Attribute --> Tag Value 91 | END --> 0 92 | Tag --> some predefined mapping to int 93 | Value --> string value 94 | 95 | For example, the following XML might be converted into the compressed string below (assuming a mapping of 96 | - family -> 1 97 | - person -> 2 98 | - firstName -> 3 99 | - lastName -> 4 100 | - state -> 5 101 | 102 | Write code to print the encoded version of an XML element (passed in Element and Attribute objects). 103 | */ 104 | func test_16_13_XMLEncoding() { 105 | let xml = """ 106 | 107 | Some Message 108 | 109 | """ 110 | XCTAssertEqual(encode(xml: xml), "1 4 McDowell 5 CA 0 2 3 Gayle 0 Some Message 0 0") 111 | } 112 | 113 | /** 114 | 16.15: Master Mind 115 | 116 | The Game of Master Mind is played as follows: 117 | 118 | The computer has four slots, and each slot will contain a ball that is red (R), yellow (Y), green (G) or blue (B). For example, the computer might have RGGB (Slot #1 is red, Slots #2 and #3 are green, Slot #4 is blue). 119 | 120 | When you guess the correct color for the correct slot, you get a "hit". If you guess a color taht exists but is in the wrong slot, you get a "pseudo-hit". Note that a slot that is a hit can never count as a pseudo-hit. 121 | 122 | For example, if the actual solution is RGBY and you guess GGRR, you have one hit and one pseudo-hit. 123 | 124 | Write a method that, given a guess and a solution, retruns the number of hits and pseudo-hits. 125 | */ 126 | func test_16_15_MasterMind() { 127 | // tuple of (hit, pseudo-hit) 128 | XCTAssert(masterMind(solution: "RGBY", guess: "RGBY") == (4, 0)) 129 | XCTAssert(masterMind(solution: "RGBY", guess: "GBYR") == (0, 4)) 130 | XCTAssert(masterMind(solution: "RGBB", guess: "YYYY") == (0, 0)) 131 | XCTAssert(masterMind(solution: "RGBY", guess: "GGRR") == (1, 1)) 132 | XCTAssert(masterMind(solution: "RGGB", guess: "YRGB") == (2, 1)) 133 | } 134 | 135 | /** 136 | 16.17: Contiguous Sequence 137 | 138 | You are given an array of integers (both positive and negative). Find the contiguous sequence with the largest sum. Return the sum. 139 | */ 140 | func test_16_17_ContiguousSequence() { 141 | XCTAssertEqual(largestSum([8]), 8) 142 | XCTAssertEqual(largestSum([2, -8, 3, -2, 4, -10]), 5) 143 | XCTAssertEqual(largestSum([-2, 3, 2, -1]), 5) 144 | } 145 | 146 | /** 147 | 16.19: Pond Sizes 148 | 149 | You have an integer matrix representing a plot of land, where the value at that location represents the height above sea level. A value of zero indicates water. A pond is a region of water connected vertically, horizontally, or diagonally. The size of the pond is the total number of connected water cells. Write a method to compute the sizes of all ponds in the matrix. 150 | */ 151 | func test_16_19_PondSize() { 152 | var pond = [ 153 | [0, 2, 1, 0], 154 | [0, 1, 0, 1], 155 | [1, 1, 0, 1], 156 | [0, 1, 0, 1] 157 | ] 158 | XCTAssertEqual(getPondSizes(&pond), [1, 2, 4]) 159 | 160 | var emptyPond: [[Int]] = [] 161 | XCTAssertEqual(getPondSizes(&emptyPond), []) 162 | 163 | var pond1 = [[0]] 164 | XCTAssertEqual(getPondSizes(&pond1), [1]) 165 | 166 | var pond2 = [[1]] 167 | XCTAssertEqual(getPondSizes(&pond2), []) 168 | } 169 | 170 | /** 171 | 16.21: Sum Swap 172 | 173 | Given two arrays of integers, find a pair of values (one value from each array) that you can swap to give the two arrays the same sum. 174 | */ 175 | func test_16_21_SumSwap() { 176 | XCTAssertNil(sumSwap([], [])) 177 | XCTAssertNil(sumSwap([4, 2], [3, 2])) 178 | 179 | let res = sumSwap([4, 1, 2, 1, 1, 2], [3, 6, 3, 3])! 180 | XCTAssert(res == (1, 3) || res == (4, 6)) 181 | 182 | let res2 = sumSwap([3, 6, 3, 3], [4, 1, 2, 1, 1, 2])! 183 | XCTAssert(res2 == (3, 1) || res2 == (6, 4)) 184 | } 185 | 186 | /** 187 | 16.22: Langton's Ant: 188 | 189 | An ant is sitting on an infinite grid of white and black squares. Initially, the grid is all white and the ant faces right. At each step, it does the following: 190 | 191 | 1) At a white square, flip the color of the square, turn 90 degrees right (clockwise), and move forward one unit. 192 | 193 | 2) At a black square, flip the color of the square, turn 90 degrees left (counter-clockwise), and move forward one unit. 194 | 195 | Write a program to simulate the first K moves that the ant makes and print the final board as a grid. Note that you are not provided with thte data structure to represent the grid. This is something you must design yourself. The only input to your method is K. You should print the final grid and return nothing. The method signature might be something like printAnt(moves: Int) -> String. 196 | */ 197 | func test_16_22_LangtonsAnt() { 198 | XCTAssertEqual(printAnt(moves: 1), """ 199 | 1 200 | 0 201 | """ 202 | ) 203 | 204 | XCTAssertEqual(printAnt(moves: 6), """ 205 | 010 206 | 100 207 | 110 208 | """ 209 | ) 210 | 211 | XCTAssertEqual(printAnt(moves: 48), """ 212 | 001100 213 | 010010 214 | 100001 215 | 100001 216 | 011110 217 | """ 218 | ) 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /Tests/CrackingTests/RecursionAndDynamicProgrammingTests.swift: -------------------------------------------------------------------------------- 1 | import RecursionAndDynamicProgrammingQuestions 2 | import XCTest 3 | 4 | class RecursionAndDynamicProgrammingTests: XCTestCase { 5 | 6 | /** 7 | 8.1: Insertion 8 | 9 | A child is running up a staircase with n steps and can hop either 1 step, 2 steps, or 3 steps at a a time. Implement a method to count how many possible ways the child can run up the stairs. 10 | */ 11 | func test_8_1_TripleSteps() { 12 | XCTAssertEqual(possibleWaysToStep(n: 1), 1) 13 | XCTAssertEqual(possibleWaysToStep(n: 2), 2) 14 | XCTAssertEqual(possibleWaysToStep(n: 3), 4) 15 | 16 | XCTAssertEqual(possibleWaysToStep(n: 50), 10562230626642) 17 | } 18 | 19 | /** 20 | 8.2: Robot Grid 21 | 22 | Imagine a robot sitting on the upper left corner of grid r rows and c columns. The robot can only move in two directions, right and down, but certain cells are "off limits" such that the robot cannot step on them. Design an algorithm to find a path for the robot from the top left to the bottom right. 23 | */ 24 | func test_8_2_RobotInAGrid() { 25 | XCTAssertEqual(getPath(grid: [ 26 | [0, 0, 1], 27 | [1, 0, 0], 28 | [1, 1, 0], 29 | ]), 30 | [ 31 | Point(0,0), Point(0,1), Point(1,1), Point(1,2), Point(2,2) 32 | ]) 33 | 34 | XCTAssertEqual(getPath(grid: [ 35 | [0, 0, 1, 0], 36 | [0, 0, 1, 0], 37 | [1, 0, 0, 0], 38 | [1, 1, 0, 0], 39 | ]), 40 | [ 41 | Point(0,0), Point(0,1), Point(1,1), Point(2,1), Point(2,2), Point(2,3), Point(3,3) 42 | ]) 43 | } 44 | 45 | /** 46 | 8.4: Power Set 47 | 48 | Write a method to return all subsets of a set 49 | */ 50 | func test_8_4_PowerSet() { 51 | let result = allSubset(["b", "e", "c", "a"]) 52 | XCTAssertEqual(result.count, 16) 53 | } 54 | 55 | /** 56 | 8.5: Recursive Multiply 57 | 58 | Write a recursive function to multiply two positive integers without using the * operator. You can use addition, subtraction, and bit shifting, but you should minimize the number of those operations. 59 | */ 60 | func test_8_5_RecursiveMultiply() { 61 | XCTAssertEqual(recursiveMultiply(124, 31), 3844) 62 | XCTAssertEqual(recursiveMultiply2(124, 31), 3844) 63 | } 64 | 65 | /** 66 | 8.9: Parens 67 | 68 | Implement an alforithm to rpint all valid (e.g., properly opened and closed) combinations of n pairs of parentheses 69 | 70 | EXAMPLE 71 | 72 | Input: 3 73 | 74 | Output: ((())), (()()), (())(), ()(()), ()()() 75 | */ 76 | func test_8_9_Parens() { 77 | XCTAssertEqual(generateParentheses(3), ["((()))", "(()())", "(())()", "()(())", "()()()"]) 78 | XCTAssertEqual(generateParentheses(4), [ 79 | "((()))()", "(()())()", "((()()))", "(()()())", "(()(()))", "()()(())", "()()()()", 80 | "()((()))", "()(()())", "()(())()", "(((())))", "((())())", "(())()()" 81 | ]) 82 | } 83 | 84 | /** 85 | 8.11: Coins 86 | 87 | Given an infinite number of quarters (25 cents), dimes (10 cents), nickels (5 cents), and pennies (1 cent), write code to calculate the number of ways for representing n cents. 88 | */ 89 | func test_8_11_Coins() { 90 | XCTAssertEqual(countWaysForChange(10), 4) 91 | XCTAssertEqual(countWaysForChange(26), 13) 92 | XCTAssertEqual(countWaysForChange(100), 242) 93 | XCTAssertEqual(countWaysForChange(10000), 134235101) 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /Tests/CrackingTests/SortingAndSearchingTests.swift: -------------------------------------------------------------------------------- 1 | import SortingAndSearchingQuestions 2 | import XCTest 3 | 4 | class SortingAndSearchingTests: XCTestCase { 5 | 6 | /** 7 | 10.1: Sorted Merge 8 | 9 | Youare given two sorted arrays, A and B, where A has a lage enough buffer at the end to hold B. Write a method to merge into A in sorted order. 10 | */ 11 | func test_10_1_SortedMerge() { 12 | let b = [3, 5, 8, 10] 13 | var a = [12, 12, 13] + [Int](repeating: -99, count: b.count) 14 | 15 | mergeSortedArray(&a, 3, b) 16 | XCTAssertEqual(a, [3, 5, 8, 10, 12, 12, 13]) 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Tests/CrackingTests/StacksAndQueueTests.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | import StacksAndQueuesQuestions 3 | import XCTest 4 | 5 | class StacksAndQueuesTests: XCTestCase { 6 | 7 | /** 8 | 3.1: Three in One 9 | 10 | Describe how you could use a single array to implement three stacks 11 | */ 12 | func _test_3_1_ThreeInOne() {} 13 | 14 | /** 15 | 3.2: Stack Min 16 | 17 | How would you design a stack which, in addition to `push` and `pop`, has a function `min` which returns the minimum element? `Push`, `pop` and `min` should all operate in O(1) time 18 | */ 19 | func test_3_2_StackMin() { 20 | let subject = MinStack() 21 | XCTAssertNil(subject.min()) 22 | 23 | subject.push(3) 24 | XCTAssertEqual(subject.min(), 3) 25 | 26 | subject.push(5) 27 | XCTAssertEqual(subject.min(), 3) 28 | 29 | subject.push(10) 30 | XCTAssertEqual(subject.min(), 3) 31 | 32 | subject.push(1) 33 | XCTAssertEqual(subject.min(), 1) 34 | 35 | subject.push(9) 36 | subject.push(1) 37 | XCTAssertEqual(subject.min(), 1) 38 | 39 | XCTAssertEqual(subject.pop(), 1) 40 | XCTAssertEqual(subject.min(), 1) 41 | 42 | XCTAssertEqual(subject.pop(), 9) 43 | XCTAssertEqual(subject.min(), 1) 44 | 45 | XCTAssertEqual(subject.pop(), 1) 46 | XCTAssertEqual(subject.min(), 3) 47 | 48 | XCTAssertEqual(subject.pop(), 10) 49 | XCTAssertEqual(subject.pop(), 5) 50 | XCTAssertEqual(subject.pop(), 3) 51 | 52 | XCTAssertNil(subject.pop()) 53 | XCTAssertNil(subject.min()) 54 | } 55 | 56 | /** 57 | 3.3: Stack of Plates: Imagine a (literal) stack of plates. If the stack gets too high, it might topple. Therefore, in real life, we would likely start a new stack when the previous stack exceeds some threshold. Implement a data structure `SetOfStacks` that mimics this. `SetOfStacks` should be composed of several stacks and should create a new stack once the previous one exceeds capacity. `SetOfStacks.push()` and `SetOfStacks.pop()` should behave identically to a single stack (that is, `pop()` should return the same values as it would if there were just a single stack). 58 | 59 | **FOLLOW UP**: Implement a function `popAt(int index)` which performs a pop operation on a specific sub-stack. 60 | */ 61 | func _test_3_3_StackOfPlates() {} 62 | 63 | /** 64 | 3.4: Queue via Stacks 65 | 66 | Implement a MyQueue class which implements a queue using two stacks 67 | */ 68 | func test_3_4_QueueViaStacks() { 69 | let subject = MyQueue() 70 | 71 | subject.enqueue(1) 72 | subject.enqueue(2) 73 | subject.enqueue(3) 74 | 75 | XCTAssertEqual(subject.peek(), 1) 76 | XCTAssertEqual(subject.dequeue(), 1) 77 | XCTAssertEqual(subject.peek(), 2) 78 | 79 | subject.enqueue(4) 80 | subject.enqueue(5) 81 | 82 | XCTAssertEqual(subject.dequeue(), 2) 83 | XCTAssertEqual(subject.dequeue(), 3) 84 | XCTAssertEqual(subject.dequeue(), 4) 85 | XCTAssertEqual(subject.peek(), 5) 86 | XCTAssertEqual(subject.dequeue(), 5) 87 | 88 | XCTAssertNil(subject.peek()) 89 | XCTAssert(subject.isEmpty) 90 | } 91 | 92 | /** 93 | 3.5: Sort Stack 94 | 95 | Write a program to sort a stack such that the smallest items are on the top. You can use an additional temporary stack, but you may not copy the elements into any other data structure (such as an array). The stack supports the following operations: `push`, `pop`, `peek`, and `isEmpty`. 96 | */ 97 | func test_3_5_SortStack() { 98 | let stack = Stack() 99 | stack.push(8) 100 | stack.push(5) 101 | stack.push(3) 102 | stack.push(10) 103 | stack.push(1) 104 | stack.push(5) 105 | 106 | let subject = sortStack(stack) 107 | 108 | XCTAssertEqual(subject.pop(), 1) 109 | XCTAssertEqual(subject.pop(), 3) 110 | XCTAssertEqual(subject.pop(), 5) 111 | XCTAssertEqual(subject.pop(), 5) 112 | XCTAssertEqual(subject.pop(), 8) 113 | XCTAssertEqual(subject.pop(), 10) 114 | XCTAssertNil(subject.peek()) 115 | } 116 | 117 | /** 118 | 3.6: Animal Shelter 119 | 120 | An animal shelter, which holds only dogs and cats, operates on a stricly "first in, first out" basis. People must adopt either the "oldest" (based on arrival time) of all animals at the shelter, or they can select whether they would prefer a dog or a cat (and will receive the oldest animal of that type). They cannot select which specific animal they would like. Create the data structures to maintain this system and impelement operations such as `enqueue`, `dequeueuAny`, `dequeueDog`, and `dequeueCat`. You may use the built-in LInkedList data structure. 121 | */ 122 | func _test_3_6_AnimalShelter() {} 123 | } 124 | -------------------------------------------------------------------------------- /Tests/CrackingTests/TreesAndGraphsTests.swift: -------------------------------------------------------------------------------- 1 | import TreesAndGraphsQuestions 2 | import DataStructure 3 | import XCTest 4 | 5 | class TreesAndGraphsTests: XCTestCase { 6 | 7 | /** 8 | 4.1: Route Between Nodes 9 | 10 | Given a directed graph, design an algorithm to find out whether there is a route between two nodes. 11 | */ 12 | func test_4_1_RouteBetweenNodes() { 13 | let nodes = ["a","b","c","d","e","f"] 14 | let dependencies = [("a","d"), ("f","b"), ("b","d"), ("f","a"), ("d","c") ] 15 | let graph = Graph(vertices: nodes, edges: dependencies) 16 | 17 | let f = graph.getVertex("f")! 18 | let e = graph.getVertex("e")! 19 | let c = graph.getVertex("c")! 20 | 21 | graph.reset() 22 | XCTAssertFalse(isDfsRouted(from: f, to: e, in: graph)) 23 | 24 | graph.reset() 25 | XCTAssert(isDfsRouted(from: f, to: c, in: graph)) 26 | 27 | graph.reset() 28 | XCTAssertFalse(isBfsRouted(from: f, to: e, in: graph)) 29 | 30 | graph.reset() 31 | XCTAssert(isBfsRouted(from: f, to: c, in: graph)) 32 | } 33 | 34 | /** 35 | 4.2: Minimal Tree 36 | 37 | Given a sorted (increasing order) array with unique integer elements, write an algorithm to create a binary search tree with minimal height. 38 | */ 39 | func test_4_2_MinimalTree() { 40 | let list = [1, 3, 5, 6, 9, 13, 16, 20] 41 | 42 | let one = BinaryTree.node(.empty, 1, .empty) 43 | let three = BinaryTree.node(one, 3, .empty) 44 | let six = BinaryTree.node(.empty, 6, .empty) 45 | let thirteen = BinaryTree.node(.empty, 13, .empty) 46 | let twenty = BinaryTree.node(.empty, 20, .empty) 47 | let five = BinaryTree.node(three, 5, six) 48 | let sixteen = BinaryTree.node(thirteen, 16, twenty) 49 | let expectedTree = BinaryTree.node(five, 9, sixteen) 50 | 51 | XCTAssertEqual(minimalTree(list), expectedTree) 52 | } 53 | 54 | 55 | /** 56 | 4.3: List of Depth 57 | 58 | Given a binary tree, design an algorithm which creates a linked list of all the nodes at each depth (e.g. if you have a tree with depth D, you'll have D linked lists). 59 | */ 60 | func test_4_3_ListOfDepth() { 61 | let tree = minimalTree([1, 3, 5, 6, 9, 13, 16, 20]) 62 | 63 | let subject = listOfDepth(tree) 64 | XCTAssertEqual(subject, [ 65 | [9], 66 | [5, 16], 67 | [3, 6, 13, 20], 68 | [1], 69 | ]) 70 | } 71 | 72 | /** 73 | 4.5: Validate BST 74 | 75 | Implement a function to check if a binary tree is a binary search tree 76 | */ 77 | func test_4_5_ValidateBST() { 78 | XCTAssertFalse(validateBST(tree: BinaryTree.empty)) 79 | XCTAssert(validateBST(tree: BinaryTree.node(.empty, 1, .empty))) 80 | 81 | let subject1 = minimalTree([1, 3, 5, 6, 9, 13, 16, 20]) 82 | XCTAssert(validateBST(tree: subject1)) 83 | 84 | let one = BinaryTree.node(.empty, 1, .empty) 85 | let minus = BinaryTree.node(one, -2, .empty) 86 | let six = BinaryTree.node(.empty, 6, .empty) 87 | let thirteen = BinaryTree.node(.empty, 13, .empty) 88 | let twenty = BinaryTree.node(.empty, 20, .empty) 89 | let five = BinaryTree.node(minus, 5, six) 90 | let sixteen = BinaryTree.node(thirteen, 16, twenty) 91 | let subject2 = BinaryTree.node(five, 9, sixteen) 92 | XCTAssertFalse(validateBST(tree: subject2)) 93 | } 94 | 95 | /** 96 | 4.7: Build Order 97 | 98 | You are given a list of projects and a list of dependencies (which is a list of pairs of projects, where the second project is dependent on the first project). All of a project's dependencies must be built before the project is. Find a build order that will allow the projects to be built. If there is no valid build order, return an error. 99 | 100 | Input: 101 | `projects: a, b, c, d, e, f` 102 | `dependencies: (a,d), (f,b), (b,d), (f,a), (d,c)` 103 | Output: `f, e, a, b, d, c` 104 | */ 105 | func test_4_7_BuildOrder() { 106 | let projects = ["a","b","c","d","e","f"] 107 | let dependencies = [("a","d"), ("f","b"), ("b","d"), ("f","a"), ("d","c") ] 108 | let graph = Graph(vertices: projects, edges: dependencies) 109 | 110 | graph.reset() 111 | assertOrderSorted(order(graph), in: graph) 112 | 113 | graph.reset() 114 | assertOrderSorted(order2(graph), in: graph) 115 | } 116 | 117 | /** 118 | 4.8: First Common Ancestor 119 | 120 | Design an algorithm and write code to find the first common ancestor of two nodes in a binary tree. Avoid storing additional nodes in a data structure. NOTE: This is not necessarily a binary search tree. 121 | */ 122 | func test_4_8_FirstCommonAncestor() { 123 | let three = BinaryTree.node(.empty, 3, .empty) 124 | let seven = BinaryTree.node(.empty, 7, .empty) 125 | let five = BinaryTree.node(three, 5, seven) 126 | 127 | let seventeen = BinaryTree.node(.empty, 17, .empty) 128 | let fifteen = BinaryTree.node(.empty, 15, seventeen) 129 | let ten = BinaryTree.node(five, 10, fifteen) 130 | 131 | let thirty = BinaryTree.node(.empty, 30, .empty) 132 | let tree = BinaryTree.node(ten, 20, thirty) 133 | 134 | XCTAssertEqual(commonAncestor(root: tree, p: seventeen, q: seven), ten) 135 | XCTAssertEqual(commonAncestor(root: tree, p: ten, q: seventeen), ten) 136 | XCTAssertEqual(commonAncestor(root: tree, p: ten, q: ten), ten) 137 | 138 | let hundred = BinaryTree.node(.empty, 100, .empty) 139 | XCTAssertNil(commonAncestor(root: tree, p: seven, q: hundred)) 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /Tests/CrackingTests/XCTestCase+CustomAssertion.swift: -------------------------------------------------------------------------------- 1 | import DataStructure 2 | import XCTest 3 | 4 | extension XCTestCase { 5 | func assertOrderSorted(_ order: [T], in graph: Graph, file: StaticString = #file, line: UInt = #line) { 6 | guard !graph.vertices.isEmpty && !order.isEmpty else { return XCTFail("graph/order is empty", file: file, line: line) } 7 | 8 | for (index, vertex) in order.enumerated() { 9 | for p in graph.getEdges(vertex) { 10 | let depIndex = order.index(where: { $0.description == p.description })! 11 | if depIndex <= index { XCTFail("dependents precedes parent node", file: file, line: line) } 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | // Generated using Sourcery 0.10.0 — https://github.com/krzysztofzablocki/Sourcery 2 | // DO NOT EDIT 3 | 4 | import XCTest 5 | @testable import CrackingTests 6 | 7 | extension ArrayAndStringTests { 8 | static var allTests: [(String, (ArrayAndStringTests) -> () throws -> Void)] = [ 9 | ("test_1_1_AllUnique", test_1_1_AllUnique), 10 | ("test_1_2_CheckPermutation", test_1_2_CheckPermutation), 11 | ("test_1_3_Urlify", test_1_3_Urlify), 12 | ("test_1_4_PalindromPermutation", test_1_4_PalindromPermutation), 13 | ("test_1_5_OneAway", test_1_5_OneAway), 14 | ("test_1_6_StringCompression", test_1_6_StringCompression), 15 | ("test_1_7_RotateMatrix", test_1_7_RotateMatrix), 16 | ("test_1_8_ZeroMatrix", test_1_8_ZeroMatrix), 17 | ("test_1_9_StringRotation", test_1_9_StringRotation) 18 | ] 19 | } 20 | extension BitManipulationTests { 21 | static var allTests: [(String, (BitManipulationTests) -> () throws -> Void)] = [ 22 | ("test_5_1_Insertion", test_5_1_Insertion), 23 | ("test_5_6_Conversion", test_5_6_Conversion) 24 | ] 25 | } 26 | extension HardQuestions { 27 | static var allTests: [(String, (HardQuestions) -> () throws -> Void)] = [ 28 | ("test_17_7_BabyNames", test_17_7_BabyNames), 29 | ("test_17_21_VolumeOfHistogram", test_17_21_VolumeOfHistogram) 30 | ] 31 | } 32 | extension LinkedListsTests { 33 | static var allTests: [(String, (LinkedListsTests) -> () throws -> Void)] = [ 34 | ("test_2_1_RemoveDups", test_2_1_RemoveDups), 35 | ("test_2_2_ReturnKthToLast", test_2_2_ReturnKthToLast), 36 | ("test_2_5_SumLists", test_2_5_SumLists), 37 | ("test_2_6_Palindrome", test_2_6_Palindrome), 38 | ("test_2_7_Intersection", test_2_7_Intersection), 39 | ("test_2_8_LoopDetection", test_2_8_LoopDetection) 40 | ] 41 | } 42 | extension ModerateTests { 43 | static var allTests: [(String, (ModerateTests) -> () throws -> Void)] = [ 44 | ("test_16_1_NumberSwap", test_16_1_NumberSwap), 45 | ("test_16_2_WordFrequencies", test_16_2_WordFrequencies), 46 | ("test_16_3_CountZeroFactorial", test_16_3_CountZeroFactorial), 47 | ("test_16_4_FindMinDiff", test_16_4_FindMinDiff), 48 | ("test_16_8_EnglishInt", test_16_8_EnglishInt), 49 | ("test_16_11_DivingBoard", test_16_11_DivingBoard), 50 | ("test_16_13_XMLEncoding", test_16_13_XMLEncoding), 51 | ("test_16_15_MasterMind", test_16_15_MasterMind), 52 | ("test_16_17_ContiguousSequence", test_16_17_ContiguousSequence), 53 | ("test_16_19_PondSize", test_16_19_PondSize), 54 | ("test_16_21_SumSwap", test_16_21_SumSwap), 55 | ("test_16_22_LangtonsAnt", test_16_22_LangtonsAnt) 56 | ] 57 | } 58 | extension RecursionAndDynamicProgrammingTests { 59 | static var allTests: [(String, (RecursionAndDynamicProgrammingTests) -> () throws -> Void)] = [ 60 | ("test_8_1_TripleSteps", test_8_1_TripleSteps), 61 | ("test_8_2_RobotInAGrid", test_8_2_RobotInAGrid), 62 | ("test_8_4_PowerSet", test_8_4_PowerSet), 63 | ("test_8_5_RecursiveMultiply", test_8_5_RecursiveMultiply), 64 | ("test_8_9_Parens", test_8_9_Parens), 65 | ("test_8_11_Coins", test_8_11_Coins) 66 | ] 67 | } 68 | extension SortingAndSearchingTests { 69 | static var allTests: [(String, (SortingAndSearchingTests) -> () throws -> Void)] = [ 70 | ("test_10_1_SortedMerge", test_10_1_SortedMerge) 71 | ] 72 | } 73 | extension StacksAndQueuesTests { 74 | static var allTests: [(String, (StacksAndQueuesTests) -> () throws -> Void)] = [ 75 | ("test_3_2_StackMin", test_3_2_StackMin), 76 | ("test_3_4_QueueViaStacks", test_3_4_QueueViaStacks), 77 | ("test_3_5_SortStack", test_3_5_SortStack), 78 | ] 79 | } 80 | extension TreesAndGraphsTests { 81 | static var allTests: [(String, (TreesAndGraphsTests) -> () throws -> Void)] = [ 82 | ("test_4_1_RouteBetweenNodes", test_4_1_RouteBetweenNodes), 83 | ("test_4_2_MinimalTree", test_4_2_MinimalTree), 84 | ("test_4_3_ListOfDepth", test_4_3_ListOfDepth), 85 | ("test_4_5_ValidateBST", test_4_5_ValidateBST), 86 | ("test_4_7_BuildOrder", test_4_7_BuildOrder), 87 | ("test_4_8_FirstCommonAncestor", test_4_8_FirstCommonAncestor) 88 | ] 89 | } 90 | 91 | // swiftlint:disable trailing_comma 92 | XCTMain([ 93 | testCase(ArrayAndStringTests.allTests), 94 | testCase(BitManipulationTests.allTests), 95 | testCase(HardQuestions.allTests), 96 | testCase(LinkedListsTests.allTests), 97 | testCase(ModerateTests.allTests), 98 | testCase(RecursionAndDynamicProgrammingTests.allTests), 99 | testCase(SortingAndSearchingTests.allTests), 100 | testCase(StacksAndQueuesTests.allTests), 101 | testCase(TreesAndGraphsTests.allTests), 102 | ]) 103 | // swiftlint:enable trailing_comma 104 | -------------------------------------------------------------------------------- /templates/LinuxMain.stencil: -------------------------------------------------------------------------------- 1 | // sourcery:file:Tests/LinuxMain.swift 2 | import XCTest 3 | @testable import CrackingTests 4 | 5 | {% for type in types.classes|based:"XCTestCase" %} 6 | {% if not type.annotations.disableTests %}extension {{ type.name }} { 7 | static var allTests: [(String, ({{ type.name }}) -> () throws -> Void)] = [ 8 | {% for method in type.methods %}{% if method.parameters.count == 0 and method.shortName|hasPrefix:"test" %} ("{{ method.shortName }}", {{ method.shortName }}){% if not forloop.last %},{% endif %} 9 | {% endif %}{% endfor %}] 10 | } 11 | {% endif %}{% endfor %} 12 | 13 | // swiftlint:disable trailing_comma 14 | XCTMain([ 15 | {% for type in types.classes|based:"XCTestCase" %}{% if not type.annotations.disableTests %} testCase({{ type.name }}.allTests), 16 | {% endif %}{% endfor %}]) 17 | // swiftlint:enable trailing_comma 18 | 19 | // sourcery:end 20 | -------------------------------------------------------------------------------- /templates/Readme.stencil: -------------------------------------------------------------------------------- 1 | // sourcery:file:README.md 2 | # Cracking The Coding Interview 3 | 4 | [![Build Status](https://travis-ci.org/ikhsan/ctci-swift.svg?branch=master)](https://travis-ci.org/ikhsan/ctci-swift) 5 | ![Swift 4](https://img.shields.io/badge/Swift-4.0-orange.svg) 6 | 7 | Solutions of Cracking The Coding Interview written in Swift. 8 | 9 | ## Tests 10 | 11 | Tests are updated by using [Sourcery](https://github.com/krzysztofzablocki/Sourcery). When editing tests (add, remove, disable, enable tests) run `sourcery` from the root folder. You can unzip `sourcery`'s [latest binary](https://github.com/krzysztofzablocki/Sourcery/releases) and put the `bin` directory in the root directory, then run `bin/sourcery` from the root directory. 12 | 13 | Run the test by using SPM's test command: 14 | 15 | ```bash 16 | $ swift test 17 | ``` 18 | 19 | You can also run individual tests by using its number. 20 | 21 | ```bash 22 | $ swift test --filter 2.1 23 | ``` 24 | 25 | ## Solved Problems 26 | 27 | {% for type in types.classes|based:"XCTestCase" %} 28 | {% if not type.annotations.disableTests %}- {{ type.name|replace:"Tests","" }} 29 | {% for method in type.methods %}{% if method.parameters.count == 0 and method.shortName|hasPrefix:"test" %} 30 | - {{ method.shortName|replace:"test_",""|replace:"_","." }} 31 | {% endif %}{% endfor %} 32 | {% endif %}{% endfor %} 33 | 34 | ## License 35 | 36 | MIT 37 | 38 | // sourcery:end 39 | --------------------------------------------------------------------------------