题目地址:Birthday Chocolate | HackerRank
题目大意:
给定:
- 数组 s
- 个数 m
- 总和 d
判定 s 中,连续 m 个数字总和为 d 的情况共有几种?
例子:给定数组
[1, 3, 2, 2, 7]
,判定该数组中,连续 2 个数字总和为 4 的情况共有几种?
答案:2 种,分别为(1,3)
、(2,2)
编程语言:Scala
1. 原问题
由于原题中限定了连续,因而一个循环便可以得到答案:
def solve(s: Array[Int], d: Int, m: Int): Int = {
val length = s.length
var count = 0
if(m > length) {
count = 0
} else {
for ((_, index) <- s.zipWithIndex) {
if (index + m - 1 <= length) {
val sum = s.slice(index, index + m).sum
if (sum.equals(d)) count += 1
}
}
}
count
}
2. 延伸问题
2.1 问题介绍
如果我们把原题中的连续限制删去,问题就可以理解为:
给定一组数,每次选取 m 个数,可以选择的形式有哪些?
假定 m 小于等于数组的长度,下同。
至于这 m 个数的和是否等于 d,只需要将上述问题的结果依次求和判断即可。
如果只需要求出组合的个数,那就是排列组合问题。而若要得到组合的全部形式,则更类似于离散中的可读问题。
比如,对于数组 [1, 2, 3, 1]
,选择两个数字的所有形式为:(1, 2)
,(1, 3)
,(1, 1)
,(2, 3)
,(2, 1)
,(3, 1)
。
注意,对于数组 [1, 2, 3, 1]
,「第一位的 1 和第三位的 3」与「第三位的 3 和第四位的 1」,被看做是不同的组合,而「第一位的 1 和第三位的 3」与「第一位的 1 和第三位的 3」是相同的组合。即只考虑因颠倒顺序导致的重复。
2.2 参考思路
关于这一问题的求解和编码思路,可以参考:获取排列组合的结果集。
2.3 参考代码
根据 2.2 中的思路,我们可以编写递归方法如下:
/**
* 递归函数
*
* @param count 可选个数
* @param candidates 给定的待选数组
* @param bag 前面递归层级中已经选择的 N,N',N''... 的元素集合
* @param container 用于存储可选类型的容器
*/
def traverse(count: Int, candidates: ArrayBuffer[Int], bag: ArrayBuffer[Int], container: ArrayBuffer[ArrayBuffer[Int]]): Unit = {
if (count <= candidates.length) {
if (count.equals(1)) {
for (item <- candidates) {
val finalBag = bag.clone()
finalBag += item
container += finalBag
}
} else {
for ((item, index) <- candidates.zipWithIndex) {
val nextBag = bag.clone()
nextBag += item
val nextCandidates = candidates.slice(index + 1, candidates.length)
traverse(count - 1, nextCandidates, nextBag, container)
}
}
}
}
对于递归初始阶段,其待选数组即为问题中的全量数组 s。
在主函数中,我们可以这样调用该递归方法:
def main(args: Array[String]): Unit = {
val candidates = ArrayBuffer[Int](1, 3, 7, 5, 9)
val count = 3
val container = ArrayBuffer[ArrayBuffer[Int]]()
val bag = ArrayBuffer[Int]()
traverse(count, candidates, bag, container)
println(container.mkString("\n"))
}
其结果为:
ArrayBuffer(1, 3, 7)
ArrayBuffer(1, 3, 5)
ArrayBuffer(1, 3, 9)
ArrayBuffer(1, 7, 5)
ArrayBuffer(1, 7, 9)
ArrayBuffer(1, 5, 9)
ArrayBuffer(3, 7, 5)
ArrayBuffer(3, 7, 9)
ArrayBuffer(3, 5, 9)
ArrayBuffer(7, 5, 9)
代码 Gist 地址:Select all combinations of N elements from the collection. · GitHub
参考链接
- Birthday Chocolate | HackerRank
- How to convert a Scala Array to ArrayBuffer? - Stack Overflow
- What is the fastest way to sum a collection in Scala - Stack Overflow
- 获取排列组合的结果集 - DB.Reid - SegmentFault 思否