【问题标题】:Logic to check the number is divisible by 3 or not?检查数字是否能被3整除的逻辑?
【发布时间】:2011-05-10 07:49:02
【问题描述】:

不使用 %, / 或 * ,我必须找到编号。能被3整除吗?

这可能是一个面试问题。

谢谢。

【问题讨论】:

  • 你的意思是它没有提醒吗?所有数字都可以被 3 整除。
  • @Ash:dictionary.reference.com/browse/divisible。 “可分”有两个含义,字面意思是“能够被分”,以及更具体的数学含义。你会在多大程度上打赌调用者在这里真正想要的是非数学含义,或者他在谈论域中的除法而不是整数环? ;-)

标签: c math


【解决方案1】:

有多种方法。最简单的很明显:

int isdivby3(int n) {
    if (n < 0) n = -n;

    while (n > 0) n -= 3;

    return n == 0;
}

但我们可以改进它。任何数字都可以这样表示:(“,”表示包含范围):

Base2 (AKA binary)
(0,1) + 2*(0,1) + 4*(0,1)

Base4
(0,3) + 4*(0,3) + 16*(0,3)

BaseN
(0,N-1) + N*(0,N-1) + N*N*(0,N-1)

现在的诀窍是,当且仅当基数 n 中的 x 的数字和可被 n-1 整除时,数字 x 可以被 n-1 整除。这个技巧以 9 闻名:

1926 = 6 + 2*10 + 9*100 + 1*1000
6+2+9+1 = 8 + 1*10
8+1 = 9 thus 1926 is divisible by 9

现在我们也可以在 base4 中将其应用于 3。很幸运,因为 4 是 2 的幂,我们可以进行二进制位运算。我使用符号number(base)

27(10) = 123(4)
Digitsum
12(4)
Digitsum again
3(4) = Divisible!

现在让我们把它翻译成 C:

int div3(int n) {
    if (n < 0) n = -n;
    else if (n == 0) return 1;

    while (n > 3) {
        int d = 0;

        while (n > 0) {
            d += n & 3;
            n >>= 2;
        }

        n = d;
    }

    return n == 3;
}

速度极快。

【讨论】:

  • 第二个版本+1,虽然它不适用于负输入。它应该,还是仅记录对非负输入有效?
  • @Steve Jessop:很好地抓住了非负输入。我刚回到家,我会做一个更好的版本。
  • @Steve Jessop:用新版本和解释编辑了我的答案。
【解决方案2】:

减去 3 直到你有一个

命中 0 - 数字可以被 3 整除(或)

得到一个小于 0 的数字 - 数字不可整除

 if (number > 0)
 {
        while (number > 0)
        {
            number -= 3;
    }
}
else if( number < 0)
{
    while number < 0:
        number += 3
}
return number == 0

【讨论】:

  • 我们也可以先做temp_no = (number &lt; 0)? -number : number;number = abs (number);来缩短代码,然后继续第一个循环
【解决方案3】:

这是一个相当有效的大数算法。 (嗯,效率不是很高,但考虑到约束是合理的。)

使用sprintf 将其转换为字符串,将每个数字转换回数字。把数字加起来。如果你想出 3、6 或 9,它可以被 3 整除。任何小于 10 的都不能。任何超过 9 的,递归。

例如,要测试您要字符串化的数字 813478902,然后将数字相加得到 42,将这些数字相加得到 6,因此它可以被 3 整除。

