Ruby递归计算端点的累积和?

Ruby递归计算端点的累积和?,ruby,recursion,Ruby,Recursion,给定两个数字,比如(14,18),问题是递归地找到这个范围内所有数字的和,14,15,16,17,18。现在,我已经使用循环完成了这项工作,但是我在递归地完成这项工作时遇到了困难 以下是我的递归解决方案: def sum_cumulative_recursive(a,b) total = 0 #base case is a == b, the stopping condition if a - b == 0 puts "sum is: "

给定两个数字,比如(14,18),问题是递归地找到这个范围内所有数字的和,14,15,16,17,18。现在,我已经使用循环完成了这项工作,但是我在递归地完成这项工作时遇到了困难

以下是我的递归解决方案:

def sum_cumulative_recursive(a,b)

    total = 0

    #base case is a == b, the stopping condition
    if a - b == 0 
        puts "sum is: "
        return total + a 
    end

    if b - a == 0
        puts "sum is: "
        return total + b
    end

    #case 1: a > b, start from b, and increment recursively
    if a > b
        until b > a
            puts "case 1"
            total  = b + sum_cumulative_recursive(a, b+1)
            return total
        end
    end

    #case 2: a < b, start from a, and increment recursively
    if a < b
        until a > b
            puts "case 2"
            total = a + sum_cumulative_recursive(a+1, b)
            return total
        end 
    end
end
Benchmark.measure { 10.times { (1000..5000).inject(:+) } }
# =>   0.010000   0.000000   0.010000 (  0.027827)

Benchmark.measure { 10.times { sum_cumulative_recursive(1000,5000) } }
# =>   0.010000   0.010000   0.020000 (  0.019441)
我的解决方案适用于a>b和a 如何修复此代码以使其正常工作

谢谢你抽出时间

我会这样做:

def sum_cumulative_recursive(a, b)
  a, b = a.to_i, b.to_i # Only works with ints
  return sum_cumulative_recursive(b, a) if a > b
  return a if a == b
  return a + sum_cumulative_recursive(a+1, b)
end

这里有一种方法。我假设这只是一个练习,因为范围
r
的元素之和当然就是
(r.first+r.last)*(f.last-r.first+1)/2

def sum_range(range)
  return nil if range.last < range.first
  case range.size
  when 1 then range.first
  when 2 then range.first + range.last
  else
    range.first + range.last + sum_range(range.first+1..range.last-1)
  end
end

sum_range(14..18)  #=> 80
sum_range(14..14)  #=> 14
sum_range(14..140) #=> 9779
sum_range(14..139) #=> 9639
def sum_范围(范围)
如果range.last80
求和范围(14..14)#=>14
求和范围(14..140)#=>9779
求和范围(14..139)#=>9639
编辑

以下是我从一些非正式基准中看到的最有效的解决方案:

def sum_cumulative_recursive(a,b)
  return a if a == b
  a, b = b, a if a > b
  a + sum_cumulative_recursive(a + 1, b)
end
使用:

Benchmark.measure { sum_cumulative_recursive(14,139) }
我的初始响应基准:0.005733

@Ajedi32响应的基准:0.000371

我的新答复的基准:0.000115

我还惊讶地发现,在某些情况下,递归解决方案接近或超过了更自然的
inject
解决方案的效率:

def sum_cumulative_recursive(a,b)

    total = 0

    #base case is a == b, the stopping condition
    if a - b == 0 
        puts "sum is: "
        return total + a 
    end

    if b - a == 0
        puts "sum is: "
        return total + b
    end

    #case 1: a > b, start from b, and increment recursively
    if a > b
        until b > a
            puts "case 1"
            total  = b + sum_cumulative_recursive(a, b+1)
            return total
        end
    end

    #case 2: a < b, start from a, and increment recursively
    if a < b
        until a > b
            puts "case 2"
            total = a + sum_cumulative_recursive(a+1, b)
            return total
        end 
    end
end
Benchmark.measure { 10.times { (1000..5000).inject(:+) } }
# =>   0.010000   0.000000   0.010000 (  0.027827)

Benchmark.measure { 10.times { sum_cumulative_recursive(1000,5000) } }
# =>   0.010000   0.010000   0.020000 (  0.019441)

尽管如果做得太过分,您会遇到
堆栈级别太深的错误…

另一个解决方案是使用前端调用修复无序参数,然后使用专用递归后端执行实际工作。我发现这有助于避免反复检查论点,一旦你确定它们是干净的

def sum_cumulative_recursive(a, b)
  a, b = b, a if b < a
  _worker_bee_(a, b)
end

private
def _worker_bee_(a, b)
  a < b ? (a + _worker_bee_(a+1,b-1) + b) : a == b ? a : 0
end
def sum_累计_递归(a,b)
a、 b=b,如果b
这种变体通过从两端求和将堆栈需求减半

如果您不喜欢这种方法和/或确实想修剪堆栈大小:

def sum_cumulative_recursive(a, b)
  if a < b 
    mid = (a + b) / 2
    sum_cumulative_recursive(a, mid) + sum_cumulative_recursive(mid+1, b)
  elsif a == b
    a
  else
    sum_cumulative_recursive(b, a)
  end
end
def sum_累计_递归(a,b)
如果a

这将使堆栈大小保持为O(log | b-a |)。

听起来像是家庭作业。闻起来像是家庭作业。是作业吗,宝贝?咕噜,咕噜。当
a==b
时,结果应该是什么?不,这是一个实习职位的面试问题。返回a+b+结果(a+1,b),并包括一个案例,如果a==b返回0,它将级联初始调用,您将获得一个粗略的结果?啊,我想说的是
(14..18)。减少(:+)
;-)当
a>b
@kardeiz时,这不会产生期望的结果。您能澄清一下吗?当
a>b
时,期望的结果是什么?根据海报的代码,它基本上应该翻转变量,这样你就有了
min..max
的范围。什么?它甚至不起作用:
未定义的方法'size'用于14..18:Range
@Kardeiz,你用词的方法很好。它似乎在v2.0中可用。(我使用的是v2.1)。对于早期版本,我想你必须使用
range.last range.first+1
@Cary,我没有不尊重的意思。感谢您指出版本差异。@Cary,另外,如果您的答案使用了问题的方法签名并解决了其他答案所处理的最小/最大问题,那就太好了。@kardeiz,在发布我的解决方案后,我注意到我使用了一个范围作为方法参数,而不是端点,但我得出的结论是,差异太小,不值得编辑。此外,我认为询问者可以了解如何使用范围参数。是的,我应该处理范围问题(参见编辑)。我以前没有这样做,因为我错误地假设
(18..14)
(例如)会引发异常。(奇怪的是,
(18..14).size=>0)
)在这种情况下,我现在返回
nil
,但可以相反地反转范围。我不理解永远不会使用的基准测试方法的意义。如果你想要一个范围内元素的总和,他们肯定会直接从端点计算出来。我并不是说基准确定了最佳解决方案。我主要只是好奇地想看看在asker的约束条件下事情是如何发展的(例如,在我的初始响应中实例化一个数组的成本有多高)。当然,在正常情况下,我会做
(14..18)。注入(:+)
,如上面@Ajedi32所述。感谢分享您的见解,这是一个非常好的解决方案。