C# 求一个数的因子

C# 求一个数的因子,c#,performance,math,factors,C#,Performance,Math,Factors,我正试图重构这个算法,使其更快。为了提高速度,这里的第一次重构是什么 public int GetHowManyFactors(int numberToCheck) { // we know 1 is a factor and the numberToCheck int factorCount = 2; // start from 2 as we know 1 is a factor, and less than as numberToC

我正试图重构这个算法,使其更快。为了提高速度,这里的第一次重构是什么

public int GetHowManyFactors(int numberToCheck)
    {
        // we know 1 is a factor and the numberToCheck
        int factorCount = 2; 
        // start from 2 as we know 1 is a factor, and less than as numberToCheck is a factor
        for (int i = 2; i < numberToCheck; i++) 
        {
            if (numberToCheck % i == 0)
                factorCount++;
        }
        return factorCount;
    }
public int GetHowManyFactors(int numberToCheck)
{
//我们知道1是一个因子,数字是一个校验
整数因子计数=2;
//从2开始,我们知道1是一个因子,小于numberToCheck是一个因子
对于(int i=2;i
减少你必须达到的高度的界限,因为你可以故意停在数字的平方根处,尽管这确实需要谨慎地挑选出具有奇数因子的正方形,但是它确实有助于减少循环的执行频率。

您可以进行的第一个优化是,您只需要检查数字的平方根。这是因为因子成对出现,其中一个小于平方根,另一个大于平方根

一个例外是,如果
n
是一个精确的平方,那么它的平方根是
n
的一个因子,但不是一对的一部分

例如,如果您的数字为30,则系数为以下几对:

  • 1 x 30
  • 2 x 15
  • 3 x 10
  • 5 x 6
因此,您不需要检查任何大于5的数字,因为一旦您在该对中找到相应的小因子,就可以推断出所有其他因子都存在

在C#中有一种方法可以做到这一点:

public int GetFactorCount(int numberToCheck)
{
整数因子计数=0;
intsqrt=(int)Math.天花(Math.sqrt(numberToCheck));
//从1开始,因为我们希望我们的方法在numberToCheck为0或1时也能工作。
对于(int i=1;i
您还可以使用其他更快的方法,但您可能会发现,这已经足够满足您的需要,特别是当您只需要它来处理32位整数时

  • 您可以将FOR循环的上限限制为numberToCheck/2
  • 在2(如果数字为偶数)或3(对于奇数值)处启动循环计数器。这应该允许您每隔一个数字检查一次,将循环计数再减少50%

    public int GetHowManyFactors(int numberToCheck)
    {
      // we know 1 is a factor and the numberToCheck
      int factorCount = 2; 
    
      int i = 2 + ( numberToCheck % 2 ); //start at 2 (or 3 if numberToCheck is odd)
    
      for( ; i < numberToCheck / 2; i+=2) 
      {
         if (numberToCheck % i == 0)
            factorCount++;
      }
      return factorCount;
    }
    
    public int GetHowManyFactors(int numberToCheck)
    {
    //我们知道1是一个因子,数字是一个校验
    整数因子计数=2;
    int i=2+(numberToCheck%2);//从2开始(如果numberToCheck为奇数,则从3开始)
    对于(;i

  • 看起来这里有一个关于这个主题的冗长讨论:


    希望这对你有帮助,如果你打算经常使用这个函数,你可以使用修改后的埃拉托斯涅斯算法,在数组中以1到最大的间隔存储answars。它将运行initializearray()一次,然后在0(1)中返回答案

    const int Max=1000000;
    int arr[]=新int[Max+1];
    公共无效初始值设定项array()
    {
    
    对于(int i=1;i首先要注意的是,找到所有的素数因子就足够了。一旦有了这些因子,就很容易找到总因子的数目:对于每个素数,在它出现的次数上加1,然后将它们相乘。因此对于12=2*2*3,就有(2+1)*(1+1)=3*2=6个因子

    接下来的事情从第一个方面开始:当你找到一个因子时,把它划分出来,这样得到的数字就更小了。当你把它与你只需要检查当前数的平方根的事实结合起来时,这是一个巨大的改进。例如,考虑n=10714293844487412。天真地,它需要N个步骤。平方根需要sqrt(N)或大约1亿步。但是由于因子2、2、3和953在早期就被发现了,所以实际上只需要检查到100万步——100倍的改进

    另一个改进:你不需要检查每个数字,看它是否能将你的数字除,只需检查素数。如果更方便的话,你可以使用2和奇数,或者2、3和数字6n-1和6n+1(一种基本的轮筛)

    这是另一个很好的改进。如果你能快速确定一个数字是否为素数,你可以进一步减少除法的需要。假设在去掉小因子后,你有120528291333090808192969。即使检查它的平方根也需要很长时间——3000亿步。但是米勒-拉宾测试(非常快——可能10到20纳秒)将显示这个数字是复合的。这有什么帮助?这意味着如果你查到它的立方根,没有发现任何因子,那么只剩下两个素数。如果这个数字是平方的,它的因子是素数;如果这个数字不是平方的,这些数是不同的素数。这意味着你可以将你的“运行总数”乘以3或4,r特别是,要得到最终的答案——即使不知道因素!这比你想象的要大得多:所需的步骤数从3000亿减少到5000万,这是6000倍的改进


    上面提到的唯一问题是,Miller Rabin只能证明数字是复合的;如果给它一个素数,它就不能证明这个数字是素数。在这种情况下,你可能希望编写一个素数证明函数来省去分解数字平方根的工作。(或者,如果你对自己的答案是正确的信心很高,而不是证明答案是正确的,你可以再做几次米勒-拉宾测试。如果一个数字通过15次测试,那么它的合成概率小于十亿分之一。)

    一个易于实现的算法,它将
    public int GetHowManyFactors(int numberToCheck)
    {
      // we know 1 is a factor and the numberToCheck
      int factorCount = 2; 
    
      int i = 2 + ( numberToCheck % 2 ); //start at 2 (or 3 if numberToCheck is odd)
    
      for( ; i < numberToCheck / 2; i+=2) 
      {
         if (numberToCheck % i == 0)
            factorCount++;
      }
      return factorCount;
    }
    
    const int Max =1000000;
    int arr [] = new int [Max+1];
    
    public void InitializeArray()
    {
        for(int i=1;i<=Max;++i)
            arr[i]=1;//1 is factor for everyone
    
        for(int i=2;i<=Max;++i)
            for(int j=i;i<=Max;i+=j)
               ++arr[j];
    }
    public int GetHowManyFactors(int numberToCheck)
    {
       return arr[numberToCheck];
    }
    
     public int solution(int n) {
          var counter = 0;          
          if (n == 1) return 1;
          counter = 2; //1 and itself      
          int sqrtPoint = (Int32)(Math.Truncate(Math.Sqrt(n)));
          for (int i = 2; i <= sqrtPoint; i++)
          {
            if (n % i == 0)
            {
              counter += 2; //  We found a pair of factors.         
            }       
          }
          // Check if our number is an exact square.
          if (sqrtPoint * sqrtPoint == n)
          {
            counter -=1;
          }
    
          return counter;
        }
    
    def solution(N):
    """
    Problem Statement can be found here-
    https://app.codility.com/demo/results/trainingJNNRF6-VG4/
    Codility 100%
    
    Idea is count decedent factor in single travers. ie. if 24 is divisible by 4 then it is also divisible by 8
    Traverse only up to square root of number ie. in case of 24, 4*4 < 24 but 5*5!<24 so loop through only i*i<N
    """
    print(N)
    count = 0
    i = 1
    while i * i <= N:
        if N % i == 0:
            print()
            print("Divisible by " + str(i))
            if i * i == N:
                count += 1
                print("Count increase by one " + str(count))
            else:
                count += 2
                print("Also divisible by " + str(int(N / i)))
                print("Count increase by two count " + str(count))
        i += 1
    return count
    
    if __name__ == '__main__':
    # result = solution(24)
    # result = solution(35)
    result = solution(1)
    print("")
    print("Solution " + str(result))
    
    if (N == 1) return 1;
        int divisors = 0;
        int max = N;
        for (int div = 1; div < max; div++) {
            if (N % div == 0) {
                divisors++;
                if (div != N/div) {
                    divisors++;
                }
            }
            if (N/div < max) {
                max = N/div;
            }
        }
        return divisors;