算法day43|1049,494,474

1049. 最后一块石头的重量 II

class Solution:
    def lastStoneWeightII(self, stones: List[int]) -> int:
        summ = sum(stones)
        target = summ//2
        #dp下标和数组的定义,dp[j]代表的是最大价值
        dp = [0]*15001
        #递归公式
        for i in range(len(stones)):
            for j in range(target,stones[i]-1,-1):
        #包括i,不包括i
                dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
        return summ - dp[target]-dp[target]

为什么会想到01背包也是一件很棘手的问题。

因为summ//2是向下取整,所以,summ-dp[target]一定比dp[target]大

代码随想录

二刷(未ac)

var lastStoneWeightII = function(stones) {
    let summ = stones.reduce((a,b)=>a+b)
    let target1 = Math.floor(summ/2)
    let dp = new Array(target1+1).fill(0)
    for(let i = 0;i<stones.length;i++){
        for(let j = target1;j>=stones[i];j--){
            dp[j] = Math.max(dp[j],dp[j-stones[i]]+stones[i])
        }
    }
    return summ-dp[target1]-dp[target1]
};

494. 目标和

整个背包全部用加法运算的话,总和为sum

部分用加分符号的话:x(正数的集合)

其它减法符号:sum-x(负数的集合)

我们要求x - (sum-x) = target

转化一下: x = (target+sum)/2

就像找两个集合,正数的集合和负数的集合

递推公式的推导也挺抽象的,dp[j]代表容量为j,有dp[j]种方法

已有物品为1,在dp[4]种方法的基础上凑成dp[5]

已有物品2,dp[3]种方法的基础上凑成dp[5]。。。

可以推出公式dp[j] += dp[j-nums[i]

 初始化:

dp[0] = 1

为了让后面的数都不会等于0,使用临界条件判断

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        #dp[j]的含义:容量为j的时候有dp[j]种方法
        summ = sum(nums)
        #没有方案的时候
        if abs(target) > summ:
            return 0
        if (target+summ)%2 == 1:
            return 0
        want = (target+summ)//2
        #初始化
        dp = [0]*(want+1)
        dp[0] = 1
        #遍历顺序
        for i in range(len(nums)):
            for j in range(want,nums[i]-1,-1):
                #递归公式
                dp[j] += dp[j-nums[i]]
        #打印dp数组
        return dp[want]

大家重点理解 递推公式:dp[j] += dp[j - nums[i]],这个公式后面的提问 我们还会用到。

代码随想录

二刷:(未ac)

var findTargetSumWays = function(nums, target) {
    // 如何转化为01背包问题
    let summ = nums.reduce((a,b)=>a+b)
    // 求目标背包容量
    let weight = (target+summ)/2
    if(Math.abs(target)>summ){
        return 0
    }
    // 都是int 类型,所以小数的话不可能凑成
    if((target+summ) % 2 !== 0){
        return 0
    }
    // dp[j]代表装满j容量的包,有dp[j]种方法
    let dp = new Array(weight+1).fill(0)
    //初始化
    dp[0] = 1
    for(let i = 0;i<nums.length;i++){ // 遍历物品
        for(let j = weight;j>=nums[i];j--){ // 遍历容量
            dp[j] += dp[j-nums[i]]        
        }
    }
    //打印dp数组
    console.log(dp)
    return dp[weight]
    
};

474.一和零

通过这道题目,大家先粗略了解, 01背包,完全背包,多重背包的区别,不过不用细扣,因为后面 对于 完全背包,多重背包 还有单独讲解。

class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        #dp数组的含义,dp[i][j]指的是有i个0,j个1的背包,最大能装多少个物品
        dp = [[0]*(n+1)for _ in range(m+1)]
        #初始化
        dp[0][0] = 0    
        #遍历顺序
        x = 0
        y = 0
        #遍历物品
        for str in strs:
            #统计有多少个0,多少个1
            one = str.count('1')
            zero = str.count('0')
            #遍历背包
            for i in range(m,zero-1,-1):
                for j in range(n,one-1,-1):
                    dp[i][j] = max(dp[i][j],dp[i-zero][j-one]+1)
        #递归公式
        return dp[m][n]
        #打印

代码随想录

二刷(未ac)

var findMaxForm = function(strs, m, n) {
    // let dp = Array.from(Array(m),()=>new Array(n).fill(0))
    let dp = Array(m+1).fill(0).map(()=>Array(n+1).fill(0))
    for(let str of strs){
        let numOfZero = 0
        let numOfOne = 0
        for(digit of str){
            if(digit === '0'){
                numOfZero ++
            }else{
                numOfOne ++
            }
        }
        for(let i = m;i>=numOfZero;i--){
            for(let j = n;j>=numOfOne;j--){
                dp[i][j] = Math.max(dp[i][j],dp[i-numOfZero][j-numOfOne]+1)
            }
        }
    }
    return dp[m][n]

    
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值