9.8分割等和子集(LC416-M)

算法:

可以转换为背包问题:

一个商品如果可以重复多次放入是完全背包,而只能放入一次是01背包,写法还是不一样的。

要明确本题中我们要使用的是01背包,因为元素我们只能用一次。

只有确定了如下四点,才能把01背包问题套到本题上来。

  • 背包的体积为sum / 2
  • 背包要放入的商品:集合里的元素。重量为 元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素不可重复放入。

动规五步曲:

1.确定dp数组及其下标:

01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。

本题:dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]

2.确定递推公式:

01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

本题,相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。

所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);

3.dp初始化:

从dp[j]的定义来看,dp[0]一定是0。

如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。

这样才能让dp数组在递推的过程中取得最大的价值,而不是被初始值覆盖了

4.确定遍历顺序:

01背包如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!

// 开始 01背包
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]);
    }
}

5.举例推导dp

dp[j]的数值一定是小于等于j的。

如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,理解这一点很重要。

dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])

    • `dp` 数组初始化为 `[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`(长度为 `target + 1`,即 12)。
    • `i = 0``nums[0] = 1`
      • 内层循环从 `target`(11)到 `nums[0]`(1):
        • `j = 11``dp[11] = Math.max(0, dp[11 - 1] + 1) = 1`
        • `j = 10``dp[10] = Math.max(0, dp[10 - 1] + 1) = 1`
        • `j = 5``dp[5] = Math.max(0, dp[5 - 1] + 1) = 1`
        • `j = 1``dp[1] = Math.max(0, dp[1 - 1] + 1) = 1`
    • `i = 1``nums[1] = 5`
      • 内层循环从 `target`(11)到 `nums[1]`(5):
        • `j = 11``dp[11] = Math.max(1, dp[11 - 5] + 5) = 6`
        • `j = 10``dp[10] = Math.max(1, dp[10 - 5] + 5) = 6`
        • `j = 5``dp[5] = Math.max(1, dp[5 - 5] + 5) = 6`
        • `j = 1``dp[1] = Math.max(1, dp[1 - 5] + 5) = 5`
    • `i = 2``nums[2] = 11`
      • 内层循环从 `target`(11)到 `nums[2]`(11):
        • `j = 11``dp[11] = Math.max(6, dp[11 - 11] + 11) = 11`
        • `j = 10``dp[10] = Math.max(6, dp[10 - 11] + 11) = 11`
        • `j = 5``dp[5] = Math.max(6, dp[5 - 11] + 11) = 11`
        • `j = 1``dp[1] = Math.max(6, dp[1 - 11] + 11) = 11`
    • `i = 3``nums[3] = 5`
      • 内层循环从 `target`(11)到 `nums[3]`(5):
        • `j = 11``dp[11] = Math.max(11, dp[11 - 5] + 5) = 11`
        • `j = 10``dp[10] = Math.max(11, dp[10 - 5] + 5) = 11`
        • `j = 5``dp[5] = Math.max(11, dp[5 - 5] + 5) = 11`
        • `j = 1``dp[1] = Math.max(11, dp[1 - 5] + 5) = 11`

由于在 `i = 3` 时 `dp[target] == target`,所以最终返回 `true`

正确代码:

class Solution {
    public boolean canPartition(int[] nums) {

        int sum = 0;
        //求和
        for(int a=0; a<nums.length; a++){
            sum += nums[a];
        }
        //若sum为奇数,无法等分
        if (sum % 2 != 0) return false;
        //求target
        int target = sum/2;
        int[] dp = new int[target+1];
        //dp初始化,所有值都为0(就算不初始化,java也会自动把int数组初始化为0)
        for (int i=0; i<dp.length;i++){
            dp[i]=0;
        }

        for(int i = 0; i<nums.length; i++){
            for(int j=target; j>=nums[i]; j--){
                dp[j] = Math.max(dp[j], dp[j-nums[i]]+nums[i]);
            }
        }
        //若背包装满了,return true
        return dp[target] == target;
    }}

注意:

1.使用sum时,要将sum初始化:int sum = 0;

2.求target之前,要考虑sum能不能被等分

3.dp数组的长度为target+1

4.for循环时j>=nums[i]

