在解决了一段时间以来我一直被束缚的编程挑战之后,我总是在想,“它有效,那就足够了”。
我认为这不是正确的心态,在我看来,我认为我应该始终尝试以最佳的性能进行编码。
无论如何,说到这里,我只是试了一个ProjectEuler问题。具体问题#2。
我怎样才能改进此解决方案。我觉得它的真的详细。就像我在递归中传递前一个数字一样。
<?php
/* Each new term in the Fibonacci sequence is generated by adding the previous two
terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
Find the sum of all the even-valued terms in the sequence which do not exceed
four million.
*/
function fibonacci ( $number, $previous = 1 ) {
global $answer;
$fibonacci = $number + $previous;
if($fibonacci > 4000000) return;
if($fibonacci % 2 == 0) {
$answer = is_numeric($answer) ? $answer + $fibonacci : $fibonacci;
}
return fibonacci($fibonacci, $number);
}
fibonacci(1);
echo $answer;
?>
请注意,这不是作业。几百年前我离开了学校。我只是感到无聊并且经历了项目欧拉问题
答案 0 :(得分:7)
解决后我总是在想 我有一个编程挑战 被捆绑了一段时间,“它 工作,那太好了“。
我认为这不是真的 在我看来,我是正确的心态 我想我应该一直努力 代码性能最佳。
Code Complete中提出的一个经典事物是,程序员在给定目标的情况下,可以使用众多指标之一创建“最佳”计算机程序,但无法针对所有一次参数。参数如
随意对这些参数中的任何一个进行优化,但请记住,同时优化所有这些参数可能会令人沮丧,或导致系统过度设计。
你应该问自己:你的目标是什么?在这种情况下,什么是“足够好”?如果你只是在学习并想要让事情更加优化,那么一定要去做,只要意识到一个完美的程序需要无限的时间来构建,而时间本身就是有价值的。
答案 1 :(得分:2)
你可以通过三次操作来避免mod 2部分(每三个元素是偶数),所以它读取: $ fibonacci = 3 * $ number + 2 * $ previous; 而斐波那契的新输入是($ fibonnacci,2 * $ number + $ previous) 我不熟悉php,所以这只是一般的算法建议,我不知道它是否是正确的语法。它实际上是相同的操作,它只是用几个乘法代替模数和加法。
另外,请确保以$ even开头,$ previous作为序列中前面的奇数(你可以从$ number开始为2,$ previous为1,并且总和也开始在2)。
答案 2 :(得分:1)
忘记斐波纳契(问题2),我说只是在欧拉进步。不要浪费时间为每个问题找到最佳代码。
如果您的答案达到一分钟规则,那么您可以尝试下一个。在遇到一些问题之后,事情将变得更加困难,并且您将在编写代码时优化代码以实现该目标
答案 3 :(得分:0)
其他人也在这里说过“这是问题的一部分,例如问题与真正的<强>商业问题”
由于多种原因,这个问题的答案很难回答:
我想最重要的是,如果你认为它是一个很好的解决方案,而你的客户/购买者/团队/等同意那么它是一个很好的解决方案。你可能会在未来改变主意,但现在它是一个很好的解决方案。
答案 4 :(得分:0)
我实际上没有对此进行测试...但是在我称之为“完成”之前,我个人本可以尝试在此解决方案中解决此问题。
通过使用sum参数实现递归来尽可能地避免全局变量
编辑:根据nnythm的算法推荐更新(很酷!)
function fibonacci ( $number, $previous, $sum ) {
if($fibonacci > 4000000) { return $sum; }
else {
$fibonacci = 3*$number + 2*$previous;
return fibonacci($fibonnacci,2*$number+$previous,$sum+$fibonacci);
}
}
echo fibonacci(2,1,2);
答案 5 :(得分:0)
使用指南来解决问题的代码执行时间不应超过一分钟。这对欧拉问题最重要,IMO。
除此之外,只需确保它的可读性 - 确保您可以轻松查看代码的工作原理。通过这种方式,您可以更轻松地了解如果遇到类似您解决的Euler问题之一的问题,这样可以更快地解决问题 - 因为您已经知道应该如何解决它。
你可以为自己设定其他标准,但我认为这超出了欧拉问题的意图 - 对我而言,问题的背景似乎更适合关注效率和可读性而不是其他任何事情
答案 6 :(得分:0)
[耸肩]
应根据要求评估解决方案。如果满足所有要求,那么其他一切都是满满的。如果满足所有要求,并且您个人对解决方案不满意,则可能需要重新评估要求。这就是你可以采取这个元物理问题,因为我们开始涉及项目管理和业务:S
嗯,关于你的Euler-Project问题,只有我的两便士:例如
public const ulong TermLimit = 4000000;
public static ulong CalculateSumOfEvenTermsTo (ulong termLimit)
{
// sum!
ulong sum = 0;
// initial conditions
ulong prevTerm = 1;
ulong currTerm = 1;
ulong swapTerm = 0;
// unroll first even term, [odd + odd = even]
swapTerm = currTerm + prevTerm;
prevTerm = currTerm;
currTerm = swapTerm;
// begin iterative sum,
for (; currTerm < termLimit;)
{
// we have ensured currTerm is even,
// and loop condition ensures it is
// less than limit
sum += currTerm;
// next odd term, [odd + even = odd]
swapTerm = currTerm + prevTerm;
prevTerm = currTerm;
currTerm = swapTerm;
// next odd term, [even + odd = odd]
swapTerm = currTerm + prevTerm;
prevTerm = currTerm;
currTerm = swapTerm;
// next even term, [odd + odd = even]
swapTerm = currTerm + prevTerm;
prevTerm = currTerm;
currTerm = swapTerm;
}
return sum;
}
所以,也许更多的代码行,但[实际上]保证更快。迭代方法不像“优雅”,但保存递归方法调用并节省堆栈空间。其次,展开术语生成[即显式扩展循环]减少了您必须执行模数运算和测试“偶数”条件的次数。扩展还减少了评估结束条件[如果当前术语小于限制]的次数。
它是“更好”,不,它只是“另一种”解决方案。
为C#道歉,不熟悉php,但我相信你可以很好地翻译它。
希望这会有所帮助,:))
干杯
答案 7 :(得分:0)
完全是您的选择,您是否对解决方案感到满意,或者您是否希望进一步改进。有很多项目欧拉问题,蛮力解决方案需要太长时间,而且你必须寻找一个聪明的算法。
问题2不需要任何优化。您的解决方案已经足够快了。 还是让我解释一下什么样的优化是可能的。通常有助于对该主题进行一些研究。例如。 Fibonacci numbers上的维基页面包含此公式
fib(n)=(phi ^ n - (1-phi)^ n)/ sqrt(5)
其中phi是黄金比例。即。
phi =(sqrt(5)+1)/ 2。
如果你使用fib(n)大约是phi ^ n / sqrt(5)那么你可以找到小于M的最大Fibonacci数的索引
n = floor(log(M * sqrt(5))/ log(phi))。
E.g。对于M = 4000000,我们得到n = 33,因此fib(33)是最小的斐波纳契数小于4000000.可以观察到,即使n是3的倍数,fib(n)也是偶数。因此,偶数斐波那契的总和数字是
fib(0)+ fib(3)+ fib(6)+ ... + fib(3k)
要查找已关闭的表单,我们使用维基百科页面中的上述公式并注意到 总和基本上只有两个geometric series。数学并非完全无足轻重,但使用这些想法可以证明
fib(0)+ fib(3)+ fib(6)+ ... + fib(3k)=(fib(3k + 2)-1)/ 2.
由于fib(n)的大小为O(n),因此直接解决方案的复杂度为O(n ^ 2)。 使用上面的闭合公式和快速方法来评估斐波纳契数 具有O(n log(n)^(1 + epsilon))的复杂度。对于小数字,任何解决方案当然都可以。