从质因数(递归地)重构一个除数列表

本文关键字:一个 数列 列表 重构 质因数 递归 | 更新日期: 2023-09-27 17:54:08

我有一个素数因子的列表,格式如下:Int [] factors ={因子个数,factor1, factor1,factor2,poweroffactor2,…};

我想要得到动态嵌套的for循环的等效物,它将产生所有的因子,其中for循环将看起来像这样:

int currentpod = 1;
for(int i=0;i<factors[2];i++)
{
    currentprod *= Math.Pow(factors[1],i);
    for(int j=0;j<factors[4];j++)
    {
         currentprod *= Math.Pow(factors[3],i);
         ...
         //When it hits the last level (i.e. the last prime in the list, it writes it to a list of divisors
         for(int k=0;k<factors[6];k++)
         {
              divisors.Add(Math.Pow(factors[5],k)*currentprod);
         }
    }
}

不幸的是,这段代码爆炸了,因为currentprod没有得到足够的重置。下面是我用来尝试完成这个任务的实际代码:

        public static List<int> createdivisorlist(int level, List<int> factors, int[] prodsofar,List<int> listsofar)
    {
        if (level == factors[0])
        {
            prodsofar[0] = 1;
        }
        if (level > 1)
        {
            for (int i = 0; i <= 2*(factors[0]-level)+1; i++)
            {
                prodsofar[level-1] = prodsofar[level] * (int)Math.Pow(factors[2 * (factors[0] - level) + 1], i);
                listsofar =  createdivisorlist(level - 1, factors, prodsofar, listsofar);
            }
        }
        else
        {
            for (int i = 0; i <= factors.Last(); i++)
            {
                listsofar.Add(prodsofar[level] * (int)Math.Pow(factors[2 * (factors[0] - level) + 1], i));
                if (listsofar.Last() < 0)
                {
                    int p = 0;
                }
            }
            return listsofar;
        }
        return listsofar;
    }

的原始参数是:Level = factors[0]因子=上面指定格式的质数因子列表Prodsofar[] =所有元素都是1Listsofar =一个空列表

我怎么能重置prodso到目前为止,使它不"爆炸",而只是做什么我概述?注意:作为测试,请使用2310,因为在当前代码中,要添加的除数是负的(int overflow)。

从质因数(递归地)重构一个除数列表

您所想到的递归算法的思想是保持一个累加的除数列表。为此,下面的代码是如何做到这一点的示例(保留您的表示法:因为"除数"answers"因子"意味着完全相同的东西,多个术语是不幸的):

public static List<int> divisors(int[] factors, List<int> foundfactors, int level)
{
    if(level > factors[0]) return foundfactors;
    int current = 1;
    List<int> curpowers = new List<int>();
    for(int i=0; i<factors[2*level]+1; ++i)
    {
        curpowers.Add(current);
        current *= factors[2*level-1];
    }
    List<int> newfactors = new List<int>();
    foreach(int d in foundfactors)
        foreach(int n in curpowers)
            newfactors.Add(d*n);
    return divisors(factors, newfactors, level + 1);
}

用类似

的东西命名
    // 600 = 2^3 * 3^1 * 5^2
    int[] pfactors = new int[] {3, 2,3, 3,1, 5,2};
    List<int> foundfactors = new List<int> {1};
    List<int> ds = divisors(pfactors, foundfactors, 1);
    foreach(int d in ds) Console.WriteLine(d);

打印600的所有24个因数

这只是一个"生成所有组合"的问题。你可以使用你最喜欢的搜索引擎在c#中找到这样做的方法;下面是一个例子。

请注意,您需要将"prime p used k times"映射到{p, p, p, ...} (k times)。

这与公认的答案相似——对于试图理解发生了什么事的人来说,这可能更清楚一些。

def divisors_from_primes(primes, v = 1)
  if primes.empty?
    puts v
    return
  end
  p = primes.keys.first
  m = primes[p]
  primes.delete(p)
  0.upto(m) do |power|
    divisors_from_primes(primes, v * (p**power))
  end  
  primes[p] = m
end
/* 72 = 2**3 * 3**2  */
divisors_from_primes({ 2 => 3, 3 => 2})

所以在这个例子(72)中,它基本上是一个递归版本的:

0.upto(3) do |twopower|
  0.upto(2) |threepower|
    puts 2**twopower * 3**threepower
  end
end