【讨论】:

  • 我考虑过放弃这个答案,但 sprintf 在内部使用 %/
  • -1 如果没有%/,您将如何对数字进行字符串化?
  • @nightcracker:问题是说不使用这些运算符,也不是说不使用标准函数大概是使用这些运算符实现的,但未指定如此。在可以调用标准库的子 C 编译器中,这将是一个完全合理的答案,但其自己的 %/* 运算符被神秘地破坏了。 +1 反对 -1,我认为如果面试官施加了不切实际的限制,那么他们应该期待狡猾的答案,并且应该准备一个带有更具体限制的后续问题。
【解决方案4】:

只需使用 for 循环一遍又一遍地减去 3,看看你是否得到 0。如果你得到负数而没有得到 0,那么你知道它不能被 3 整除

【讨论】:

    【解决方案5】:

    打印一个可被 3 整除的计数序列,无需除法或取模运算符。

    注意计数顺序:

    00: 00(00)
    01: 0001
    02: 0010
    03: 00(11)
    04: 0100
    05: 0101
    06: 01(10)
    07: 0111
    08: 1000
    09: 10(01)
    10: 1010
    11: 1011
    12: 11(00)
    13: 1101
    14: 1110
    15: 11(11)
    16: 10000
    17: 10001
    18: 100(10)
    19: 10011
    20: 10100
    21: 101(01)
    

    请注意,可以被三整除的数字的最后两位(显示在括号中)循环通过 {00, 11, 10, 01} 。我们需要检查的是计数序列的最后两位是否有这些位在一个序列中。

    首先我们开始匹配mask = 00 并循环,而第一个数字没有遇到低两位00。当找到匹配项时,我们会执行(mask + 03) &amp; 0x03,这会为我们提供集合中的下一个掩码。我们继续将下一个计数的最后两位与11 匹配。可以由((count &amp; 3) == mask)完成

    代码是

    #include <stdio.h>
    
    int main (void)
    {
      int i=0;
      unsigned int mask = 0x00;
    
      for (i=0; i<100;i++)
      {
        if ((i&0x03) == mask)
        {
          printf ("\n%d", i);
          mask = (mask + 3) & 0x03;
        }
      }
      printf ("\n");
      return 0;
    }
    

    这不是一般的。最好是使用@nightcracker 建议的解决方案

    如果你真的想在不使用除法操作的情况下实现除法操作。我会告诉你看一下非恢复除法算法,这可以在程序中通过位运算符进行大量位操作来完成。这里有一些链接和参考。

    Wikipedia Link

    Here is a demo from UMass

    也可以看看Computer Organization by Carl Hamacher, Zvonko Vranesic, Safwat Zaky

    【讨论】:

      【解决方案6】:
      number = abs(number)
      
      while (number > 0)
      {
         number -= 3;
      }
      
      return number == 0
      

      【讨论】:

        【解决方案7】:

        假设 n 是有问题的数字,并且它是非负数。

        如果 n 为 0,则它可以被 3 整除;否则 n = (2^p)*(2*n1+1) 且 n 可被 3 整除当且仅当 2*n1+1 是,当且仅当 ak>=0 且 2*n1+1 = 3*(2*k +1) iff n1 = 3*k+1 iff n1=1 或 n1> 1 且 n1-1 可被 3 整除。所以:

        int ism3( int n)
        {   for(;n;)
            {    while( !(n & 1)) n >>= 1;
                 n >>= 1;
                 if ( n == 0) return 0;
                 n-= 1;
            }
            return 1;
         }
        

        【讨论】:

          【解决方案8】:

          知道一个数是否能被 3 整除的最简单方法是将其所有数字相加,然后除以 3。如果数字之和能被 3 整除,那么这个数字本身就能被 3 整除。例如, 54467565687 能被 3 整除,因为 5+4+4+6+7+5+6+5+6+8+7 = 63,而 63 能被 3 整除。所以,不管这个数有多大,你只需将所有数字相加,然后从该总和的值中减去 3,直到得到小于 3 的结果,即可找到它是否可被 3 整除。如果此结果为 0,则总和的值可被 3 整除(因此原始数字),否则总和不能被 3 整除(并且原始数字也不能整除)。它比从原始数字连续减去 3 快得多(当然,特别是如果它是一个大数字)并且没有除法。嗯,abraço a todos。

          阿图尔

          【讨论】:

            【解决方案9】:

            如果一个数字的二进制交替数字和为零,则该数字可以被三整除:

            bool by3(int n) {
              int s=0;
              for (int q=1; n; s+=q*(n&1), n>>=1, q*=-1);
              return !s;
            }
            

            【讨论】:

              【解决方案10】:

              您可以使用用户反馈:

              int isDivisibleBy3(int n)
              {
                 int areDivisibleBy3[] = {};
                 for(int i = 0; i < 0; i++)
                 {
                     if(n == areDivisibleBy3[i])
                     {
                         return 1;
                     }
                 }
              
                 return 0;
              }
              

              当用户报告错误指出可被 3 整除的数字未给出正确结果时,您只需将该数字添加到数组中并增加与 for 循环条件中比较的数字 i

              这很好,因为这样您就不必担心用户从不使用的数字。

              不要忘记在用户报告错误时添加单元测试!

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-10-25
                • 1970-01-01
                • 2011-01-06
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多