第37天|LeetCode1049. 最后一块石头的重量 II、LeetCode494. 目标和、LeetCode474. 一和零

文章介绍了如何使用背包策略来解决三种不同的编程挑战:石头碰撞求最小重量、构造目标和的表达式计数以及二进制字符串的最大子集长度。每种问题都转化为求解不同条件下的背包问题,并应用01背包的递推公式来找到解决方案。
摘要由CSDN通过智能技术生成

1.题目链接:1049. 最后一块石头的重量 II

题目描述:

                有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

                每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

                如果 x == y,那么两块石头都会被完全粉碎;
                如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
                最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。

解法:

        1.五步曲:

                ①本题求的是返回最小可能的重量。那么我们就将这堆石头分成尽可能重量相近的两堆,然后他们相撞,就会得到最小的可能重量。

                ②将其类比成背包问题就是,向容量为Sum/2的背包中尽可能装石头,这样就得到了尽可能装满后的价值即dp[j]。故dp[j]的含义就是,向容量为j的背包中尽可能装石头,得到的价值就是dp[j].

                ③递推公式:dp[j] = max(dp[j-stones[i]] + stone[i]---装了, dp[j---没装,价值不变]) --- 根据01背包的1维解法类比推导过来的。

                ④初始化:因为根据前面的值得到的dp[j],所以初始化dp[0] = 0---因为容量为0,所以价值为0。其他位置,因为根据递推公式,要和本身比较,不能覆盖且价值要大于0,所以取0

                ⑤遍历顺序:先物品后背包;背包倒序。

                ⑥最后返回sum - dp[sum/2] - dp[sum/2]

        2.步骤:

                ①创建dp[],长度为Sum/2+1

                ②初始化dp[0] = 0;

                ③遍历{递推公式;}

                ④此时我们把dp[Sum/2]求出来了,即是一堆石头的量。因为Sum/2是向下取整,所以Sum-dp[Sum/2]一定大于dp[Sum/2],即背包容量小,装的石头重量就小

                ⑤最后返回Sum - dp[Sum/2] - dp[Sum/2]就是两堆石头相碰后的最小重量。

下面为代码(java):

2.题目链接:494. 目标和 

题目描述:

                给你一个整数数组 nums 和一个整数 target 。

                向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

                例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
                返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

解法:

        1.五步曲:

                ①此题要求的是结果等于target的不同表达式的数目。我们可以将其也分成两部分,正数集left,负数集right

                ②left + right = sum;left - right = target;left = (sum+target)/2 --- 即我们要从nums中找出和为left的表达式共有多少种。类比成背包问题就是选取物品放到背包容量为left的背包中,选取物品的方法有多少种。故dp[j] 就表示填充容量为j的背包,共有dp[j]种填充方法

                ③递推公式:dp[j]  = ? 举例容量为5,如果背包中有1,那么有dp[5-1]种方式;有2,就有dp[5-2]种方式,有nums[i],就有dp[j-nums[i]]种方式。所以dp[j] += dp[j-nums[i]] --- 即将所有的情况都加起来,之后遇到填充背包求有多少种填充方法的时候是一样的递推公式

                ④初始化:因为根据前面的求,所以要初始化dp[0] = ?即背包容量为0的时候,有多少种填充方法,1种---即没填充其他位置初始化为什么呢?初始化为0,因为我们递推公式是将所有情况加一起用到了dp[j] += dp[j-nums[i]],如果其他位置初始化不为0的话会影响到递推公式的推导,所以为0.

                ⑤遍历顺序:先物品,后背包。背包倒序。

                ⑥特殊情况:如果(sum+target) % 2 != 0,说明我们需要从nums中找到正数集和有小数才能满足target,但是nums中都是整数,不可能是小数,就说明了不可能找到满足target的方法集返回0.

                ⑦如果target小于0,且target+sum<0,说明target太小了,从nums中取值根本不能满足,所有返回0.

                ⑧可能有疑惑了,如过target>0且target>sum呢?用不用判断呢?因为我们在求bagsize的时候 = target+sum 除以2,如果target大于sum,最后的值也大于sum,而在初始化的时候我们就已经将dp[bagSize] 初始化成0了,而根据递推公式它一直都是0,所以不用再判断了。

        2.步骤:

                ①先求sum

                ②判断不能整除返回0.

                ③判断target为负数且和sum的和也小于0,返回0.

                ④定义bagsize = (sum + target)/2 。创建dp数组,长度为(sum+target)/2 +1.

                ⑤初始化dp[0] = 1;

                ⑥遍历{dp[j] += dp[i-nums[i]];}先物品后背包,倒序背包。

                ⑦最后返回dp[bagSize]

下面为代码(java):

 

3.题目链接:474. 一和零 

题目描述:

                给你一个二进制字符串数组 strs 和两个整数 m 和 n 。

                请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。

                如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

解法:

        1.五步曲:

                ①此题要求最大子集长度。类比于背包问题,就相当于尽量往背包里装物品,求最多能装多少个物品。那么背包容量是多少呢?是m个0和n个1,因为只有背包容量越大,可能装下的物品就越多。而此时背包容量是二维的所以dp数组创建成二维的,dp[i][j]表示的是尽可能向容量为i个0,j个1的背包里装物品,最多能装dp[i][j]个物品

                ②递推公式:dp[i][j] = max(dp[i-x][j-y] + 1, dp[i][j])为什么呢?要么装要么不装,不装就说明没放物品,说明物品数目没变,即dp[i][j]。装了说明把剩余容量取个数+1---即新装了一个。

                ③初始化:因为根据前面的值求的所以初始化dp[0][0] = 0,其余位置因为要和本身比较,不能覆盖又不能为负数所以为0.

                ④遍历顺序:先物品后背包;背包倒叙。

                ⑤最后返回dp[m][n]

        2.步骤:

                ①创建dp[m][n]

                ②初始化dp[0][0] = 0

                ③遍历物品先增强for遍历字符数组的字符串,再将字符串变成char数组,再增强for每个字符串的字符,如果字符为0,x++;否则y++。这样就统计出了每个字符串的重量x,y。

                ④遍历背包for(m){

                        for(n){

                                        dp[i][j] = max(dp[i-x][j-y] + 1, dp[i][j])

                ⑤最后返回dp[m][n]

下面为代码(java):

 

4.总结:

                ①最后石头重量 --- 给定一个容量(sum/2)的背包,尽可能的向背包里放。总统思路就是分成尽可能相近的两堆石头,然后相撞。递推公式 dp[j] = max(dp[j], dp[j-nums[i]] + nums[i])。不放价值不变,放了价值变。

                ②目标和 --- 给定一个容量的背包((sum+target)/2),求将其放满有多少种方法。总统思路将集合分为正数集和负数集,然后数学推导得到背包容量 = (sum+target)/2。要注意递推公式:dp[j] += dp[j- nums[i]],即以后涉及到求放进背包中有多少种方法,都这样求。

                ③10和 --- 给定一个容量的背包(m个0,n个1),尽可能的向背包里放,求最多能放多少个物品。递推公式:dp[i][i] = max(dp[i-x][j-y] + 1, dp[i][j]).不放个数不变,放了个数变。

                ④第一个和第三的递推公式都是根据01背包1维解法来的(即根据放与不放的价值变化或者个数变化),而2呢要计算有多少种方法是一种新的推导过程,计算的是方法数目。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值