大于等于!

 `j>=nums[i]` 时,考虑的是包括当前物品的情况,因为想要确保当前物品可以放入背包中。

如果使用 `j>nums[i]`,那么就会漏掉考虑将当前物品放入背包的情况,因为此时不包括当前物品的情况也会被考虑到。

5.函数的返回值是bool,所以最后return dp[target] == target;

6.如果将数组 `dp` 的初始化部分注释掉,代码仍然能够正常工作

Java中对于未显式初始化的数组,会自动将数组的元素初始化为默认值。

对于基本数据类型 `int`,其默认值为0。因此,当创建一个 `int` 类型的数组时,如果没有显式地对数组进行初始化,Java会自动将数组的元素初始化为0。

时间空间复杂度:

  • 时间复杂度:O(n^2)

  • 空间复杂度:O(n),虽然dp数组大小为一个常数,但是大常数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/425329.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++_程序流程结构_循环结构_while

while循环结构 作用 满足循环条件&#xff0c;执行循环语句 语法 while (循环条件&#xff09;{循环语句}解释 只要循环条件的结果为真&#xff0c;就执行循环语句 流程图 示例 注意 在执行循环语句时候&#xff0c;程序必须提供跳出循环的出口&#xff0c;否则出现死循…

B083-SpringCloud-eureka ribbon feign hystrix

目录 eureka基础项目准备注册中心的搭建生产者注册到eureka消费者注册到eureka并通过eureka调用生产者eureka集群 服务提供者集群集群以后消费者调用服务的问题ribbon消费者使用ribbon负载均衡赋值负载均衡策略负载均衡优化 feignHystrixHystrix概述Ribbon搭配Hystrix降级处理F…

springboot+vue学生信息管理系统学籍 成绩 选课 奖惩,奖学金缴费idea maven mysql

技术栈 ide工具&#xff1a;IDEA 或者eclipse 编程语言: java 数据库: mysql5.7 框架&#xff1a;ssmspringboot都有 前端&#xff1a;vue.jsElementUI 详细技术&#xff1a;springbootSSMvueMYSQLMAVEN 数据库工具&#xff1a;Navicat/SQLyog都可以学生信息管理系统主要实现角…

★【递归】【链表】Leetcode 21. 合并两个有序链表

★【递归】【链表】Leetcode 21. 合并两个有序链表 解法1 &#xff1a;递归链表 简直是好题啊好题多做做 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法1 &#xff1a;递归链表 简直是好题啊好题多做做 >>>…

解决Excel客户端中的Copilot灰色不可用

很多小伙伴已经用上了office套件中的copilot功能 Copilot for Microsoft 365账号介绍与相关问题的解答 Copilot for Microsoft 365账号登录指南 Copilot for Microsoft 365功能使用指南 问题发现 大部分人使用的都是Word和PowerPoint功能&#xff0c;但是也有部分小伙伴使…

(学习日记)2024.03.03:UCOSIII第五节:常用汇编指令+OS初始化+启动任务+任务切换

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

力扣hot5---双指针

题目&#xff1a; 解决方案&#xff1a;双指针 指针 i 指向最左侧&#xff0c;指针 j 指向最右侧。此时在宽度上达到了最大值&#xff0c;那么哪个柱子更矮&#xff0c;哪个柱子向内部移动&#xff0c;知道 i 与 j 相遇。为什么呢&#xff1f; 如果哪个哪个柱子更矮&#xff0c…

Python实现DMI工具判断信号:股票技术分析的工具系列(3)

Python实现DMI工具判断信号&#xff1a;股票技术分析的工具系列&#xff08;3&#xff09; 介绍算法解释 代码rolling函数介绍完整代码 介绍 先看看官方介绍&#xff1a; DMI (趋向指标&#xff09; 用法 1.PDI线从下向上突破MDI线&#xff0c;显示有新多头进场&#xff0c;为…

SketchUp Pro 2023:颠覆传统,重塑设计世界mac/win版

SketchUp Pro 2023是一款强大的三维建模软件&#xff0c;专为设计师、建筑师和创意专业人士打造。这款软件以其直观易用的界面和强大的功能而著称&#xff0c;为用户提供了无限的创意空间。 SketchUp Pro 2023软件获取 SketchUp Pro 2023在用户体验方面进行了全面的优化&#…

