关于第一个有500个除数的三角形数,我正在研究问题12。我试图暴力破解解决方案。我在大约35秒内获得300个除数,并且在10分钟内无法获得400。我将改变我的解决方案以使用素因子方法,但我现在已经看到人们仍在不到一分钟内蛮力地获得这个解决方案。
请你批评一下我的代码并告诉我,如果我遗漏的东西会导致这种效率非常低效吗?
unsigned long long TriangleNumberDivisors(int divisorTarget)
{
unsigned long long triangleNum=1;
unsigned long long currentNum=2;
int numOfDivisors=0;
numOfDivisors=NumOfDivisors(triangleNum);
while(numOfDivisors<divisorTarget)
{
triangleNum+=currentNum;
currentNum++;
numOfDivisors=NumOfDivisors(triangleNum);
}
return triangleNum;
}
int NumOfDivisors(unsigned long long dividend)
{
int numDivisors=0;
set<unsigned long long> divisors;
set<unsigned long long>::iterator it;
for(unsigned long long index=1; index<=dividend/2; index++)
{
if(dividend%index==0)
{
divisors.insert(index);
numDivisors++;
it=divisors.find(dividend/index);
if(it==divisors.end())
{
divisors.insert(dividend/index);
numDivisors++;
}
/*for some reason not checking for dups above and
just checking for how many items are in the set at the end is slower
for(it=divisors.begin();it!=divisors.end();it++)
{
numDivisors++;
}
*/
}
}
return numDivisors;
}
int main()
{
cout<<TriangleNumberDivisors(500)<<endl;
return 0;
}
更新:现在知道了,谢谢。改为只检查数字的平方根,并做了一个额外的检查,看看它是否是一个完美的正方形。这允许我完全删除该组。 500秒的分数在12秒内完成。
答案 0 :(得分:10)
您目前检查最高dividend/2
的除数。您可以将其减少到sqrt(dividend)
,这是渐近更快的。如果dividend
是正方形,则可能需要特殊情况。
问题12的我的C ++代码(它与你的基本相同,但是使用这个下限,并且只计算除数而不是将它们存储在集合中)需要大约1秒
答案 1 :(得分:4)
for(unsigned long long index=1; index<=dividend/2; index++)
我发现您已尝试通过将循环限制为dividend/2
来优化此操作,而不是一直迭代到dividend
。将自己限制在sqrt(dividend)
会更好(从你检查更少的除数的意义上来说)。
另外,如果你用被除数的平方根限制自己,你不必检查重复的除数。这只会发生在正方形数字上,所以只需检查index == dividend / index,以避免重复插入。
答案 2 :(得分:2)
我不确定为什么在NumOfDivisors方法中需要divisors
,set
类型变量。为什么计算numDivisors
(索引高达sqrt( dividend )
)是不够的? (set
是作为一个平衡的二叉搜索树实现的,它正在减慢方法的速度。)。此外,您似乎正在调用divisors.insert( .. )
两次。
答案 3 :(得分:1)
如果您在进行特定数字时缓存了除数的数量,似乎可以获得一些性能。