You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.
Example 1:
Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
- 1 step + 1 step
- 2 steps
Example 2:
Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
3. 1 step + 1 step + 1 step
4. 1 step + 2 steps
5. 2 steps + 1 step
思路:如果没接触过这种类型的题目,猛一看非常复杂,无从下手,难道要用穷举法?仔细想一下,就会发现是迭代类型的问题,当然能不能想到,看造化,一般想不到😂。
可以尝试推,找规律:
n=1,1
n=2,2
n=3,3
n=4,5
n=5,8
这时候就会想到斐波那契数列(Fibonacci sequence),1、1、2、3、5、8、13、21、34、……,在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n) = F(n - 1) + F(n - 2)(n ≥ 3,n ∈ N*)。
其实,还可以这样想,给定n个台阶,一开始可以爬 1 步,也可以爬 2 步,那么n个台阶爬楼的方法数(记为F(n))就等于一开始爬1步的方法数 + 一开始爬2步的方法数。如果一开始爬1步,那么还有n-1个台阶,如果一开始爬2步,那么还有n-2个台阶。n-1个台阶爬楼的方法数(记为F(n-1))等于一开始爬1步的方法数 + 一开始爬2步的方法数。n-2个台阶爬楼的方法数(记为F(n-2))等于一开始爬1步的方法数 + 一开始爬2步的方法数。、、、、、、一直下去,当剩下2个台阶时,2个台阶的爬楼方法数(记为F(2))等于一开始爬1步(1,1)的方法数+等于一开始爬2步的方法数(2,),前者为1,后者也为1。当台阶数为1时,爬楼方法数(记为F(1))只有一种选择,一开始爬1步的方法数为1,一开始爬2步的方法数为0。所以F(2),F(1)是本题递归的出口。
显然最容易想到的方法是递归:
# 递归的写法
# n表示楼梯的阶数
def climbingStair(n):
if n > 2:
return climbingStair(n-1)+climbingStair(n-2)
else:
return n
print(climbingStair(4))
for n in range(18):
print(climbingStair(n))
照顾到n==0的情况:
def climbingStair(n):
if n > 2:
return climbingStair(n-1)+climbingStair(n-2)
elif n == 0:
return 1
else:
return n
for n in range(18):# test
print(climbingStair(n))
学习递归的时候,老师经常讲不要轻易用递归,复杂度太高。
迭代通常可以和递归相互转化:
迭代的思想:
# 迭代的写法
def climbingStair(n):
if n > 2:
step1 = 1
step = 1
for _ in range(2,n+1):
step1,step = step,step1+step
return step
elif n == 0:
return 1
else:
return n
for n in range(18):
print(climbingStair(n))
动态规划的思想:
# 动态规划的写法
def climbingStair(n):
climb = {} # 字典,存储
climb[0]=1
climb[1]=1
if n>2:
for i in range(2,n+1):
climb[i] = climb[i-1] + climb[i-2]
# print(climb)
return climb[i]
elif n == 0:
return 1
else:
return n
for n in range(18):
print(climbingStair(n))
说到这里,那么 递归、迭代、动态规划 有什么区别呢?
递归——程序调用自身,也就是函数自己调用自己。递归通常从顶部将问题分解,通过解决掉所有分解出来的小问题,来解决整个问题;(对于本题中,你会发现递归中含有很多重复的运算)
迭代——利用变量的原值推算出变量的一个新值。递归中一定有迭代,但是迭代中不一定有递归,大部分可以相互转换;
动态规划——通常与递归相反,其从底部开始解决问题。将所有小问题解决掉,进而解决的整个问题。
动态规划相关简介可以阅读动态规划(dynamic programming)