Arrays 从数组中查找项的最小计数,其中项的总和为X
我最近遇到了一个面试问题,你必须从一个数组中找到最少需要的项目,这个数组可以加在一起生成Arrays 从数组中查找项的最小计数,其中项的总和为X,arrays,swift,algorithm,Arrays,Swift,Algorithm,我最近遇到了一个面试问题,你必须从一个数组中找到最少需要的项目,这个数组可以加在一起生成X值 例如: [1,9,2,5,3,10]目标是:13,=>应该是[10,3] 不能在数组外使用任何数字。所以[10,9,9,2]和20->[10,10]是无效的,但是[9,9,2]非常好 时间复杂性并不重要(但更高效的解决方案将受到欢迎) 允许的任何数字,包括负数 我试着对物品进行分类,一个接一个地从头部取出一些其他东西,但没有成功。尽管如此,我已经用一个不太好的解决方案解决了这个问题,我将把它作为一个
X
值
例如:
[1,9,2,5,3,10]
目标是:13
,=>应该是[10,3]
- 不能在数组外使用任何数字。所以
和[10,9,9,2]
->20
是无效的,但是[10,10]
非常好[9,9,2]
- 时间复杂性并不重要(但更高效的解决方案将受到欢迎)
- 允许的任何数字,包括负数
首先,我们必须找到数组的所有子集:
extension Array {
var allSubsets: [[Element]] {
guard count > 0 else { return [[]] }
let tail = Array(self[1..<endIndex]
let head = self[0]
let withoutHead = tail.allSubsets
let withHead = withoutHead.map { $0 + [head] }
return withHead + withoutHead
}
}
最后,通过其计数找到最小子集:
validSubsets.reduce(array) { $0.count < $1.count ? $0 : $1 }
validSubsets.reduce(数组){$0.count<$1.count?$0:$1}
将其包装在函数中,将是:
func minimumElements(in array: [Int], goal: Int) -> [Int] {
let subsets = array.allSubsets
let validSubsets = subsets.filter { subset in
subset.reduce(0) { $0 + $1 } == goal
}
return validSubsets.reduce(array) { $0.count < $1.count ? $0 : $1 }
}
func最小元素(数组:[Int],目标:Int)->[Int]{
设subsets=array.allSubsets
设validSubsets=subsets.filter{subset in
subset.reduce(0){$0+$1}==goal
}
返回有效子集。减少(数组){$0.count<$1.count?$0:$1}
}
注意我认为这不是很有效,如果有人能计算时间复杂度就好了,但由于问题提到复杂度无关紧要,这是一个有效的解决方案。首先我们必须找到数组的所有子集:
extension Array {
var allSubsets: [[Element]] {
guard count > 0 else { return [[]] }
let tail = Array(self[1..<endIndex]
let head = self[0]
let withoutHead = tail.allSubsets
let withHead = withoutHead.map { $0 + [head] }
return withHead + withoutHead
}
}
最后,通过其计数找到最小子集:
validSubsets.reduce(array) { $0.count < $1.count ? $0 : $1 }
validSubsets.reduce(数组){$0.count<$1.count?$0:$1}
将其包装在函数中,将是:
func minimumElements(in array: [Int], goal: Int) -> [Int] {
let subsets = array.allSubsets
let validSubsets = subsets.filter { subset in
subset.reduce(0) { $0 + $1 } == goal
}
return validSubsets.reduce(array) { $0.count < $1.count ? $0 : $1 }
}
func最小元素(数组:[Int],目标:Int)->[Int]{
设subsets=array.allSubsets
设validSubsets=subsets.filter{subset in
subset.reduce(0){$0+$1}==goal
}
返回有效子集。减少(数组){$0.count<$1.count?$0:$1}
}
注意我认为这不是很有效,如果有人能计算时间复杂度就好了,但由于问题提到复杂度无关紧要,这是一个有效的解决方案。回溯
我能想到的最好的解决方案(从时间复杂性的角度来看)是回溯算法
这与暴力非常相似。在最坏的情况下,它具有与暴力相同的时间复杂性。但它稍微好一点,因为它只检查有意义的组合
理论
我们使用递归的visit
函数来探索组合树
每个组合都由一条从根到一片叶子的路径表示
在这之前跟暴力没什么区别,对吧
然而,我们的函数将足够聪明,当它构建的部分解决方案等于或大于目标值(在您的例子中为13)时,将停止探索树的分支
对于某些输入,这个小东西使回溯比蛮力更好
在最坏的情况下,回程将是一个缓慢而残酷的过程
但是有一个问题!
感谢@MartinR指出当前的想法不适用于负数
例如,给定此数组[1,1,1,5,-1]
和4
作为目标值,算法将返回[1,1,1]
作为最佳解决方案,而不考虑[5,-1]
确实更好
管理负数
为了管理负数,我添加了以下逻辑
如果目标值为0或正数,则输入数组按升序排序(负数将放在第一位)
所以[1,1,1,5,-1]
将变成[-1,1,1,1,5]
否则,如果目标为负,则输入数组将按降序排序
所以[1,1,1,1,5,-1]
将变成[5,1,1,1,1,-1]
编码回溯
我能想到的最好的解决方案(从时间复杂性的角度来看)是回溯算法
这与暴力非常相似。在最坏的情况下,它具有与暴力相同的时间复杂性。但它稍微好一点,因为它只检查有意义的组合
理论
我们使用递归的visit
函数来探索组合树
每个组合都由一条从根到一片叶子的路径表示
在这之前跟暴力没什么区别,对吧
然而,我们的函数将足够聪明,当它构建的部分解决方案等于或大于目标值(在您的例子中为13)时,将停止探索树的分支
对于某些输入,这个小东西使回溯比蛮力更好
在最坏的情况下,回程将是一个缓慢而残酷的过程
但是有一个问题!
感谢@MartinR指出当前的想法不适用于负数
例如,给定此数组[1,1,1,5,-1]
和4
作为目标值,算法将返回[1,1,1]
作为最佳解决方案,而不考虑[5,-1]
确实更好
管理负数
为了管理负数,我添加了以下逻辑
如果目标值为0或正数,则输入数组按升序排序(负数将放在第一位)
所以[1,1,1,1,5,