zoukankan      html  css  js  c++  java
  • Leetcode 416. 分割等和子集 背包问题变种 动态规划

    /*
     * @lc app=leetcode.cn id=416 lang=cpp
     *
     * [416] 分割等和子集
     *
     * https://leetcode-cn.com/problems/partition-equal-subset-sum/description/
     *
     * algorithms
     * Medium (49.73%)
     * Likes:    761
     * Dislikes: 0
     * Total Accepted:    122.1K
     * Total Submissions: 245.5K
     * Testcase Example:  '[1,5,11,5]'
     *
     * 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
     * 
     * 
     * 
     * 示例 1:
     * 
     * 
     * 输入:nums = [1,5,11,5]
     * 输出:true
     * 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
     * 
     * 示例 2:
     * 
     * 
     * 输入:nums = [1,2,3,5]
     * 输出:false
     * 解释:数组不能分割成两个元素和相等的子集。
     * 
     * 
     * 
     * 
     * 提示:
     * 
     * 
     * 1 
     * 1 
     * 
     * 
     */

    思路:

    labuladong

    可以转化为背包问题,即,能否得到sum/2

    dp[i][j]表示使用0-(i-1)的物品,得到和为j.

    base状态为dp[i][0]=true,因为sum=0肯定都可以实现

    dp[i][j]=dp[i-1][j](不放入nums[i])|dp[i-1][j-nums[i]](放入nums[i])

    class Solution {
    public:
        bool canPartition(vector<int>& nums) {
            int sum=0;
            for(int num:nums) sum+=num;
            if(sum%2!=0) return false;
            sum/=2;
            int n=nums.size();
            vector<vector<int>> dp(n+1,vector<int>(sum+1,false));
            for(int i=0;i<=n;++i) dp[i][0]=true;
            for(int i=1;i<=n;++i){
                for(int j=1;j<=sum;++j){
                    if(j<nums[i-1]) dp[i][j]=dp[i-1][j];
                    else 
                        dp[i][j]=dp[i-1][j]|dp[i-1][j-nums[i-1]];
                }
            }
            return dp[n][sum];
        }
    };

    进阶:

    状态压缩:dp[i][j]都是通过上一行dp[i-1][..]转移过来的,之前的数据都不会再使用了

    所以,我们可以进行状态压缩,将二维dp数组压缩为一维

    只在一行dp数组上操作,i每进行一轮迭代,dp[j]其实就相当于dp[i-1][j],所以只需要一维数组就够用了。

    唯一需要注意的是j应该从后往前反向遍历,因为每个物品(或者说数字)只能用一次,以免之前的结果影响其他的结果

    也就是i=n时,dp[j]为n-1的状态,又因为更新状态时需要用到dp[j-nums[i-1]],所以从后往前更新状态,保证用到dp时是i-1的原值,而不是更新后的值

    class Solution {
    public:
        bool canPartition(vector<int>& nums) {
            int sum=0;
            for(int num:nums) sum+=num;
            if(sum%2!=0) return false;
            sum/=2;
            int n=nums.size();
            vector<bool> dp(sum+1,false);
            dp[0]=true;
            for(int i=1;i<=n;++i){
                for(int j=sum;j>=0;--j){
                    if(j<nums[i-1]) continue;
                    else 
                        dp[j]=dp[j-nums[i-1]]|dp[j];
                }
            }
            return dp[sum];
        }
    };
    联系方式:emhhbmdfbGlhbmcxOTkxQDEyNi5jb20=
  • 相关阅读:
    IDEA添加注释模板
    Docker安装Mysql
    Linux使用
    Linux使用
    Spring Cloud入门 (5)
    在IDEA中将SpringBoot项目打包成jar包
    Linux使用
    Linux使用
    Linux使用- 虚拟机安装 Linux
    Spring Cloud入门 (4)
  • 原文地址:https://www.cnblogs.com/zl1991/p/14718883.html
Copyright © 2011-2022 走看看