Skip to content

Commit

Permalink
Add solutions to Chapter 16 Moderate
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewcarroll authored and Matthew Carroll committed Jul 15, 2019
1 parent 943d639 commit 0dbf24e
Show file tree
Hide file tree
Showing 11 changed files with 875 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Foundation

/*:
16.1 Swap a number without using a temp variable
*/
extension BinaryInteger {

mutating func swap(x: inout Self) {
self += x
x = self - x
self = self - x
}
}

let y = 1
var ycopy = y
let x = -1
var xcopy = x

ycopy.swap(x: &xcopy)
assert(ycopy == x && xcopy == y)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Foundation

/*:
16.20 On old cell phones, users typed on a numeric keypad and the phone would provide a list of words that matched these numbers. Each digit mapped to a set of 0—4 letters. Implement an algorithm to return a list of matching words, given a sequence of digits. You are provided a list of valid words (provided in whatever data strucutre you'd like).
*/

let path = "/usr/share/dict/words"
let url = URL(fileURLWithPath: path, isDirectory: false)
let dictString = try! String(contentsOf: url, encoding: .utf8)
let words = dictString.components(separatedBy: "\n").compactMap { word -> String? in
let nonLetter = word.rangeOfCharacter(from: CharacterSet.letters.inverted) != nil
return nonLetter ? nil : word.lowercased()
}

let digitsToChars: [Character: String] = ["2": "abc", "3": "def", "4": "ghi", "5": "jkl", "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz"]

let charToDigit: [Character: Character] = {
digitsToChars.reduce(into: [Character: Character]()) { map, digitChars in
for char in digitChars.value {
map[char] = digitChars.key
}
}
}()

func digits(from: String) -> String {
return from.reduce(into: "") { digits, chars in
if let char = charToDigit[chars] {
digits.append(char)
}
}
}

let digitsToWords = Dictionary(grouping: words, by: digits)

let swift = digitsToWords["79438"]?[0]
assert(swift == "swift", "\(String(describing: swift))")
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Foundation

/*:
16.5 Count the number of trailing zeros in n factorial
*/

extension Int {

func zerosInFactorial() -> Int {
guard self > 0 else { return 0 }
let range = (1...self)
return range.reduce(0) {
$1 % 5 == 0 ? $0 + 1 : $0
}
}

func factorial() -> Int {
guard self > 0 else { return 1 }
let range = (1...self)
return range.reduce(1, *)
}
}

