最小的倍数

时间:2013-01-30 08:22:38

标签: c# performance

我在这里用C#编写了一个代码,它找到了从1到20的所有数字的最小倍数。但是,我发现它效率非常低,因为在生成正确答案之前执行需要一段时间。我想知道我可以采取哪些不同的方法来改进代码。谢谢。

        public static void SmallestMultiple()
    {
        const ushort ARRAY_SIZE = 21;
        ushort[] array = new ushort[ARRAY_SIZE];
        ushort check = 0;
        for (uint value = 1; value < uint.MaxValue; value++)
        {
            for (ushort j = 1; j < ARRAY_SIZE; j++)
            {
                array[j] = j;
                if (value % array[j] == 0)
                {   
                    check++;
                }
            }
            if (check == 20)
            {
                Console.WriteLine("The value is {0}", value);
            }
            else
            {
                check = 0;
            }
        }
    }

6 个答案:

答案 0 :(得分:2)

由于结果也必须可以被19(这是最大的素数)整除,最多20,你可能只能循环19的倍数。

这应该会使结果快19倍。

这是执行此操作的代码:

public static void SmallestMultiple()
{
    const ushort ARRAY_SIZE = 21;
    ushort[] array = new ushort[ARRAY_SIZE];
    ushort check = 0;

    for (uint value = 19; value < uint.MaxValue; value += 19)
    {
        for (ushort j = 1; j < ARRAY_SIZE; j++)
        {
            array[j] = j;
            if (value % array[j] == 0)
            {
                check++;
            }
        }
        if (check == 20)
        {
            Console.WriteLine("The value is {0}", value);
            return;
        }
        else
        {
            check = 0;
        }
    }
}

在我的机器上,它会在2秒多的时间内找到结果232792560

更新

另外,请注意,初始程序在达成解决方案时并没有停止;我添加了return语句以使其停止。

答案 1 :(得分:2)

您只是在寻找从1到20的LCM数字:

formula

使用Euclidean algorithm可以有效地计算GCD。

我不知道C#,但这个Python解决方案不应该难以翻译:

def gcd(a, b):
    while b != 0:
       a, b = b, a % b

    return a

def lcm(a, b):
    return (a * b) / gcd(a, b)

numbers = range(1, 20 + 1)

print reduce(numbers, lcm)

它也很快:

>>> %timeit reduce(lcm, range(1, 20000))
1 loops, best of 3: 258 ms per loop

答案 2 :(得分:2)

    static void Main(string[] args)
    {
        int[] nums = Enumerable.Range(1, 20).ToArray();
        int lcm = 1;

        for (int i = 0; i < nums.Length; i++)
        {
            lcm = LCM(lcm, nums[i]);
        }
        Console.WriteLine("LCM = {0}", lcm);
    }

    public static int LCM(int value1, int value2)
    {
        int a = Math.Abs(value1);
        int b = Math.Abs(value2);

        // perform division first to avoid potential overflow
        a = checked((a / GCD(a, b)));
        return checked((a * b));
    }

    public static int GCD(int value1, int value2)
    {
        int gcd = 1;     // Greates Common Divisor

        // throw exception if any value=0
        if (value1 == 0 || value2 == 0)
        {
            throw new ArgumentOutOfRangeException();
        }

        // assign absolute values to local vars
        int a = Math.Abs(value1);            // local var1
        int b = Math.Abs(value2);            // local var2

        // if numbers are equal return the first
        if (a == b) { return a; }
            // if var "b" is GCD return "b"
        if (a > b && a % b == 0) { return b; }
            // if var "a" is GCD return "a"
        if (b > a && b % a == 0) { return a; }

        // Euclid algorithm to find GCD (a,b):
        // estimated maximum iterations: 
        // 5* (number of dec digits in smallest number)
        while (b != 0)
        {
            gcd = b;
            b = a % b;
            a = gcd;
        }
        return gcd;
    }
}

来源:Fast Integer Algorithms: Greatest Common Divisor and Least Common Multiple, .NET solution

答案 3 :(得分:1)

编辑: v2.0 - 主要速度提升

以w0lf的解决方案为基础。更快的解决方案:

public static void SmallestMultiple()
{
    // this is a bit quick and dirty
    //   (not too difficult to change to generate primeProduct dynamically for any range)
    int primeProduct = 2*3*5*7*11*13*17*19;
    for (int value = primeProduct; ; value += primeProduct)
    {
       bool success = true;
        for (int j = 11; j < 21; j++)
        {
            if (value % j != 0)
            {
                success = false;
                break;
            }
        }
        if (success)
        {
            Console.WriteLine("The value is {0}", value);
            break;
        }
    }
}

您无需检查1-10,因为如果某些内容可被x整除(例如12),则它可被x / n整除(例如12/2 = 6)。最小的倍数将始终是所有素数的乘积的倍数。

没有基准测试C#解决方案,但是等效的Java解决方案在大约0.0000006秒内运行。

答案 4 :(得分:0)

嗯,我不确定你在这里想要完成的是什么,但你的外线for循环将运行大约4,294,967,295次(uint.MaxValue)。所以这需要一些时间......

如果你有办法避免去uint.MaxValue - 就像你已经完成了你所需要的那样打破你的循环 - 这将加快它。

另外,由于你将数组[j]设置为等于j,然后显然再也不使用数组,为什么不这样做呢?

value % j

而不是

value % array[j]

答案 5 :(得分:0)

使用W0lf编写的代码(抱歉,但我不能对你的帖子发表评论)我会改进它(只是一点点)删除我认为没用的数组..

public static void SmallestMultiple()
{
    const ushort ARRAY_SIZE = 21;
    ushort check = 0;
    for (uint value = 1; value < uint.MaxValue; value++)
    {
        for (ushort j = 1; j < ARRAY_SIZE; j++)
        {
            if (value % j == 0)
            {   
                check++;
            }
        }
        if (check == 20)
        {
            Console.WriteLine("The value is {0}", value);
        }
        else
        {
            check = 0;
        }
    }
}