让我建议你在Python中实现你的想法。您可能会惊讶地发现工作代码与伪代码非常相似。
这是原来的算法:
def sum_of_n_odds(n):
if n == 1:
return 1
else:
return sum_of_n_odds(n-1) + (2*n-1)
这是你写的一个:
def sum_of_odds_up_to_n(n):
if n == 1:
return 1
if n % 2 > 0: # this means n is odd
return n + sum_of_odds_up_to_n(n-1)
if n % 2 == 0: # this means it's even
return 0 + sum_of_odds_up_to_n(n-1)
这两种算法计算不同的东西。调用sum_of_n_odds(10)的结果与调用sum_of_odds_up_to_n(19)或sum_of_odds_up_to_n(20)的结果相同。通常,sum_of_odds_up_to_n(n)等于sum_of_n_odds((n+1)//2),其中//表示整数除法。
如果您有兴趣使您的实施更高效一点,我建议您省略最后的if条件,其中n % 2 == 0。整数是奇数或偶数,所以如果它不是奇数,它必须是偶数。
当n为奇数时,您可以通过递归调用sum_of_odds_up_to(n-2)来获得另一个性能增益。目前,你正在将一半的函数调用浪费在偶数上。
有了这两个方面的改进,代码变为:
def sum_of_odds_up_to_n(n):
if n <= 0:
return 0
if n % 2 == 0:
return sum_of_odds_up_to_n(n-1)
return n + sum_of_odds_up_to_n(n-2)
这是尾递归版本:
def sum_of_odds_up_to_n(n, partial=0):
if n <= 0:
return partial
if n % 2 == 0:
return sum_of_odds_up_to_n(n-1, partial)
return sum_of_odds_up_to_n(n-2, partial+n)
你不应该指望从上面的性能提升,因为Python没有优化用于尾递归。但是,你可以重写尾递归迭代为,其运行速度将更快,因为它不花时间对每个递归调用分配栈帧:
def sum_of_odds_up_to_n(n):
partial = 0
if n % 2 == 0:
n -= 1
while n > 0:
partial += n
n -= 2
return partial
最快的实现所有的依赖于数学洞察力。考虑总和:
1 + 3 + 5 + ... + (n-4) + (n-2) + n
观察,你可以配对的第一个元素与最后一个元素,倒数第二个元素的第二个元素,与倒数第三元素的第三个元素,依此类推:
(1 + n) + (3 + n-2) + (5 + n-4) + ...
这是很容易看到,这等于:
(n + 1) + (n + 1) + (n + 1) + ...
多少项(n + 1)有哪些?由于我们从原始序列中每次配对两个项目,因此(n + 1)序列中的项目数量是其中的一半。
您可以检查自己的原始序列是否有(n + 1)/2条款。 (提示:如果您为每个术语添加1,请参阅获得的结果。)
新序列的数量是该术语的一半,或(n + 1)/4。而在该序列的每个术语(n + 1),所以整个序列的总和:
(n + 1) * (n + 1)/4
产生的Python程序是这样的:
def sum_of_odds_up_to_n(n):
if n <= 0:
return 0
if n % 2 == 0:
n -= 1
return (n+1)*(n+1)//4