参考:https://yq.aliyun.com/articles/664969
三道题都是找规律
斐波那契数列
- 最基本的方法(运用递归)
这个解法是最基本的方法,但是存在很严重的效率问题。
用树形结构图来分析的话,你会发现很多重复的结点。而重复的结点数会随着n的增大而急剧增加,这就意味着计算量会随着n的增大而急剧增大,导致时间变得巨长无比。
- 优化后的方法
其实改进的方法并不复杂,只需要避免1.最基本方法中的重复计算即可。
所以,我们可以把已经得到的数列中间项保存起来,如果下次需要计算的时候,先查找一下,如果已经计算过,就不用重复计算了。
当然,更简单的方法是,自下而上计算,首先根据f(0) 和f(1)算出f(2),再根据f(1)和f(2)算出f(3)……依此类推,可以算出第n项。
那么,自然的,这种时间复杂度便是O(n)。
def Fibonacci(self, n):
# write code here
res = [0,1]
if n < len(res): #n从0开始
return res[n]
c = 0
for i in range(2, n+1):
c = res[-2] + res[-1]
res[-2], res[-1] = res[-1], c
return c
跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
分析如下:
假如现在台阶只有 1 级,n = 1,那么这只青蛙就在只有 1 种跳法:1(1 代表一次跳 1 级台阶)也就是 f(1) = 1 种跳法
假如现在台阶只有 2 级,n = 2,那么这只青蛙可以有 2 种跳法:1 1、2(1 代表一次跳 1 级台阶,2 代表一次跳 2 级台阶),也就是 f(2) = 2 种跳法
假如现在台阶有 3 级,n = 3,青蛙可以有几种跳法呢?
假如青蛙先跳了 1 级台阶,还剩下 2 级台阶,那它还有几种跳法呢?通过第 2 个情况分析知道有 2 种跳法即f(2);假如青蛙先跳了 2 级台阶,根据第 1 个情况分析知道有 1 种跳法即f(1),所以这时候得出 f(3) = f(2) + f(1) 种方法
假如现在台阶有 4 级,n = 4,我们利用上面的规律继续分析可得:f(4) = f(3) + f(2)
综上所述,我们得出其实这个算法就是一个(变形)斐波那契数列问题,公式如下:
n = 1, f(1) = 1
n = 2, f(2) = 2
n > 2, f(n) = f(n -1) + f(n -2)
所以至此明白了,青蛙跳台阶问题就是一个(变形)斐波那契数列问题。
def jumpFloor(number):
# write code here
res = [1,2]
if number <= len(res): #n从1开始,故后面减一
return res[number-1]
c = 0
for i in range(3, number+1):
c = res[-1] + res[-2]
res[-2], res[-1] = res[-1], c
return c
变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
分析如下:
假如现在台阶只有 1 级,n = 1,那么这只青蛙就在只有 1 种跳法:1(1 代表一次跳 1 级台阶)也就是 f(1) = 1 种跳法
假如现在台阶只有 2 级,n = 2,那么这只青蛙可以有 2 种跳法:1 1、2(1 代表一次跳 1 级台阶,2 代表一次跳 2 级台阶),也就是 f(2) = 2 种跳法
假如现在台阶有 3 级,n = 3,青蛙可以有几种跳法呢?
假如青蛙先跳了 1 级台阶,还剩下 2 级台阶,那它还有几种跳法呢?通过第 2 个情况分析知道有 2 种跳法即f(2);假如青蛙先跳了 2 级台阶,根据第 1 个情况分析知道有 1 种跳法即f(1);最后,青蛙可以一下子跳3级台阶,是1种跳法,所以这时候得出 f(3) =f(3)+ f(2)+f(1)+1 =4种方法
假如现在台阶有 4 级,n = 4,我们利用上面的规律继续分析可得:f(4) = f(3) + f(2) +f(1) + 1 = 8
综上所述,我们得出其实这个算法就是一个(变形)斐波那契数列问题,公式如下:
n = 1, f(1) = 1
n = 2, f(2) = 2
n > 2, f(n) = f(n -1) + f(n -2) + …+f(1) + 1
又,f(n-1) = f(n-2) + f(n-3) +…+f(1) + 1
两式相减,可得f(n) = 2f(n-1) 是个等比数列,而且初项为1
def jumpFloorII(self, number):
# write code here
return pow(2, number-1)
矩形覆盖
我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
分析:
当n=1时,矩形大小2x1,小矩形只有竖着覆盖一种方法f(1) = 1;
当n=2时,矩形2x2,小矩形可以横着覆盖,也可以竖着覆盖,则有2种方法f(2) = 2
当n=3时,矩形2x3,第一个矩形竖着覆盖,则剩下一个2x2的矩形有f(2)=2种覆盖方法,如果第一个矩形横着覆盖,则剩下矩形只有一覆盖方法,所以f(3)=f(2) + f(1)
当n=4时,矩形2x4,如果第一个矩形竖着覆盖,则剩下2x3矩形有f(3)种覆盖方法,如果第一个矩形为横着覆盖,则剩下一个1x2,一个2x2,有f(2)种覆盖方法,故f(4) = f(3) + f(2)
因此,本题和青蛙跳台阶问题的规律一样
n = 1, f(1) = 1
n = 2, f(2) = 2
n > 2, f(n) = f(n -1) + f(n -2)
def rectCover(self, number):
# write code here
res = [0,1,2]
if number < len(res):
return res[number]
c = 0
for i in range(3, number + 1):
c = res[-2] + res[-1]
res[-2], res[-1] = res[-1], c
return c