算法训练营第四十六天 | 卡码网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


这题基本还是完全背包的思路,不过是计算方法数类型的问题。需要改动的地方主要是初始化这一块,要将dp0置为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数组的话,每一轮中的dpi0都要设置为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];
    }
}
相关推荐
考研保研资料分享2 小时前
中国人民大学英语笔译保研面经:五校考核、视译口译与择校复盘
面试
企业数字化笔记4 小时前
视频人体姿态怎么做三维可视化?2D关键点、深度局限与技术选型
人工智能·算法·音视频
古希腊掌管代码的神THU4 小时前
为什么DPO中chosen/rejected概率同时下降?
人工智能·深度学习·机器学习·自然语言处理·面试
?abc!5 小时前
(数组)581. 最短无序连续子数组
数据结构·算法·leetcode
小郎君6587 小时前
MPTT树复选框的半选状态:一棵百万节点树从递归到计数器,再到区间覆盖
算法
酌沧7 小时前
MemT让记忆成为模型内生能力
jvm·人工智能·算法
Shimeri8 小时前
越卷越像:我用遗传算法做了个"内卷"实验
算法·three.js·数据可视化·遗传算法·进化算法
Evand J8 小时前
【PMSM例程1】永磁同步电机(PMSM)转速与转子电角度观测算法|基于扩展卡尔曼滤波(EKF)的传感器状态估计与误差。附下载链接
算法·电机·1024程序员节·卡尔曼滤波
guo_wen_qiang8 小时前
二叉树的层序遍历-使用双端队列Deque
算法·leetcode·1024程序员节
爱读书的小胖8 小时前
LeetCode 55 跳跃游戏 C 语言解题分析
c语言·数据结构·算法·leetcode·1024程序员节