背包问题集合

背包问题专项

1. 背包问题_无价值

题目描述

https://www.lintcode.com/problem/backpack/description

解题思路

思路1:利用动态规划算法,动态更新背包的装载量

  1. 新建一个一维动态规划数组,索引index为背包的容量,value为此容量背包的最大装载量。
  2. 遍历A数组,动态更新背包:当加入A数组的某元素时,加与不加谁的装载量大,更新dp。
  3. 输出dp[len]。
    思路2:
  4. 新建一个二维数组,一维索引为遍历第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. 无价值背包问题,需要动态更新背包装载量。

下次遇到此类题我要注意的地方

1. dp数组,索引index代表背包的容量,value为此容量背包的最大装载量。2. 记得动归题、背包题等,索引和value分别代表的意义。
  1. 记得动归题、背包题等,索引和value分别代表的意义。
  2. 此题中dp数组,索引index代表背包的容量,value为此容量背包的最大装载量。

时间、空间复杂度

思路1:
sf:n^2
kf:n

此类题模板代码

  1. 状态转移方程
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]);
			}
		 } 

启发性或普适性

  1. 动归题,背包题,注意好索引和value代表的意义。

总结

  1. 动归题=数组+索引意义+value意义。

2. 分割等和子集

题目描述

https://leetcode-cn.com/problems/partition-equal-subset-sum/

解题思路

思路1:

  1. 新建一个二维数组,一维索引为第i个元素,二维索引为和为j的target,初始化二维数组为0。
  2. 一个外层循环遍历i个元素,判断其是否加入;内层循环遍历为j-num[i]的target(加第i个元素的情况 )或 **dp[i][j-num[i]] (不加num[i]的情况)**能不能满足。

思路2:问题简化为求解是否存在数组的子元素之和等于数组和的一半。

  1. 新建一个一维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];
    }
};

题型分析

  1. 判断为背包问题依据:是不是有第i个元素放与不放,同时从前面的放入中拿出某个元素,进行比较选择的问题。
  2. 作为“0-1 背包问题”,它的特点是:“每个数只能用一次”。思路是:物品一个一个选,容量也一点一点放大考虑(这一点是“动态规划”的思想,特别重要)。

下次遇到此类题我要注意的地方

1. 动态规划的思想:加入nums[i]与不加入nums[i]谁更好,这里是有没有存在等于m的情况。
  1. 动归题:
    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©

此类题模板代码

  1. 缩减版的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]];
			}
		}

启发性或普适性

  1. 识别动归题:放与不放。
  2. dp[j-nums[i]]即是利用了之前的状态或最优值。

总结

  1. dp[j-nums[i]] = 利用了之前的状态或最优值。

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

此类题模板代码

启发性或普适性

总结

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

此类题模板代码

启发性或普适性

总结

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

此类题模板代码

启发性或普适性

总结

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

此类题模板代码

启发性或普适性

总结

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

此类题模板代码

启发性或普适性

总结

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

此类题模板代码

启发性或普适性

总结

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

此类题模板代码

启发性或普适性

总结

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值