找到范围内数字的除数

时间:2014-09-04 09:12:03

标签: java algorithm

我对Codility中的CountDiv问题有疑问。

给出的问题是:写一个函数:

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

,给定三个整数A,B和K,返回[A..B]范围内可被K整除的整数数,即:

{ i : A ≤ i ≤ B, i mod K = 0 }

我的代码:

class Solution {
    public int solution(int A, int B, int K) {        
         int start=0;
         if (B<A || K==0 || K>B )
            return 0;
         else if (K<A)
            start = K * ( A/K +1);
         else if (K<=B)
            start = K;

         return (B-start+1)/K+ 1;
    }
} 

我不明白为什么我错了,特别是这个测试用例:

extreme_ifempty 
A = 10, B = 10, K in {5,7,20}
WRONG ANSWER 
got 1 expected 0

如果K =5然后使用i=10 A<=i<=Bi%k =0那么为什么我应该为0? Problem statement

27 个答案:

答案 0 :(得分:24)

这是O(1)解决方案,它通过了test

int solution(int A, int B, int K) {
    int b = B/K;
    int a = (A > 0 ? (A - 1)/K: 0);
    if(A == 0){
        b++;
    }
    return b - a;
}

说明:[1 .. X]范围内可被K整除的整数数为X/K。因此,在[A .. B]范围内,结果为B/K - (A - 1)/K

如果A为0,因为0可以被任何正数整除,我们需要计算它。

答案 1 :(得分:12)

具有O(1)和100%编码的Java解决方案,为那些想要尝试但没有看到其他解决方案的人添加一些测试用例和解决方案:

  // Test cases
  //  [1,1,1] = 1
  // [0,99,2] = 50
  // [0, 100, 3] = 34  
  // [11,345,17] = 20
  // [10,10,5] = 1
  // [3, 6, 2] = 2
  // [6,11,2] = 3  
  // [16,29,7] = 2
  // [1,2,1] = 2    
public int solution(int A, int B, int K) {
   int offsetForLeftRange = 0;
   if ( A % K == 0) { ++offsetForLeftRange; }

   return  (B/K) - (A /K) + offsetForLeftRange;
}

答案 2 :(得分:10)

解决这个问题的方法是Prefix Sums,因为这是Codility中该部分的一部分。

https://codility.com/programmers/lessons/3/

https://codility.com/media/train/3-PrefixSums.pdf

使用这种技术,可以减去0和A之间的整数计数,它可以被K(A / K + 1)整除,从0和B之间的整数计数可以被K整除(B / K + 1) )。

请记住,A是包容性的,所以如果它是可分的,那么将其作为结果的一部分包括在内。

以下是我的解决方案:

class Solution {
public int solution(int A, int B, int K) {
        int b = (B/K) + 1;  // From 0 to B the integers divisible by K
        int a = (A/K) + 1;  // From 0 to A the integers divisible by K

        if (A%K == 0) { // "A" is inclusive; if divisible by K then
            --a;        //   remove 1 from "a"
        }
        return b-a;     // return integers in range
    }
}

答案 3 :(得分:7)

return A==B  ? (A%K==0 ? 1:0) : 1+((B-A)/K)*K /K; 

嗯,这是一个完全难以辨认的oneliner,但我发布它只是因为我可以; - )

在这里完成java代码:

package countDiv;

public class Solution {

    /**
     * First observe that
     * <li> the amount of numbers n in [A..B] that are divisible by K  is the same as the amount of numbers n between [0..B-A]
     *      they are not the same numbes of course, but the question is a range question.
     *      Now because we have as a starting point the zero, it saves a lot of code.
     * <li> For that matter, also A=-1000 and B=-100 would work
     * 
     * <li> Next, consider the corner cases.
     *      The case where A==B is a special one: 
     *      there is just one number inside and it either is divisible by K or not, so return a 1 or a 0. 
     * <li> if K==1 then the result is all the numbers between and including the borders.          
     * <p/>
     * So the algorithm simplifies to
     * <pre>
     * int D = B-A; //11-5=6
     * if(D==0) return B%K==0 ? 1:0;
     * int last = (D/K)*K; //6
     * int parts = last/K; //3
     * return 1+parts;//+1 because the left part (the 0) is always divisible by any K>=1.
     * </pre>
     * 
     * @param A : A>=1
     * @param B : 1<=A<=B<=2000000000
     * @param K : K>=1  
     */
    private static int countDiv(int A, int B, int K) {      
        return A==B  ? A%K==0 ? 1:0 : 1+((B-A)/K)*K /K; 
    }   

