代码随想录算法训练营 day42 || 01背包问题,416. 分割等和子集

视频讲解:

带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili

带你学透01背包问题(滚动数组篇) | 从此对背包问题不再迷茫!_哔哩哔哩_bilibili

动态规划之背包问题,这个包能装满吗?| LeetCode:416.分割等和子集_哔哩哔哩_bilibili

01背包问题

思路:总结一下自己的思路体会:

  • 01背包问题的维度分别是物品数量,物品的特征体现(如重量);
  • 01背包问题的递归公式从前i-1种物品的考虑,然后考虑当前的第i种物品,其实这和我们前面所做的双指针类型的题目一样,都是对于数组开始从无到有的一个个开始遍历的,所有前面已经遍历完成的一定包含了前面的元素所有可行的最佳情况,所以动态规划本质上也是一种贪心;
  • 关于状态转换,我觉得最难以理解的就是,如果当前物品放不进去,就是直接继承上一层的同列元素,这是我认为01背包中最难以理解的部分,也是我目前使用说"前i-1种操作都包含在dpi-1j",所以当前放不进去的话就可以直接继承下来,我暂时还说服自己。
  • 最后想要学习的一点就是01背包考虑的是怎么性价比最大的放入元素。
  • 第二点是重量维度进行遍历时需要从后往前遍历,可以减少某些小重量物品的重复加入!!!那么反过来想,支持重复加入的从前遍历,是否就是完全背包问题的解法?
java 复制代码
// 时间复杂度O(n^2)
// 空间复杂度O(n)或O(n^2)

import java.util.*;

public class runafter {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        int N = scanner.nextInt();
        int[] weights = new int[M];
        int[] values = new int[M];

        for(int i=0; i<M; i++)
            weights[i] = scanner.nextInt();
        for(int i=0; i<M; i++)
            values[i] = scanner.nextInt();

        // 定义dp数组,数组的下标表示的是在容量N下物品i+1的所有组合情况,比如重量为1,可以单放;重量为3了,我和物品j一起放了进去,所以每次遍历时是仅仅考虑当前物品的重量与价值,而出现超过当前重量的内容,可以再组合一些其他的,也是一种纯暴力的思路
        // 数组的值表示的是第i+1个物品操作后前i+1个共取得的最大价值
        int[][] dp = new int[M][N+1];
        for(int i=1; i<=N; i++)
            if(i>=weights[0])
                dp[0][i] = values[0];
//        for (int i=0; i<M; i++)
//            dp[i][0] = 0;

        for (int i=1; i<M; i++){
            for(int j=1; j<=N; j++){
                // j表示当前背包的容量
                if(j>=weights[i]){
                    dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weights[i]]+values[i]);
                }
                else
                    dp[i][j] = dp[i-1][j];
            }
        }

        System.out.println(dp[M-1][N]);

        int[] DP = new int[N+1];
        for(int i=0; i<M; i++){             // 物品个数
            for(int j=N; j>=1; j--){        // 重量
                if(j >= weights[i])
                    DP[j] = Math.max(DP[j], DP[j - weights[i]] + values[i]);
            }
        }
        System.out.println(DP[N]);
        return;
    }
}

416. 分割等和子集

思路:在拿到这道题目时,其实第一想法是回溯,去不断试错当前的子集和;但回溯的时间复杂度必定是指数级,大概率会超时。其次想到贪心,走动态规划,因为这是一个不断加入元素尝试的过程,所以是动规。那么再看分割子集,其实也是一个不断加入元素从一个集合至另一个集合的过程,所以可以视作背包问题,并且每个元素可以取一次,所以是01背包问题,下面需要处理的就是动态规划,我们的目标是操作数组和,所以和就是本题所理解的重量,以物品数和数组和作为两个维度构建数据即可求解。

java 复制代码
class Solution {
    public boolean canPartition(int[] nums) {
        
        if(nums.length == 1)
            return false;

        int m = nums.length;
        int n = 0;
        for(int i=0; i<m; i++)
            n += nums[i];
        
        if(n%2 == 1)
            return false;
        // if(nums[0] == n/2)
        //     return true;

        // int[][] dp = new int[m][n+1];
        // // 初始化
        // for(int j=1; j<=n; j++)
        //     if(j >= nums[0]){
        //         dp[0][j] = nums[0];
        //     }
        
        // for(int i=1; i<m; i++){
        //     for(int j=n; j>=1; j--){
        //         if(j>=nums[i]){
        //             dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-nums[i]]+nums[i]);
        //         }
        //         else
        //             dp[i][j] = dp[i-1][j];
                
        //         if(dp[i][j] == n/2)
        //             return true;
        //     }
        // }
        int[] dp = new int[n/2+1];
        for(int i=0; i<m; i++){     // 数字的编号
            for(int j=n/2; j>=1; j--){    // 类似于重量
                if(j >= nums[i])
                    dp[j] = Math.max(dp[j], dp[j-nums[i]]+nums[i]);
                if(dp[j] == n/2)
                    return true;
            }
        }
        return false;
               
    }
}
相关推荐
2601_962218614 小时前
万象生鲜系统业财一体化底层打通技术自动生成经营账单
大数据·数据库·人工智能·python·算法
吞下星星的少年·-·5 小时前
The 2026 ICPC Asia East Continent Online Contest (II)(构造)
数据结构·算法
stolentime6 小时前
洛谷P10515 转圈题解
c++·算法·数学建模·贪心算法
和裕7 小时前
蜂窝板 vs 七层瓦楞重型纸箱:大件工业设备运输性能与成本全对比
大数据·运维·网络·人工智能·算法
衡石科技7 小时前
Data_Agent记忆机制与经验复用衡石分析智能体会话记忆与长期学习技术解析
人工智能·科技·学习·算法·企业级bi
shirsl9 小时前
算法 Day 2 滑动窗口 + 栈 / 单调栈
开发语言·python·算法
土司大王10 小时前
LeetCode hot100 回溯专题总结:Java 通用模板、决策树模型
java·算法·leetcode·决策树
2601_9622186110 小时前
万象生鲜系统订单全生命周期状态同步技术实现业务可视
大数据·数据库·人工智能·python·算法
那年窗外下的雪.10 小时前
AIDC 学习日志|第 22 天|All-Active/Single-Active 故障演练设计
服务器·网络·学习·算法·哈希算法
wzdark11 小时前
基于启发式搜索的最优路径规划算法研究4
算法