LeetCode 416.分割等和子集 | 类0-1背包问题 | 解题思路及代码

Given a nonempty array nums, which only contains positive number. Find if the array can be divided into two parts such that the sum of each part is equal.

Input: nums = [1,5,11,5]
Output: true
Explanation: divide into [1,5,5] and [11].

To satisfy two part sum are equal, then each part sum is half of total sum. If the total sum is an odd or the max number in the array is bigger than half of total sum, then it’s can’t satisfy the requirement.

This problem is similar to 0-1 package problem. What differs is that the total sum we chose can’t exceed the capacity of the package in 0-1 package problem, while the chosen number’s sum must equal to half of total sum in this question. Similar to traditional 0-1 package problem, we can use dynamic programming to solve this problem.

We use a two-dimensional array boolean dp[n][half+1] for dynamic programming. Where n is the length of nums and half is the half of total sum. We define dp[i][j]:

  • i ranges from 0 to n-1, which means the subset(0, i) of nums.

  • j ranges from 0 to half, which means if the subset(0, i) can constitute a sum of value j.

dp[i][j] is true if subset(0, i) of nums can constitute a sum of value j. Then dp[n-1][half] means in the whole array nums, if it can constitute a sum of half.

The state transition equation is as follows:

[dp[i][j]=\begin{cases} dp[i-1][j]\ ||\ dp[i-1][j-num[i]]&num[i]\leq j\ dp[i-1][j]&num[i]>j \end{cases}]

dp[i][j] means we are deciding if we count nums[i] to constitute a sum of j for subset(0, i).

The upper case means: nums[i]<=j< code>, if we not choose this number, then our result(can constitute or not) is equal to "if the subset(0, i-1) can constitute a sum of <code>j</code>", that is<code>dp[i-1][j]</code>. If we choose this number, then our result is equal to "if the subset(0, i-1) can constitute a sum of <code>j-num[i]</code>". Either of them is true, then we can constitute a sum of <code>j</code> by subset(0, i) of <code>nums</code>.<br>The lower case means: <code>nums[i]>j</code>, the number is bigger than the number(<code>j</code>) we want to constitute, so we can't choose. Our result is same as <code>dp[i-1][j]</code>.<!--=j<-->

Observe the transition equation, we found that each line of our two-dimensional array dp only related to the previous line(dp[i] is decided by dp[i-1] only). So we can store the dp in only one line:
When we handle the new line i, the 1-dimensional array stores the i-1 line data! For each line, we ranges j from half to 0. The new state transition equation is as follows:

[dp[j]=dp[j]\ ||\ dp[j-nums[i]] ]

