Python Prep随想练习-Day4

Day4-part1

Coin Change Problems 零钱找零问题

问题描述

你有一些硬币(硬币区分面值:1,2,5,10),你要用这些硬币组成你的找零数额,你所面对的事情呢有两个。

  1. 怎么确定找零所需的最少硬币数
  2. 共有多少种可能的硬币组合
    coin = [ 1,2,5,10 ]
    value=7 min_number=2 combinations={1,1,1,1,1,1,1} ; {2,5} ; {1,1,5} ; {2,2,1,1,1} ; {2,2,2,1};{2,1,1,1,1,1}
    总共有好多好多种,我们要确定一个算法来实现

找零问题解决思路

[1 ] 确定dp数组(dp table)以及下标的含义
[2 ] 确定递推公式
[3 ] dp数组如何初始化
[4 ] 确定遍历顺序
[5 ] 举例推导dp数组

我们先把问题拆分,从获得最少的硬币数开始解决这个问题
1.确定dp数组
在昨天的学习中,我们知道了可以通过一维数组解决动态规划问题。在这里我们也设置dp数组为一维数组,同时dp数组存储的内容 dp[ i ] 应该意味着此时所对应的最小硬币数量。具体创建之后长这样:
在这里插入图片描述
2.确定递推公式

如果coin[ i ]==j ,那就是说明,刚好可以用一个硬币coin[ i ]来完成找零任务。dp[ j ]=1
如果coin[ i ]!= j ,那就是说明还需要别的零钱共同完成找零任务。
dp[ j ]=min(dp[ j ],dp[ j-coin[ i ] ]+1) 在上一个方案基础上加一枚coin[ i ]硬币

3.数组初始化
在之前我们求最大值的时候,是让数组初始值设为0,便于我们去寻找最大值。这里我们让数组初始值设为最大值,便于我们去寻找最小值

coin=[1,2,5]
def get_min_coin(weight):
	dp=[float('inf')] * (weight+1)
	dp[0]=0
	for i in range(len(coin)):
		for j in range(coin[i],weight+1):
			dp[j]=min(dp[ j ],dp[ j-coin[i] ]+1)
	return dp[weight]

尝试自己实现一下这段代码吧!
在这里插入图片描述

零钱组合问题

目的是找到最大的组合数,还是用动态规划的思路来解决这个题目。
1.确定dp数组
和上面的一样,同样采用一维数组,但是现在dp数组中存放的信息是:最大零钱组合数
2.确定递推公式
dp[ j ]=dp[ j-coin[i] ]+dp[ j ] 这里说的是什么事情呢?
在这里插入图片描述

先看黄色的部分
看第二行:这里是不是对应没有考虑硬币6的情况下,weight=6的话最多的组合方法。
当考虑硬币6之后,看第三行。现在的可能组合数就变成了:没有考虑6的组合数+配合6出现的可能情况 也就是dp[6]=dp[6]+dp[6-6]=1+2=3
再看蓝色的部分,这时候你很容易就知道了dp[7]=dp[7]+dp[1]=1
dp[ j ]=dp[ j-coin[i] ]+dp[ j ] 这个公式十分显然了吧!

3.dp数组初始化
想求最大,那么理应设置为全0!但是我们需要对dp[ 0 ]赋值,认为0这种情况也是一种有效组合,不然你想想(如果dp[ 0 ]=0,整个递推还有意义吗?) dp[ 0 ]=1

def get_max_combination(weight):
	dp=[0]*(weight+1)
	dp[0]=1
	for i in range(len(coin)):
		for j in range(coin[i],weight+1):
			dp[j]+=dp[j-coin[i]]
	return dp[weight]

在这里插入图片描述
教材中采用二维数组实现,我们采用一维数组实现,也不失为一桩好事。
动手试试吧!

Day4-part2

Longest Increasing Subsequence 最长递增子序列

问题描述

给你一个序列,比如 5,12,2,7,1,8,13,12,获得最长子序列长度
5,7,8,13 len=4
2,7,8,13 len=4
采用动态规划解决这个题目

解决思路

[1 ] 确定dp数组(dp table)以及下标的含义
[2 ] 确定递推公式
[3 ] dp数组如何初始化
[4 ] 确定遍历顺序
[5 ] 举例推导dp数组

1.确定dp数组
同样首先采用一维数组解决这个问题,dp[ i ]代表的是当前点(其作为递增子序列的最后一个值)所包含的最长子序列的长度。
根据目前分析的定义,我们同时可以对这个数组进行初始化。每个点对应的最长子序列长度至少包含他本身的长度,也就是1,所以在这里进行赋值操作。
在这里插入图片描述

