背包问题专项
1. 背包问题_无价值
题目描述
https://www.lintcode.com/problem/backpack/description
解题思路
思路1:利用动态规划算法,动态更新背包的装载量
- 新建一个一维动态规划数组,索引index为背包的容量,value为此容量背包的最大装载量。
- 遍历A数组,动态更新背包:当加入A数组的某元素时,加与不加谁的装载量大,更新dp。
- 输出dp[len]。
思路2: - 新建一个二维数组,一维索引为遍历第i个元素,二维索引为容量为j的背包,value为遍历第i个元素,容量为j的背包的最大装载量。
源代码
思路1:
class Solution {
public:
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @return: The maximum size
*/
int backPack(int m, vector<int> &A) {
// write your code here
int len = A.size();
int dp[m+1] = {0};
for(int i = 0; i < len; i++)
{
for(int j = m; j >= A[i]; j--)
{
dp[j] = max(dp[j], dp[j-A[i]] + A[i]);
}
}
return dp[m];
}
};
思路2:
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @return: The maximum size
*/
public int backPack(int m, int[] A) {
int n = A.length;
int dp[][] = new int[n+1][m+1];
for(int i = 0; i < n; i ++){
for(int j = 0; j <= m ; j ++){//为了放入第i个物品,找到对于特定空间j的最优放置方案
if(A[i] > j){//第i件大小大于当前背包大小
dp[i+1][j] = dp[i][j];
}else{
dp[i+1][j] = Math.max(dp[i][j],dp[i][j-A[i]] + A[i]);//是否为了放置新的而拿出旧的
}
}
}
return dp[n][m];
}
题型分析
- 无价值背包问题,需要动态更新背包装载量。
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | 1. dp数组,索引index代表背包的容量,value为此容量背包的最大装载量。2. 记得动归题、背包题等,索引和value分别代表的意义。 | ||
般 | |||
必 |
- 记得动归题、背包题等,索引和value分别代表的意义。
- 此题中dp数组,索引index代表背包的容量,value为此容量背包的最大装载量。
时间、空间复杂度
思路1:
sf:n^2
kf:n
此类题模板代码
- 状态转移方程
for(int i = 0; i < len; i++)
{
for(int j = 1; j <= m; j++)
{
dp[i][j] = max(dp[i][j], dp[i][j-A[i]] + A[i]);
}
}
启发性或普适性
- 动归题,背包题,注意好索引和value代表的意义。
总结
- 动归题=数组+索引意义+value意义。
2. 分割等和子集
题目描述
https://leetcode-cn.com/problems/partition-equal-subset-sum/
解题思路
思路1:
- 新建一个二维数组,一维索引为第i个元素,二维索引为和为j的target,初始化二维数组为0。
- 一个外层循环遍历i个元素,判断其是否加入;内层循环遍历为j-num[i]的target(加第i个元素的情况 )或 **dp[i][j-num[i]] (不加num[i]的情况)**能不能满足。
思路2:问题简化为求解是否存在数组的子元素之和等于数组和的一半。
- 新建一个一维dp数组,从最大容量m从后往前遍历加入nums[i]与不加nums[i]是不是可以。
源代码
思路1:
class Solution {
public:
bool canPartition(vector<int>& nums) {
int len = nums.size();
int sum = 0;
int m = 0;
for(int i = 0; i < len; i++)
{
sum += nums[i];
}
if(sum%2 == 1)
{
return false;
}
m = sum/2;
bool dp[len][m+1];
memset(dp,0,sizeof(dp));
if (nums[0] <= m) {
dp[0][nums[0]] = true;
}
for(int i = 1; i < len; i++)
{
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i-1][j];
if(j == nums[i])
{
dp[i][j] = true;
}
if(j > nums[i])
{
dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]];
}
}
}
return dp[len-1][m];
}
};
思路2:
class Solution {
public:
bool canPartition(vector<int>& nums) {
int len = nums.size();
int sum = 0;
int m = 0;
for(int i = 0; i < len; i++)
{
sum += nums[i];
}
if(sum%2 == 1)
{
return false;
}
m = sum/2;
bool dp[m+1];
memset(dp,0,sizeof(dp));
if (nums[0] <= m) {
dp[nums[0]] = true;
}
for(int i = 1; i < len; i++)
{
for(int j = m; j >= nums[i]; j--)
{
dp[j] = dp[j] || dp[j-nums[i]];
}
}
return dp[m];
}
};
题型分析
- 判断为背包问题依据:是不是有第i个元素放与不放,同时从前面的放入中拿出某个元素,进行比较选择的问题。
- 作为“0-1 背包问题”,它的特点是:“每个数只能用一次”。思路是:物品一个一个选,容量也一点一点放大考虑(这一点是“动态规划”的思想,特别重要)。
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | 1. 动态规划的思想:加入nums[i]与不加入nums[i]谁更好,这里是有没有存在等于m的情况。 | ||
般 | |||
必 |
- 动归题:
1、状态定义;
2、状态转移方程;
3、初始化;
4、输出;
5、思考状态压缩。
2. memset(dp, 0, sizeof(dp))z的头文件为cstring。
3.
时间、空间复杂度
思路1:
sf:O(NC)
kf:O(NC)
思路2:
sf:O(NC)
kf:O©
此类题模板代码
- 缩减版的dp
bool dp[m+1];
memset(dp,0,sizeof(dp));
if (nums[0] <= m) {
dp[nums[0]] = true;
}
for(int i = 1; i < len; i++)
{
for(int j = m; j >= nums[i]; j--)
{
dp[j] = dp[j] || dp[j-nums[i]];
}
}
启发性或普适性
- 识别动归题:放与不放。
- dp[j-nums[i]]即是利用了之前的状态或最优值。
总结
- dp[j-nums[i]] = 利用了之前的状态或最优值。
题目描述
解题思路
思路1:
源代码
题型分析
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | |||
般 | |||
必 |
时间、空间复杂度
此类题模板代码
启发性或普适性
总结
题目描述
解题思路
思路1:
源代码
题型分析
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | |||
般 | |||
必 |
时间、空间复杂度
此类题模板代码
启发性或普适性
总结
题目描述
解题思路
思路1:
源代码
题型分析
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | |||
般 | |||
必 |
时间、空间复杂度
此类题模板代码
启发性或普适性
总结
题目描述
解题思路
思路1:
源代码
题型分析
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | |||
般 | |||
必 |
时间、空间复杂度
此类题模板代码
启发性或普适性
总结
题目描述
解题思路
思路1:
源代码
题型分析
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | |||
般 | |||
必 |
时间、空间复杂度
此类题模板代码
启发性或普适性
总结
题目描述
解题思路
思路1:
源代码
题型分析
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | |||
般 | |||
必 |
时间、空间复杂度
此类题模板代码
启发性或普适性
总结
题目描述
解题思路
思路1:
源代码
题型分析
下次遇到此类题我要注意的地方
易 | 中 | 难 | |
---|---|---|---|
紧 | |||
般 | |||
必 |