Сначала вам нужно создать метод, чтобы найти все возможные подмножества вашей исходной коллекции, как я написал здесь Сумма подмножеств Swift .Тогда вам просто нужно проверить, равна ли любая сумма подмножества n:
extension RangeReplaceableCollection {
var subSets: [SubSequence] {
return isEmpty ? [SubSequence()] : dropFirst().subSets.lazy.flatMap { [$0, prefix(1) + $0] }
}
}
let a = [4, 2, 10, 8, 13, 1]
let n = 18
let matches = a.subSets.lazy.filter { $0.reduce(0,+) == n }
print("Matches:", Array(matches.map{Array($0)})) // Matches: [[10, 8], [4, 13, 1]]
Вы также можете использовать нерекурсивный подход, как вы можете видеть в другом посте, который я сделал здесь Найти все комбинации строкового массива в swift .Обратите внимание, что во втором подходе я сделал это таким образом, чтобы не рассматривать пустой набор как подмножество:
extension RangeReplaceableCollection {
var subSetsNotRecursive : [SubSequence] {
guard !isEmpty else { return [] }
let count = self.count
let n = 1 << count - 1
var subSequences: [SubSequence] = .init(repeating: SubSequence(), count: n-1)
(0 ..< n).map {
var counter = 0
for element in self {
if $0 & 1 << counter > 0 {
subSequences[$0-1].append(element)
}
counter += 1
}
}
return subSequences + [self[...]]
}
}
let matches2 = a.subSetsNotRecursive.lazy.filter { $0.reduce(0,+) == n }
print("Matches2:", Array(matches2.map{Array($0)})) // Matches2: [[10, 8], [4, 13, 1]]
Или расширять его дальше.Если вас интересуют только те наборы, которые суммируются, равны определенному значению, вы можете проверять каждый раз, когда завершаете создание своего набора, равна ли сумма элементов, к которым добавлено, значение, которое вы хотите:
extension RangeReplaceableCollection where Element: BinaryInteger {
func subSetsThatSummedAre(equalTo value: Element) -> [SubSequence] {
guard !isEmpty else { return [] }
let count = self.count
let n = 1 << count - 1
var subSets: [SubSequence] = []
(0 ..< n).map {
var counter = 0
var sum: Element = 0
var subSequence = SubSequence()
for element in self {
if $0 & 1 << counter > 0 {
subSequence.append(element)
sum += element
}
counter += 1
}
if sum == value {
subSets.append(subSequence)
}
}
if reduce(0, +) == value {
subSets.append(self[...])
}
return subSets
}
}
let matches4 = a.subSetsThatSummedAre(equalTo: n)
print("Matches4:", Array(matches4.map{Array($0)})) // Matches4: [[10, 8], [4, 13, 1]]