1. 代码随想录-动规14.LC1049.最后一块石头的重量II
题目链接
最小重量,即最小的相差重量。
石头总重/2,用01背包。
本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。因为石头总重/2是向下取整,所以剩下的重量为sum-target*2
代码
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int i=0; i<stones.length; i++){
sum += stones[i];
}
int target = sum/2;
int[] dp = new int[target+1];
for (int i=0; i<stones.length; i++){
for (int j=target; j>=stones[i]; j--){
dp[j] = Math.max(dp[j], dp[j-stones[i]]+stones[i]);
}
}
return (sum-dp[target]*2);
}
}
2. 代码随想录-动规18.完全背包
完全背包和01背包区别就是:完全背包可以重复多次,01背包一个物品只能放一次。
总结下:
01背包二维:
遍历顺序:先背包或者先物品都可以。
先物品,再背包:从1开始遍历,判断j<weight[i]条件
初始化:i=0和j=0
01背包一维:
遍历顺序:物品从0开始遍历,背包从最大递减到weight[i]遍历(为了保证物品只能放一次)。且必须先物品再背包(因为遍历公式依赖左上角,必须左上角先有值)。
初始化:dp[0]=0;背包容量为0,最大价值为0。
完全背包:
遍历顺序:物品从0开始遍历,背包从小递增遍历(保证物品可重复多次)。此时先物品再背包或先背包再物品都可。先物品再背包的话j从=weight[i]开始遍历。
初始化:dp[0]=0;背包容量为0,最大价值为0。
import java.util.*;
public class Main{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int V = sc.nextInt();
int[] weight = new int[N];
int[] value = new int[N];
int flag = 0;
for (int i=0; i<N; i++){
for (int j=0; j<2; j++){
if (flag == 0){
weight[i] = sc.nextInt();
flag = 1;
}else{
value[i] = sc.nextInt();
flag = 0;
}
}
}
int[] dp = new int[V+1];
for (int i=0; i<N; i++){
for (int j=weight[i]; j<V+1; j++){
dp[j] = Math.max(dp[j], dp[j-weight[i]]+value[i]);
}
}
System.out.println(dp[V]);
sc.close();
}
}
3. LC动规118.杨辉三角
题目链接
思路:
dp数组:dp[i][j] = dp[i-1][j-1]+dp[i-1][j];
10000
11000
12100
13310
14641
也可直接用list,row.add(ret.get(i - 1).get(j - 1) + ret.get(i - 1).get(j));,用从list里取元素的方法。
代码:
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> list = new ArrayList<>();
int[][] dp = new int[numRows][numRows];
for (int temp=0; temp<numRows; temp++){
dp[temp][0] = 1;
}
for (int i=1; i<numRows; i++){
for (int j=1; j<numRows; j++){
dp[i][j] = dp[i-1][j-1]+dp[i-1][j];
}
}
for (int i=0; i<numRows; i++){
List<Integer> temp = new ArrayList<>();
for (int j=0; j<numRows; j++){
if (dp[i][j] != 0){
temp.add(dp[i][j]);
}else{
break;
}
}
list.add(new ArrayList<>(temp));
}
return list;
}
}
4. LC322.零钱兑换
题目链接
代码
// 动规完全背包
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
dp[0] = 0;
for (int temp=1; temp<amount+1; temp++){
dp[temp] = Integer.MAX_VALUE;
}
for (int i=0; i<coins.length; i++){
for (int j=coins[i]; j<amount+1; j++){
if (dp[j-coins[i]] != Integer.MAX_VALUE){
dp[j] = Math.min(dp[j],dp[j-coins[i]]+1);
}
}
}
if (dp[amount] != Integer.MAX_VALUE){
return dp[amount];
}else{
return -1;
}
}
}
动规完全背包。注意这里是Min
所以初始化为了不让初始化的值覆盖应得到的值,dp[0] = 0,其余初始化为Integer.MAX_VALUE;
易错注意:
for循环里加了条件if (dp[j-coins[i]] != Integer.MAX_VALUE)
最后结尾也要考虑(dp[j-coins[i]] = Integer.MAX_VALUE)的情况
5. LC279.完全平方数
题目链接
代码
//动规完全背包
class Solution {
public int numSquares(int n) {
int[] dp = new int[n+1];
int num = (int)Math.sqrt(n);
for (int temp=0; temp<dp.length; temp++){
dp[temp] = Integer.MAX_VALUE;
}
dp[0] = 0;
dp[1] = 1;
for (int i=1; i<=num; i++){
for (int j=i*i; j<=n; j++){
dp[j] = Math.min(dp[j], dp[j-i*i]+1);
}
}
return dp[n];
}
}
dp[j],和为j的完全平方数的最少数量。
1,4,9…是物品。
没从0开始是因为题目是从1开始
不需要像上题的if statement,因爲在完全平方數這一題不會有"湊不成"的狀況發生( 一定可以用"1"來組成任何一個n),故comment掉這個if statement。