From de449984bb010e3a0921da1a747c6d47ead19757 Mon Sep 17 00:00:00 2001 From: Lanre Adedara Date: Mon, 27 May 2024 09:05:02 +0100 Subject: [PATCH 1/2] Swift implementation for LCOF 41 --- .../README.md" | 38 +++++++++++++++++++ .../Solution.swift" | 33 ++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 "lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" diff --git "a/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" index faf2fdce52817..685db0fb2bd5f 100644 --- "a/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" +++ "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" @@ -412,6 +412,44 @@ public class MedianFinder { */ ``` +#### Swift + +```swift +class MedianFinder { + private var lowerHalf = [Int]() + private var upperHalf = [Int]() + + init() {} + + func addNum(_ num: Int) { + if lowerHalf.count > upperHalf.count { + lowerHalf.append(num) + lowerHalf.sort(by: >) + upperHalf.append(lowerHalf.removeFirst()) + } else { + upperHalf.append(num) + upperHalf.sort() + lowerHalf.append(upperHalf.removeFirst()) + } + } + + func findMedian() -> Double { + if lowerHalf.count > upperHalf.count { + return Double(lowerHalf.first!) + } else { + return (Double(lowerHalf.first!) + Double(upperHalf.first!)) / 2.0 + } + } +} + +/** + * Your MedianFinder object will be instantiated and called as such: + * let obj = MedianFinder(); + * obj.addNum(num); + * let param_2 = obj.findMedian(); + */ +``` + diff --git "a/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" new file mode 100644 index 0000000000000..c0aba33cc7bd5 --- /dev/null +++ "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" @@ -0,0 +1,33 @@ +class MedianFinder { + private var lowerHalf = [Int]() + private var upperHalf = [Int]() + + init() {} + + func addNum(_ num: Int) { + if lowerHalf.count > upperHalf.count { + lowerHalf.append(num) + lowerHalf.sort(by: >) + upperHalf.append(lowerHalf.removeFirst()) + } else { + upperHalf.append(num) + upperHalf.sort() + lowerHalf.append(upperHalf.removeFirst()) + } + } + + func findMedian() -> Double { + if lowerHalf.count > upperHalf.count { + return Double(lowerHalf.first!) + } else { + return (Double(lowerHalf.first!) + Double(upperHalf.first!)) / 2.0 + } + } +} + +/** + * Your MedianFinder object will be instantiated and called as such: + * let obj = MedianFinder(); + * obj.addNum(num); + * let param_2 = obj.findMedian(); + */ \ No newline at end of file From e71ee36478b9afdf7eb41cf2c9624f8b2dffa1a0 Mon Sep 17 00:00:00 2001 From: Lanre Adedara Date: Mon, 27 May 2024 10:12:35 +0100 Subject: [PATCH 2/2] code update --- .../README.md" | 101 ++++++++++++++++-- .../Solution.swift" | 101 ++++++++++++++++-- 2 files changed, 180 insertions(+), 22 deletions(-) diff --git "a/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" index 685db0fb2bd5f..53d8d1703d7d0 100644 --- "a/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" +++ "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/README.md" @@ -416,30 +416,109 @@ public class MedianFinder { ```swift class MedianFinder { - private var lowerHalf = [Int]() - private var upperHalf = [Int]() + private var lowerHalf = Heap(sort: >) + private var upperHalf = Heap(sort: <) init() {} func addNum(_ num: Int) { - if lowerHalf.count > upperHalf.count { - lowerHalf.append(num) - lowerHalf.sort(by: >) - upperHalf.append(lowerHalf.removeFirst()) + if lowerHalf.count == 0 || num <= lowerHalf.peek()! { + lowerHalf.insert(num) } else { - upperHalf.append(num) - upperHalf.sort() - lowerHalf.append(upperHalf.removeFirst()) + upperHalf.insert(num) + } + + if lowerHalf.count > upperHalf.count + 1 { + upperHalf.insert(lowerHalf.remove()!) + } else if upperHalf.count > lowerHalf.count { + lowerHalf.insert(upperHalf.remove()!) } } func findMedian() -> Double { if lowerHalf.count > upperHalf.count { - return Double(lowerHalf.first!) + return Double(lowerHalf.peek()!) + } else { + return (Double(lowerHalf.peek()!) + Double(upperHalf.peek()!)) / 2.0 + } + } +} + +struct Heap { + var elements: [T] + let sort: (T, T) -> Bool + + init(sort: @escaping (T, T) -> Bool) { + self.sort = sort + self.elements = [] + } + + var count: Int { + return elements.count + } + + func peek() -> T? { + return elements.first + } + + mutating func insert(_ value: T) { + elements.append(value) + siftUp(from: elements.count - 1) + } + + mutating func remove() -> T? { + guard !elements.isEmpty else { return nil } + if elements.count == 1 { + return elements.removeLast() } else { - return (Double(lowerHalf.first!) + Double(upperHalf.first!)) / 2.0 + let value = elements[0] + elements[0] = elements.removeLast() + siftDown(from: 0) + return value + } + } + + private mutating func siftUp(from index: Int) { + var child = index + var parent = parentIndex(of: child) + while child > 0 && sort(elements[child], elements[parent]) { + elements.swapAt(child, parent) + child = parent + parent = self.parentIndex(of: child) + } + } + + private mutating func siftDown(from index: Int) { + var parent = index + while true { + let left = leftChildIndex(of: parent) + let right = rightChildIndex(of: parent) + var candidate = parent + if left < elements.count && sort(elements[left], elements[candidate]) { + candidate = left + } + if right < elements.count && sort(elements[right], elements[candidate]) { + candidate = right + } + if candidate == parent { + return + } + elements.swapAt(parent, candidate) + parent = candidate } } + + private func parentIndex(of index: Int) -> Int { + return (index - 1) / 2 + } + + private func leftChildIndex(of index: Int) -> Int { + return 2 * index + 1 + } + + private func rightChildIndex(of index: Int) -> Int { + return 2 * index + 2 + } } /** diff --git "a/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" index c0aba33cc7bd5..20d2c1114cce4 100644 --- "a/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" +++ "b/lcof/\351\235\242\350\257\225\351\242\23041. \346\225\260\346\215\256\346\265\201\344\270\255\347\232\204\344\270\255\344\275\215\346\225\260/Solution.swift" @@ -1,30 +1,109 @@ class MedianFinder { - private var lowerHalf = [Int]() - private var upperHalf = [Int]() + private var lowerHalf = Heap(sort: >) + private var upperHalf = Heap(sort: <) init() {} func addNum(_ num: Int) { - if lowerHalf.count > upperHalf.count { - lowerHalf.append(num) - lowerHalf.sort(by: >) - upperHalf.append(lowerHalf.removeFirst()) + if lowerHalf.count == 0 || num <= lowerHalf.peek()! { + lowerHalf.insert(num) } else { - upperHalf.append(num) - upperHalf.sort() - lowerHalf.append(upperHalf.removeFirst()) + upperHalf.insert(num) + } + + if lowerHalf.count > upperHalf.count + 1 { + upperHalf.insert(lowerHalf.remove()!) + } else if upperHalf.count > lowerHalf.count { + lowerHalf.insert(upperHalf.remove()!) } } func findMedian() -> Double { if lowerHalf.count > upperHalf.count { - return Double(lowerHalf.first!) + return Double(lowerHalf.peek()!) } else { - return (Double(lowerHalf.first!) + Double(upperHalf.first!)) / 2.0 + return (Double(lowerHalf.peek()!) + Double(upperHalf.peek()!)) / 2.0 } } } +struct Heap { + var elements: [T] + let sort: (T, T) -> Bool + + init(sort: @escaping (T, T) -> Bool) { + self.sort = sort + self.elements = [] + } + + var count: Int { + return elements.count + } + + func peek() -> T? { + return elements.first + } + + mutating func insert(_ value: T) { + elements.append(value) + siftUp(from: elements.count - 1) + } + + mutating func remove() -> T? { + guard !elements.isEmpty else { return nil } + if elements.count == 1 { + return elements.removeLast() + } else { + let value = elements[0] + elements[0] = elements.removeLast() + siftDown(from: 0) + return value + } + } + + private mutating func siftUp(from index: Int) { + var child = index + var parent = parentIndex(of: child) + while child > 0 && sort(elements[child], elements[parent]) { + elements.swapAt(child, parent) + child = parent + parent = self.parentIndex(of: child) + } + } + + private mutating func siftDown(from index: Int) { + var parent = index + while true { + let left = leftChildIndex(of: parent) + let right = rightChildIndex(of: parent) + var candidate = parent + if left < elements.count && sort(elements[left], elements[candidate]) { + candidate = left + } + if right < elements.count && sort(elements[right], elements[candidate]) { + candidate = right + } + if candidate == parent { + return + } + elements.swapAt(parent, candidate) + parent = candidate + } + } + + private func parentIndex(of index: Int) -> Int { + return (index - 1) / 2 + } + + private func leftChildIndex(of index: Int) -> Int { + return 2 * index + 1 + } + + private func rightChildIndex(of index: Int) -> Int { + return 2 * index + 2 + } +} + /** * Your MedianFinder object will be instantiated and called as such: * let obj = MedianFinder();