剑指offer 10.1 斐波那契数列

解法一:dp
题目都告诉你递归式了,再写不出来怎么说你呢。

class Solution:
    def fib(self, n: int) -> int:
        MOD = 1000000007
        dp = [0, 1]
        if n < 2: return dp[n]
        for i in range(2, n+1):
            dp.append((dp[i-1] + dp[i-2])%MOD)
        return dp[n] % MOD

解法二:空间优化dp
把dp数组从二维降到一维比较常见,这次我们可以把数组从一维降到0维。因为我们每次只需要用到两个数,需要做一个滑动的操作。这时python的特性可以起到无敌的效果,即同时赋值,省去中间变量。

class Solution:
    def fib(self, n: int) -> int:
        MOD = 1000000007
        a, b = 0, 1
        for _ in range(n):
            a, b = b, (a+b)%MOD
        return a%MOD

解法三:O(logN)
首先我们需要利用一个公式,
[ f ( n ) f ( n − 1 ) f ( n − 1 ) f ( n − 2 ) ] = [ 1 1 1 0 ] n − 1 \begin{bmatrix} f(n) & f(n-1) \\ f(n-1) & f(n-2) \end{bmatrix}= \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n-1} [f(n)f(n1)f(n1)f(n2)]=[1110]n1
在n >= 2时,可以利用上述公式求出f(n)的值,当n比较大时,这种做法是很高效的。但不足是没办法预存,但处理单个大数是很有用。之后,我们可以用dfs解决这个问题。由于n次方可以写成两个n/2次方相乘,可以通过分治的思路解决问题。

import numpy as np
class Solution:
    def fib(self, n: int) -> int:
        if n == 0: return 0

        MOD = 1000000007
        one = np.array([[1, 1],
                        [1, 0]])

        # 求t个矩阵one相乘的结果
        def dfs(t):
            if t <= 1:
                return one
            if t&1:
                m = dfs((t-1)//2)
                m = m%MOD
                return np.dot(np.dot(m, m), one)
            else:
                m = dfs(t//2)
                m = m%MOD
                return np.dot(m, m)

        ret = dfs(n-1)%MOD
        return int(ret[0][0])

变形:现在有一个2X8的矩形,咱们有1X2的小矩形,小矩形可以横着或者竖着放入大矩形中,请问有多少种放法?
开始放的时候,用dp,不要老想着往中间放然后分治,其实放前面也是很好的一种思路。在131题中,要求求出所有子集,此题就是从前往后,只要记录个下标就行,如果从中间分治会比较复杂,而且占用空间多。
此题只考虑最左边即可,如果最左边竖着放就是f(n-1),横着两个就是f(n-2)。所以我们可以得到递推公式。
f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n1)+f(n2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值