web-dev-qa-db-ja.com

与えられた数のすべての因子を見つける最良の方法

Xに均等に分割されるすべての数値。

私はそれを返します:4、2、1

編集:私はそれが宿題に聞こえることを知っています。一部の製品テーブルに半ランダムテストデータを入力する小さなアプリを書いています。プロパティの2つは、ItemMaximumとItem Multiplierです。乗数が、さらに1つのアイテムを購入すると注文が最大許容数を超えるという非論理的な状況が発生しないことを確認する必要があります。したがって、因子は私のテストデータの有効な値のリストを提供します。

edit ++:これは、結局のところ、皆さんからの助けのおかげです。再度、感謝します!

edit#:3つの異なるバージョンを作成して、どちらがより良いかを確認し、小さい数と非常に大きい数の因数分解に対してテストしました。結果を貼り付けます。

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

private IEnumerable<int> GetFactors3(int x)
{            
    for (int factor = 1; factor * factor <= x; factor++)
    {
        if (x % factor == 0)
        {
            yield return factor;
            if (factor * factor != x)
                yield return x / factor;
        }
    }
}

private IEnumerable<int> GetFactors1(int x)
{
    int max = (int)Math.Ceiling(Math.Sqrt(x));
    for (int factor = 1; factor < max; factor++)
    {
        if(x % factor == 0)
        {
            yield return factor;
            if(factor != max)
                yield return x / factor;
        }
    }
}

ダニ。数20を因数分解する場合、それぞれ5回:

  • GetFactors1〜5、445、881
  • GetFactors2-4、308、234
  • GetFactors3-2、913、659

数値20000を因数分解する場合、それぞれ5回:

  • GetFactors1〜5、644、457
  • GetFactors2〜12、117、938
  • GetFactors3〜3、108、182
30
Echostorm

疑似コード:

  • 1から数値の平方根までループし、インデックス "i"を呼び出します。
  • number mod iが0の場合、因子のリストにiおよびnumber/iを追加します。

realocode:

public List<int> Factor(int number) {
    List<int> factors = new List<int>();
    int max = (int)Math.Sqrt(number);  //round down
    for(int factor = 1; factor <= max; ++factor) { //test from 1 to the square root, or the int below it, inclusive.
        if(number % factor == 0) {
            factors.Add(factor);
            if(factor != number/factor) { // Don't add the square root twice!  Thanks Jon
                factors.Add(number/factor);
            }
        }
    }
    return factors;
}

Jon Skeetが述べたように、これをIEnumerable<int>として実装することもできます-リストに追加する代わりに yield を使用します。 List<int>の利点は、必要に応じて返す前にソートできることです。次に、ハイブリッドアプローチでソートされた列挙子を取得し、最初の要素を生成し、ループの各反復で2番目の要素を格納し、逆の順序で格納された各値を生成することができます。

また、負の数が関数に渡された場合を処理するために何かをしたいと思うでしょう。

38

%(剰余)演算子は、ここで使用するものです。 x % y == 0の場合、xyで割り切れます。 (0 < y <= xと仮定)

これを、イテレータブロックを使用してIEnumerable<int>を返すメソッドとして個人的に実装します。

20
Jon Skeet

非常に遅いですが、受け入れられた回答(しばらく前)は正しい結果を与えませんでした。

Merlynのおかげで、修正されたサンプルの下の「最大」として四角形の理由がわかりました。エコーストームからの答えはより完全に思えますが。

    public static IEnumerable<uint> getFactors(uint x)
    {
        for (uint i = 1; i*i <= x; i++)
        {
            if (0 == (x % i))
            {
                yield return i;
                if (i != (x / i))
                {
                    yield return x / i;
                }
            }
        }
    }
14
call me Steve

拡張メソッドとして:

    public static bool Divides(this int potentialFactor, int i)
    {
        return i % potentialFactor == 0;
    }

    public static IEnumerable<int> Factors(this int i)
    {
        return from potentialFactor in Enumerable.Range(1, i)
               where potentialFactor.Divides(i)
               select potentialFactor;
    }

