【问题标题】:How to check whether a no is factorial or not?如何检查否是否是阶乘?
【发布时间】:2014-02-07 14:56:50
【问题描述】:

我有一个问题,然后给定一些输入数字 n,我们必须检查这个 no 是否是其他 no 的阶乘。

输入 24,输出为真
输入 25,输出错误
我为此编写了以下程序:-

    int factorial(int num1) 
    {
        if(num1 > 1)
        {
           return num1* factorial(num1-1) ; 
        }
        else
        {
          return 1 ; 
        }
    }

    int is_factorial(int num2) 
    {
        int fact = 0  ; 
        int i = 0  ;
        while(fact < num2)
        {
             fact = factorial(i) ; 
             i++ ;
        }
        if(fact == num2)
        {
             return 0  ;
        }
        else
        {
             return -1;
        }
    }

这两个功能似乎都可以正常工作。
当我们为大量输入重复提供它们时,is_factorial 将重复调用factorial,这真的是浪费时间。
我也尝试过维护一个阶乘表

那么,我的问题是,有没有更有效的方法来检查一个数字是否是阶乘?

【问题讨论】:

  • 有一个已知阶乘数组......
  • 我试过了。抱歉,我忘了在问题中提及。
  • “我试过了。” - 那意味着什么?
  • 定义优雅。你的问题是“有没有更有效的方法来检查一个数字是否是阶乘?” - 答案是:最有效的方法是......鼓声......拥有一系列已知的阶乘。
  • “我正在寻找一个比在数组中存储阶乘列表更优雅的解决方案。”——在哪里?一个明显的优雅解决方案直接来自阶乘的定义。另一种有效的方法是动态构建阶乘表,看看其中是否包含数字。

标签: c performance algorithm factorial


【解决方案1】:

如果这个数是阶乘,那么它的因数是 1..n 对于某些 n。

假设 n 是一个整数变量,我们可以这样做:

int findFactNum(int test){
  for(int i=1, int sum=1; sum <= test; i++){
    sum *= i; //Increment factorial number
    if(sum == test)
        return i; //Factorial of i

   }
return 0; // factorial not found
}

现在将数字 24 传递给这个功能块,它应该可以工作了。此函数返回您刚刚传递的阶乘数字。