SMBGhost漏洞技术分析与防御方案

事件分析 最近国内外各安全厂商都发布了SMBGhost(CVE-2020-0796)漏洞的预警报告和分析报告&#xff0c;笔者利用周末休息时间也研究了一下&#xff0c;就算是做一个笔记了&#xff0c;分享给大家一起学习下&#xff0c;目前外面研究的POC大部分是通过SMB压缩数据包长度整数溢出…

YOLOv9改进|使用CARAFE轻量级通用上采样算子

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 CARAFE 发表于ICCV2019。上采样操作可以表示为每个位置的上采样核和输入特征图中对应邻域的像素做点积&#xff0c;我们称之为特征重…

笔记74:在SLAM建图过程中,为什么要使用【障碍物点云配准算法】和【里程计估算算法】结合的方法

仅使用【障碍物点云配准算法】&#xff0c;很容易导致在一条长通道中&#xff0c;因为前后两帧的雷达点云图过于相似&#xff0c;导致特征匹配一直完全重合&#xff0c;使得机器人建图一直停留在原地&#xff0c;但实体机器人早就沿着通道跑向远端了&#xff1b; 使用Hector_ma…

【JavaEE进阶】CSS选择器的常见用法

CSS选择器的主要功能就是选中页面指定的标签元素&#xff0c;选中了元素&#xff0c;才可以设置元素的属性。 CSS选择器主要有以下几种: 标签选择器类选择器id选择器复合选择器通配符选择器 接下来用代码来学习这几个选择器的使用。 <!DOCTYPE html> <html lang&q…

springboot2入门到实战-整合QQ邮箱

springboot整合QQ邮箱 配置邮箱 登录邮箱服务器&#xff1a; 登录QQ邮箱 springboot整合email 导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency>配…

【Android】View 的滑动

View 的滑动是 Android 实现自定义控件的基础&#xff0c;同时在开发中我们也难免会遇到 View 的滑动处理。其实不管是哪种滑动方式&#xff0c;其基本思想都是类似的&#xff1a;当点击事件传到 View 时&#xff0c;系统记下触摸点的坐标&#xff0c;手指移动时系统记下移动后…

行为树入门:BehaviorTree.CPP Groot2练习(前置后置条件)(3)

前置与后置条件理论 前置条件 例程&#xff1a; //hp_get叶节点class hp_get : public BT::SyncActionNode{public:hp_get(const std::string& name, const BT::NodeConfig& config) :BT::SyncActionNode(name, config){}// 给该节点申明端口static BT::PortsList pro…

使用ChatGPT写代码靠谱吗?

原文链接&#xff1a;使用ChatGPT写代码靠谱吗&#xff1f; 写在前面 对于ChatGPT从我们“惊讶”到现在已经快一年多了&#xff0c;但是&#xff0c;对于个人来说&#xff0c;使用还是比较少的。更确切的来说&#xff0c;也许有些同学是没有使用过。 ChatGPT功能确实比较强大…

代码随想录算法训练营第三十天| 回溯篇总结

文章目录 前言一、组合问题二、切割问题三、子集问题四、排列问题五、性能分析总结 前言 回溯法就是暴力搜索&#xff0c;并不是什么高效的算法&#xff0c;最多再剪枝一下。 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合 排列问题&#xff1a;N个数按一定规则全…

快速上手vercel,免费部署上线你的前端项目,3分钟学会

在你还不了解 vercel的时候&#xff0c;我已经部署了三个自己的项目了&#xff0c;都是免费&#xff0c;而且实时同步github并更新&#xff0c;当然也可以你自己本地直接部署到vercel&#xff0c;不经过github&#xff0c;今天三分钟教会你&#xff0c;但是注意&#xff1a;国内…

花28块,薅自己的羊毛!我错在哪里?

这些年返利类型的网站也是参差不齐&#xff0c;他就发现了赚钱的大门 而这个人就是我的大姨&#xff0c;他的喜好和别人不一样&#xff0c; 特别爱薅羊毛&#xff0c;但他都不知道我也被他拉在那个群里了&#xff01; 她对自媒体颇感兴趣&#xff0c;并创建了一个团体的小群…