如何从给定的数字中找到一个随机组合,这些组合加起来就是Swift中的另一个数字?

时间:2019-02-17 04:19:19

标签: ios swift algorithm

给出一个随机的正整数集A,找到一个整数的随机组合,它们的总和为N

例如

A = [4, 2, 10, 8, 13, 1, ...]  
N = 18  
The possibilities are [10, 8], [4, 13, 1], etc.

集合A也可以是任意长度,并且只能容纳正整数。

N可以是任何正整数。

我只需要一个数字组合,而不是全部。我也想随机选择,所以如果给我相同的答案,我就不会每次都得到相同的答案,我正在寻找可以在Swift中以编程方式进行此操作的最有效方法。

1 个答案:

答案 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]]