给出一个随机的正整数集A
,找到一个整数的随机组合,它们的总和为N
。
例如
A = [4, 2, 10, 8, 13, 1, ...]
N = 18
The possibilities are [10, 8], [4, 13, 1], etc.
集合A
也可以是任意长度,并且只能容纳正整数。
N
可以是任何正整数。
我只需要一个数字组合,而不是全部。我也想随机选择,所以如果给我相同的答案,我就不会每次都得到相同的答案,我正在寻找可以在Swift中以编程方式进行此操作的最有效方法。
答案 0 :(得分:1)
您首先需要创建一种方法来查找原始集合的所有可能子集,正如我在此处Subset sum 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]]
您也可以使用非递归方法,正如您在我在此处Find all combination of string array in 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]]