题目地址:https://www.hackerrank.com/ch...
题目大意:
给定:
- 集合 S,其中含有不同的整数;
- k。
判定所能得到的 S 的子集 S' 的最大元素个数。其中,S' 需要满足:其中的任意两数之和均不能被 k 整除。
例子:给定集合
{1, 7, 2, 4}
和数字 3。我们可以将 2 从集合中删去,得到子集{1, 7, 4}
,从而使得其中任意两数之和均不能被 3 整除。因而该情况的结果为 3。编程语言:Scala
1. 参考思路
对于这一题目,如果我们采用递归方式求解,则会导致问题的复杂度极大,从而无法通过超时检测。我们需要另想思路。
1.1 转换 S 集合
首先,由于集合中的元素可能非常大。而在这一问题中,集合 S 与 k 的解,与 S(余) 与 k 的解是没有区别的。其中 S(余) 指的是对 S 中每一个元素求其对 k 的余数,所组成的集合。
对于 S(余),其中的每一个元素的值都小于 k。
在这个基础上,我们再考虑,对于 S(余) 中为 0 的元素,实际是不会对问题的结果产生影响的。因为 0 与任意数字求和结果相对 k 的整除性都不会因其而改变。也就是说,只要我们能保证,除 0 以外的其他元素的集合能够满足题目要求,则原集合也能满足。
现在,我们将 S 转换成了一个新集合 Sa,其中,Sa 为 S 中任一元素对 k 求余之后的集合,且其中不包含余数为 0 的数。
1.2 考虑集合中两数相加被 k 整除的情况
在集合 Sa 中,如果存在两个数字 m 和 n 能够被整除,那么 m + n 一定等于 k( 考虑 Sa 中元素的形式 )。
也就意味着,能够被整除,即不满足题目要求的数字是会成对出现的,二者仅会与对方形成不满足条件的组合,且和为 k。
那么对于这样一对数 m 和 n,我们需要从原集合中将 m 或 n 全部删除,才能保证子集满足题目所要求的条件。当然,为了达到题目要求的集合最大元素数,我们需要根据 m 和 n 在集合中的个数,删除较小的那个数。
这样一来,我们需要遍历 Sa 集合,得到其中每一个数字在集合中重复的个数。即得到一个 HashMap 对象,假设为 map
,map
的最大长度为 k - 1( 去除了 0 )。
然后,我们需要遍历 map
,找到上述成对出现的数字组合,并记录每一对中最小个数的值。
但是,如果在遍历过程中,对每一个数字都进行处理的话,会导致重复计算。这里,我们需要约定,只计算数字组合中,较大的或较小的那个。由于 m + n 等于 k,所以我们可用 k / 2 作为判定条件。
但这又带来一个问题:k / 2 对 k 为奇数的情况是没有问题的。但当 k 为偶数时,由于值为 k / 2 的数字,其组合就是自身,那么我们需要对这一情况特殊考虑,即值为 k / 2 的数字在最终的子集中只能保留 1 个。
综上所述,通过对 S 集合的转换,和两次遍历,我们就可以得到最终的结果了。
但是,这里还有一个特例,即 k = 1 的情况。
1.3 k 为 1 的情况
当 k 为 1 时,由于任意数字都能被 1 整除,为了满足题目条件,我们只能将子集中元素的个数调整为 1,使得其无法满足「求和」。
2. 参考代码
由上述可知,参考代码如下,重点在于 S 集合的转换部分,以及 map
的生成和遍历:
def nonDivisibleSubset(k: Int, S: Array[Int]): Int = {
var maxSubsetLength = 0
// 注意 1
if (1.equals(k)) {
maxSubsetLength = 1
} else {
val hashMap = mutable.HashMap[Int, Int]()
var invalidCount = 0
for (item <- S) {
val remainder = item % k
if (0.equals(remainder) == false) {
val current = hashMap.get(remainder)
current match {
case None => hashMap(remainder) = 1
case Some(_) => hashMap(remainder) += 1
}
}else{
invalidCount += 1
}
}
maxSubsetLength = S.length - invalidCount
if (invalidCount > 0) {
maxSubsetLength += 1
}
var halfOfK = k / 2
if (0.equals(k % 2)) {
val countOfHalfK = hashMap.get(halfOfK)
if (countOfHalfK != None) {
maxSubsetLength = maxSubsetLength - countOfHalfK.get + 1
}
halfOfK = k / 2 - 1
}
for ((key, value) <- hashMap) {
// 注意奇数偶数
if (key <= halfOfK) {
val complement = hashMap.get(k - key)
if (complement != None) {
maxSubsetLength -= Math.min(value, complement.get)
}
}
}
}
maxSubsetLength
}
代码 Gist 地址为:Answer of question from https://www.hackerrank.com/challenges/non-divisible-subset/problem · GitHub
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。