分割等和子集

分割等和子集

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]

输出:true

解释:数组可以分割成 [1, 5, 5] 和 [11]

示例 2:

输入:nums = [1,2,3,5]

输出:false

解释:数组不能分割成两个元素和相等的子集。

提示:

1 <= nums.length <= 200

1 <= nums[i] <= 100

思路

题意分析

题目是要找是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

那么只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。

例如示例1:

输入元素总和是22,要分成两个元素和相等的子集,那这两个子集各自之和肯定都是11,即sum / 2

解题方法

既然这题出现在dp章节了,那肯定就是用dp来做了

但是,如果第一次遇见,应该怎么确定适用dp来解呢?可以先尝试分析一下题目,看看能不能把题目往这边靠

比如,这题中,每个构成子集的每个元素只能使用一次(关键点1)

这个描述可以联想到01背包问题,那就尝试去抽象一下:

本题可以转换为一个01背包问题,目标是给定一个数组,用数组中的元素去填满一个容量为 sum / 2 的背包(如果能填满的话,就找到了题目要求的子集)

还不够,还要继续确定什么是物品(物品重量),什么是价值

显然,能够作为物品的只有数组里的元素了,那么物品的重量就是元素数值,物品的价值也是元素数值

现在就把01背包问题套进来了,当前问题的条件如下:

  • 背包的体积是 sum / 2
  • 要放入背包的物品是数组元素,其重量为元素数值,重量也为元素数值
  • 背包中每个元素不可重复使用
  • 如果背包正好装满,那么说明找到了总和为 sum / 2 的子集(有一种就行,不用最优)

ok,现在可以五部曲去分析了

五步走

以一维01背包问题为模板来解题,详见

1、确定dp数组含义

回顾一下分析一维数组的背包问题时,dp[j]的定义:在容量为j时,背包能装下的物品的最大价值

根据上面的分析,本题中物品重量是数组元素数值,物品价值还是数组元素数值

那上面的定义可以改为:背包总容量是j,放入物品后,背包的最大重量为dp[j]

即本题dp数组的含义

举个例子,假设背包容量为target,那么dp[target]就是背包装满时的重量

当dp[target] = target,背包就装满了,此时变找到了题解子集

这里会出现一种情况:在所给的背包容量下,没有物品能装满

什么意思?举个例子,输入是数组 [1, 5, 11, 5],target是7

那么,当dp[7]的时候,背包只能放1、5,总价为6,没放满,显然这不是我们需要的结果(不满足dp数组定义),不过好在我们是倒序遍历,在之后的遍历中,dp[6] = 6,满足dp定义,并且我们也找到了一个满足条件的子集[1,5]

2、确定递推公式

其实可以直接套用一维dp数组背包问题的递推公式:dp[j] = max(dp[j], dp[j - wight[i]] + value[i])

本题中,物品重量和价值都是数组元素,所以可以改成:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])

其含义是:

不放入物品时,容量为j的背包最大的价值是dp[j];

放入物品时,容量为j - nums[i]的背包所背的最大价值是dp[j - nums[i]];

3、确定如何初始化

还是参考一维背包问题,当背包容量为0,也就是dp[0]时,里面不可能装东西

因此,dp[0] = 0;

