一
假设楼梯有n阶。每次可以爬 1 阶或 2阶。有多少种不同的方法可以爬到楼顶
-
题目分析:
- 设f(n)为n阶台阶的情况下,所有不同的方法的总和!
- 1.如果起始跳一阶的话,剩余的n-1阶就有 f(n-1) 种跳法;
- 2.如果起始跳二阶的话,剩余的n-2阶就有 f(n-2) 种跳法;
- 所以f(n) = f(n-1) + f(n-2),实际结果即为 斐波纳契数。
1、递归法
def climbStairs(n):
if n == 1:
return 1
elif n == 2:
return 2
else:
s1 = climbStairs(n-1)
s2 = climbStairs(n-2)
return s1+s2
2、迭代法
def climbStairs(n):
nums = [0,1,2]
if n == 1:
return nums[1]
elif n == 2:
return nums[2]
else:
for i in range(3,n+1):
nums.append(nums[i-1] + nums[i-2])
return nums[n]
3、迭代优化版
def climbStairs(n):
condition = [0] * (n + 1)
condition[0] = 1
condition[1] = 1
for i in range(2, n+1):
condition[i] = condition[i-1] + condition[i-2]
return condition[n]
二
假设楼梯有n阶。每次可以爬 1 阶或 2阶或3阶。有多少种不同的方法可以爬到楼顶
-
题目分析:
- 设f(n)为n阶台阶的情况下,所有不同的方法的总和!
- 1.如果起始跳一阶的话,剩余的n-1阶就有 f(n-1) 种跳法;
- 2.如果起始跳二阶的话,剩余的n-2阶就有 f(n-2) 种跳法;
- 3.如果起始跳二阶的话,剩余的n-2阶就有 f(n-2) 种跳法;
- 4.第一个台阶只有1种上法,第二个台阶有2种上法,第三个台阶有4种上法。
-
5.从第n个台阶上往回看,有3种方法可以上来(从第n-1个台阶上爬1个台阶上来,从第n-2个台阶上一步爬2个台阶上来,从第n-3个台阶上爬3个台阶上来),
从而得到公式f(n) = f(n-1) + f(n-2) + f(n-3)
1、递归法
def climbStairs2(n):
first = {1:1, 2:2, 3:4}
if n in first.keys():
return first[n]
else:
return climbStairs2(n-1) + climbStairs2(n-2) + climbStairs2(n-3)
2、迭代法
def climbStairs(n):
a = 1
b = 2
c = 4
for i in range(n-3):
c, b, a = a+b+c, c, b
return c
3、递归优化版
使用递归效率非常低,因为递归时上下文的保存和恢复比较耗时,还涉及大量的重复计算。可使用functools标准库提供的缓冲修饰器lru_cache来缓解这个问题。
@functools.lru_cache(maxsize=64)
def climbStairs(n):
#带缓冲的递归法
first = {1:1, 2:2, 3:4}
if n in first.keys():
return first[n]
else:
return climbStairs3(n-1) + climbStairs3(n-2) + climbStairs3(n-3)
三
假设楼梯有 n 阶。每次最多可以爬 m 阶。有多少种不同的方法可以爬到楼顶
def suanfa(n, m):
sumStep = 0
if n == 0:
return 1
if n >= m:
i = 1
while i <= m:
sumStep += suanfa(n - i, m)
i += 1
else:
sumStep += suanfa(n, n)
return sumStep
四
假设楼梯有 n 阶。每次最多可以爬 n 阶。有多少种不同的方法可以爬到楼顶
-
设f(n)为n阶台阶的情况下,所有不同的跳法方法的总和!
- 1.如果起始跳一阶的话,剩余的n-1阶就有 f(n-1) 种跳法;
- 2.如果起始跳二阶的话,剩余的n-2阶就有 f(n-2) 种跳法;
-
3.如果起始跳三阶的话,剩余的n-3阶就有 f(n-3) 种跳法;
… - n.如果起始跳n阶的话,剩余的n-n阶就有 f(n-n) 种跳法;
- f(0) = 1,f(1) = 1, f(2) = 2
- f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(n-(n-1)) + f(n-n)
- f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(1) + f(0)
- f(n-1) = f(n-2) + f(n-3) + … + f(0)
-
f(n-2) = f(n-3) + … + f(0)
… -
f(n) = 2 * f(n-1)
= 2^2 * f(n-2)
= 2^(n-2) * f(2)
= 2^(n-1)
最终结果f(n) = 2^(n-1)
五
假设楼梯有 n 阶。每次可以爬的 阶数 是集合 X 中的元素(正数)。有多少种不同的方法可以爬到楼顶
1、递归法
def staircase(n, X):
if n < 0:
return 0
elif n == 0:
return 1
elif n in X:
return 1 + sum(staircase(n - x, X) for x in X if x < n)
else:
return sum(staircase(n - x, X) for x in X if x < n)
print(staircase(10, {1, 2}))
2、迭代法
def staircase(n, X):
cache = [0 for _ in range(n + 1)]
cache[0] = 1
for i in range(n + 1):
cache[i] += sum(cache[i - x] for x in X if i - x > 0)
cache[i] += 1 if i in X else 0
return cache[-1]
print(staircase(10, {1, 2}))
六
列表的索引 i 对应楼梯的第 i 阶,第 i 阶对应列表索引为 i 的一个非负数的体力值 cost[i]。
每爬上一个阶梯都要消耗对应的体力值,每次可以选择爬一阶或者爬两阶。
需要找到达到楼梯顶部,消耗的体力值总和最小的方法。
1、
def minCostClimbingStairs(cost):
cost.append(cost[-1])
dp = [0]*(len(cost)+1)
if len(cost) == 1:
return cost[0]
if len(cost) == 2:
return min(cost[0], cost[1])
if len(set(cost)) == 1:
return cost[0]*((len(cost)//2) + (len(cost) % 2))
else:
for i in range(2, len(cost)+1):
dp[i] = min(dp[i-2]+cost[i-2], dp[i-1]+cost[i-1])
return dp[-1]
print(minCostClimbingStairs([1, 2, 1, 1, 1, 1, 1, 1, 1, 2]))
2、
def minCostClimbingStairs(cost):
cost.append(cost[-1])
f1 = f2 = 0
for x in reversed(cost):
f1, f2 = x + min(f1, f2), f1 # 用f1,f2轮流遍历列表,轮流保存最小值
return min(f1, f2)
print(minCostClimbingStairs([1, 2, 1, 1, 1, 1, 1, 1, 1, 2]))