算法训练营第四十六天 | 卡码网52 携带研究材料、LeetCode 518 零钱兑换II、LeetCode 377 组合总和IV

写在前面


这次算法训练营题目,其实完全是按照代码随想录 一路跟着来的,上面也有更好的、讲得更清楚的题解,有需要的小伙伴可以去那里看。

我这里是之前已经大体刷过一遍,为了应对有可能会考到的面试题,现在在跟着一个专门的、要花钱的训练营补完笔记,加深理解。

下面开始今天的刷题和笔记。

卡码网 52


这题是完全背包问题的典型,完全背包也就是每个物品可以取无限次。

如果用二维dp的话,我们每个物品都要再加一个在能取次数内几个次数的循环比较。

而用一维dp数组的内层正向遍历就能很好地解决这个问题,所以我们修改下内层遍历顺序就行了。

代码如下:

java 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int bagSize = in.nextInt();
        int[] w = new int[n];
        int[] v = new int[n];
        for (int i = 0; i < n; i++) {
            w[i] = in.nextInt();
            v[i] = in.nextInt();
        }
        int[] dp = new int[bagSize + 1];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= bagSize; j++) {
                if (j >= w[i])
                    dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
            }
        }
        System.out.println(dp[bagSize]);
    }
}

LeetCode 518 零钱兑换II


这题基本还是完全背包的思路,不过是计算方法数类型的问题。需要改动的地方主要是初始化这一块,要将dp[0]置为1,然后利用滚动数组的特性,可以让每种方法都计数为1。

代码如下:

java 复制代码
class Solution {
    public int change(int amount, int[] coins) {
        int[] dp = new int[amount + 1];
        dp[0] = 1;
        for (int i = 0; i < coins.length; i++) {
            for (int j = 0; j <= amount; j++) {
                if (j >= coins[i])
                    dp[j] += dp[j - coins[i]];
            }
        }
        return dp[amount];
    }
}

如果是二维dp数组的话,每一轮中的dp[i][0]都要设置为1。递推逻辑也要稍微变化下。

代码如下:

java 复制代码
class Solution {
    public int change(int amount, int[] coins) {
        int[][] dp = new int[coins.length][amount + 1];
        for (int i = 0; i < coins.length; i++) dp[i][0] = 1;
        for (int i = 0; i < coins.length; i++) {
            for (int j = 0; j <= amount; j++) {
                if (j >= coins[i])
                    if (i == 0) dp[i][j] += dp[i][j - coins[i]];
                    else 
                        dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i]];
                else 
                    if (i == 0) continue;
                    else 
                        dp[i][j] = dp[i - 1][j];
            }
        }
        return dp[coins.length - 1][amount];
    }
}

LeetCode 377 组合总和IV


这题是排列问题,上面一题是组合问题。两个问题在遍历顺序上有较大差别。这是方法数问题在dp这一块的特殊问题,如果只是单纯的求总价值的话就没有这个问题了。

解决方法是将内重外重循环反过来,这样在每个背包重量下,放入某个价值的物品最后构成的不同顺序的方法都会被计算进去。

比如这组数据

两重循环顺序反过来后就是这样

原先是这样

确实可以看出由遍历顺序引起的放入次数的问题,这是由于原先总是按照物品下标从小到大放入,顺序倒转后有可能下标较大的物品先被放入造成了次序上的不一致。而且也可以看出这其实也是完全背包这一块的特殊问题,01背包问题很少会问到排列。

代码如下:

java 复制代码
class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target + 1];
        dp[0] = 1;
        for (int j = 0; j <= target; j++) {
            for (int i = 0; i < nums.length; i++) {
                if (j >= nums[i]) 
                    dp[j] += dp[j - nums[i]];
                System.out.print(dp[j] + " ");
            }
            System.out.println();
        }
        return dp[target];
    }
}
相关推荐
YuTaoShao7 小时前
【LeetCode 每日一题】1653. 使字符串平衡的最少删除次数——(解法一)前后缀分解
算法·leetcode·职场和发展
VT.馒头7 小时前
【力扣】2727. 判断对象是否为空
javascript·数据结构·算法·leetcode·职场和发展
goodluckyaa7 小时前
LCR 006. 两数之和 II - 输入有序数组
算法
孤狼warrior7 小时前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪
Σίσυφος19008 小时前
PCL法向量估计 之 RANSAC 平面估计法向量
算法·机器学习·平面
xhbaitxl8 小时前
算法学习day39-动态规划
学习·算法·动态规划
I_LPL8 小时前
day23 代码随想录算法训练营 回溯专题2
算法·hot100·回溯算法·求职面试
智者知已应修善业8 小时前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法
猿小羽8 小时前
AIGC 应用工程师(3-5 年)面试题精讲:从基础到实战的系统备战清单
面试·大模型·aigc·agent·rag
m0_736919108 小时前
C++中的委托构造函数
开发语言·c++·算法