如何找到给定范围内的值可以被给定值整除?

时间:2013-05-05 05:55:46

标签: algorithm math

我有三个数字x,y,z。

对于数字x和y之间的范围。

如何找到%与z为0的总数,即x和y之间的数字可以被z整除?

14 个答案:

答案 0 :(得分:25)

可以在O(1)中完成:找到第一个,找到最后一个,找到所有其他的计数。

我假设范围是包容性的。如果您的范围是独占的,请将边界调整为:

  • 找到x之后可被z整除的第一个值。您可以放弃x

    x_mod = x % z;
    
    if(x_mod != 0)
      x += (z - x_mod);
    
  • 找到y之前可被y整除的最后一个值。您可以放弃y

    y -= y % z;
    
  • 找到此范围的大小:

    if(x > y)
      return 0;
    else
      return (y - x) / z + 1;
    

如果可以使用数学floorceil函数,则可以更可读地编写前两部分。最后一部分也可以使用数学函数进行压缩:

 x = ceil  (x, z);
 y = floor (y, z);
 return max((y - x) / z + 1, 0);

如果输入保证是有效范围(x >= y),则最后一次测试或max是不必要的:

 x = ceil  (x, z);
 y = floor (y, z);
 return (y - x) / z + 1;

答案 1 :(得分:14)

2017,答案由于评论重写
数字 n z 的倍数仅为n / z

/是整数除法,意味着除法可能导致的小数被忽略(例如17/5 => 3而不是3.4)。

现在,在 x y 的范围内,有多少 z

让我们看看 m m

0----------------------------------x------------------------y
-m---m---m---m---m---m---m---m---m---m---m---m---m---m---m---

你看到我要去的地方......得到[ x, y ]范围内的倍数,得到 y 的倍数,然后减去之前的倍数em> x ,(x-1) / z

解决方案:( y / z ) - (( x - 1 ) / z )


以编程方式,您可以创建一个函数numberOfMultiples

function numberOfMultiples(n, z) {
   return n / z;
}

获取范围[x, y]

中的倍数
numberOfMultiples(y) - numberOfMultiples(x-1)

该函数是 O(1),不需要循环来获取倍数。

您应该找到的结果示例

  • [30, 90] ÷ 13 => 4
  • [1, 1000] ÷ 6 => 166
  • [100, 1000000] ÷ 7 => 142843
  • [777, 777777777] ÷ 7 => 111111001

对于第一个示例,90 / 13 = 6(30-1) / 13 = 26-2 = 4

---26---39---52---65---78---91--
     ^                      ^
     30<---(4 multiples)-->90

答案 2 :(得分:12)

我也在Codility上遇到过这个。我花了很长时间才愿意承认提出一个好的解决方案,所以我想我会分享我认为优雅的解决方案!

直截了当的方法1/2:

带有循环和计数器的O(N)时间解决方案,当N = 20亿时不切实际。

令人敬畏的方法3:

我们希望某个范围内可被K整除的位数。

简单情况:假设范围[0 .. n * K],N = n * K

  

N / K表示[0,N]中可被K整除的位数,给定N%K = 0(也称为N可被K整除)

离。 N = 9,K = 3,Num digits = | {0 3 6} | = 3 = 9/3

类似地,

  

N / K + 1表示可被K

整除的[0,N]中的位数

离。 N = 9,K = 3,Num digits = | {0 3 6 9} | = 4 = 9/3 + 1

我认为真正理解上述事实是这个问题中最棘手的部分,我无法解释其确切原因。   其余部分归结为前缀总和处理特殊情况

