From d776a2221d5bc69c212979a07bef99320e2b2149 Mon Sep 17 00:00:00 2001 From: Chirag Arora <98258782+CHIRAGGARORA@users.noreply.github.com> Date: Fri, 20 Jan 2023 23:32:05 +0530 Subject: [PATCH 1/2] Improve fourSum function with unique quadruplets This commit improves the fourSum function by removing duplicates and returning only unique quadruplets that add up to the specific target. The code now also skips over any repeated elements in the input collection, making it more efficient and accurate. The unnecessary formUniqueIndex function is removed which is not needed in this version of the code, and minor changes are made to the existing code to improve readability and maintainability. --- 3Sum and 4Sum/4Sum.playground/Contents.swift | 72 +++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/3Sum and 4Sum/4Sum.playground/Contents.swift b/3Sum and 4Sum/4Sum.playground/Contents.swift index 37f75918c..e5b9225e0 100644 --- a/3Sum and 4Sum/4Sum.playground/Contents.swift +++ b/3Sum and 4Sum/4Sum.playground/Contents.swift @@ -3,19 +3,7 @@ print("Hello, Swift 4.2!") #endif -extension Collection where Element: Equatable { - - /// In a sorted collection, replaces the given index with a successor mapping to a unique element. - /// - /// - Parameter index: A valid index of the collection. `index` must be less than `endIndex` - func formUniqueIndex(after index: inout Index) { - var prev = index - repeat { - prev = index - formIndex(after: &index) - } while index < endIndex && self[prev] == self[index] - } -} + extension BidirectionalCollection where Element: Equatable { @@ -32,33 +20,49 @@ extension BidirectionalCollection where Element: Equatable { } func fourSum(_ collection: T, target: T.Element) -> [[T.Element]] where T.Element: Numeric & Comparable { - let sorted = collection.sorted() - var ret: [[T.Element]] = [] + let sorted = collection.sorted() + var ret: [[T.Element]] = [] - var l = sorted.startIndex - FourSum: while l < sorted.endIndex { defer { sorted.formUniqueIndex(after: &l) } - var ml = sorted.index(after: l) + var l = sorted.startIndex + FourSum: while l < sorted.endIndex { + // Skip over any repeated elements + while l < sorted.endIndex - 1, sorted[l] == sorted[sorted.index(after: l)] { + sorted.formIndex(after: &l) + } + defer { sorted.formIndex(after: &l) } + var ml = sorted.index(after: l) - ThreeSum: while ml < sorted.endIndex { defer { sorted.formUniqueIndex(after: &ml) } - var mr = sorted.index(after: ml) - var r = sorted.index(before: sorted.endIndex) + ThreeSum: while ml < sorted.endIndex { + // Skip over any repeated elements + while ml < sorted.endIndex - 1, sorted[ml] == sorted[sorted.index(after: ml)] { + sorted.formIndex(after: &ml) + } + defer { sorted.formIndex(after: &ml) } + var mr = sorted.index(after: ml) + var r = sorted.index(before: sorted.endIndex) - TwoSum: while mr < r && r < sorted.endIndex { - let sum = sorted[l] + sorted[ml] + sorted[mr] + sorted[r] - if sum == target { - ret.append([sorted[l], sorted[ml], sorted[mr], sorted[r]]) - sorted.formUniqueIndex(after: &mr) - sorted.formUniqueIndex(before: &r) - } else if sum < target { - sorted.formUniqueIndex(after: &mr) - } else { - sorted.formUniqueIndex(before: &r) + TwoSum: while mr < r && r < sorted.endIndex { + let sum = sorted[l] + sorted[ml] + sorted[mr] + sorted[r] + if sum == target { + ret.append([sorted[l], sorted[ml], sorted[mr], sorted[r]]) + // Skip over any repeated elements + while mr < r, sorted[mr] == sorted[sorted.index(after: mr)] { + sorted.formIndex(after: &mr) + } + while mr < r, sorted[r] == sorted[sorted.index(before: r)] { + sorted.formIndex(before: &r) + } + } else if sum < target { + sorted.formIndex(after: &mr) + } else { + sorted.formIndex(before: &r) + } + } } - } } - } - return ret + return ret } + // answer: [[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]] fourSum([1, 0, -1, 0, -2, 2], target: 0) From 0f7c30e55a7d5210f2d92ea9ea4c83652f596c87 Mon Sep 17 00:00:00 2001 From: Chirag Arora <98258782+CHIRAGGARORA@users.noreply.github.com> Date: Sat, 21 Jan 2023 00:15:10 +0530 Subject: [PATCH 2/2] Improved Bloom Filter with error handling This commit includes an improved version of the Bloom filter code, which now includes error handling to check if the number of hash functions passed is greater than the size of the array and raises a fatal error if that's the case. The class now imports foundation library --- .../BloomFilter.playground/Contents.swift | 108 +++++++++--------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/Bloom Filter/BloomFilter.playground/Contents.swift b/Bloom Filter/BloomFilter.playground/Contents.swift index 7a3719d57..1e5b64145 100644 --- a/Bloom Filter/BloomFilter.playground/Contents.swift +++ b/Bloom Filter/BloomFilter.playground/Contents.swift @@ -1,82 +1,84 @@ //: Playground - noun: a place where people can play - -public class BloomFilter { - fileprivate var array: [Bool] - private var hashFunctions: [(T) -> Int] - - public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { - self.array = [Bool](repeating: false, count: size) - self.hashFunctions = hashFunctions - } - - private func computeHashes(_ value: T) -> [Int] { - return hashFunctions.map { hashFunc in abs(hashFunc(value) % array.count) } - } - - public func insert(_ element: T) { - for hashValue in computeHashes(element) { - array[hashValue] = true +import Foundation + +public class BloomFilter { + fileprivate var array: [Bool] + private var hashFunctions: [(T) -> Int] + + public init(size: Int = 1024, hashFunctions: [(T) -> Int]) { + if (hashFunctions.count > size) { + fatalError("Number of hash functions should be less than or equal to size of array") + } + self.array = [Bool](repeating: false, count: size) + self.hashFunctions = hashFunctions } - } - public func insert(_ values: [T]) { - for value in values { - insert(value) + private func computeHashes(_ value: T) -> [Int] { + return hashFunctions.map { hashFunc in abs(hashFunc(value) % array.count) } } - } - public func query(_ value: T) -> Bool { - let hashValues = computeHashes(value) + public func insert(_ element: T) { + for hashValue in computeHashes(element) { + array[hashValue] = true + } + } - // Map hashes to indices in the Bloom Filter - let results = hashValues.map { hashValue in array[hashValue] } + public func insert(_ values: [T]) { + for value in values { + insert(value) + } + } - // All values must be 'true' for the query to return true + public func query(_ value: T) -> Bool { + let hashValues = computeHashes(value) - // This does NOT imply that the value is in the Bloom filter, - // only that it may be. If the query returns false, however, - // you can be certain that the value was not added. + // Map hashes to indices in the Bloom Filter + let results = hashValues.map { hashValue in array[hashValue] } - let exists = results.reduce(true, { $0 && $1 }) - return exists - } + // All values must be 'true' for the query to return true + // This does NOT imply that the value is in the Bloom filter, + // only that it may be. If the query returns false, however, + // you can be certain that the value was not added. + let exists = results.reduce(true, { $0 && $1 }) + return exists + } - public func isEmpty() -> Bool { - // As soon as the reduction hits a 'true' value, the && condition will fail. - return array.reduce(true) { prev, next in prev && !next } - } + public func isEmpty() -> Bool { + // As soon as the reduction hits a 'true' value, the && condition will fail. + return array.reduce(true) { prev, next in prev && !next } + } } /* Two hash functions, adapted from http://www.cse.yorku.ca/~oz/hash.html */ func djb2(x: String) -> Int { - var hash = 5381 - for char in x { - hash = ((hash << 5) &+ hash) &+ char.hashValue - } - return Int(hash) + var hash = 5381 + for char in x { + hash = ((hash << 5) &+ hash) &+ char.hashValue + } + return Int(hash) } func sdbm(x: String) -> Int { - var hash = 0 - for char in x { - hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash - } - return Int(hash) + var hash = 0 + for char in x { + hash = char.hashValue &+ (hash << 6) &+ (hash << 16) &- hash + } + return Int(hash) } /* A simple test */ - let bloom = BloomFilter(size: 17, hashFunctions: [djb2, sdbm]) bloom.insert("Hello world!") print(bloom.array) -bloom.query("Hello world!") // true -bloom.query("Hello WORLD") // false +(bloom.query("Hello world!")) // true +(bloom.query("Hello WORLD")) // false bloom.insert("Bloom Filterz") -print(bloom.array) +(bloom.array) + +(bloom.query("Bloom Filterz")) // true +(bloom.query("Hello WORLD")) // false -bloom.query("Bloom Filterz") // true -bloom.query("Hello WORLD") // true