力扣算法学习day29-3
377-组合总和 IV
题目
代码实现
class Solution {
public int combinationSum4(int[] nums, int target) {
// dp: 1ms 做过组合情况,这种情况就只是变一下遍历顺序而已,主要是原理理解要难点。
// target很容易想到背包容量,且题目要求的是和为target的个数而不是组合,那么容易想到dp的背包问题
// 由示例1可以知道,每个元素可以取多次,那么考虑完全背包解法,然后是求次数,考虑元素间的关系应该
// 是有和的关系(先想背包问题的二维数组,在大脑很容易想到元素间应该是有符合条件迭代相加的关系。)
// 然后,循序不同的序列被视为不同的组合,那么在遍历顺序考虑的时候,元素应该在内层遍历,使之结果为
// 排列次数,而不是组合,具体的再具体看和修改。
// 1.创建dp数组,dp[i] 表示目标和为i的元素组合(这里准确说叫排序)的个数。
int[] dp = new int[target+1];
// 2.迭代公式:dp[i] += dp[i-nums[j]],0 <= i <= target,j为nums数组元素
// 3.初始化
dp[0] = 1;// 为0,说明有本身那一种.即i-nums[j]=0
// 4.确定遍历循序,上面已近分析,由于题目需要求的实际上是排列次数,简单的说就是元素组合顺序交换
// 也算一种组合所以元素遍历需要在内层。
for(int i = 1;i < dp.length;i++){
for(int j = 0;j < nums.length;j++){
if(i - nums[j] >= 0){
dp[i] += dp[i-nums[j]];
}
}
}
return dp[target];
}
}
70-爬楼梯 --再回顾:完全背包解法
代码实现
class Solution {
// 爬楼梯,背包版本
// 注:背包思路换成能够爬1-m个台阶则更好换了,只需要换元素即可,已实验,两种方法解决1-m问题结果一样。
public int climbStairs(int n) {
// 题目分析,楼梯n阶,即n为背包容量,每次可以爬楼梯1,或2为元素,且为元素重量,元素可以重复取,为完全
// 背包解法,然后通过示例2可以看出,组合结果如果顺序不同也会被视为一种组合方式,故次数是求排列结果。
// 1.创建dp数组
int[] dp = new int[n+1];
// 2.确定迭代公式:dp[i] += dp[i-j],j为1,或2,即元素。
// 3.初始化
dp[0] = 1;
// 4.确定遍历顺序
for(int i = 1;i < dp.length;i++){
for(int j = 1;j < 3;j++){
if(i-j >= 0){
dp[i] += dp[i-j];
}
}
}
return dp[n];
}
// 以下为之前的,做过这道题。
// 0ms
// public int climbStairs(int n) {
// if(n < 3){
// return n;
// }
// // dp
// // 1.初始化dp数组
// int[] dp = new int[n];
// // 2.找递归公式:比如第三层,第一层跨2步能够到第三层,第二层跨1步能够到第三层
// // 用1,2标识是为了突出这两种情况,所以第一层的情况+第二层的情况=第三层的情况
// // 所以递归公式:dp[i] = dp[i-1] + dp[i-2];
// // 3.初始化dp数组
// dp[0] = 1;
// dp[1] = 2;
// // 4.找递归的顺序
// for(int i = 2;i < n;i++){
// dp[i] = dp[i-1] + dp[i-2];
// }
// // 5.略
// return dp[n-1];
// }
// 进阶思考:对于n阶楼梯,每次可以爬1-m个台阶问题的思考
// int climbStairs(int n,int m) {
// // int m = 2;// 实验m=2本题是否成立,需要去掉输入的int m,结果通过 3ms
// // 创建dp数组
// int[] dp = new int[n];
// // 递归公式:i > m 由上面那道题很容易推出:dp[i] = dp[i-1] + dp[i-2] + ... + dp[i-m]
// // i <= m,dp[i] = d[i-1] + d[i-2] + ... + d[0] + 1(本身)
// // 初始化
// dp[0] = 1;
// for (int i = 1; i < n; i++) {
// if(i < m){// 我这里0是第一层
// for(int j = 1;j <= i;j++){
// dp[i] += dp[i-j];
// }
// dp[i]++;// 加上一步到位的情况
// } else{// i > m
// for(int j = 1;j <= m;j++){
// dp[i] += dp[i-j];
// }
// }
// }
// for(int i = 0;i < n;i++){
// System.out.println(dp[i]);
// }
// return dp[n-1];
// }
}
322-零钱兑换
题目
代码实现
class Solution {
public int coinChange(int[] coins, int amount) {
// dp 速度 10-11ms
// 题目分析:看完题目,很明显需要用硬币凑成amount,所以考虑背包,硬币是元素,硬币面值是硬币重量,
// amount是背包容量。每种硬币可以取多次,考虑完全背包,需要求总金额最少的硬币个数,那么硬币个数
// 相当于是价值,而与常规相反,这里需要求满背包最小价值,所以迭代公式修改求最小应该就可以了。
// 1.创建dp数组
int[] dp = new int[amount+1];
// 2.确定迭代公式:dp[i] = Math.min(dp[i],dp[i-coins[j]]+1),最小就求最小。
// 3.初始化dp数组,因为是求最小,所以每个都初始化为最大即可。除了重量为0.
for(int i = 1;i < dp.length;i++){
dp[i] = Integer.MAX_VALUE;
}
// 4.确定遍历顺序,一样
for(int i = 0;i < coins.length;i++){
for(int j = coins[i];j < dp.length;j++){
if(dp[j-coins[i]] != Integer.MAX_VALUE){
dp[j] = Math.min(dp[j],dp[j-coins[i]] + 1);
}
// System.out.print(dp[j]);
}
// System.out.println();
}
if(dp[amount] == Integer.MAX_VALUE){
return -1;
}
return dp[amount];
}
}