我想使用动态编程从给定数组中获取所有子集的总和。
subsets([1,2,3]) = 24
Since the subsets are {1}{2}{3}{1,2}{2,3}{1,3}{1,2,3}
我正在尝试计算= 6的子集([1,2]) 我在下面的实现得到5
func subsets(_ arr: [Int]) -> Int {
var mem = Array(repeating: 0, count: arr.count)
return subsetsRecursive(arr, 0, &mem)
}
// correct result, but too slow so requires memorization
func subsetsRecursive(_ arr: [Int], _ ptr: Int, _ memo : inout [Int]) -> Int {
if (ptr > arr.count - 1) {return 0}
if memo[ptr] != 0 {return memo[ptr]}
// either take the next number, or don't
let res = (
subsetsRecursive(arr, ptr + 1, &memo) + arr[ptr]
+
subsetsRecursive(arr, ptr + 1, &memo)
)
memo[ptr] = res
return res
}
需要什么纠正才能得到正确的答案?这里的方法很重要,它不是家庭作业,而是我对动态编程的自学(我可以找到其他方法,但是想了解这种方法或为什么它不可能)。
答案 0 :(得分:1)
您可以首先获取所有子集元素,将它们加入并使用reduce求和:
extension RangeReplaceableCollection {
public var subSets: [SubSequence] {
return isEmpty ? [SubSequence()] : dropFirst().subSets.lazy.flatMap { [$0, prefix(1) + $0] }
}
}
let subSets = [1,2,3].subSets // [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
let sum = subSets.joined().reduce(0,+) // 24
或
let sum = subSets.reduce(0) { $1.reduce($0,+) }
请注意,扩展RangePlaceableCollection
并返回SubSequence
后,您还可以将其与StringProtocol类型(例如String
和Substring
s)一起使用:
let characters = Array("123")
let charactersSubSets = characters.subSets // [[], ["1"], ["2"], ["1", "2"], ["3"], ["1", "3"], ["2", "3"], ["1", "2", "3"]]
let stringSubSets = "123".subSets // ["", "1", "2", "12", "3", "13", "23", "123"]
let substringSubSets = "1234".dropLast().subSets // ["", "1", "2", "12", "3", "13", "23", "123"]
答案 1 :(得分:1)
您的方法存在的问题是,递归步骤未考虑当前元素arr[ptr]
可以组合的多少个子集。例如,subsets([1,2])
计算子集{1、2}和{2}的总和,但省略子集{1}。
动态编程方法的一种可能的解决方法是不仅记住总和,还要记住从某个位置开始的所有子集的 count :
func subsets(_ arr: [Int]) -> Int {
var mem = Array(repeating: (sum: 0, count: 0), count: arr.count)
return subsetsRecursive(arr, 0, &mem).sum
}
func subsetsRecursive(_ arr: [Int], _ ptr: Int, _ memo : inout [(sum: Int, count: Int)]) -> (sum: Int, count: Int) {
if (ptr > arr.count - 1) { return (sum: 0, count: 1) }
if memo[ptr].sum != 0 { return memo[ptr] }
let res = subsetsRecursive(arr, ptr + 1, &memo)
memo[ptr] = (2 * res.sum + arr[ptr] * res.count, 2 * res.count)
return memo[ptr]
}
示例:
print(subsets([1, 2])) // 6
print(subsets([1, 2, 3])) // 24
这可以进一步简化,但希望能回答您的紧迫问题。
迭代解决方案是
func subsetsum(_ arr: [Int]) -> Int {
var sum = 0
var count = 1
for elem in arr {
sum = 2 * sum + count * elem
count = 2 * count
}
return sum
}
可以简写为
func subsetsum(_ arr: [Int]) -> Int {
return arr.reduce((sum: 0, count: 1)) {
(2 * $0.sum + $0.count * $1, 2 * $0.count )
}.sum
}
或者,请注意,n个数组元素中的每一个都可以位于2 n 个子集中的2 n-1 中:
func subsetsum(_ arr: [Int]) -> Int {
return arr.reduce(0, +) * (1 << (arr.count - 1))
}