【问题标题】:Performance issue with CountDiv (Codility) challenge algorithmCountDiv(Codility)质询算法的性能问题
【发布时间】:2020-05-26 22:18:17
【问题描述】:

需要一些关于我为解决这个代码挑战而制作的算法的帮助:

编写一个函数,给定三个整数 A、B 和 K,返回 [A..B] 范围内可被 K 整除的整数个数。 例如,对于 A = 6、B = 11 和 K = 2,您的函数应返回 3,因为在 [6..11] 范围内有三个可被 2 整除的数字,即 6、8 和 10。
A 和 B 是 [0..2,000,000,000] 范围内的整数; K 是 [1..2,000,000,000] 范围内的整数; A≤B。

public class Solution {
        public int solution(int A, int B, int K) {

            int counter = 0;
            ArrayList<Integer> listOfNumbersInBetween = new ArrayList<>();

            for (int i = A; i <= B; i++) {
                listOfNumbersInBetween.add(i);
            }

            for (int arrayElement : listOfNumbersInBetween) {
                if (arrayElement % K == 0) {
                    counter++;
                }
            }

            return counter;

        }}

如您所见,我的解决方案运行良好,但在性能方面,由于时间复杂度 O(B-A),它的得分为 0%。

如何改进此代码以使其得分 100%?

【问题讨论】:

    标签: java performance sorting testing


    【解决方案1】:

    使用循环是蛮力的,这样的挑战不能用蛮力来完成。

    这意味着您必须计算结果。像这样的挑战更多的是数学问题,而不是编程问题,所以戴上数学帽子吧。

    所以想想吧。在一个整数范围内,计算有多少可以被 K 整除。如果我要求你手动执行此操作(允许使用简单的计算器),无需使用计算机蛮力它,你会怎么做?例如。找出111999 之间有多少个整数可以被13 整除

    提示

    查找范围内可被 K 整除的第一个数字,以及范围内可被 K 整除的最后一个数字。对于上面的示例,这将是 117988

    现在计算从第一个整数到最后一个整数有多少个整数可以被 K 整除,记住要计算这两个整数。那么,117988 之间有多少个整数可以被13 整除?

    答案:(988 - 117) / 13 + 1 = 871 / 13 + 1 = 67 + 1 = 68

    【讨论】:

    • 为什么我们需要在结果中添加1?如果我们改用988 - 111 会发生什么?
    • @Cyber​​Mew 因为:“记得数他们两个” --- 例如16 到 20 之间的偶数,包括:(20 - 16) / 2 = 4 / 2 = 2,然后 +1,因为这两个数字都包括在内,所以总数为 3 (16, 18, 20)。
    • 感谢您的快速响应!明白了。但似乎,例如,我们得到 1 和 3 之间的数字,如果我们除以 5,我们应该得到总和 0,而在另一个例子中,在 5 和 5 之间,我们除以 5,我认为我们应该得到共 1 个。我会尝试测试一下,谢谢!
    • @Cyber​​Mew 如果你除以 5,即 K=5,那么当你 normalize 1-3 的 min-max 值,你得到 5-0,所以它们之间没有值:result=0。
    • @Cyber​​Mew 如果您需要找到 5-25 范围内可被 6 整除的数字,我们首先将边界归一化为自身可被 6 整除。首先这样的数字 >=5 是 6,最后这样的数字
    【解决方案2】:

    一种可能性是利用整数运算来摆脱一些边缘情况。有时AB 两者都不是,或者两者都不能被k 整除。仅仅减去它们并不能真正帮助解决问题。所以一种解决方案是在减去它们之前将它们除以k

    k = 7, A = 12, and B = 5454/7 - 12/7 = 7 - 1 = 6 (14,21,28,35,42,49)

    但是如果A14 呢?

    54/7 - 14/7 = 7 - 2 = 5 (14,21,28,35,42,49) 答案是一次性的。所以当A能被k整除时,需要加上1

    如果AB 都可以被k 整除呢?

    56/7 - 14/7 = 8 - 2 = 6 = (14,21,28,34,42,49,56)。答案又是一次,所以Ak 整除的特殊情况通过添加1 来处理它

    int result = (B/k - A/k) + ((A%k == 0) ? 1 : 0);
    
    
    

    【讨论】:

      【解决方案3】:

      我的 C# 解决方案,基于 @Andreas 的出色解决方案。这最终让我达到了 100%。最令人惊讶(也许是错误的?)是 [0, 0, 11] 需要产生 1 的结果,这意味着 0 被认为可以被 11 整除。你会看到我必须注释掉一个错误捕获器以允许 B为零,让我得到“预期”的答案。我很惊讶 (0-0)/11 没有产生运行时错误,但它没有。

          public int solutionCountDiv4(int A, int B, int K)
          {
              //Errors
              if (K == 0)
                  return 0;
      
              //if (B == 0)
              //    return 0;
      
              if (A > B)
                  return 0;
      
              var first = 0;
              var last = 0;
      
              for (first = A; first <= B; first++)
              {
                  if (first % K == 0)
                      break;
              }
              for (last = B; last >= A; last--)
              {
                  if (last % K == 0)
                      break;
              }
      
              if (first > last)
                  return 0;
      
              var result = (last - first) / K + 1;
              return result;
          }
      

      【讨论】:

        猜你喜欢
        • 2015-05-02
        • 2022-10-04
        • 1970-01-01
        • 1970-01-01
        • 2022-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多