次に使用例を示します。

        foreach (int i in 4.Factors())
        {
            Console.WriteLine(i);
        }

パフォーマンスではなく、明確にするために最適化したことに注意してください。 iの値が大きい場合、このアルゴリズムには時間がかかる場合があります。

5
Jay Bazuzi

ここでも、他の人が述べたように、平方根まで数えています。パフォーマンスの向上を望んでいるなら、人々はそのアイデアに惹かれていると思います。ソフトウェアをテストした後、最初にエレガントなコードを書き、後でパフォーマンスを最適化したいと思います。

それでも、参考までに、これは次のとおりです。

    public static bool Divides(this int potentialFactor, int i)
    {
        return i % potentialFactor == 0;
    }

    public static IEnumerable<int> Factors(this int i)
    {
        foreach (int result in from potentialFactor in Enumerable.Range(1, (int)Math.Sqrt(i))
                               where potentialFactor.Divides(i)
                               select potentialFactor)
        {
            yield return result;
            if (i / result != result)
            {
                yield return i / result;
            }
        }
    }

結果の可読性が大幅に低下するだけでなく、要因もこのように乱れます。

2
Jay Bazuzi

私はそれを怠惰なやり方でやった。私はあまり知りませんが、シンプルさがエレガンスを意味することもあると言われています。これは、これを行う1つの可能な方法です。

    public static IEnumerable<int> GetDivisors(int number)
    {
        var searched = Enumerable.Range(1, number)
             .Where((x) =>  number % x == 0)
             .Select(x => number / x);

        foreach (var s in searched)          
            yield return s;
    }

[〜#〜] edit [〜#〜]:Kraang Primeが指摘したように、この関数は整数の制限を超えることはできず、(確かに)この問題を処理する最も効率的な方法ではありません。

2
Spencer

別のLINQスタイルとO(sqrt(n))複雑さを維持するための結合

        static IEnumerable<int> GetFactors(int n)
        {
            Debug.Assert(n >= 1);
            var pairList = from i in Enumerable.Range(1, (int)(Math.Round(Math.Sqrt(n) + 1)))
                    where n % i == 0
                    select new { A = i, B = n / i };

            foreach(var pair in pairList)
            {
                yield return pair.A;
                yield return pair.B;
            }


        }
2
Pablo Retyk

そしてもう一つの解決策。読みやすいという以外の利点があるかどうかはわかりません。

List<int> GetFactors(int n)
{
    var f = new List<int>() { 1 };  // adding trivial factor, optional
    int m = n;
    int i = 2;
    while (m > 1)
    {
        if (m % i == 0)
        {
            f.Add(i);
            m /= i;
        }
        else i++;
    }
    // f.Add(n);   // adding trivial factor, optional
    return f;
}
1
TaW

2から始めて、チェックした数値に基づいて継続的に再計算されている上限値に向かうのも意味がないのではないでしょうか。 N/iを参照してください(Nは係数を見つけようとしている数値で、iは現在チェックする数値です...)理想的には、modの代わりに、N/iも返す除算関数を使用します。それが持っているかもしれない残りとして。このようにして、1つの除算演算を実行して、上限と、除算をチェックする残りの部分を再作成します。

Math.DivRem http://msdn.Microsoft.com/en-us/library/wwc1t3y1.aspx

1
mspmsp

Doubleを使用する場合、次のように機能します。1から因数分解したい数まで反復するforループを使用します。各反復で、因数分解する数値をiで割ります。 (数値/ i)%1 == 0の場合、数値/ iの商と同様に、iは因子です。これらの1つまたは両方をリストに入れると、すべての要素が得られます。

1
JEJoll

JavaScriptコードで整数の素因数を取得するプログラム。

function getFactors(num1){
    var factors = [];
    var divider = 2;
    while(num1 != 1){
        if(num1 % divider == 0){
            num1 = num1 / divider;
            factors.Push(divider);
        }
        else{
            divider++;
        }
    }
    console.log(factors);
    return factors;
}

getFactors(20);
0
honey