s=[5,12,2,7,1,8,13,12]
dp=[1]*len(s)

2.确定递推公式
在这里插入图片描述

针对5分析,显然dp[ 0 ]=1
针对5 12分析,5<12 dp[ 1 ]=max(dp[ 1 ],dp[ 0 ]+1)
针对 5 12 2分析, 显然不递增 dp[ 2 ]=1
针对 5 12 2 7 分析,
5<7 dp[ 3 ]=max(dp[ 3 ],dp[ 0 ]+1)=2
2<7 dp[ 3 ]=max(dp[ 3 ],dp[ 2 ]+1)=2
自己进行一下推导,是不是有:
if a[ i ]<a[ j ] dp[ j ]=max(dp[ j ],dp[ i ]+1) 感受一下整体过程吧!自己画一下,动动手!
在这里插入图片描述

s=[5,12,2,7,1,8,13,12]
def get_subsequence(s):
    dp=[1]*len(s)
    for i in range(0,len(s)):
        for j in range(i,len(s)):
            if s[j]>s[i]:
                dp[j]=max(dp[j],dp[i]+1)
    return dp
print(get_subsequence(s))

最终得到了整个数组,每个元素作为端点值对应的最长子序列长度。

Day4-part3

Edit Distance 编辑字符串

问题描述

给定一个源字符串和一个目标字符串,把源字符串怎么修改才能得到目标字符串?
字符串的操作包括:insert(插入),delete(删除),replace(替换)
s_source=banana
s_target=anaconda
肯定要进行若干次插入、删除、替换,我们想寻求最少的次数。

解题思路

[1 ] 确定dp数组(dp table)以及下标的含义
[2 ] 确定递推公式
[3 ] dp数组如何初始化
[4 ] 确定遍历顺序
[5 ] 举例推导dp数组

1.确定dp数组
在这里参照Day3-part1的思路,针对两个字符串还是采用二维数组才比较直观可靠。我们来确定一下dp[ i ][ j ]究竟代表的是什么呢?
dp[ i ][ j ]代表着操作数,从行的角度来看,我们关注第一行,第一行的意思是针对字符“”
,需要dp[ 0 ][ i ]个操作来实现s_target[ i ],具体填充方式参照下图。
从列的角度来看,第一列意味着针对字符“”,需要dp[ j ][ 0 ]个操作来实现s_source[ i ],具体填充方式参照下图。
分析的同时,我们也对dp数组完成了初始化
在这里插入图片描述
在这里插入图片描述
2. 确定递推公式

去看一下day3的part1!
if s_source[ i ]== s_target[ j ] 那么 dp[ i ][ j ]=dp[ i-1 ][ j-1 ],什么意思呢,为什么呢。其实这里就代表着如果两个对应的字符相等的话,那么其实就不需要额外的操作了,直接继承两者未考虑前的dp值就好了!
if s_source[ i ]!= s_target[ j ] , 这种情况下肯定是要进行一次操作的,千真万确的,但是是在什么基础上进行这一次操作的呢?
dp[ i ][ j ]=1+min(dp[ i-1 ][ j-1],dp[ i ][ j-1 ],dp[ i-1 ][ j ]) 其实这一次添加的操作应该是在其邻接的三个状态之后完成,毕竟邻接三个状态都可以,仅通过一次操作实现当前状态。并且我们想知道总体的最少操作数,因此三者取最小值就好啦!

自己动手画一下,看看能不能实现这张图对应的效果呢!
在这里插入图片描述

s_source='banana'
s_target='ananconda'
def get_min_operation(s_source,s_target):
	dp=[[0 for i in range(len(s_target)+1)]] for j in range(len(s_source)+1)
	for i in range(len(s_target)+1):
		dp[0][i]=i
	for i in range(len(s_source)+1):
		dp[i][0]=i
	for i in range(1,len(s_source)+1):
		for j in range(1,len(s_target)+1):
			if s_source[i-1]==s_target[j-1]:
				dp[i][j]=dp[i-1][j-1]
			else:
				dp[i][j]=1+min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])
	return dp[len(s_source)][len(s_target)]

动手实现一下,实现好了就会了!

结语

在第四天的学习中,我们完成了三道题目的学习,分别对应动态规划的不同题目类型。
相信你已经学会了,你是最棒的哦!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值