    public static void main(String[] args) {
        {
            int a=10;  int b=10; int k=5; int result=1;
            System.out.println( a + "..." + b + "/" + k + " = " +  countDiv(a,b,k)  + (result!=countDiv(a,b,k) ? " WRONG" :" (OK)" ));
        }

        {
            int a=10;  int b=10; int k=7; int result=0;
            System.out.println( a + "..." + b + "/" + k + " = " +  countDiv(a,b,k)  + (result!=countDiv(a,b,k) ? " WRONG" :" (OK)" ));
        }

        {
            int a=6;  int b=11; int k=2; int result=3;
            System.out.println( a + "..." + b + "/" + k + " = " +  countDiv(a,b,k)  + (result!=countDiv(a,b,k) ? " WRONG" :" (OK)" ));
        }

        {
            int a=6;  int b=2000000000; int k=1; int result=b-a+1;
            System.out.println( a + "..." + b + "/" + k + " = " +  countDiv(a,b,k)  + (result!=countDiv(a,b,k) ? " WRONG" :" (OK)" ));
        }
    }
}//~countDiv

答案 4 :(得分:2)

这是我的100/100解决方案:

https://codility.com/demo/results/trainingRQDSFJ-CMR/

{{1}}

此解决方案的主要方面:

  1. 如果A = 1,则在B / K中找到除数的数量。
  2. 如果A = 0,则在B / K加1中找到除数的数量。
  3. 如果B = 0,那么只有一个i%K = 0,即自身为零。

答案 5 :(得分:1)

我不确定你在代码中尝试做什么,但更简单的方法是使用模运算符(%)。

public int solution(int A, int B, int K) 
{
    int noOfDivisors = 0;
    if(B < A || K == 0 || K > B )
        return 0;
    for(int i = A; i <= B; i++) 
    {
        if((i % K) == 0) 
        {
            noOfDivisors++;
        }
    }
    return noOfDivisors;
}

答案 6 :(得分:1)

面对挑战,找不到使用我想要的Prefix Sum技术的解决方案。这是我的解决方案:

问题:从A-> B可以将K整除多少个数字?

答案:prefSum [B + 1]-prefSum [A]

让A,B,K为0,3,2;相应的prefSum的值为[0,1,1,2,2]-带有

  

prefSum [0] = 0

  

prefSum [N] =(N-1)/ K +1;

请记住,0可以被任何数字整除。这是代码:

func Solution(A int, B int, K int) int {
    b := getPrefSum(B+1, K)
    a := getPrefSum(A, K)
    return b - a
}
func getPrefSum(N int, K int) int {
    if N == 0 {
        return 0
    }
    return (N-1)/K + 1
}

它是passed,复杂度为O(1)。

答案 7 :(得分:1)

这适用于O(1)Test link

    using System;
    class Solution 
    {
      public int solution(int A, int B, int K) 
      {
       int value = (B/K)-(A/K);
       if(A%K == 0)
       {
        value=value+1;
       }
       return value;
      }
    }

答案 8 :(得分:1)

如果我正确理解了这个问题,我相信这是解决方案:

public static int solution(int A, int B, int K) {
    int count = 0;
    if(K == 0) {
        return (-1);
    }
    if(K > B) {
        return 0;
    }
    for(int i = A; i <= B; ++i) {
        if((i % K) == 0) {
            ++count;
        }
    }
    return count;
}

返回-1是由于非法操作(除以零)

答案 9 :(得分:1)

这是我的解决方案,两行Java代码。

public int solution(int A, int B, int K) {
    int a = (A == 0) ? -1 : (A - 1) / K;
    return B / K - a;
}

