LeetCode 第二十九天 2024.8.15

1. :分割等和子集
 题目链接: 416. 分割等和子集 - 力扣(LeetCode)
应用条件:动态规划

难点:

# 转化为01背包问题,j为sum(nums)//2,看在数组中能否取出来总和的一半,能就True,不能就False
# 确定dp数组(dp table)以及下标的含义:dp[i][j]表示在容量为j的背包中i个物品可以取得的最大价值
# 确定递推公式: 如果nums[i]>j: dp[i][j] = dp[i-1][j],else:不放进去dp[i][j]=max(dp[i-1][j],放进去dp[i-1][j-nums[i]]+nums[i])
# dp数组如何初始化:  dp[0][j]都是1,dp[j][0]中小于nums[0]为0否则为nums[0]
# 确定遍历顺序: i从1到len(nums) j 从1到sum(nums)//2

个人错误:

一定要想到,能分成两个子集可以转化成找一个和为sum(nums)//2 的子集

思路:

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        summ = sum(nums)
        
        if  summ % 2 != 0:
            return False
        target = summ // 2
        dp = [[0]*(target+1) for i in range(len(nums))]
        for j in range(nums[0],target+1):
            dp[0][j] = nums[0]
        for i in range(1,len(nums)):
            for j in range(1,target+1):
                if nums[i] > j:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i])
        if dp[len(nums)-1][-1] == target:
            return True
        else:
            return False

2. :最后一块石头的重量II
 题目链接: 1049. 最后一块石头的重量 II - 力扣(LeetCode)
应用条件:动态规划

难点:

# 转化为01背包问题,j为sum(stones)//2,看在数组中能否取出来总和的一半,能就返回0,不能就返回剩下的减去这个最接近一半的值
# 确定dp数组(dp table)以及下标的含义:dp[i][j]表示在容量为j的背包中i个物品可以取得的最大价值
# 确定递推公式: 如果stones[i]>j: dp[i][j] = dp[i-1][j],else:不放进去dp[i][j]=max(dp[i-1][j],放进去dp[i-1][j-stones[i]]+stones[i])
# dp数组如何初始化:  dp[0][j]都是1,dp[j][0]中小于stones[0]为0否则为stones[0]
# 确定遍历顺序: i从1到len(stones) j 从1到sum(stones)//2

个人错误:

也是要想到可以转化为01背包问题,找到最能接近石头总重量一半的石头群,然后总重量-这个最大值-这个最大值就OK了,不用管石头总重量能否整除2,不影响。

思路:

class Solution:
    def lastStoneWeightII(self, stones: List[int]) -> int:
        if len(stones) == 0:
            return 0
        if len(stones) == 1:
            return stones[0]
        target = sum(stones)//2

        dp = [[0]*(target+1) for i in range(len(stones))]
        for j in range(stones[0],target+1):
            dp[0][j] = stones[0]
        for i in range(1,len(stones)):
            for j in range(1,target+1):
                if stones[i] > j:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = max(dp[i-1][j],dp[i-1][j-stones[i]]+stones[i])

        return sum(stones)-dp[len(stones)-1][-1]-dp[len(stones)-1][-1]

3. :目标和
 题目链接: 494. 目标和 - 力扣(LeetCode)
应用条件:

难点:

# 本题要如何使表达式结果为target,既然为target,那么就一定有 left组合 - right组合 = target。left + right = sum,而sum是固定的。right = sum - left 公式来了, left - (sum - left) = target 推导出 left = (target + sum)/2 。target是固定的,sum是固定的,left就可以求出来。
# 转化为01背包问题,用一维数组来解决,dp[j]表示容量问j的背包,要达到j能有多少种放法,j为(target + sum)/2,不用担心有余数情况,有余数说明不能达到target
# 确定dp数组(dp table)以及下标的含义:dp[j]表示容量问j的背包,能有多少种放法
# 确定递推公式: for i in range(j):dp[j] += dp[j-nums[i]]
# dp数组如何初始化:  因为要累加dp[0] = 1
# 确定遍历顺序: i放外循环从0到len(nums)   j放内循环从(target + sum)/2到nums[i] 倒着循环

个人错误:

要想到left = (target + sum)/2

思路:

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        if abs(target) > sum(nums):
            return 0
        if len(nums) == 0 or (target+sum(nums)) %2 != 0:
            return 0
        curtarget = (target+sum(nums))//2
        dp = [0]*(curtarget+1)
        dp[0] = 1
        for i in range(len(nums)):
            for j in range(curtarget,nums[i]-1,-1):
                dp[j] += dp[j-nums[i]]
        return dp[curtarget]

4. :一和零
 题目链接: 474. 一和零 - 力扣(LeetCode)
应用条件:

难点:

# 转化为01背包问题,dp[i][j]表示背包可以放下i个0和j个1,其中放物品的最大数量
# 确定dp数组(dp table)以及下标的含义:dp[i][j]表示背包可以放下i个0和j个1,其中放物品的最大数量 
# 确定递推公式: dp[i][j]=max(dp[i-x][j-y]+1,dp[i][j]) x,y表示这个物品x个0,y个1
# dp数组如何初始化:  因为是所放物品数量dp[0] = 0
# 确定遍历顺序: s放外循环从0到len(strs)  i放内循环从m到x 倒着循环 j放内循环从n到y 倒着循环

个人错误:

思路:

class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        dp = [[0]*(n+1) for i in range(m+1)]
        for s in strs:
            y = s.count('1') 
            x  = s.count('0') 
            for i in range(m,x-1,-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]

5. :完全背包
 题目链接: 
应用条件:

难点:

完全背包就物品数量无限,一个物品可以放不限次,在01背包一维数组的方法中我们内循环是让j从最大bagsize倒叙向当前i物品的重量wight【i】循环,为的就是防止一个物品被放进去多次,那么对于完全背包,我们可以直接将j正序循环即可实现无限次放物品。

个人错误:

思路:

模板

def test_CompletePack(weight, value, bagWeight):
    dp = [0] * (bagWeight + 1)
    for i in range(len(weight)):  # 遍历物品
        for j in range(weight[i], bagWeight + 1):  # 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
    return dp[bagWeight]

6. :零钱兑换II
 题目链接: 518. 零钱兑换 II - 力扣(LeetCode)
应用条件:

难点:

# 确定dp数组(dp table)以及下标的含义:dp[j]表示金额为amount的硬币组合数
# 确定递推公式: dp[j] += dp[j-coins[i]]
# dp数组如何初始化:  dp[0]=1
# 确定遍历顺序: i从0到len(coins) j 从coins[i]到amount

个人错误:

把 j从0开始遍历了,不能从0开始要从coins[i]开始。

思路:

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        dp=[0]*(amount+1)
        dp[0] =1
        for i in range(len(coins)):
            for j in range(coins[i],amount+1):
                dp[j] += dp[j-coins[i]]
                print(dp)
        
        return dp[amount]

7. :组合总和 Ⅳ
 题目链接: 
应用条件:

难点:

# 确定dp数组(dp table)以及下标的含义:dp[j]表示目标target能有多少组合
# 确定递推公式: dp[j] += dp[j-nums[i]]
# dp数组如何初始化:  dp[0]=1
# 确定遍历顺序: 排列先背包再物品 j 从0到target i从0到len(nums)

个人错误:

没有在遍历j的时候加判断条件,j - nums[i] >= 0的情况下才对dp数组进行操作

思路:

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [0]*(target+1)
        dp[0] = 1
        for j in range(1,target+1):
            for i in range(len(nums)):
                if j - nums[i] >=0:
                    dp[j] += dp[j-nums[i]]
        return dp[target]
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值