任务是找到一个至少有500个除数的三角形数。
例如28有6个除数:1,2,4,7,14,28
我的代码适用于最多200个除数,但对于500,它会永远运行...
有没有办法优化代码。比如我想过动态优化和memoization,但找不到办法呢?
int sum = 0;
int counter = 0;
int count = 1;
bool isTrue = true;
while (isTrue)
{
counter = 0;
sum += count;
for (int j = 1; j <= sum; j++)
{
if (sum % j == 0)
{
counter++;
if (counter == 500)
{
isTrue = false;
Console.WriteLine("Triangle number: {0}", sum);
break;
}
}
}
count++;
}
Console.WriteLine("Number of divisors: {0}", counter);
答案 0 :(得分:5)
忽略这个数字是三角形数字的事实。如果你能快速解决这个问题:
那么如何快速确定除数的数量呢?正如你所发现的那样,当数字变大时,这是很多工作。
这是一个提示。假设您已经拥有素数因子分解。让我们选一个数字,比方说,196.将其分解为素数:
196 = 2 x 2 x 7 x 7
我只能通过看一下196具有九个除数的因子分解来告诉你。怎么样?
因为任何除数为196的形式为:
(1, 2 or 2x2) x (1, 7 or 7x7)
显然有九种可能的组合:
1 x 1
1 x 7
1 x 7 x 7
2 x 1
2 x 7
2 x 7 x 7
2 x 2 x 1
2 x 2 x 7
2 x 2 x 7 x 7
选择另一个号码。 200,让我们说。那是2 x 2 x 2 x 5 x 5.所以有十二的可能性:
1 x 1
1 x 5
1 x 5 x 5
2 x 1
2 x 5
...
2 x 2 x 2 x 5 x 5
看模式?您采用素数分解,按素数对它们进行分组,并计算每组中的数量。然后,为每个数字添加一个并将它们相乘。同样,在200中,素数因子分解中有三个两个和两个五个。每个添加一个:四个和三个。将它们相乘:十二。这就是有多少除数。
如果你知道素数分解,你可以很快找到除数的数量。我们已将除数问题简化为更容易解决的问题:您能否弄清楚如何快速生成素数分解?
答案 1 :(得分:2)
这里有一些优化,我会把它扔给你。
最简单的事情是改变
for (int j = 1; j <= sum; j++)
{
if (sum % j == 0)
{
counter++;
if (counter == 500)
{
isTrue = false;
Console.WriteLine("Triangle number: {0}", sum);
break;
}
}
}
如果你找到了1个除数,你就找到了2个除数,所以将其改为
for (int j = 1; j <= sum; j++)
{
if (sum % j == 0)
{
if(sum/j < j)
break;
else if(sum/j == j)
counter++;
else
counter +=2;
if (counter == 500)
{
isTrue = false;
Console.WriteLine("Triangle number: {0}", sum);
break;
}
}
}
这将大大减少运行时间,但仍需要很长时间。
您可以做的另一个优化是不开始检查表单sum
,但计算具有500个除数的最小数字。
然后你可以在那之后找到最大的三角形数字,并从那里开始。
如果你能找到关于这个问题的本质的特别之处,那么你可以减少运行时间。
答案 2 :(得分:1)
数字的除数是主要因子加上1的幂的乘积。例如:28 = 2^2*7^1
,因此除数的数量为(2+1)*(1+1) = 6
。
这意味着,如果你想要多个除数与数字的大小相比,你不希望任何一个素数过于频繁。换句话说:至少有500个除数的最小三角数可能是小素数的小权力的乘积。
因此,不是检查每个数字以查看它是否划分三角形数字,而是查看最小素数的列表,并查看每个数字在素数因子分解中出现的频率。然后使用上面的公式计算除数的数量。
答案 3 :(得分:0)
采取以下步骤:
1。)计算第一个log(2,499)素数(不是500,因为如果我错了,因为它不是素数,因为它只有一个除数,因此1被算作除数)。那里有很多解决方案,但你抓住了我的漂移。
2。)三角形数字的形式为n *(n + 1)/ 2,因为 1 + 2 + ... + 100 =(1 + 100)+(2 + 99)+ ... +(50 + 51)= 101 * 50 = 101 * 100/2 = 5050(当Cauchy解决它时是一个八岁男孩,老师用这个任务惩罚他。)
1 + ... + n =(1 + n)+(2 + n - 1)+ ... = n *(n + 1)/ 2.
3。)S = prod(第一个log(2,499)素数)
4。)求解n *(n + 1)/ 2 = S的等式并计算其上限。你将有一个整数,我们称之为m。
5。)
while (not(found))
found = isCorrect(m)
if (not(found)) then
m = m + 1
end if
end while
return m
然后你去。如果我能够帮助你,请告诉我。
答案 4 :(得分:0)
正如@EricLippert和@LajosArpad所提到的,关键的想法是仅迭代triangle numbers。您可以使用以下公式计算它们:
T(n)= n *(n + 1)/ 2
以下是JSFiddle,您可能会觉得有帮助。
function generateTriangleNumber(n) {
return (n * (n + 1)) / 2;
}
function findTriangleNumberWithOver500Divisors() {
var nextTriangleNum;
var sqrt;
for (i = 2;; i++) {
var factors = [];
factors[0] = 1;
nextTriangleNum = generateTriangleNumber(i);
sqrt = Math.pow(nextTriangleNum, 0.5);
sqrt = Math.floor(sqrt);
var j;
for (j = 2; j <= sqrt; j++) {
if (nextTriangleNum % j == 0) {
var quotient = nextTriangleNum / j;
factors[factors.length] = j;
factors[factors.length] = quotient;
}
}
factors[factors.length] = nextTriangleNum;
if (factors.length > 500) {
break;
}
}
console.log(nextTriangleNum);
}
答案 5 :(得分:-1)
顺便提一下,divisors of triangular number
搜索查询的第一个Google结果就是这样:)
Project Euler 12: Triangle Number with 500 Divisors
看看它是否有帮助。
编辑:该文章中的文字:
超过500位的第一个三角形数字是:76576500解决方案 花了1毫秒