这个想法很简单 a指的是[1..A-1]中可分割的数量 B / K指的是[1..B]中可分割的数量 0可以被任何整数整除,所以如果A是0,你应该在答案中加一。

答案 10 :(得分:1)

class Solution {
    public int solution(int A, int B, int K) {
        int a = A/K, b = B/K;
        if (A/K == 0)
            b++;
        return b - a;
    }
}

这会传递test

类似于“ 2到5的数字”。我们都知道它是(5 - 2 + 1)。我们最后添加1的原因是第一个数字2计数。

A/K, B/K之后,此问题与上述问题相同。在这里,我们需要确定A是否计入此问题。只有当A%K == 0计算时,我们才需要将1添加到结果b - a(与b+1相同)。

答案 11 :(得分:1)

100/100 - 解决方案的另一种变体,基于Pham Trung的想法

class Solution {
    public int solution(int A, int B, int K) {
         int numOfDivs = A > 0 ? (B / K - ((A - 1) / K)) : ((B / K) + 1);
         return numOfDivs;
    }
}

答案 12 :(得分:1)

另一种O(1)溶液在测试中获得100%。

int solution(int A, int B, int K) {
    if (A%K)   
        A = A+ (K-A%K);

    if (A>B)
        return 0;

    return (B-A)/K+1;
}

答案 13 :(得分:1)

int solution(int A, int B, int K) {
    int tmp=(A%K==0?1:0);
    int x1=A/K-tmp ;
    int x2=B/K;
    return x2-x1;
}

答案 14 :(得分:0)

    int divB = B / K;
    int divA = A / K;
    if(A % K != 0) {
        divA++;
    }
    return (divB - divA) + 1;

密码通过率100%

答案 15 :(得分:0)

Python 3单行解决方案得分为100%

from math import ceil, floor


def solution(A, B, K):
    return floor(B / K) - ceil(A / K) + 1

答案 16 :(得分:0)

这是我的简单解决方案,其中100% https://app.codility.com/demo/results/trainingQ5XMG7-8UY/

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

    while (A % K != 0) {
        ++A;
    }
    while (B % K != 0) {
        --B;
    }
    return (B - A) / K + 1;
}

答案 17 :(得分:0)

Python 中的简单解决方案:

def solution(A, B, K):
    count = 0
    if A % K == 0:
        count += 1
    count += int((B / K) - int(A / K))
    return count 

说明:

B/K is the total numbers divisible by K [1..B]

A/K is the total numbers divisible by K [1..A]

The subtracts gives the total numbers divisible by K [A..B]

if A%K == 0, then we need to add it as well.

答案 18 :(得分:0)

我认为以上答案并未就每个解决方案为何有效(解决方案背后的数学原理)提供足够的逻辑解释,因此,我在此处发布了solution

想法是在这里使用arithmetic sequence。如果我们有第一个可除数(> = A)和最后一个可除数(<= B),则我们有一个距离为K的算术序列。现在我们要做的就是找到[newA,newB]范围内的项总数是[newA,newB]范围内的可除数总数

first term (a1) = newA
last/n-th term (an) = newB
distance (d) = K
Sn = a1 + (a1+K) + (a1 + 2k) + (a1 + 3k) + ... + (a1 + (n-1)K)

`n` in the above equation is what we are interested in finding. We know that

n-th term = an = a1 + (n-1)K 
as an = newB, a1 = newA so
newB = newA + (n-1)K
newB = newA + nK - K
nK = newB - newA + K
n = (newB - newA + K) / K

现在我们有了上述公式,因此只需将其应用到代码中即可。

