【问题标题】:Efficiently finding all divisors of a number有效地找到一个数字的所有除数
【发布时间】:2011-08-13 04:12:34
【问题描述】:

所以我只想找到给定数字的所有除数(数字本身除外)。 目前,我有这个:

public static List<int> proper_divisors(int x)
{
    List<int> toreturn = new List<int>();
    toreturn.Add(1);
    int i = 0;
    int j=1;
    int z = 0;
    while (primes.ElementAt(i) < Math.Sqrt(x))
    {
        if (x % primes.ElementAt(i) == 0)
        {
            toreturn.Add(primes.ElementAt(i));
            toreturn.Add(x / primes.ElementAt(i));
            j = 2;
            z = (int)Math.Pow(primes.ElementAt(i), 2);
            while (z < x)
            {
                if (x % z == 0)
                {
                    toreturn.Add(z);
                    toreturn.Add(x / z);
                    j++;
                    z = (int)Math.Pow(primes.ElementAt(i), j);
                }
                else
                {
                    z = x;
                }
            }
        }
        i++;
    }
    toreturn = toreturn.Distinct().ToList<int>();
    return toreturn;
}

其中 primes 是一个素数列表(假设它是正确的,并且足够大)。 该算法的工作原理是它找到所有主要因素,但不是所有因素(即给定 34534,它返回 {1,2,17267,31,1114} 但错过 {62, 557} 因为 62 是一个组合,因此也错过了 557。

我也尝试过获取一个数字的质因数,但我不知道如何将其转换为所有正确组合的列表。

该算法的代码如下:

public static List<int> prime_factors(int x)
{
    List<int> toreturn = new List<int>();
    int i = 0;
    while (primes.ElementAt(i) <= x)
    {
        if (x % primes.ElementAt(i) == 0)
        {
            toreturn.Add(primes.ElementAt(i));
            x = x / primes.ElementAt(i);
        }
        else
        {
            i++;
        }
    }
    return toreturn;
}

关于如何修复第一个或如何从第二个创建组合列表的任何想法(我更喜欢这样,因为它会更快)?

【问题讨论】:

标签: c# prime-factoring factorization


【解决方案1】:

由于您已经有了一个主要因素的列表,您要做的是计算该列表的幂集。

现在,一个问题是列表中可能有重复项(例如,20 = 2 * 2 * 5 的素数因子),但集合不允许重复项。因此,我们可以通过将列表中的每个元素投影到 {x, y} 形式的结构中来使列表中的每个元素唯一,其中 x 是素数,y 是列表中素数的索引。

var all_primes = primes.Select((x, y) => new { x, y }).ToList();

现在,all_primes 是 {x, y} 形式的列表,其中 x 是素数,y 是列表中的索引。

然后我们计算幂集(下面GetPowerSet的定义):

var power_set_primes = GetPowerSet(all_primes);

因此,power_set_primesIEnumerable&lt;IEnumerable&lt;T&gt;&gt;,其中 T 是匿名类型 {x, y},其中 x 和 y 是 int 类型。

接下来,我们计算幂集中每个元素的乘积

foreach (var p in power_set_primes)
{
    var factor = p.Select(x => x.x).Aggregate(1, (x, y) => x * y);
    factors.Add(factor);
}

把它们放在一起:

var all_primes = primes.Select((x, y) => new { x, y }).ToList(); //assuming that primes contains duplicates.
var power_set_primes = GetPowerSet(all_primes);
var factors = new HashSet<int>();

foreach (var p in power_set_primes)
{
    var factor = p.Select(x => x.x).Aggregate(1, (x, y) => x * y);
    factors.Add(factor);
}

来自http://rosettacode.org/wiki/Power_Set,了解 powerset 的实现。

public IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
    return from m in Enumerable.Range(0, 1 << list.Count)
           select
               from i in Enumerable.Range(0, list.Count)
               where (m & (1 << i)) != 0
               select list[i];
}

【讨论】:

  • 我不关注。 Factors 是我发现的主要因素的列表?而且由于我想要的是乘以小于或等于数字的因素的所有组合,因此必须有更好的方法。
  • 这并不真正起作用。目前,如果素数超过自身的次数,这将不会给出正确的因子(这种情况经常发生,即每次 9 都是一个因子......)
  • 我不需要...返回列表中有多个素数副本的事实已经绰绰有余,因为我需要获取乘积小于数字的所有组合反正
  • 啊,我明白你的意思了。您需要获得另一条评论中提到的笛卡尔积......
  • 对于其他查看此内容的人,只需删除 .x,代码即可正常工作
【解决方案2】:

有一个类似的问题before,它有一个使用 IEnumerable 的有趣解决方案。如果您想要所有除数而不是因数,并假设您至少使用 C# 3.0,您可以使用如下内容:

static IEnumerable<int> GetDivisors(int n)
{
    return from a in Enumerable.Range(2, n / 2)
           where n % a == 0
           select a;                      
}

然后像这样使用它:

foreach(var divisor in GetDivisors(10))
    Console.WriteLine(divisor);

或者,如果你想要一个列表,只需:

List<int> divisors = GetDivisors(10).ToList();

【讨论】:

  • 再次,这是蛮力的好方法。但鉴于我有一个必要素数的列表,没有理由这样做。
  • 所以,如果你有这个数字的所有质因数并且只想要它们之间的所有组合,为什么不使用笛卡尔积,有点像:from x in primes from y in primes where x != y select x * y?这可以解决您的问题,前提是您的素数中有 1(否则 .Concat(primes) 会解决该问题)
  • 但是我必须乘以的因子的数量是未知的。可能是三个或更多......
  • 我明白你的意思。您要问的是一种方法,可以让您拥有所有可能的主要因素组合。这可以通过一些组合算法来解决,在我看来,正确实现并不是那么简单。除此之外,您可能会最终得到一个解决方案,在尝试优化速度的同时,它的性能可能比更简单的方法低,而且可读性也差很多。也许您可能想考虑先编写一个可读的解决方案,然后在给定任务的性能不可接受时尝试对其进行优化。
  • 在搜索素数因数时,此方法无效。例如n=5 它给出一个空列表!
猜你喜欢
  • 2015-01-01
  • 2015-11-17
  • 1970-01-01
  • 2013-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-24
  • 1970-01-01
相关资源
最近更新 更多