算法训练营第四十六天 | 卡码网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];
    }
}
相关推荐
Pandaconda17 分钟前
【Golang 面试题】每日 3 题(三十九)
开发语言·经验分享·笔记·后端·面试·golang·go
半盏茶香19 分钟前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
CodeJourney.38 分钟前
小型分布式发电项目优化设计方案
算法
带多刺的玫瑰1 小时前
Leecode刷题C语言之从栈中取出K个硬币的最大面积和
数据结构·算法·图论
Cando学算法1 小时前
Codeforces Round 1000 (Div. 2)(前三题)
数据结构·c++·算法
薯条不要番茄酱1 小时前
【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题
算法·动态规划
小林熬夜学编程1 小时前
【Python】第三弹---编程基础进阶:掌握输入输出与运算符的全面指南
开发语言·python·算法
字节高级特工1 小时前
【优选算法】5----有效三角形个数
c++·算法
小孟Java攻城狮7 小时前
leetcode-不同路径问题
算法·leetcode·职场和发展
查理零世7 小时前
算法竞赛之差分进阶——等差数列差分 python
python·算法·差分