Since j ranges from half to 0, dp[j] or dp[j-nums[i] store the date of last line(i-1). After each round of j, we updated a line.

If nums.length<2< code> or <code>sum(nums)</code> is odd or <code>max(nums)>sum(nums)/2</code>, return <code>false</code>.<br>Create a boolean array <code>dp[sum(nums)/2+1]</code>. For <code>i</code> in range from 0 to <code>num.length</code>, for <code>j</code> in range from <code>sum(nums)/2</code> to 0, if <code>dp[j]==true</code> or <code>dp[j-nums[i]==true</code>, the <code>dp[j]=true</code>.<br>Finally, return <code>dp[sum(nums)/2]</code>.<!--2<-->

The detailed code is as follows

public class p416 {
    public static boolean canPartition(int[] nums) {
        int len = nums.length;
        if (len < 2) {
            return false;
        }
        int totalSum = 0, half = 0, maxNum = 0;
        for (int num : nums) {
            totalSum += num;
            maxNum = Math.max(maxNum, num);
        }
        if (totalSum % 2 != 0 || totalSum / 2 < maxNum) {
            return false;
        }
        half = totalSum / 2;
        boolean[] dp = new boolean[half + 1];
        dp[0] = true;
        for (int i = 0; i < len; i++) {
            int num = nums[i];
            for (int j = half; j >= num; j--) {
                dp[j] = dp[j] | dp[j - num];
            }
        }
        return dp[half];
    }
}

Time complexity: The outer loop nums.length, the inner loop sum(nums)/2, so the total time complexity is O(nums.length &#xD7; sum(nums)/2)
Space complexity: After optimization, the space we used are sum(nums)/2, so the total space complexity is O(sum(nums)/2)

Original: https://www.cnblogs.com/liuzhch1/p/16197049.html
Author: liuzhch1
Title: LeetCode 416.分割等和子集 | 类0-1背包问题 | 解题思路及代码

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606686/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Question07-查询学过”张三”老师授课的同学的信息

    * SELECT DISTINCT Student.* FROM Student , SC , Course , Teacher WHERE Student.SID = SC.SI…

    Linux 2023年6月7日
    098
  • 搭建k8s

    一、设置基本环境(需要开启超级用户权限) 安装控制selinux的命令: apt-get install -y selinux-utils 禁止selinux: setenforc…

    Linux 2023年5月27日
    076
  • Linux——基础命令用法(上)

    一、Linux基础命令 1、Linux命令的语法 一条完整的Linux命令的组成部分: 命令 选项 参数 命令:是某个具体的功能 选项:是对函数的修改(通常以-开头,-表示选项的短…

    Linux 2023年5月27日
    072
  • 华为IPv6 GRE隧道

    IPv6 over IPv4 GRE封装隧道 实验目标: 该实验参考了华为官网案例配置https://support.huawei.com/enterprise/zh/doc/ED…

    Linux 2023年6月7日
    071
  • 【Example】C++ 虚基类与虚继承 (菱形继承问题)

    C++ 是支持多继承的语言, 但是实际项目开发中非必要不要使用多继承以降低代码逻辑的复杂性,当然 C++ 多继承的特性带来一些问题即 菱形继承。 当一个类继承了两个来自同父类的子类…

    Linux 2023年6月13日
    072
  • 消费税

    1994年税制改革时,我国才设置了独立的消费税,与实行普遍征收的增值税配套,对特定消费品进行特殊调节。 消费税的特点: (一)征税范围具有选择性 有选择地确定若干个征税项目,在税法…

    Linux 2023年6月14日
    099
  • JavaScript快速入门-04-运算符

    4 运算符 4.1 算术运算符 4.1.1 概述 JavaScript 提供的算术运算符如下所示: 类型 符号 示例 加法运算符 + a+b 减法运算符 – a-b 乘…

    Linux 2023年6月7日
    063
  • 当前硬件版本不支持设备“nvme”。 vmx 未能启动虚拟机 2022-06-30T06:44:04.446Z In(05)+

    由于系统发生了dwm.exe内存泄露问题,为了处理就更新了一下系统,再 我打开VMware的时候运行不了虚拟机 再此记录一下: 发生此问题是硬件兼容性问题,解决办法: 根据VMMw…

    Linux 2023年6月8日
    0242
  • Jstack排查线上CPU100%

    Jstack排查线上CPU100% 介绍 jstack是JVM自带的Java堆栈跟踪工具,用于生成java虚拟机当前时刻的线程快照,来帮助定位线程出现长时间停顿的原因,例如死锁、死…

    Linux 2023年6月6日
    094
  • Shell第三章《for循环》

    语法结构: for &#x53D8;&#x91CF;&#x540D; [ in &#x53D6;&#x503C;&#x5217;&a…

    Linux 2023年6月6日
    0127
  • JavaScript闭包

    <!doctype html> <html lang="en"> <head> <title>&#x95…

    Linux 2023年6月13日
    073
  • WEB自动化-12-Cypress 调试

    12 调试 Cypress的测试代码和被测试程序在同一生命周期中的浏览器中,也就是意味着,可以使用浏览器的开发者工具直接参与调试。Cypress提供了几种调试方法,分别为: deb…

    Linux 2023年6月7日
    074
  • Android:hook很“危险”,使用需谨慎。

    前言 上篇文章《Android安卓进阶技术分享之AGP工作原理》和大家分析了 AGP(Android Gradle Plugin) 做了哪些事,了解到 AGP 就是为打包这个过程服…

    Linux 2023年6月13日
    075
  • 【转】 一条 SQL 的执行过程详解

    MySQL 体系架构 – 连接池组件 1、负责与客户端的通信,是半双工模式,这就意味着某一固定时刻只能由客户端向服务器请求或者服务器向客户端发送数据,而不能同时进行。 …

    Linux 2023年6月13日
    0111
  • 2022年5月16号开始整理habse

    关于本次整理的hbase内容是基于原理的学习的笔记 Original: https://www.cnblogs.com/yxb123/p/16277454.htmlAuthor: …

    Linux 2023年6月7日
    0110
  • Linux 常用目录管理命令

    cp:复制文件或目录,直接复制,如,cp /root/install.sh /home cp -a:相当於 -pdr 的意思,至於 pdr 请参考下列说明;(常用),如 cp -a…

    Linux 2023年6月14日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球