2021/01/21 动态规划/ Dynamic Programming (华为机试-购物单)

本文介绍了动态规划在解决华为机试购物单问题中的应用,通过斐波那契数列举例说明动态规划如何优化递归,降低复杂度。文章还提到0/1背包问题,并推荐了相关YouTube教程,解释了二维列表逻辑顺序的重要性,以及在解决此类问题时为何需要从右往左计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划/ Dynamic Programming (华为机试-购物单)

最近报名了华为的机试,刷题的时候遇到了购物单那道题,于是稍微去了解了一下动态规划。所谓动态规划的优点,我的理解就是用空间去换取了时间,来解决了over-lap subproblem。很多recursion(递归)的题目都可以用dynamic programming来进行优化。
最经典的例子就是Fibonacci Sequence 即 斐波那契数列。
如果用递归的方式来计算f(n)= f(n-1) + f(n-2)时,比如f(n-2)这项,在计算f(n)和 f(n-1)都会计算一次。所以会导致复杂度比较高,而如果我们用一个list来保存每一项的值,那么f(n-2)这项就不需要重复计算了。算出来一次,第二次直接拿来用就行,这大概就是我对动态规划的初步理解。
这里推荐Youtube上 黄浩杰的动态规划两讲, 讲的非常清楚。

接下来举几个例子来讲解一下:

第一题为黄浩杰视频中的一道例题,大概是讲用列表a中的数字能否加起来等于b(每个数字用一次或不用)
比如 a = [5,2,3] b = 7, 答案是True,因为 7 = 5+2
同理 a = [5,2,3] b = 9, 答案是False,
特殊的,a = [1,2,3] b = 0,答案是True

#1. 判断a中的数字能否加起来等于b
import numpy  as np
a = [1,4,7,3,5]
b = 20
def dp_subset(a,b):
    dp = np.zeros((len(a),b+1),dtype=bool) #dp[i,j] i表示此时为用a[0,i]的数 , j为此时目标值
    dp[0,:] = False #a[0]只有一个数,除了0和a[0],不能加出其他数, 所以下面会把dp[0,0],dp[0,a[0]]改为True
    dp[:,0] = True  #当目标值都为0时,任何长度的a都能得到目标值,即每个数都不使用
    dp[0,a[0]] = True
    for i in range(1,len(a)):
        for j in range(1,b+1):
            if a[i] > j:
                dp[i,j] = dp[i-1,j]   #如果a[i]>j,即这个数大于目标值,则考虑不使用a[i],dp[i,j]和dp[i-1,j]的值是一样的
            else:
                A = dp[i-1,j]		#不用a[i],能否加出来j,则考虑dp[i-1,j]
                B = dp[i-1,j-a[i]]	#用了a[i],则目标值变成了j-a[i],则考虑dp[i-1,j-a[i]]
                dp[i,j] = A or B 	#两种选择,有一种是True就行
    m,n = dp.shape
    return dp[m-1,n-1]
print(dp_subset(a,b
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值