代码随想录算法训练营第四十三天| LeetCode1049. 最后一块石头的重量 II、LeetCode494. 目标和、LeetCode474. 一和零
创始人
2024-02-09 04:50:18
0

一、LeetCode1049. 最后一块石头的重量 II

        1:题目描述(1049. 最后一块石头的重量 II)

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

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

  • 如果 x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x

        最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0

        2:解题思路

class Solution:def lastStoneWeightII(self, stones: List[int]) -> int:# 将一堆石头分成两堆重量相近的两堆石头,这样两堆石头碰撞之后,得到的重量就是最小重量# 如何获得两堆重量相近的石头呢?# 把这一堆石头的重量,除以2,向下取整,就是其中一堆石头的重量# 另外一堆石头的重量就是原石头总重量-向下取整得到的石头重量# 然后我们就可以把向下取整得到的石头重量,看做背包容量,石头的重量看做物品的重量和价值# 就将这个问题转化成了0-1背包问题,就可以用01背包的思路来进行求解# target = sum(stones) // 2          # 求石头总重量的一半,向下取整# 定义dp数组,dp[j]表示,容量为j的背包得到的最大价值为dp[j]# 初始化,j=0时,无法装物品,所以dp[0]=0# 其他的是求上一个容量所装的最大价值和上一个容量所装的最大价值+当前物品重量的最大值,所以其他元素也初始化为0dp = [0] * (target+1)        # 防止元素溢出,长度为target+1# 遍历顺序,先遍历物品,再倒序遍历背包容量(防止同一个物品重复加入)for i in range(len(stones)):# j从target开始,从后向前遍历,直到j>=sones[i]for j in range(target, stones[i]-1, -1):  # 递推公式,0-1背包的递推公式为:dp[j] = max(dp[j], dp[j-weight[i]]+value[i])# 本题中石头的重量就是石头的价值,所以dp[j] = max(dp[j], dp[j-stones[i]]+stones[i])dp[j] = max(dp[j], dp[j-stones[i]]+stones[i])# dp[target]是容量为target的背包所能装的最大价值,及石头的最大重量# sum(stones)-dp[target]是,剩余的石头重量res = sum(stones)-dp[target] - dp[target]    # res就是两堆石头碰撞之后,所剩的最小重量return res

二、LeetCode494. 目标和

        1:题目描述(494. 目标和)

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

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

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

        返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

        2:解题思路

        确定dp数据的含义:

        dp[j]表示,装满容量为j的背包有dp[j]种方式

        递推公式:

        不考虑nums[i]的情况下,填满容量为j的背包,有dp[j]种方法。

        那么考虑nums[i]的话(只要搞到nums[i]),凑成dp[j]就有dp[j - nums[i]] 种方法。

        例如:dp[j],j 为5,

  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 dp[5]。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 dp[5]。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 dp[5]
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 dp[5]
  • 已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 dp[5]

        那么凑整dp[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起来。

        所以递推公式为:dp[j] += dp[j - nums[i]](求组合类问题的公式,都类似于这种)

class Solution:def findTargetSumWays(self, nums: List[int], target: int) -> int:# 将nums分为两个数组,一个数组放正数(left),一个数组放负数(right)# 由题意得出:# sun(left) + sum(right) = sum(nums)# sum(left) - sum(right) = target# 可得出:sun(left) - (sum(nums)-sum(left)) = target,sum(left) = (target+sum(nums))/2# 即正数数组left中,有多少种方式,可以使得sum(left) = (target+sum(nums))/2# 由此可看做0-1背包问题# 定义:dp[j]表示,装满容量为j的背包有dp[j]种方式# 初始化:j=0时,dp[0] = 1# 递推公式:dp[j] += dp[j-nums[i]]# 遍历顺序,先遍历物品,再倒序遍历背包容量,直到背包容量小于物品重量if abs(target) > sum(nums) or (target+sum(nums))%2 != 0:# 如果正数数组的和不能被2整除的话,说明找不到符合题意的组合# 若目标值的绝对值已经大于了nums的元素和,说明没有符合题意的组合return 0          left = int((target+sum(nums))/2)       # 正数数组的和dp = [0] * (left+1)dp[0] = 1for i in range(len(nums)):for j in range(left, nums[i]-1, -1):dp[j] += dp[j-nums[i]]return dp[left]

三、LeetCode474. 一和零

        1:题目描述(474. 一和零)

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

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

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

        2:解题思路

        确定dp数组含义:

        定义dp[i][j],表示装满i个0,j个1,最多有dp]i[j]个物品;即最多有i个0和j个1的strs的最大子集的大小为dp[i][j]

        递推公式:

        dp[i][j] 可以由前一个strs里的字符串推导出来,strs里的字符串有x个0,y个1。

        dp[i][j] 就可以是 dp[i - x][j - y] + 1。

        然后我们在遍历的过程中,取dp[i][j]的最大值。

        所以递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);

        01背包的递推公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

        字符串的x和y相当于物品的重量(weight[i]),字符串本身的个数相当于物品的价值(value[i])。 只不过物品的重量有了两个维度而已。

class Solution:def findMaxForm(self, strs: List[str], m: int, n: int) -> int:# 看做0-1背包问题,背包容量是m个0,n个1# 定义dp[i][j],表示装满i个0,j个1,最多有dp]i[j]个物品;即最多有i个0和j个1的strs的最大子集的大小为dp[i][j]# 递推公式:dp[i][j] = max(dp[i][j], dp[i-x][j-y]+1),x表示当前物品有x个0,y个1# 初始化:当i=0,j=0,初始化为0,即dp[0][0] = 0,其他元素也初始化为0# 遍历顺序,先遍历字符串(物品),即strs,统计物品中有x个0,y个1# 再倒序遍历m,ndp = [[0] * (n + 1) for _ in range(m + 1)]for s in strs:           # 遍历字符串x, y = 0, 0for item in s:# 统计字符串中,0和1的个数if item == "0": x += 1else: y += 1for i in range(m, x-1, -1):     # 倒序遍历0的个数,1的个数for j in range(n, y-1, -1):dp[i][j] = max(dp[i][j], dp[i-x][j-y]+1)return dp[m][n]

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...