fun countDiv(A: Int, B: Int, K: Int): Int {
    //NOTE: each divisible number has to be in range [A, B] and we can not exceed this range
    //find the first divisible (by k) number after A (greater than A but less than B to stay in range)
    var newA = A
    while (newA % K != 0 && newA < B)
        newA++

    //find the first divisible (by k) number before B (less than B but greater than A to stay in range)
    var newB = B
    while (newB % K != 0 && newB > newA)
        newB--

    //now that we have final new range ([newA, newB]), verify that both newA and newB are not equal
    //because in that case there can be only number (newA or newB as both are equal) and we can just check
    //if that number is divisible or not
    if (newA == newB) {
        return (newA % K == 0).toInt()
    }

    //Now that both newA and newB are divisible by K (a complete arithmetic sequence)
    //we can calculate total divisions by using arithmetic sequence with following params
    //a1 = newA, an = newB, d = K
    // we know that n-th term (an) can also be calculated using following formula
    //an = a1 + (n - 1)d
    //n (total terms in sequence with distance d=K) is what we are interested in finding, put all values
    //newB = newA + (n - 1)K
    //re-arrange -> n =  (newB - newA + K) / K
    //Note: convert calculation to Long to avoid integer overflow otherwise result will be incorrect
    val result = ((newB - newA + K.toLong()) / K.toDouble()).toInt()
    return result
}

我希望这对某人有帮助。仅供参考,codility solution with 100% score

答案 19 :(得分:0)

如果仍然有人对此练习感兴趣,请分享我的Python解决方案(Codility中100%)

def solution(A, B, K):

    if not (B-A)%K:
        res = int((B-A)/K)
    else:
        res = int(B/K) - int(A/K)

    return res + (not A%K)

答案 20 :(得分:0)

我将在go中显示我的代码:)

func CountDiv(a int, b int, k int) int {
   count := int(math.Floor(float64(b/k)) - math.Floor(float64(a/k)));
   if (math.Mod(float64(a), float64(k)) == 0) {
      count++
   }

   return count
}

总分为100%

答案 21 :(得分:0)

There is a lot of great answers, but I think this one has some elegance in it, also gives 100% on codility.


public int solution(int a, int b, int k) {
    return Math.floorDiv(b, k) - Math.floorDiv(a-1, k);
}

Explanation: Number of integers in the range [1 .. B] that divisible by K is B/K. Range [A .. B] can be transformed to [1 .. B] - [1 .. A) (notice that round bracket after A means that A does not belong to that range). That gives as a result B/K - (A-1)/K. Math.floorDiv is used to divide numbers and skip remaining decimal parts.

答案 22 :(得分:0)

这是O(1)解决方案,(a的分裂不需要检查)

public static int countDiv(int a, int b, int k) {
        double l1 = (double)a / k;
        double l = -1 * Math.floor(-1 * l1);        
        double h1 = (double) b / k; 
        double h =  Math.floor(h1);
        Double diff = h-l+1;
        return diff.intValue();
    }

答案 23 :(得分:0)

这是我的解决方案并获得100%

public int solution(int A, int B, int K) {
    int count = B/K - A/K;
    if(A%K == 0) {
        count++;
    }
    return count;
}
  1. B / K将为您提供可被K [1..B]
  2. 整除的总数
  3. A / K会为您提供可被K [1..A]
  4. 整除的总数
  5. 然后减去,这将为您提供可被K [A..B]
  6. 整除的总数
  7. 检查A%K == 0,如果为真,则+ 1到计数

答案 24 :(得分:0)

这是我的100/100解决方案:

public int solution1(int A, int B, int K) {
    return A == 0 ? B / K - A / K + 1 : (B) / K - (A - 1) / K;
}

0可被任何整数整除,因此如果A为0,则应在答案中加一。

答案 25 :(得分:-1)

假设: A和B是[0..2,000,000,000]范围内的整数; K是[1..2,000,000,000]范围内的整数; A≤B。

int from = A+(K-A%K)%K;
if (from > B) {
    return 0;
}
return (B-from)/K + 1;

答案 26 :(得分:-1)

int solution(int A, int B, int K)
{
    // write your code in C++14 (g++ 6.2.0)
    int counter = 0;

    if (A == B)
        A % K == 0 ? counter++ : 0;
    else
    {
        counter = (B - A) / K;

        if (A % K == 0) counter++;
        else if (B % K == 0) counter++;
        else if ((counter*K + K) > A && (counter*K + K) < B) counter++;
    }

    return counter;
}