我在这里用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;
}
}
}
答案 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数字:
使用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;
}
}
}