class Solution(object):
def minCostClimbingStairs(self, cost):
n = len(cost)
dp = [0] * n
dp[0], dp[1] = cost[0], cost[1]
for i in range(2, n):
dp[i] = min(dp[i-1], dp[i-2]) + cost[i]
return min(dp[-1], dp[-2])
代码思路:
使用动态规划的思想,定义一个长度为n的dp数组,其中dp[i]表示到达第i个台阶所需的最小花费。由于可以从下标为0或1的台阶开始爬楼梯,所以dp[0]和dp[1]的值分别为cost[0]和cost[1]。从第2个台阶开始,每次计算dp[i]时,可以选择从dp[i-1]或dp[i-2]的位置跳上来,所以dp[i]的值为min(dp[i-1], dp[i-2]) + cost[i]。最后返回dp[-1]和dp[-2]中的较小值即可。
也就是说比较它的前一阶和前两阶加现在阶的花费,类似于70的爬楼梯,只是之前要的是爬上楼梯有多少种方法,而现在要的是具体花销。但有类似之处在于现在所求的这一个都是之前的累加。这就是动态规划,我们熟悉的递归调用在于从上到下,比如计算阶乘n!=(n-1)!*n。这种情况下会一直分解到1!再一层层乘上来,如下:
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n-1)
但是动态规划是一种自下而上的解决问题的方法,它将问题分解成多个子问题,并且保存子问题的解,以便后续使用。动态规划通常需要用到一个表格来保存子问题的解,然后根据表格中的数据计算出大问题的解。
在这个例子中,我们将阶乘问题分解成许多小问题,例如计算4的阶乘需要先计算3的阶乘,计算3的阶乘需要先计算2的阶乘,以此类推。通过使用dic字典来存储已经计算过的阶乘值,我们可以避免重复计算,从而提高程序的效率。
这个函数使用了一个名为dic的字典来存储已经计算过的阶乘值。如果n在dic中已经存在,那么函数直接返回dic[n]的值。否则,函数计算n的阶乘并将结果存储在dic[n]中,然后返回dic[n]的值。
这个函数的时间复杂度是O(n),因为它只需要计算每个n值一次。使用动态规划的好处是可以避免重复计算,从而提高程序的效率。
python
def factorial(n, dic={}):
if n == 0:
return 1
if n in dic:
return dic[n]
dic[n] = n * factorial(n-1, dic)
return dic[n]
可以看到,递归的方式是自上而下地解决问题,每次都需要重新计算子问题的解,而动态规划的方式是自下而上地解决问题,每次都利用之前计算的结果来计算当前的结果。
这是我的初始代码,存在多个错误,下面逐一列出:
-
第2行的
cost[] = input()
应该删除,因为cost
已经作为参数传入函数中了,不需要再次输入。 -
第3行的
n=len(cost[])
应该改为n=len(cost)
,因为cost
是一个列表,不需要再加上[]
。 -
第4行的
dp[]=0*n
应该改为dp=[0]*n
,因为dp
是一个列表,需要用*
运算符来初始化。 -
第10行的
if dp[i] <= dp[i+1]:
和else:
后面的return
语句应该移动到循环结束后,因为需要遍历完整个列表才能确定最小代价。 -
第13行的
print sum(dp[])
应该改为print(sum(dp))
,因为sum()
是一个函数,需要用括号来调用。
改进后成了这样,但是第一个测试用例通过之后没有通过第二个测试用例。原因在于没有保存之前的花销,导致以下结果