【讨论】:

    【解决方案2】:

    您可以创建一个包含阶乘列表的数组:
    就像在下面的代码中一样,我创建了一个包含最多 20 个阶乘的数组。 现在你只需要输入数字并检查它是否在数组中..

    #include <stdio.h>
    int main()
    {
        int b[19];
        int i, j = 0;
        int k, l;
    
        /*writing factorials*/
        for (i = 0; i <= 19; i++) {
            k = i + 1;
            b[i] = factorial(k);
        }
        printf("enter a number\n");
        scanf("%d", &l);
        for (j = 0; j <= 19; j++) {
            if (l == b[j]) {
                printf("given number is a factorial of %d\n", j + 1);
            }
            if (j == 19 && l != b[j]) {
                printf("given number is not a factorial number\n");
            }
        }
    }
    int factorial(int a)
    {
        int i;
        int facto = 1;
        for (i = 1; i <= a; i++) {
            facto = facto * i;
        }
        return facto;
    }
    

    【讨论】:

      【解决方案3】:
      public long generateFactorial(int num){
          if(num==0 || num==1){
              return 1;
          } else{
              return num*generateFactorial(num-1);
          }
      }
      public int getOriginalNum(long num){
          List<Integer> factors=new LinkedList<>();   //This is list of all factors of num
          List<Integer> factors2=new LinkedList<>();     //List of all Factorial factors for eg: (1,2,3,4,5) for 120 (=5!)
          int origin=1;               //number representing the root of Factorial value ( for eg origin=5 if num=120)
          for(int i=1;i<=num;i++){
              if(num%i==0){
                  factors.add(i);     //it will add all factors of num including 1 and num
              }
          }
      
          /*
           * amoong "factors" we need to find  "Factorial factors for eg: (1,2,3,4,5) for 120"
           * for that create new list factors2
           * */
          for (int i=1;i<factors.size();i++) {         
              if((factors.get(i))-(factors.get(i-1))==1){   
      
                  /*
                   * 120 = 5! =5*4*3*2*1*1   (1!=1 and 0!=1 ..hence 2 times 1)
                   * 720 = 6! =6*5*4*3*2*1*1
                   * 5040 = 7! = 7*6*5*4*3*2*1*1
                   * 3628800 = 10! =10*9*8*7*6*5*4*3*2*1*1  
                   * ... and so on
                   * 
                   * in all cases any 2 succeding factors  inf list having diff=1
                   * for eg: for 5 : (5-4=1)(4-3=1)(3-2=1)(2-1=1)(1-0=1)  Hence difference=1 in each case
                   * */
      
                  factors2.add(i);  //in such case add factors from 1st list " factors " to " factors2"
              } else break; 
              //else if(this diff>1) it is not factorial number hence break
              //Now last element in the list is largest num and ROOT of Factorial
          }
          for(Integer integer:factors2){
              System.out.print(" "+integer);
          }
          System.out.println();
      
          if(generateFactorial(factors2.get(factors2.size()-1))==num){   //last element is at  "factors2.size()-1"
              origin=factors2.get(factors2.size()-1);
          }
          return origin; 
      
          /*
           * Above logic works only for 5! but not other numbers ?? 
           * */
      }
      

      【讨论】:

      • 问题被标记为C。这个答案不在C 中。这个答案是错误的。
      【解决方案4】:
      #include<stdio.h>
      main()
      {
            float i,a;
            scanf("%f",&a);
            for(i=2;a>1;i++)
            a/=i;
            if(a==1)
            printf("it is a factorial");
            else
            printf("not a factorial");
      }
      

      【讨论】:

      • printf("it is a factorial",a); ?
      • 谢谢!!已经改正了
      【解决方案5】:

      像这样连续计算阶乘很浪费,因为当你在做(x+1)!(x+2)! 等时,你正在重复在x! 中完成的工作。


      一种方法是在给定范围内维护一个阶乘列表(例如所有 64 位无符号阶乘),然后将其与之进行比较。考虑到阶乘的价值增长速度有多快,这个列表不会很大。事实上,这是一个 C 元程序,它实际上为您生成了函数:

      #include <stdio.h>
      
      int main (void) {
          unsigned long long last = 1ULL, current = 2ULL, mult = 2ULL;
          size_t szOut;
      
          puts ("int isFactorial (unsigned long long num) {");
          puts ("    static const unsigned long long arr[] = {");
          szOut = printf ("        %lluULL,", last);
          while (current / mult == last) {
              if (szOut > 50)
                  szOut = printf ("\n       ") - 1;
              szOut += printf (" %lluULL,", current);
              last = current;
              current *= ++mult;
          }
          puts ("\n    };");
          puts ("    static const size_t len = sizeof (arr) / sizeof (*arr);");
          puts ("    for (size_t idx = 0; idx < len; idx++)");
          puts ("        if (arr[idx] == num)");
          puts ("            return 1;");
          puts ("    return 0;");
          puts ("}");
      
          return 0;
      }
      

      当你运行它时,你会得到这个函数:

      int isFactorial (unsigned long long num) {
          static const unsigned long long arr[] = {
              1ULL, 2ULL, 6ULL, 24ULL, 120ULL, 720ULL, 5040ULL,
              40320ULL, 362880ULL, 3628800ULL, 39916800ULL,
              479001600ULL, 6227020800ULL, 87178291200ULL,
              1307674368000ULL, 20922789888000ULL, 355687428096000ULL,
              6402373705728000ULL, 121645100408832000ULL,
              2432902008176640000ULL,
          };
          static const size_t len = sizeof (arr) / sizeof (*arr);
          for (size_t idx = 0; idx < len; idx++)
              if (arr[idx] == num)
                  return 1;
          return 0;
      }
      

      即使对于 64 位阶乘,它也非常简短且高效。


      如果您使用纯编程方法(没有查找表),则可以使用阶乘数为的属性:

      1 x 2 x 3 x 4 x ... x (n-1) x n
      

      对于n 的某个值。

      因此,您可以简单地开始将您的测试编号除以2,然后是3,然后是4,依此类推。两种情况中的一种会发生。

      首先,您可能会得到一个非整数结果,在这种情况下它不是阶乘。

      其次,您最终可能会得到来自部门的1,在这种情况下,它一个阶乘。

      假设您的部门是完整的,以下代码将是一个很好的起点:

      int isFactorial (unsigned long long num) {
          unsigned long long currDiv = 2ULL;
          while (num != 1ULL) {
              if ((num % currDiv) != 0)
                  return 0;
              num /= currDiv;
              currDiv++;
          }
          return 1;
      }
      

      然而,效率,最好的选择可能是第一个。将计算成本转移到构建阶段而不是运行时。在计算成本比表查找高的情况下,这是一个标准技巧。

      可以甚至通过使用查找表的二进制搜索来使其模式高效,但考虑到其中只有 20 个元素,这可能不是必需的。

      【讨论】:

        【解决方案6】:

        您可以通过简单检查数字是奇数还是偶数来加快至少一半的情况(使用 %2)。没有奇数(除了 1)可以是任何其他数的阶乘

        【讨论】:

        • 另外,如果您对高范围不是很感兴趣(您使用的是 int),那么您只需要一个包含 13 个值的数组。除此之外,没有其他阶乘将适合 int 范围。因此,您可以获得最佳情况 O(1) 时间和工作情况 O(nlog(n)) 时间。
        猜你喜欢
        • 2020-01-28
        • 2021-12-31
        • 1970-01-01
        • 2019-09-07
        • 1970-01-01
        • 2015-08-26
        • 1970-01-01
        • 1970-01-01
        • 2020-12-23
        相关资源
        最近更新 更多