现在我们并不总是有一个以0开头的范围,我们不能假设这两个边界可以被K整除。   可是等等!我们可以通过计算我们自己漂亮的上限和下限以及使用一些减法魔法来解决这个问题:)

  1. 首先找到可被K整除的范围[A,B]中最接近的上限和下限。

    • 上限(更容易):ex。 B = 10,K = 3,new_B = 9 ......模式为B-B%K
    • 下限:ex。 A = 10,K = 3,new_A = 12 ...再试几次,你会看到模式是A - A%K + K
  2. 然后使用上述技术计算以下内容:

    • 确定可被K
    • 整除的[0,B]之间的总位数X.
    • 确定可被K
    • 整除的[0,A]之间的总位数Y.
  3. 通过表达式X - Y

  4. 计算可以被K整除的[A,B]之间的位数

    网站:https://codility.com/demo/take-sample-test/count_div/

    class CountDiv {
        public int solution(int A, int B, int K) {
            int firstDivisible = A%K == 0 ? A : A + (K - A%K);
            int lastDivisible = B%K == 0 ? B : B - B%K; //B/K behaves this way by default.
            return (lastDivisible - firstDivisible)/K + 1;
        }
    }
    

    这是我第一次解释这样的方法。反馈非常感谢:)

答案 3 :(得分:10)

这是Codility Lesson 3的一个问题。对于这个问题,输入保证在有效范围内。我用Javascript回答了它:

function solution(x, y, z) {
    var totalDivisibles =  Math.floor(y / z),
        excludeDivisibles = Math.floor((x - 1) / z),
        divisiblesInArray = totalDivisibles - excludeDivisibles;
   return divisiblesInArray;
}

https://codility.com/demo/results/demoQX3MJC-8AP/

(我实际上想问一下这个页面上的其他一些评论,但我还没有足够的代表点。)

答案 4 :(得分:5)

y-x除以z,向下舍入。如果y%z < x%zx%z == 0,则添加一个。

没有数学证明,除非有人在Perl中提供一个,但测试用例:

#!perl
use strict;
use warnings;
use Test::More;

sub multiples_in_range {
  my ($x, $y, $z) = @_;
  return 0 if $x > $y;
  my $ret = int( ($y - $x) / $z);
  $ret++ if $y%$z < $x%$z or $x%$z == 0;
  return $ret;
}   

for my $z (2 .. 10) {
  for my $x (0 .. 2*$z) {
    for my $y (0 .. 4*$z) {
      is multiples_in_range($x, $y, $z),
         scalar(grep { $_ % $z == 0 } $x..$y),
         "[$x..$y] mod $z";
    }
  }
}

done_testing;

输出:

$ prove divrange.pl 
divrange.pl .. ok      
All tests successful.
Files=1, Tests=3405,  0 wallclock secs ( 0.20 usr  0.02 sys +  0.26 cusr  0.01 csys =  0.49 CPU)
Result: PASS

答案 5 :(得分:3)

这是我在C ++中的简短解决方案,它在编码方面获得了100/100。 :) 在O(1)时间内运行。我希望它不难理解。

int solution(int A, int B, int K) {
    // write your code in C++11
    int cnt=0;
    if( A%K==0 or B%K==0)
        cnt++;
    if(A>=K)
        cnt+= (B - A)/K;
    else
        cnt+=B/K;

    return cnt;
}

答案 6 :(得分:3)

Models.Movie为正整数的区间,包括 A B ,以便namespace Movies.EntityModels { using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; public partial class Movie { public int ID { get; set; } public string Title { get; set; } public Nullable<System.DateTime> ReleaseDate { get; set; } public Nullable<int> ID_Genre { get; set; } public decimal Price { get; set; } public string Rating { get; set; } public int Quantity { get; set; } public virtual Genre Genre { get; set; } } } K 为除数。

