问题描述
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.
你正在爬楼梯。需要n步才能到达顶端。
每次你可以爬1或2级台阶。你可以用多少种不同的方式爬到山顶?
注意:给定n是一个正整数。
例子1:
输入: 2
输出: 2
期待结果: 存在两种方式爬到最顶端
1. 1 步 + 1 步
2. 2 步
例子2:
输入: 3
输出: 3
期待结果: 存在三种方式爬到最顶端
1. 1 步 + 1 步 + 1 步
2. 1 步 + 2 步
3. 2 步 + 1 步
Python 实现
其实这是一个很经典的算法题,乍看之下不知道从何下手,但我们可以换个角度来看:从结果出发。
根据题目可知,每次行动只有两种可能,要么爬 1 级台阶,要么爬 2 级台阶,所以我们可以这么来思考:假设到达第 n 个台阶共有 f(n) 种方式,则
- 到达第 n 个台阶,要么从 第 n-1 个台阶爬 1 级台阶到达,要么从 第 n-2 个台阶爬 2 级台阶到达。到达第 n-1 个台阶共有 f(n-1) 种方式,到达第 n-2 个台阶共有 f(n-2) 种方式,所以 f(n) = f(n-1) + f(n-2);
- 到达第 n-1 个台阶,要么从 第 n-2 个台阶爬 1 级台阶到达,要么从 第 n-3 个台阶爬 2 级台阶到达。到达第 n-2 个台阶共有 f(n-2) 种方式,到达第 n-3 个台阶共有 f(n-3) 种方式,所以 f(n-1) = f(n-2) + f(n-3);
- 。。。
显然,这个问题的答案就是一个斐波拉契数列了。斐波拉契数列的表达式:f(n) = f(n-1) + f(n-2)。
在该问题中,两个基础条件是 f(2) = 2,f(1) = 1。
因此,最后代码实现一个斐波拉契数列就可以了。
实现一:递归实现
这种实现方式很直观,但是有经验的朋友都知道,在这个过程中,有些结果被重复计算,浪费的计算资源。例如
- f(n) = f(n-1) + f(n-2)
- f(n-1) = f(n-2) + f(n-3)
在这里 f(n-2) 就被重复计算了两遍。不仅如此,当 n 的值特别大的时候,使用递归实现很可能因为函数调用次数过多,从而导致栈溢出。因此,实现斐波拉契数列常常使用下面第二种方法。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
# May be stack overloaded.
return self.climbStairs(n-1) + self.climbStairs(n-2)
实现二:数组(列表)实现
斐波拉契数列实际上从 1 到 n 分别对应一个结果值,因此使用数组或者列表来记录结果最直观。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
F = [1, 2]
for i in range(n-2):
F.append(F[-1] + F[-2])
return F[-1]
实现三:直接获取结果
同样是斐波拉契数列的一种实现形式,由于我们只需要获取值为 n 时的结果,因此通过分析得到基础条件的值(f(2) = 2, f(1) = 1)之后,我们可以直接通过斐波拉契数列的计算公式,算出最后 f(n) 的值返回即可,这样就可以避免使用数组或者列表记录中间值,以节省内存空间。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
s = 0
a = 2
b = 1
for i in range(n-2):
s = a + b
b = a
a = s
return s