其他部分全部初始化为0(因为题目说了数组元素全是正数),目的是为了防止倒序遍历过程中,上一层的值与当前值叠加(详见:一维dp数组如何初始化

又因为题目给了:每个数组元素不会超过100,数组本身的大小不会超过200,且元素总和不会超过20000

那么创建dp数组时只需要取一半的大小即可

vector<int> dp(10001, 0);
4、确定遍历顺序

都套一维dp数组的背包问题了,肯定是倒序遍历

原因详见:为什么要倒序遍历?

for(int i = 0; i < nums.size(); ++i){//遍历物品
for(int j = target; j > 0; --j){//遍历背包容量
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
}
}

代码

根据上面的分析可写出一下代码

步骤:

1、求数组的总和,用于求背包容量target

2、判断当前总和sum是否为偶数,不为偶数就直接返回false

3、根据题目提示定义dp数组,同时进行初始化

4、倒序遍历dp数组,先遍历物品,再遍历背包容量,计算dp[j]

5、判断dp[target] 是否等于 target

class Solution {
public:
bool canPartition(vector<int>& nums) {
//求背包容量,也就是target
//先定义一个sum用于求数组总和
int sum = 0;
for(auto num : nums) sum += num; //如果sum值不能均分(不是偶数),那么一定无法分为两个和相等的子集,直接返回false
if(sum % 2 == 1) return false;
int target = sum / 2; //定义dp数组,同时初始化
vector<int> dp(10001, 0);
// //初始化dp数组
// dp[0] = 0;
//遍历dp数组(注意是倒序遍历)
for(int i = 0; i < nums.size(); ++i){//遍历物品
// 如果当前背包容量小于物品重量,换一个物品继续遍历容量
// 每一个元素一定是不可重复放入,所以从大到小遍历
for(int j = target; j >= nums[i]; --j){//遍历背包容量
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
//判断是否满足题意条件
if(dp[target] == target) return true;
return false;
}
};

【LeetCode动态规划#06】分割等和子集(01背包问题一维写法实战)的更多相关文章

  1. [LeetCode]494. 目标和、416. 分割等和子集(0-1背包,DP)

    题目一 494. 目标和 给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S.现在你有两个符号 + 和 -.对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前 ...

  2. Leetcode 416.分割等和子集

    分割等和子集 给定一个只包含正整数的非空数组.是否可以将这个数组分割成两个子集,使得两个子集的元素和相等. 注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200 示例 1: 输入: [ ...

  3. Java实现 LeetCode 416 分割等和子集

    416. 分割等和子集 给定一个只包含正整数的非空数组.是否可以将这个数组分割成两个子集,使得两个子集的元素和相等. 注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200 示例 1: ...

  4. Leetcode 416分割等和子集

    416. 分割等和子集 已知是个背包问题,由于可以等分为两部分,所以必定是个偶数. 一开始想到的是回溯法 bool helper(vector<int>&nums, int i, ...

  5. leetcode动态规划题目总结

    Hello everyone, I am a Chinese noob programmer. I have practiced questions on leetcode.com for 2 yea ...

  6. 动态规划---等和的分隔子集(计蒜课)、从一个小白的角度剖析DP问题

    自己还是太菜了,算法还是很难...这么简单的题目竟然花费了我很多时间...在这里我用一个小白的角度剖析一下这道题目. 晓萌希望将1到N的连续整数组成的集合划分成两个子集合,且保证每个集合的数字和是相等 ...

  7. c语言数据结构:01背包问题-------动态规划

    两天的时间都在学习动态规划:小作业(01背包问题:) 数据结构老师布置的这个小作业还真是让人伤头脑,自己实在想不出来了便去网上寻找讲解,看到一篇不错的文章: http://www.cnblogs.co ...

  8. PAT1048. Find Coins(01背包问题动态规划解法)

    问题描述: Eva loves to collect coins from all over the universe, including some other planets like Mars. ...

  9. 01背包问题(动态规划)python实现

    01背包问题(动态规划)python实现 在01背包问题中,在选择是否要把一个物品加到背包中.必须把该物品加进去的子问题的解与不取该物品的子问题的解进行比較,这样的方式形成的问题导致了很多重叠子问题, ...

  10. [Leetcode 90]求含有重复数的子集 Subset II

    [题目] Given a collection of integers that might contain duplicates, nums, return all possible subsets ...

随机推荐

  1. Python+Django(3)——创建主页

    打开项目主文件夹learning_log中的文件urls.py: from django.contrib import admin from django.urls import path,re_pa ...

  2. JS Math与一些原始类型

    镇楼图 Pixiv:DSマイル 一.值属性.函数 globalThis JS有全局对象,但是在不同环境中全局对象均不同.在Web环境中,window.self.frames取得全局对象,在Web Wo ...

  3. 基于vue2.0创建vue项目

    一.安装node环境 1.下载地址为:https://nodejs.org/en/ 2.检查是否安装成功:如果输出版本号,说明我们安装node环境成功 3.为了提高我们的效率,可以使用淘宝的镜像:ht ...

  4. jsp第4个作业(1)

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"% ...

  5. Vue父子组件传值——第一次传不过去之“怪象”?

    前言:最近写Vue父子组件传值出现第一次传不过去之"怪象",以为Vue的BUG呢.然则,是自己太菜"^_^"!!!特此记录以警己 <spec-param& ...

  6. axios实现无感刷新

    前言 最近在做需求的时候,涉及到登录token,产品提出一个问题:能不能让token过期时间长一点,我频繁的要去登录. 前端:后端,你能不能把token 过期时间设置的长一点. 后端:可以,但是那样做 ...

  7. jQuery实现论坛发帖Demo

    目录 效果展示 思路 代码 改进空间 效果展示 思路 主要知识点:运用jQuery对HTML元素节点的操作(append)来添加帖子. 交互设计:用户点击页面上的"论坛发帖"按钮, ...

  8. 微信小程序 实现点击返回顶部

    效果: wxml: <!-- 点击回顶部 --> <image src='/images/top.jpg' class='goTop' hidden='{{showTop}}' bi ...

  9. .net core 版本避坑 无法打开项目文件。 无法找到 .NET SDK。请检查确保已安装此项且 global.json 中指定的版本(如有)与所安装的版本相匹配。

    打开项目根目录,输入 dotnet --version  ,查看本机安装的最高版本的sdk: 如果源文件中存在global.json文件,直接打开修改即可: 不存在则接着在1步骤后输入: dotnet ...

  10. [.Net]Framwork WebAPI添加接口请求监控

    思路: 通过重写 ActionFilterAttribute 拦截Action的请求及返回信息,实现对接口请求的监听. 最终效果如下: 全局启用需配置如下: 局部启用需配置如下: 源码如下: 1 // ...