算法面试真题详解:背包问题 V

简介: 算法面试真题详解:背包问题 V

给出 n 个物品, 以及一个数组, nums[i] 代表第i个物品的大小, 保证大小均为正数, 正整数 target 表示背包的大小, 找到能填满背包的方案数。
每一个物品只能使用一次

在线评测地址:领扣题库官网

样例

给出候选物品集合 [1,2,3,3,7] 以及 target 7
结果的集合为:
[7]
[1,3,3]
返回 2

算法:DP(动态规划)

题目描述
nums[i]表示第i个物品的大小 ;target 表示背包的大小;每个物品只能使用一次;求装满背包的方案数。
算法思路

  • 题目说物品只能使用一次和求方案数,可以看出这题的模型是01背包
  • 我们定义状态dpi 来表示前i个物品重量有多少种方式组出重量j
  • 状态转移方程为:
    当不放第i个物品时 : dpi = dpi - 1

当放第i个物品时:dpi += dpi - 1]

代码思路

1. 当没有物品时直接 return false
2. 定义一个二维数组dp[i][j]来表示前i个物品重量有多少种方式组出重量j
3. 两层循环嵌套来实现
4. 第一层循环枚举i表示前i个物品的重量
5. 第二层循环枚举j表示重量
6. 根据算法思路中的状态转移方程来实现
7. dp[n][target]方案数
8. return dp[n][target]

复杂度分析

  • 空间复杂度:O(N*target)
  • 时间复杂度:O(N*target)
    优化
  • 我们可以利用滚动数组将状态定义成一维数组,dp[j]表示组成重量j的方案
  • 下面是优化的核心部分的伪代码

for i 1 to n

 old = now; 
 now = 1 + now;
 for j 0 to target 
     dp[now][j] = dp[old][j]
     if (j >= nums[i - 1])
         dp[now][j] += dp[old][j - nums[i - 1]];

原本是 老值 + 老值 = 新值,如果正着更新,可能会出现 老值 + 新值,所以需要倒着更新。dpi = dpi-1 + dpi-1],新值 = 两个老值加起来

for i 1 to n

 for j target to 0
         if (j >= nums[i - 1])
                 // old + old ==> new 
                 // old1 = dp[j]
                 // old2 = dp[j - nums[i - 1]]
                 dp[j] += dp[j - nums[i - 1]];

优化后复杂度分析

  • 空间复杂度:O(target)
  • 时间复杂度:O(N*target)
public class Solution {

    /**
     * @param nums: an integer array and all positive numbers
     * @param target: An integer
     * @return: An integer
     */
    public int backPackV(int[] nums, int target) {
        // write your code here
        int n = nums.length;
        // 当没有物品时方案数为0
        if (n == 0) {
            return 0;
        }
        // dp[i][j]表示前i个数字有多少种方式拼出数字j
        int[][] dp = new int[n + 2][target + 2];    
        // 初始化dp[i][j]
        for (int i = 0; i <= target; i++) {
            if(i == 0) {
                dp[0][i] = 1;
            }
            else {
                dp[0][i] = 0;
            }
        }
        for (int i = 1; i <= n; i++) {
            // 装入的重量
            for (int j = 0; j <= target; j++) {
                // 不放物品
                dp[i][j] = dp[i - 1][j];
                // 放入物品

                if (j >= nums[i - 1]) {     
                    dp[i][j] += dp[i - 1][j - nums[i - 1]];
                }
            }
        }
        return dp[n][target];
    }
}

更多题解参考:九章官网solution

相关文章
|
5月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
678 1
|
5月前
|
算法 搜索推荐 Java
贪心算法:部分背包问题深度解析
该Java代码基于贪心算法求解分数背包问题,通过按单位价值降序排序,优先装入高价值物品,并支持部分装入。核心包括冒泡排序优化、分阶段装入策略及精度控制,体现贪心选择性质,适用于可分割资源的最优化场景。
407 1
贪心算法:部分背包问题深度解析
|
11月前
|
算法
面试场景题:如何设计一个抢红包随机算法
本文详细解析了抢红包随机算法的设计与实现,涵盖三种解法:随机分配法、二倍均值法和线段切割法。随机分配法通过逐次随机分配金额确保总额不变,但易导致两极分化;二倍均值法优化了金额分布,使每次抢到的金额更均衡;线段切割法则将总金额视为线段,通过随机切割点生成子金额,手气最佳金额可能更高。代码示例清晰,结果对比直观,为面试中类似算法题提供了全面思路。
1792 16
|
算法 安全 Java
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
538 16
|
算法 Java C++
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
本文介绍了经典的0/1背包问题及其动态规划解法。
467 5
|
算法 Java 数据库
美团面试:百亿级分片,如何设计基因算法?
40岁老架构师尼恩分享分库分表的基因算法设计,涵盖分片键选择、水平拆分策略及基因法优化查询效率等内容,助力面试者应对大厂技术面试,提高架构设计能力。
美团面试:百亿级分片,如何设计基因算法?
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
757 2
动态规划算法学习三:0-1背包问题
|
算法 前端开发 Java
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
这篇文章总结了单链表的常见面试题,并提供了详细的问题分析、思路分析以及Java代码实现,包括求单链表中有效节点的个数、查找单链表中的倒数第k个节点、单链表的反转以及从尾到头打印单链表等题目。
197 1
数据结构与算法学习四:单链表面试题,新浪、腾讯【有难度】、百度面试题
|
存储 算法
算法之背包问题
本文讨论了可分背包问题和0-1背包问题的区别及解决方法,其中可分背包问题可以使用贪心算法解决,而0-1背包问题则通常采用动态规划方法来找到最大价值的解决方案。
248 0
算法之背包问题
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)