一维动态规划-求解斐波那契数列

1.💖利用记忆自顶向下实现斐波那契数💖

1.1 🌸斐波那契数列由以下递归式定义🌸:

f ( n ) = { n , n = 0 , 1 f ( n − 1 ) + f ( n − 2 ) , 其 他 \begin{aligned} f(n)= \begin{cases} n,&n=0,1\\ f(n-1)+f(n-2),&其他 \end{cases} \end{aligned} f(n)={n,f(n1)+f(n2),n=0,1

1.2 当n=5时的斐波那契数列递归树🌲

为了便于理解,将利用时间复杂度 O(2n) 递归算法计算n=5时的 fib(5) 斐波那契数列执行过程表示为一棵递归树(如下图所示)。树中每一个结点表示一次函数调用,不难发现为了计算fib(5),需要深度优先依次遍历树中每一个结点,然而这棵树存在许多重复结点,如2个fib(3)结点和3个fib(2)结点。这些重复的结点在求解过程中都会被重复的展开进行计算,这是导致递归算法求解斐波那契数列效率低下的主要原因。
斐波那契数列递归树

fib5
fib4
fib3
fib3
fib2
fib2
fib1
fib2
fib1
fib1
fib0
fib1
fib0
fib1
fib0

1.3 🌸记忆优化重复递归子问题🌸

既然算法的实现过程存在诸多重复的函数调用,那么为了提高算法执行效率,应该考虑优化这些重复的函数调用。我们采用的方法非常简单,记忆。也就是说,在计算出一个输入参数为n的斐波那契数fib(n)后,就把fib(n)用表的形式存储下来。在函数递归调用前,首先在表中查找函数对应参数的值是否在表中。如果表中没有对应的值,说明该参数对应的函数还未被调用,那么就调用该参数对应的递归函数;否则,说明该参数的斐波那契数已经计算出来,这时就不用调用该参数对应的递归函数,而是直接将表中存储的斐波那契数返回即可。

1.4 🌸Python自顶向下实现斐波那契数🌸

代码1.4

def fib_top_bottom(nth):
    """
    自顶向下求解斐波那契数列第nth项
    :param nth: 第n项
    :return: the nth item of fibonacci sequence
    """
    if nth in memo:  # 判断第n项是否已经求出,若是则直接返回
        return memo[nth]
    else:
        if nth <= 2:  # boundary conditions
            fib = 1
        else:
            fib = fib_top_bottom(nth - 1) + fib_top_bottom(nth - 2)
        memo[nth] = fib
    return memo[nth]

2.🌹自底向上实现斐波那契数🌹

2.1 🎆自底向上实现递归🎆

除了利用记忆实现递归外,还可以用自底向上的方法来实现递归,如代码2.3所示。代码直接采用循环来代替递归函数调用。fib(0)和fib(1)是边界条件,有了它们就可以求出fib(2)。有了fib(1)和fib(2),则可以求fib(3)。因此,索引i从2依次递增到n,根据递归式仅仅使用循环,而非递归函数实现求解斐波那契数。
代码2.3的实现可看作如图2.2所示的执行过程。图中每一结点代表一个参数对应的斐波那契数。任意一个结点求值所需要的信息,都是已经求出的结点值。也就是说,当前结点的值只与该结点左边的结点有关,与该结点右边结点无关,而当前结点左边结点的值均已经算出。具体而言,如果要求fib(5)这个结点的值,需要知道这个结点左边结点的值,而该结点左边结点的值在求结点fib(5)之前便已经得到。

2.2 🎇斐波那契数列有向无环图🎇

如果将代码1.4看作是自顶向下的求解斐波那契数,那么代码2.3就是自底向上求解斐波那契数。之所以称为自底向上,是因为在求解fib(n)的值时,我们从fib(0),fib(1),fib(2)开始直到fib(n)。自底向上的实现递归,总是利用已知的信息去求未知的信息,这相当于对图2.2进行拓扑排序后得到的结点顺序。

图2.2 求解斐波那契数列的有向无环图

拓扑排序
fib(1) fib(2) fib(3) fib(4) fib(5) - - -

2.3 🎉Python自底向上实现斐波那契数🎉

代码2.3

# 定义记忆字典
memo = {0: 0}


def fib_bottom_top(nth):
    """
    自底向上求解斐波那契数列第nth项
    :param nth: 第n项
    :return: the nth item of fibonacci sequence
    """
    fib = {0: 0}
    for i in range(1, nth + 1):
        if i <= 2:  # boundary conditions
            fib_i = 1
        else:
            fib_i = fib[i - 1] + fib[i - 2]
        fib[i] = fib_i
    return fib[nth]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个经典的斐波那契数列问题。由于 n 的范围很大,所以直接递归或者暴力计算是不可行的,需要使用动态规划或矩阵快速幂的方法来求解。 方法一:动态规划 可以使用一个长度为 n+1 的一维数组 dp 来存储斐波那契数列中前 n 项的值,其中 dp[i] 表示第 i 项的值。根据斐波那契数列的递推公式,可以得到状态转移方程:dp[i] = (dp[i-1] + dp[i-2]) % 998244353。 最终 dp[n] 就是该数列的第 n 项了。 下面是 Python 代码实现: ```python def fibonacci(n): mod = 998244353 dp = [0] * (n + 1) dp[1] = dp[2] = 1 for i in range(3, n+1): dp[i] = (dp[i-1] + dp[i-2]) % mod return dp[n] ``` 方法二:矩阵快速幂 斐波那契数列也可以用矩阵快速幂的方式来求解。首先,将斐波那契数列的递推公式转化成矩阵形式: ``` | F(n) | | 1 1 | | F(n-1) | | | = | | * | | | F(n-1) | | 1 0 | | F(n-2) | ``` 然后,对于求解第 n 项的问题,我们只需要计算矩阵 A = [1 1; 1 0] 的 n-1 次方,即可得到结果。具体地,可以使用矩阵快速幂的方法来计算。 下面是 Python 代码实现: ```python def fibonacci(n): mod = 998244353 def matrix_multiply(a, b): c = [[0, 0], [0, 0]] for i in range(2): for j in range(2): for k in range(2): c[i][j] += a[i][k] * b[k][j] c[i][j] %= mod return c def matrix_power(a, n): res = [[1, 0], [0, 1]] while n > 0: if n % 2 == 1: res = matrix_multiply(res, a) a = matrix_multiply(a, a) n //= 2 return res a = [[1, 1], [1, 0]] res = matrix_power(a, n-1) return res[0][0] ``` 以上两种方法都可以求解斐波那契数列的第 n 项,时间复杂度均为 O(n) 或 O(log n)。 ### 回答2: 斐波那契数列是由两个初始项1开始,每一项都是前两项的和。为了求解数列的第n项,可以使用递归或循环的方法。 使用递归的方法,可以定义一个递归函数fibonacci(n),该函数的参数为n,表示要求解的第n项。如果n小于等于2,则直接返回1;否则,返回fibonacci(n-1)加上fibonacci(n-2)的模998244353的结果。 示例如下: ```python def fibonacci(n): if n <= 2: return 1 else: return (fibonacci(n-1) + fibonacci(n-2)) % 998244353 ``` 如果使用循环的方法,可以通过初始化前两项为1,然后从第3项开始循环求解。定义变量a和b分别表示当前项和前一项的值,并用一个循环从3到n迭代更新a和b的值。每次更新都使a的值变为a与b的和模998244353,同时b的值变为原来的a值。循环结束后,返回a的值即为第n项。 示例如下: ```python def fibonacci(n): if n <= 2: return 1 else: a, b = 1, 1 for i in range(3, n+1): a, b = (a + b) % 998244353, a return a ``` 以上是用Python编写的求解斐波那契数列第n项的方法。当然,也可以使用其他编程语言来实现相同的逻辑。 ### 回答3: 斐波那契数列是一种特殊的数列,每一项都是前两项的和。已知 F n ​ =F n−1 ​ +F n−2 ​ ,其中 n>=3,F 1 ​ =1,F 2 ​ =1。 为了求解该数列的第n项,并且结果对998244353取模,我们可以使用动态规划的方法。 首先,我们可以定义一个数组 dp,dp[i] 表示第i项的斐波那契数值。 然后,我们可以通过迭代的方式计算每一项的斐波那契数值。具体步骤如下: 1. 初始化数组 dp,将前两项 F 1 和 F 2 的值赋给 dp[1] 和 dp[2]; 2. 使用循环从3开始遍历,计算每一项的斐波那契数值,即 dp[i] = dp[i-1] + dp[i-2]; 3. 循环结束后,dp[n] 中存储的即为第 n 项的斐波那契数值。 最后,我们将 dp[n] 对 998244353 取模,得到的结果即为第 n 项的斐波那契数对 998244353 取模的值。 以上就是求解斐波那契数列第n项,并对998244353取模的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值