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

视频讲解:

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

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

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

01背包问题

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

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

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;
               
    }
}

 

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值