不明白 Codility CountDiv 解决方案是如何正确的

Sim*_*ett 4 c algorithm

Codility CountDiv 练习

给定范围 A..B 和值 K,返回范围内可被 K 整除的值的数量。

给出的例子是 A = 6, B = 11 和 K = 2。在 6 到 11 的范围内,能被 2 整除的数是 6、8 和 10,所以答案是 3。所需的解决方案必须是 O(1) - 所以需要一个简单的计算。

您可以假设 A 和 B 的范围是 0..2,000,000,000,K 是 1..2,000,000,000 并且 0 <= A <= B。

得分为 100% 的公认解决方案如下:

int solution(int A, int B, int K)
{
    int inclusive = ((A%K)==0) ? 1 : 0;
    return (B/K) - (A/K) + inclusive;
}
Run Code Online (Sandbox Code Playgroud)

我感到困惑的是,当我使用输入 A=0、B=0 和 K=1 测试此解决方案时,结果是 1?我原以为在 0 到 0 的范围内,可被 1 整除的值的数量是... 0!

我认为这是一个错误,只有在 A 非零时才应设置 A 的包含值的 +1。

所以我提交了以下解决方案(测试 A 非零):

int solution(int A, int B, int K)
{
    int inclusive = (A && (A%K)==0) ? 1 : 0;
    return (B/K) - (A/K) + inclusive;
}
Run Code Online (Sandbox Code Playgroud)

但这仅获得了 62%(50% 的正确率和 75% 的性能)。它失败的一些测试用例是:

  • A = 0,B = 1,K = 11 - 得到 0,预期为 1
  • A = 0, B = MAXINT, K in {1,MAXINT},得到 2000000000,预期为 2000000001

有人可以解释一下吗?

Mar*_*ata 8

该值0可被K所有K允许的值(非零)整除。零没有什么特别之处。可整除的定义是指除后没有余数。


chq*_*lie 7

的范围是包括性的:有范围为1个值00:该值0本身。所有值都可以被 整除1,因此结果确实是1值。

请注意,建议的代码是多余的:

int inclusive = ((A%K)==0) ? 1 : 0;相当于int inclusive = (A%K)==0;。它可以进一步简化为int inclusive = !(A%K);完整的解决方案成为一个单线:

int solution(int A, int B, int K) { return B/K - A/K + !(A%K); }
Run Code Online (Sandbox Code Playgroud)

这是一个只有 2 个分区的变体:

int solution(int A, int B, int K) { return B/K - (A ? (A-1)/K : -1); }
Run Code Online (Sandbox Code Playgroud)

  • 看来你对此很了解。您可能知道这个任务与 PrefixSums 有什么关系吗?我在这里没有看到前缀和的用法...... (2认同)

Ste*_*sca 6

这是一个得分为 100/100 的 C++ 解决方案

int solution(int A, int B, int K) {
    return B / K - A / K + (A % K == 0 ? 1 : 0);
}
Run Code Online (Sandbox Code Playgroud)

它返回区间 [0, B] 中的倍数减去区间 [0, A] 中的倍数 - 获取区间 (A, B] 中的倍数 - 并添加 A 中的倍数,如果 A是一个倍数。