for i in 1...20 {
let s = String(i.factorial())
let trailingZerosString = s.reversed().prefix(while: { $0 == "0" })
let zerosInFactorial = i.zerosInFactorial()
assert(zerosInFactorial == trailingZerosString.count, "\(i) \(zerosInFactorial) \(trailingZerosString)")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation

/*:
16.6 Return the difference between the two smallest numbers in a and b
*/
extension Collection where Iterator.Element: FixedWidthInteger & SignedNumeric {

func minDifference<C: Collection>(c: C) -> Iterator.Element? where C.Iterator.Element == Iterator.Element {
guard !isEmpty && !c.isEmpty else { return nil }

let leftC = sorted()
let rightC = c.sorted(by: <)
var minDiff = abs(leftC[0] - rightC[0])
var i = leftC.startIndex
var k = rightC.startIndex

while i != leftC.endIndex && k != rightC.endIndex {
let left = leftC[i]
let right = rightC[k]
let absVal = abs(left - right)
if absVal < minDiff {
minDiff = absVal
}
if left <= right {
i += 1
}
else {
k += 1
}
}
return minDiff
}
}

var a = [1,3,15,11,2]
var b = [23,127,235,19,8]

let result = a.minDifference(c: b)
assert(result ?? 0 == 3)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Foundation

/*:
16.9 Implement subtract, multiply, and divide using only +
*/
extension FixedWidthInteger where Stride: SignedInteger {

func restrictedDivide(x: Self) -> Self {
var _self = self.absv
let absX = x.absv
let diff = absX.negate()
var quotient: Self = 0

while _self >= absX {
_self += diff
quotient = quotient.advanced(by: 1)
}
let sameSign = (self < 0 && x < 0) || (self > 0 && x > 0)
return sameSign ? quotient : quotient.negate()
}

func restrictedMultiply(x: Self) -> Self {
let absX: Self = x.absv
var _self: Self = 0
for _ in 0..<absX {
_self += self
}
return x < 0 ? _self.negate() : _self
}

func restrictedSubtract(x: Self) -> Self {
return self + x.negate()
}

func negate() -> Self {
let diff: Self = self > 0 ? -1 : 1
var _self = self
var result: Self = 0
while _self != 0 {
_self += diff
result += diff
}
return result
}

func restrictedSubtract2(x: Self) -> Self {
return self + ~x + 1
}
}

var a = 35
var b = 7

for x in a...2 * a {
assert(x.restrictedDivide(x: b) == x / b)
assert(x.restrictedMultiply(x: b) == x * b)
assert(x.restrictedSubtract(x: b) == x - b)
}



Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
//
// ArraySearching.swift
//
//
// Created by Matthew Carroll on 10/13/16.
// Copyright © 2016 Third Cup lc. All rights reserved.
//

import Foundation

//: Similar to EnumerateGenerator, but returns the index of the element instead of a counter for the enumeration
public extension Collection {

func indicesElements() -> Zip2Sequence<Indices, Self> {
return zip(indices, self)
}
}

extension Zip2Sequence.Iterator: Sequence {

public func makeIterator() -> Zip2Sequence.Iterator {
return self
}
}

public extension Collection {

func indexElementPairs() -> Zip2Sequence<Zip2Sequence<Indices, Self>.Iterator, Zip2Sequence<Indices, Self>.Iterator> {
let left = zip(indices, self).makeIterator()
var right = left
let _ = right.next()
return zip(left, right)
}

func successiveElements() -> Zip2Sequence<Self, Self.SubSequence> {
return zip(self, self.dropFirst())
}
}

public struct ElementPairsIterator<T: Sequence>: IteratorProtocol, Sequence {

var iterator: T.Iterator

init(sequence: T) {
iterator = sequence.makeIterator()
}

mutating public func next() -> (T.Element, T.Element)? {
guard let left = iterator.next(), let right = iterator.next() else { return nil }
return (left, right)
}

public func makeIterator() -> ElementPairsIterator<T> {
return self
}
}


public extension Sequence {

func elementPairs() -> ElementPairsIterator<Self> {
return ElementPairsIterator(sequence: self)
}
}

public extension Collection {

typealias IndexElementPair = (leftIndex: Index, leftElement: Iterator.Element, rightIndex: Index, rightElement: Iterator.Element)

func successiveElements(where predicate: (_ previousElement: Iterator.Element, _ element: Iterator.Element) -> Bool) -> IndexElementPair? {
for (left, right) in indexElementPairs() {
guard predicate(left.1, right.1) else { continue }
return (left.0, left.1, right.0, right.1)
}
return nil
}

func elementPair(where predicate: (_ previousElement: Element, _ element: Element) -> Bool) -> (Element, Element)? {
return elementPairs().first(where: predicate)
}

func elementPair2(where predicate: (_ previousElement: Element, _ element: Element) -> Bool) -> (Element, Element)? {
guard !isEmpty else { return nil }
var i = startIndex
var k = index(after: i)
while k < endIndex {
let left = self[i]
let right = self[k]
guard predicate(left, right) else {
i = k
k = index(after: k)
continue
}
return(left, right)
}
return nil
}
}

public extension Collection {

func unsortedRange(isUnordered: (_ left: Iterator.Element, _ right: Iterator.Element) -> Bool) -> ClosedRange<Index>? {
guard let unsortedStart = successiveElements(where: isUnordered) else { return nil }

var unsortedEnd = unsortedStart.leftIndex
var unsortedMax = unsortedStart.leftElement
let d = distance(from: startIndex, to: unsortedStart.rightIndex)

for (i, x) in indicesElements().dropFirst(numericCast(d)) {
if isUnordered(unsortedMax, x) {
unsortedEnd = i
}
else {
unsortedMax = x
}
}
return unsortedStart.leftIndex...unsortedEnd
}
}

public extension Collection {

func groupBy<Key>(f: (Iterator.Element) -> Key) -> [Key: [Iterator.Element]] {
var groups: [Key: [Iterator.Element]] = [:]
for x in self {
let key = f(x)
var array = groups[key] ?? []
array.append(x)
groups[key] = array
}
return groups
}
}

public extension Collection where Iterator.Element: Comparable, SubSequence: Collection {

func maxElementIndex() -> Index? {
guard !self.isEmpty else { return nil }
var prev = self[startIndex]
var maxI = startIndex
for (i, x) in dropFirst().indicesElements() {
if x > prev {
prev = x
maxI = i
}
}
return maxI
}
}

public extension Collection where Iterator.Element: Comparable, SubSequence: Collection {

func minElementIndex() -> Index? {
guard !self.isEmpty else { return nil }
var prev = self[startIndex]
var minI = startIndex
for (i, x) in dropFirst().indicesElements() {
if x < prev {
prev = x
minI = i
}
}
return minI
}
}
Loading

0 comments on commit 0dbf24e

Please sign in to comment.