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]
};