码迷,mamicode.com
首页 > 编程语言 > 详细

剑指offer-斐波那契数组及相关问题

时间:2019-10-31 21:39:51      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:==   大于   状态   还需要   off   output   nat   编码   div   

斐波那契数组

公式:f[0] = 0; f[1]= 1; f[n] = f[n-1] + f[n-2]

如果直接用递归实现的话,可能会出现重复计算问题:

def fibo(n):
    if n<2: return n
    return fibo(n-1) + fibo(n-2)

这里如果我们计算f(4), 则会有 f(4) = f(3) + f(2); f(3) = f(2) + f(1) 两处计算f(2) 的地方。一个很自然的改进方案:每次计算fibo(n) 是看看是不是已经计算过,如果计算过就直接返回之间计算出来的值:

def fibo(n):
    if n < 2: return n
    dp = [-1] * len(n+1)
    dp[0],dp[1] = 0,1
    return f(n)

def f(n):
    if dp[n] != -1: return dp[n]
    dp[n] = f(n-1) + f(n-2)
    return dp[n]
    

当然,我们可以不递归的方法,直接用数组记录:

def fibo(n):
    if n<2: return n
    dp = [0]*len(n+1)
    dp[1] = 1
    for i in range(2,n+1):
        dp[i] = dp[i-1] + dp[i-2]
    return dp[n]

主要到,我们实际上一直在使用的只用dp[n-1],dp[n-2],dp[n], 所以我们还可以优化下内存空间:

def fibo(n):
    if n<2: return n
    fn_1,fn = 0,1
    n -=2
    while n>=0:
        fn,fn_1 = fn+fn_1,fn
        n -= 1
    return fn

接下来说说一些相似的题目:

相似的题目

青蛙跳台阶问题:

一个青蛙可以跳上一个台阶,也可以跳上两个台阶,求改青蛙跳上一个n级的台阶共有多少种跳法?

首先考虑状态变化过程:青蛙到达当前台阶是更低一阶的台阶或者是更低二阶的台阶跳上来的。所以有:

f[0] =0, f[1] = 1, f[2] = 2

f[n] = f[n-1] + f[n-2] 当 n>2时

代码:

def jump(n):
    if n <= 2: return n
    fn,fn_1 = 1,2
    n -= 2
    while n>0:
        fn,fn_1 = fn+fn_1,fn
        n -= 1
    return fn

方块覆盖问题:

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

对于\(2 \times n\) 的矩形,如果从左向右开始填充,再最左边我们可先竖着放一个或者横着放两个,那么剩下的情况就是f(n-1) 与 f(n-2)。 所以有公式:

f[0] = 0; f[1] =1; f[2] = 2

f[n] = f[n-1] + f[n-2] 当 n>2 时

代码同上边的青蛙跳台阶题目一样。

解码方式(LeetCode 91 )

现有信息通过如下编码方式编码:

'A' -> 1
'B' -> 2
...
'Z' -> 26

先给一个编码后的字符串,请判断有多少种解码方式.

Example 1:

Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).

Example 2:

Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

这个如同上面的题目一样,从左向右扫描,也和矩阵覆盖问题一样,有两种可能:
这里以"226"为例子,当前指向6时 为例子

可以覆盖"2",也即是f(n) 可以从f(n-2)状态转移来

也可以覆盖 "22" , 也即是f(n) 可以从状态f(n-1) 转移过来。当然我们还需要检查n-2和n-1构成的编码是否不大于26.

所以我们有状态转移方程:

f[0] = 0; f[1] = 1;

if s[n] == '0':
    f[n] = f[n-1]
elif s[n] != '0' and int(s[n-1:n+1]) < 27:
    f[n] = f[n-1] + f[n-2]
elif s[n]!= '0' and int(s[n-1:n+1]) >26:
    f[n] = f[n-1]

代码:

def numDecodings(self,s:str)->int:
    if s==None: return 0
    fn,fn_1 = 1,1
    for i in range(0,len(s)):
        new_fn = 0 if s[i]=='0' else fn
        if i>0 and (s[i-1]=='1' or s[i-1]=='2' and s[i]<'7'):
            # 注意这里使用 (s[i-1]=='1' or s[i-1]=='2' and s[i]<'7') 代替 int(s[i-1:i+1])
            # 防止出现以0开始的非法编码,如 00,01等.
            new_fn += fn_1
        fn,fn_1 = new_fn,fn
    return fn

剑指offer-斐波那契数组及相关问题

标签:==   大于   状态   还需要   off   output   nat   编码   div   

原文地址:https://www.cnblogs.com/lmingde/p/11773242.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!