很容易看到区间[A;B]中有{{1>}个因素 K

0 <= A <= B

同样,区间N(A) = ⌊A / K⌋ = floor(A / K)中有[0;A]个因素 K

         1K       2K       3K       4K       5K
●········x········x··●·····x········x········x···>
0                    A

然后N(B) = ⌊B / K⌋ = floor(B / K)等于范围[0;B] K 的数量(可被 K 整除的整数的数量) 。 A 不包含,因为已减去 1K 2K 3K 4K 5K ●········x········x········x········x···●····x···> 0 B 包含此点。因此,如果N = N(B) - N(A)为零,结果应该加1:

(A;B]

在PHP中实施

N(A)

在PHP中,A mod K函数的效果可以通过转换为整数类型来实现:

N := N(B) - N(A)

if (A mod K = 0)
  N := N + 1
我认为,这更快。

答案 7 :(得分:2)

(floor)(high/d) - (floor)(low/d) - (high%d==0)

<强>解释

有一个/ d数字可以被d从0.0到a整除。 (d!= 0)

因此(地板)(高/ d) - (地板)(低/ d)将给出在该范围内可分割的数字(低,高)(注意低排除,高包含在此范围内)

现在要从范围中删除高刚刚减去(高%d == 0)

适用于整数,浮点数等(使用fmodf函数表示浮点数)

答案 8 :(得分:0)

不会争取o(1)解决方案,这留给更聪明的人:)只是觉得这是功能编程的完美使用场景。简单明了。

 > x,y,z=1,1000,6
 => [1, 1000, 6] 
 > (x..y).select {|n| n%z==0}.size
 => 166 

编辑:阅读其他的O(1)解决方案后。我感到羞愧。编程让人们懒得思考......

答案 9 :(得分:0)

除法(a / b = c) - 取一组大小a并形成大小为b的组。可以形成的这种尺寸的组的数量c是a和b的商。 - 只不过是范围/间隔内的整数数量0..a](不包括零,但包括a)可以被b整除。

所以根据定义:
Y / Z - 可以被Z整除的] 0..Y]内的整数 和
X / Z - [0..X]中可被Z整除的整数数

因此:
result = [Y / Z] - [X / Z] + x(其中x = 1当且仅当X可被Y整除,否则为0 - 假设给定范围[X..Y]包括X)

例子:
对于(6,12,2)我们有12/2 - 6/2 + 1(6%2 == 0)= 6 - 3 + 1 = 4 // {6,8,10,12} 对于(5,12,2)我们有12/2 - 5/2 + 0(5%2!= 0)= 6 - 2 + 0 = 4 // {6,8,10,12}

答案 10 :(得分:0)

解决方案的时间复杂度将是线性的。

代码段:

int countDiv(int a, int b, int m)
{
    int mod = (min(a, b)%m==0);
    int cnt  = abs(floor(b/m) - floor(a/m))  +  mod;
    return cnt;
}

答案 11 :(得分:0)

在这里n将为您提供数字计数,并打印所有k可除的数字

int a = sc.nextInt();
int b = sc.nextInt();
int k = sc.nextInt();
int first = 0;

if (a > k) {
  first = a + a/k;
} else {
  first = k;
}

int last = b - b%k;

if (first > last) {
  System.out.println(0);
} else {
  int n = (last - first)/k+1;
  System.out.println(n * (first + last)/2);
}

答案 12 :(得分:0)

这是用 Swift编程语言编写的问题的解决方案。

第1步:查找范围为z的第一个数字。

第2步:在被z整除的范围内找到最后一个数字。

第3步:使用数学公式来查找范围内按z可整除的数字。

func solution(_ x : Int, _ y : Int, _ z : Int) -> Int {
    var numberOfDivisible = 0

    var firstNumber: Int
    var lastNumber: Int

    if y == x {
        return x % z == 0 ? 1 : 0
    }
    
    //Find first number divisible by z
    let moduloX = x % z

    if moduloX == 0 {
        firstNumber = x
    } else {
        firstNumber = x + (z - moduloX)
    }

    //Fist last number divisible by z
    let moduloY = y % z
    if moduloY == 0 {
        lastNumber = y
    } else {
        lastNumber = y - moduloY
    }

    //Math formula
    numberOfDivisible = Int(floor(Double((lastNumber - firstNumber) / z))) + 1

    return numberOfDivisible
}

答案 13 :(得分:0)

公共静态int解决方案(int A,int B,int K) {

        int count = 0;

        //If A is divisible by K
        if(A % K == 0)
        {
            count = (B / K) - (A / K) + 1;
        }
        //If A is not divisible by K
        else if(A % K != 0)
        {
            count = (B / K) - (A / K);
        }

        return count;

}