版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/majichen95/article/details/89052002
在n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为A[i]
样例
样例 1:
输入: [3,4,8,5], backpack size=10
输出: 9
样例 2:
输入: [2,3,5,7], backpack size=12
输出: 12
挑战
O(n x m) time and O(m) memory.
O(n x m) memory is also acceptable if you do not know how to optimize memory.
注意事项
你不可以将物品进行切割。
解题思路:
典型的背包问题。设横坐标i为前i个物品(包含i),纵坐标为背包容量,中间每个坐标值dp[i][j]表示将前i个物品挑选若干放入容量为j的背包,所装的最大值
边界条件:第一排,若背包容量 >= 第一个物品的大小,则可以装入,否则为0
递推式:两种情况:
(1)不装入当前物品,直接为上一个物品的结果:dp[i][j] = dp[i-1][j]
(2)若能装入当前物品,则先装入当前物品,然后加上剩余容量能装下的物品:dp[i][j] = A[i]+dp[i-1][j-A[i]]
最后取这两种情况的最大值为当前dp[i][j]的结果
时间复杂度:O(m*n),空间复杂度:O(m*n),m代表背包容量,n代表物体数量
public class Solution {
/**
* @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) {
// write your code here
//dp[i][j]表示将前i个物品挑选若干放入容量为j的背包,所装的最大值
//其中i属于[0,A.length),0表示第一个物品,j属于[0,m],0表示容量为0
int[][] dp = new int[A.length][m+1];
//边界条件,第一行
for(int j=0; j<=m; j++)
dp[0][j] = ( j >= A[0] ? A[0] : 0);
//递推式
for(int i=1; i<A.length; i++){
for(int j=0; j<=m; j++){
dp[i][j] = dp[i-1][j];
if(j >= A[i])
dp[i][j] = Math.max(dp[i][j], A[i]+dp[i-1][j-A[i]]);
}
}
return dp[A.length-1][m];
}
}
空间优化1:每一次递归第i行元素都只依赖于第i-1行元素,也就是说只需要2行元素即可求解。而i与i-1恰好一个是奇数一个是偶数,所以可以通过奇偶交换来达到目的,对所有dp[i][j]变为dp[i%2][j]
此时空间复杂度为O(2*m),m为背包容量
public class Solution {
/**
* @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) {
// write your code here
int[][] dp = new int[2][m+1];
//边界条件,第一行
for(int j=0; j<=m; j++)
dp[0][j] = ( j >= A[0] ? A[0] : 0);
//递推式
for(int i=1; i<A.length; i++){
for(int j=0; j<=m; j++){
dp[i%2][j] = dp[(i-1)%2][j];
if(j >= A[i])
dp[i%2][j] = Math.max(dp[i%2][j], A[i]+dp[(i-1)%2][j-A[i]]);
}
}
return dp[(A.length-1)%2][m];
}
}
空间优化2:我们可以看出每次求dp[i][j]只需要它上面的元素和左上的元素,所以我们还可以精简右上的元素,将二维数组变为一维数组。此时只需要从右向左进行计算,比较当前元素以及左边元素即可,同时向左进行到背包无法装下当前物品为止,因为此时就等于当前元素本身,这样还节省了时间
public class Solution {
/**
* @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) {
// write your code here
int[] dp = new int[m+1];
for(int j=0; j<=m; j++)
dp[j] = (j >= A[0]) ? A[0] : 0;
for(int i=1; i<A.length; i++)
for(int j=m; j>=A[i]; j--)
dp[j] = Math.max(dp[j], dp[j - A[i]] + A[i]);
return dp[m];
}
}