Фибоначчи в кэшированном решении - PullRequest
0 голосов
/ 09 декабря 2018

Я выучил наизусть решение фибоначчи в c ++ как

#include<iostream>
using namespace std;
int F[51];

int fib(int n) {
    if (n<=1)
    {
        return n;
    }
    if (F[n] != -1)
    {
        return F[n];
    }
    F[n] =  fib(n-1) + fib(n-2);
    return F[n];
}

int main()
{   
    for (int i=0; i<51; i++)
    {
        F[i] = -1;
    }
    int n;
    cout<<"Give me an n: ";
    cin>>n;
    int result = fib(n);
    cout<<result;
}

Это работало правильно,

$ g++ fibonacci.cpp 
$ ./a.out
Give me an n: 10
55

Попробуйте воспроизвести его с помощью python

In [2]: %paste                                                                                                        
F:List = [-1] * 50

def fib2(int:n) -> int:

    if n < 2:
        return n
    if F[n] != -1:
        return F[n]
    F[n] =  fib2(n-1) + fib2(n-2)
    return F[n]

print(fib2(10))

Тем не менее, он сообщает RecursionError: maximum recursion depth exceeded in comparison

---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
<ipython-input-2-5e5ce2f4b1ad> in <module>
     10     return F[n]
     11 
---> 12 print(fib2(10))

<ipython-input-2-5e5ce2f4b1ad> in fib2(int)
      7     if F[n] != -1:
      8         return F[n]
----> 9     F[n] =  fib2(n-1) + fib2(n-2)
     10     return F[n]
     11 

... last 1 frames repeated, from the frame below ...

<ipython-input-2-5e5ce2f4b1ad> in fib2(int)
      7     if F[n] != -1:
      8         return F[n]
----> 9     F[n] =  fib2(n-1) + fib2(n-2)
     10    

Дважды проверил, что решение Python имеет ту же логику с исходным решением.

В чем проблема с моими кодами.

Ответы [ 3 ]

0 голосов
/ 09 декабря 2018

Тип подсказки были неверными, это работает для меня:

# fixed type hint
F:list = [-1] * 50

# fixed type hint
def fib2(n:int) -> int:
    if n < 2:
        return n
    if F[n] != -1:
        return F[n]
    F[n] = fib2(n-1) + fib2(n-2)
    return F[n]

fib2(49)
=> 7778742049
0 голосов
/ 09 декабря 2018

Проблема заключается в подсказке типа: она должна быть n: int вместо int: n.

В обычном сценарии вы получите NameError, как здесь:

def fib2(int: n):
    pass

---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)
<ipython-input-19-2a2734193e18> in <module>()
----> 1 def fib2(int: n):
      2     pass

NameError: name 'n' is not defined

В вашем случае происходит то, что вы, вероятно, определили n в одной из ячеек, которые вы запускали ранее в IPython.Таким образом, вы не получаете 'NameError', но ваш параметр получает имя int, а n, используемый в функции, является глобальным n, который вы использовали где-то ранее.Если это число больше 2, ваши рекурсивные вызовы никогда не прекратятся:

n = 3  # might have been in some other cell

F = [-1] * 101

def fib2(int: n):

    if n < 2:
        return n
    if F[n] != -1:
        return F[n]
    F[n] =  fib2(n-1) + fib2(n-2)
    return F[n]

print(fib2(100))
---------------------------------------------------------------------------

[...]

RuntimeError: maximum recursion depth exceeded in comparison

Просто напишите подсказку типа в правильном порядке, и все в порядке:

F = [-1] * 101

def fib2(n: int):
    if n < 2:
        return n
    if F[n] != -1:
        return F[n]
    F[n] =  fib2(n-1) + fib2(n-2)
    return F[n]

print(fib2(100))
# 354224848179261915075
0 голосов
/ 09 декабря 2018

Попробуйте это:

fib_aux = [-1] * 50
def fib(n):
    if n < 2:
        return n
    else:
        if fib_aux[n] < 0:
            fib_aux[n] = fib(n - 1) + fib(n - 2)
        return fib_aux[n]

Со списком вы также можете сделать это, чтобы избежать рекурсии:

fib_aux = [0, 1]
def fib(n):
    m = len(fib_aux)
    for i in range(m, n + 1):
        fib_aux.append(fib_aux[i - 1] + fib_aux[i - 2])
    return fib_aux[n]

Вместо управления списком вы можете использовать общую функцию запоминания:

def memoize(f):
    h = {}
    def g(*arg):
        if arg not in h:
            h[arg] = f(*arg)
        return h[arg]
    return g

@memoize
def fib(n):
    return n if n < 2 else fib(n - 1) + fib(n - 2)

См. этот вопрос для получения дополнительной информации о декораторах Python (@).

Обратите внимание, что первый и последний метод может завершиться ошибкой из-за предела рекурсии.Второе решение не использует рекурсию.Однако, если вам нужно всего несколько значений fib(n) для больших n, есть более быстрые решения, использующие удвоение аргументов (см. this в Math.SE).

...