代码随想录算法训练营第三十八天| 理论基础,509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯
理论基础
经典题型
- 背包问题
- 打家劫舍
- 股票问题
- 子序列问题
动态规划步骤
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序(for i 和for j到底是谁,到底谁先)
- 举例推导dp数组(打印dp数组来debug)
509. 斐波那契数
题目链接:斐波那契数
递归
class Solution:
def fib(self, n: int) -> int:
if n == 0:
return 0
elif n == 1:
return 1
else:
return self.fib(n-1)+self.fib(n-2)
动态规划
从五部曲开始:
- 确定dp数组(dp table)以及下标的含义:dp[i],第i个斐波那契数;
- 确定递推公式:dp[i] = dp[i-1]+dp[i-2];
- dp数组如何初始化: dp[0] = 1; dp[1] = 1;
- 确定遍历顺序:从前往后
- 举例推导dp数组:用于debug
class Solution:
def fib(self, n: int) -> int:
if n==0: return 0
dp = [0]*(n+1)
dp[0] = 0
dp[1] = 1
for i in range(2,(n+1)):
dp[i] = dp[i-1]+dp[i-2]
return dp[-1]
但其实没必要维护一整个数组,维护三个数就行。
class Solution:
def fib(self, n: int) -> int:
if n==0: return 0
if n==1: return 1
a = 0
b = 1
c = 0
for i in range(1,n):
c = a+b
a = b
b = c
return c
70. 爬楼梯
题目链接:爬楼梯
如果是n节楼梯的爬法,就是n-1节楼梯的爬法(再往上一节),再加上n-2节楼梯的爬法(再直接往上两节)
n-2节楼梯的爬法之后两节其实有两种爬法,一种两次一节,一种直接上两节,但是上两次一节的其实已经包括在n-1节楼梯的爬法,再往上一节里了,所以n-2节楼梯的爬法之后两节直接考虑两节直接上就行
n=3: 1节的爬法(1)再直接往上两节+2节的爬法(2)再往上一节=3
递归
但是迭代会超时。
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1:
return 1
elif n == 2:
return 2
else:
return self.climbStairs(n-1)+self.climbStairs(n-2)
因为你递归嵌套层数太多。这里在反复的self自引用,于是指数级上涨复杂度。这也是动态规划的优点所在。
需要动态规划。
动态规划
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1: return 1
if n == 2: return 2
dp = [0]*n
dp[0] = 1
dp[1] = 2
for i in range(2,n):
dp[i] = dp[i-1]+dp[i-2]
return dp[-1]
同样也是可以只维护三个数。
class Solution:
def climbStairs(self, n: int) -> int:
if n == 1: return 1
if n == 2: return 2
a = 1
b = 2
c = 0
for i in range(2,n):
c = a+b
a = b
b = c
return c
746. 使用最小花费爬楼梯
题目链接:使用最小花费爬楼梯
和斐波那契也差不多,如果顶楼在i层,那么可以从i-1走一层到i,或者从i-2走两层到i
dp[i] = 爬到第i层的最低花费是多少。
又因为可以从底层也可以从一楼开始,那么dp[0]和dp[1]都不花钱都是0。
从二楼往后就是,从i-2楼出发的最小花费dp[i-2]+cost[i-2],和从i-1楼出发的最小花费dp[i-1]+cost[i-1],选择小的那个作为我们的最小花费。
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
#爬到第i层的最低花费是多少
dp = [0]*(len(cost)+1)
dp[2] = min(cost[0],cost[1]) #从0开始爬两层或者1开始爬一层
for i in range(3,(len(cost)+1)):
dp[i] = min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1])
return dp[-1]