递归挣扎

时间:2018-06-24 19:57:04

标签: ruby recursion

我一直在努力学习递归。这是找到前n个数字之和的解决方案。但是,如果我们希望第一个数字为0怎么办?如果第一个数字从0开始,有人可以帮我写一个对前n个数字求和的递归算法吗?

因此,代替first_even_numbers_sum(5)是[2,4,6,8,10]的总和。 其[0,2,4,6,8]并递归求解。

def first_even_numbers_sum(n)
  return 2 if n == 1
  n*2 + first_even_numbers_sum(n-1)
end


first_even_numbers_sum(4)

1 个答案:

答案 0 :(得分:1)

我建议以下。

def add_em_up(n)
  return 1 if n == 2
  n - 1 + add_em_up(n - 1)
end

在编写递归时,添加一些puts语句以查看发生了什么,即使对经验丰富的红宝石也很有帮助。让我们开始吧。

def add_em_up(n)
  puts "entered add_em_up(#{ n })"
  puts "returning 1 when n = #{ 2 }" if n == 2
  return 1 if n == 2
  puts "calling add_em_up(#{ n - 1 }) when n = #{ n }"
  t = n - 1 + add_em_up(n - 1)
  puts "returning #{ n } - 1 + #{t - n + 1} = #{t} when n = #{ n }"
  t
end

add_em_up(5)
  #=> 10   
entered add_em_up(5)
calling add_em_up(4) when n = 5
entered add_em_up(4)
calling add_em_up(3) when n = 4
entered add_em_up(3)
calling add_em_up(2) when n = 3
entered add_em_up(2)
returning 1 when n = 2
returning 3 - 1 + 1 = 3 when n = 3
returning 4 - 1 + 3 = 6 when n = 4
returning 5 - 1 + 6 = 10 when n = 5

您可以使用缩进使情况更清晰。

INDENT = 3
$col = 0

def add_em_up(n)
  s = " " * $col
  puts "#{ s }entered add_em_up(#{ n })"
  puts "#{ s }returning 1 when n = #{ 2 }" if n == 2
  $col -= INDENT if n == 2
  return 1 if n == 2
  puts "#{ s }calling add_em_up(#{ n - 1 }) when n = #{ n }"
  $col += INDENT
  t = n - 1 + add_em_up(n - 1)
  puts "#{ s }returning #{ n } - 1 + #{t - n + 1} = #{t} when n = #{ n }"
  $col -= INDENT
  t
end

add_em_up(5)
  #=> 10   
entered add_em_up(5)
calling add_em_up(4) when n = 5
   entered add_em_up(4)
   calling add_em_up(3) when n = 4
      entered add_em_up(3)
      calling add_em_up(2) when n = 3
         entered add_em_up(2)
         returning 1 when n = 2
      returning 3 - 1 + 1 = 3 when n = 3
   returning 4 - 1 + 3 = 6 when n = 4
returning 5 - 1 + 6 = 10 when n = 5

请注意,在此方法的第一个版本(无缩进)中,可以替换

t = n - 1 + add_em_up(n - 1)
puts "returning #{ n } - 1 + #{t - n + 1} = #{t} when n = #{ n }"
t

使用

(n - 1 + add_em_up(n - 1)).
  tap { |t| puts "returning #{ n } - 1 + #{t - n + 1} = #{t} when n = #{ n }" }

或(如评论中指出)

(n - 1 + add_em_up(n - 1)).yield_self { |t| 
  puts "returning #{ n } - 1 + #{t - n + 1} = #{t} when n = #{ n }"; t }

在这里,更一般地说,方法Object#tap对于调试非常有用。 Object#yield_self(Ruby v2.5中的新功能)是另一种有用的方法。