部分Fibonacci总和,如何提高性能?

时间:2016-09-06 20:41:34

标签: ruby fibonacci

我需要提高此算法的性能。我相信答案在于皮萨诺时期的应用。

此算法必须返回从f(m)到f(n)的fib数之和的最后一位数。

这是我到目前为止所做的:

def fib(n)
    a = []
    a << 0 << 1
    (n+1).times do |i|
        a << a[-1] + a[-2]
    end
     a[n]
end


def fib_partial_sum(m, n)
    if n == m
        fib(m) % 10
    else
        m = fib(m + 1) - 1
        n = fib(n + 2) - 1
        (n - m) % 10
    end
end

if __FILE__ == $0
  m, n = gets.split().map(&:to_i)
  puts "#{fib_partial_sum(m, n)}"
end

任何纤维数的最后一位数每60个数字重复一次。因此,我们可以这样做,n,m = n%60,m%60。一项改进,但尚未完全,输入失败567717153638 567717153638):

def fib(n)
    a = []
    a << 0 << 1
    (n+1).times do |i|
        a << a[-1] + a[-2]
    end
     a[n]
end

def fib_partial_sum(m, n)
    if n == m
        fib(m)
    else
        m = m % 60
        n = n % 60

        m = fib(m + 1) - 1
        n = fib(n + 2) - 1
        (n - m) % 10
    end
end

if __FILE__ == $0
  m, n = gets.split().map(&:to_i)
  puts "#{fib_partial_sum(m, n)}"
end

2 个答案:

答案 0 :(得分:1)

这是一个很好的解决方案,它传递所有时间和内存约束。 这样你就不必计算大于f(60)的纤维数。它可以有效地处理非常大的输入。

def fib(n)
    a, b = 0, 1
    (n-1).times do
        a, b = b, (a + b) % 10
    end
    b
end

def fib_partial_sum(m, n)
    if n == m
        fib(m % 60)
    else
        m = m % 60
        n = n % 60

        m = fib(m + 1) - 1
        n = fib(n + 2) - 1

        (n - m) % 10
    end
end

if __FILE__ == $0
    m, n = gets.split().map(&:to_i)
    puts "#{fib_partial_sum(m, n)}"
end

(使用的最长时间:0.05 / 5.00,最大使用内存:8699904/536870912.)

答案 1 :(得分:0)

以下只需要在0到最多[n,m+60].min之间传递一次数字,其中m..n是感兴趣的范围,并且具有最小的内存要求。利用@ nloveladyallen的观察结果,斐波纳契数的最后一位数周期为60.

<强>代码

def fib_last(m,n)
  n -= 60*((n-m)/60)   
  fib_sum(m,n) % 10
end

def fib_sum(m,n)
  return nil if m < 0 || m > n
  return n if n < 2
  next_to_last, last = fib(m-1)
  (m..n).reduce(0) do |tot,_|
    current = next_to_last + last
    next_to_last = last
    last = current
    tot + current
  end
end

def fib(m)
  next_to_last, last = -1, 1
  0.upto(m).each do |n|
    current = next_to_last + last
    next_to_last, last = last, current
  end
  [next_to_last, last]
end

示例

m, n = 6, 12
(n+1).times { |i| puts "#{i}: #{fib(i)}" }
0:  [0,    0]
1:  [0,    1]
2:  [1,    1]
3:  [1,    2]
4:  [2,    3]
5:  [3,    5]
6:  [5,    8]
7:  [8,   13]
8:  [13,  21]
9:  [21,  34]
10: [34,  55]
11: [55,  89]
12: [89, 144]

fib_last(6,12) #=> 4 (fib_sum(6,12) #=> 8 + 13 + 21 + 34 + 55 + 89 + 144 = 364)
fib_last(1,2)  #=> 2 (fib_sum(1,2)  #=> 1 + 1 = 2)
fib_last(1,3)  #=> 4 (fib_sum(1,3)  #=> 1 + 1 + 2 = 4) 
fib_last(1,4)  #=> 7 (fib_sum(1,4)  #=> 1 + 1 + 2 + 3 = 7)
fib_last(2,3)  #=> 3 (fib_sum(2,3)  #=> 1 + 2 = 3)