LeetCode - 494 目标和

news2024/12/28 21:59:41

目录

题目来源

题目描述

示例

提示

题目解析

算法源码


题目来源

494. 目标和 - 力扣(LeetCode)

题目描述

给你一个整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。
返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例

输入nums = [1,1,1,1,1], target = 3
输出5
解释一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
输入nums = [1], target = 1
输出1
解释

提示

  • 1 <= nums.length <= 20
  • 0 <= nums[i] <= 1000
  • 0 <= sum(nums[i]) <= 1000
  • -1000 <= target <= 1000

题目解析

题目中说:

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式

其实可以理解为将数组中的数分为两类:+号的一类positive,-号的一类negative,因此可得公式如下:

  • positive + negative = sum(nums)
  • positive - negative = target

根据上面公式可得: positive = (sum(nums) + target) / 2

而sum(nums)、target都是给定的值,因此本题可以转化为,从nums数组中选出任意个数,只要选出的数之和为 (sum(nums) + target) / 2 即可。

由于本题中所有数都是整数,因此选出任意个数的和也一定是整数,如果(sum(nums) + target) / 2结果不是整数,则说明无法选出对应组合,此时应该返回0。

如果(sum(nums) + target) / 2的结果是整数,那么本题其实就可以转化为01背包问题:

有nums种物品,每种物品只有一个,每种物品的重量是nums[i],有一个背包,背包承重是(sum(nums) + target) / 2,现在问有多少种装满背包的方式?

可以发现,上面的求解还是有别于一般的01背包问题的,一般的01背包问题是:

有N种物品,每种物品只有一个,每种物品的重量为w[i],价值为p[i],有一个背包,背包承重是W,问背包装入物品的最大价值是多少?

其实上面两个问题都是01背包问题,01背包问题通常有三类:

  • 背包能装入物品的最大价值
  • 背包是否可以装满
  • 背包装满有多少种方式

本题属于01背包的第三种问题,即背包装满有多少种方式。

我们假设 dp[i][j] 表示:”从0 ~ i 物品中选择任意物品,能够装满容量 j 的背包 “ 的装满背包的方案的个数

那么按照01背包的思维,第 i 个物品我们可以选择装入或者不装入,那么:

  • 第 i 个物品我选择装入的话,那么此时dp[i][j]有多少种?
  • 第 i 个物品我们选择不装入的话,那么此时dp[i][j]又有多少种?

如果第 i 个物品不装入,那么dp[i][j]装满背包的方案数其实就等价于dp[i-1][j]装满背包的方案数,即此时:dp[i][j] = dp[i-1][j]

举个例子:

你有三件物品,重量分别为2,3,5,你有一个背包,承重为5,那么现在有两种方式装满背包:

  • 装入2,3
  • 装入5

然后又新增了一个物品,重量为x,但是目前这个x已经确定不装入背包了,那么这四件物品2,3,5,x,能够装满背包5的方案数其实还是两种。

如果第 i 个物品装入,那么dp[i][j] 装满背包的方案数其实就等价于 dp[i-1][j - nums[i]] 装满背包的方案数,即此时:dp[i][j] = dp[i-1][j - nums[i]]

举个例子:

你有三件物品,重量分别为2,3,5,你有一个背包,承重为5,那么现在有两种方式装满背包:

  • 装入2,3
  • 装入5

然后又新增了一个物品,重量为x,并且背包的承重也增加了x(背包承重从 j - nums[i] 变为了 j ),此时依旧只有两种装满背包的方案:

  • 装入2,3,x
  • 装入5,x

由于我们求得是装满背包的方案数,而不是最大价值,因此这里我们不需要Math.max去取最大,而是直接求和:

dp[i][j] = dp[i-1][j]  +  dp[i-1][j - nums[i]]

当然,如果物品nums[i]重量超过了 j 背包承重,即 j - nums[i] < 0 时,此时

dp[i][j]  =  dp[i-1][j]

最后本题还有一个问题,那就是dp[0][0]应该初始化为多少?

这里直接给出答案:dp[0][0] = 1

可能有人会产生疑问,【从0 ~ 0 物品中选择任意物品,能够装满容量 0 的背包】的方案数有1种?难道不是0种吗?

其实我觉得0种也是符合认知的,但是在这里却不符合代码逻辑,假设dp[0][0] = 0,那么dp[1][1]等于多少呢?

根据前面的状态转义公式,此时dp[1][1] = 0,但是实际上

【从0 ~ 1 物品中选择任意物品,能够装满容量 1 的背包】的方案数是有可能为1种的。因此本题dp[0][0]需要初始化为1。

Java算法源码

01背包二维数组解法

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for(int num : nums) sum += num;
        if((sum + target) % 2 != 0) return 0;

        int bag = (sum + target) / 2;
        if(bag < 0) return 0;

        int n = nums.length;

        int[][] dp = new int[n+1][bag+1];
        dp[0][0] = 1;

        for(int i=1; i<=n; i++) {
            int num = nums[i-1];
            for(int j=0; j<=bag; j++) {
                if(j < num) {
                    dp[i][j] = dp[i-1][j];
                } else {
                    dp[i][j] = dp[i-1][j] + dp[i-1][j-num];
                }
            }
        }

        return dp[n][bag];
    }
}

01背包滚动数组优化

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for(int num : nums) sum += num;
        if((sum + target) % 2 != 0) return 0;

        int bag = (sum + target) / 2;
        if(bag < 0) return 0;

        int n = nums.length;

        int[] dp = new int[bag+1];
        dp[0] = 1;

        for(int i=1; i<=n; i++) {
            int num = nums[i-1];
            for(int j=bag; j>=num; j--) {
                dp[j] = dp[j] + dp[j-num];
            }
        }

        return dp[bag];
    }
}

 

JS算法源码

01背包二维数组解法

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var findTargetSumWays = function(nums, target) {
    const sum = nums.reduce((a,b) => a + b);
    if((sum + target) % 2 != 0) return 0;

    const bag = (sum + target) / 2;
    if(bag < 0) return 0;

    const n = nums.length;

    const dp = new Array(n+1).fill(0).map(() => new Array(bag+1).fill(0));
    dp[0][0] = 1;

    for(let i=1; i<=n; i++) {
        const num = nums[i-1];
        for(let j=0; j<=bag; j++) {
            if(j < num) {
                dp[i][j] = dp[i-1][j];
            } else {
                dp[i][j] = dp[i-1][j] + dp[i-1][j - num];
            }
        }
    }

    return dp.at(-1).at(-1);
};

 

01背包滚动数组优化

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var findTargetSumWays = function(nums, target) {
    let sum = 0;
    for(let num of nums) sum += num;
    if((sum + target) % 2 != 0) return 0;

    const bag = (sum + target) / 2;
    if(bag < 0) return 0;

    const dp = new Array(bag+1).fill(0);
    dp[0] = 1;

    for(let i=1; i<=nums.length; i++) {
        const num = nums[i-1];
        for(let j=bag; j>=num; j--) {
            dp[j] = dp[j] + dp[j - num];
        }
    }

    return dp.at(-1);
};

 

Python算法源码

01背包二维数组解法

class Solution(object):
    def findTargetSumWays(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        total = sum(nums)

        if (total + target) % 2 != 0:
            return 0
        
        bag = (total + target) // 2

        if bag < 0:
            return 0
        
        n = len(nums)
        
        dp = [[0]*(bag+1) for _ in range(n+1)]
        dp[0][0] = 1

        for i in range(1, n+1):
            num = nums[i-1]
            for j in range(0, bag+1):
                if j < num:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = dp[i-1][j] + dp[i-1][j - num]
        
        return dp[-1][-1]

01背包滚动数组优化

class Solution(object):
    def findTargetSumWays(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        total = sum(nums)

        if (total + target) % 2 != 0:
            return 0
        
        bag = (total + target) // 2

        if bag < 0:
            return 0
        
        n = len(nums)
        
        dp = [0]*(bag+1)
        dp[0] = 1

        for i in range(1, n+1):
            num = nums[i-1]
            for j in range(bag, num-1, -1):
                dp[j] = dp[j] + dp[j - num]
        
        return dp[-1]

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MathType如何成功插入到word

有时候我们重装mathtype的时候&#xff0c;我们的word里嵌入的mathtype没有了&#xff0c;因此我们如何让它重新出来呢&#xff1f;下面我们来看看。 1、我们打开word&#xff0c;点击“选项”&#xff0c;点击“加载项”找到如图所示的路径内容&#xff08;根据自己电脑的实际…

IDA 知识汇总

工具使用-IDA从入门到理解 - 简书作者ID:leishi-yanmu IDA对于各位师傅应该无需简介了,如果写的不对的地方,还望师傅们多多包涵。讲解的时候会涉及到笔者在学习和使用时候的理解。 启动界面介绍: ...https://www.jianshu.com/p/190805574432[原创]【iOS逆向与安全】利用IDA…

实现网页顶部线性加载进度条

插件一&#xff1a;NProgress.js 下载链接&#xff1a;https://github.com/rstacruz/nprogress 插件二&#xff1a;MProgress.js 下载链接&#xff1a;https://github.com/lightningtgc/mprogress.js/ 这两个插件都是实现网页加载进度条&#xff0c;并且默认方法有四个&…

kitti数据集预处理

kitti数据集预处理 0.引言0.1.calib0.2.oxts(gps/imu)0.3.velodyne0.4.image_2/30.5.kitti-step/panoptics0.6.label 1.create_kitti_depth_maps2.create_kitti_masks3.create_kitti_metadata4.extract_dino_features5.run_pca 0.引言 官网参考链接1参考链接2 注&#xff1a;…

Linux基础指令(1)

Linux的基础指令 对于Linux的学习&#xff0c;先从指令开始学&#xff0c;我们先了解操作系统的一般性概念&#xff0c;然后对于Linux的一些基本的指令进行学习&#xff0c;最后我们发现Linux实际上是一个多叉树的目录结构 文章目录 Linux的基础指令操作系统操作系统是什么&am…

数据可视化开源工具软件

数据可视化工具用于通过图形、图表、表格、地图和其他详细的视觉对象来表示信息。 它们通常将数据呈现和分析结合起来&#xff0c;以帮助专业人员在数据驱动领域(如工程、数据科学和业务分析)做出更明智的决策。 选择正确的数据可视化工具将帮助您减少数据错误&#xff0c;并…

基于本地知识构建简易的chatPDF

Langchain chatglm-6b 文章目录 Langchain chatglm-6b前言一、实验记录1.1 环境配置1.2 代码理解1.3 补充内容 二、总结 前言 介绍&#xff1a;一种利用 ChatGLM-6B langchain 实现的基于本地知识的 ChatGLM 应用 Github: https://github.com/imClumsyPanda/langchain-Chat…

阳光开朗孔乙己,会否奔向大泽乡

前言 &#x1f525;学历对职业关系到底有什么影响呢&#xff1f;&#x1f525;学历给我们带来了优势吗&#xff1f;&#x1f525;到底是什么造成了"孔乙己的长衫"&#xff1f; 孔乙己是中国清代作家鲁迅创作的一篇短篇小说&#xff0c;发表于1919年。这部作品被认为是…

Blender 建模案例一(2)

目录 1. 烛台基座1.1 导入图片1.2 从立方体取一个顶点1.3 用点描边1.4 旋转1.5 实体化修改器1.6 删除内部正面1.7 封盖1.8 平滑着色1.9 表面细分修改器1.10 环切线&#xff08;卡线&#xff09; 1. 烛台基座 1.1 导入图片 1.2 从立方体取一个顶点 中间顶点尽量也X轴平行 1.…

FPGA入门系列5--运算符号

文章简介 本系列文章主要针对FPGA初学者编写&#xff0c;包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解&#xff0c;旨在更快速的提升初学者在FPGA开发方面的能力&#xff0c;每一个章节中都有针对性的代码…

( 栈和队列) 739. 每日温度 ——【Leetcode每日一题】

❓739. 每日温度 难度&#xff1a;中等 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置…

32k*16 薪,3年自动化测试历经3轮面试成功拿下华为Offer....

前言 转眼过去&#xff0c;距离读书的时候已经这么久了吗&#xff1f;&#xff0c;从18年5月本科毕业入职了一家小公司&#xff0c;到现在快4年了&#xff0c;前段时间社招想着找一个新的工作&#xff0c;前前后后花了一个多月的时间复习以及面试&#xff0c;前几天拿到了华为…

Java并发编程 —— ThreadPoolExecutor线程池详解

一、什么是线程池 线程池是一种池化技术&#xff0c;是管理一系列线程的资源池。当有任务要处理时&#xff0c;直接从线程池中获取线程来处理&#xff0c;处理完之后线程并不会立即被销毁&#xff0c;而是等待下一个任务。这样实现线程的复用&#xff0c;避免重复创建与销毁线…

司美格鲁肽进入临床竞速期,减肥“神药”生于偶然、火于乱象?

减肥作为一门市场需求旺盛的生意&#xff0c;在很多行业都有所渗透&#xff0c;如今其高潮逐渐来到了医药领域。 CDE&#xff08;国家食品药品监督管理局药品审评中心&#xff09;网站显示&#xff0c;4月17日&#xff0c;联邦制药全资附属公司联邦生物科技&#xff08;珠海横…

Figma导出源文件的方法,用这个方法快速转换其它格式

市场上设计工具层出不穷&#xff0c;Sketch、AdobeXD、Axure、InVision、Figma、Pixso等都是优秀的设计工具&#xff0c;设计师经常面临如何从设计工具中导出文件的问题。 Figma软件的导出功能非常强大&#xff0c;因为轻量化体验受到很多设计师的喜爱。如何保存导出Figma源文…

【Leetcode -19.删除链表的倒数第N个结点 -24.两两交换链表中的节点】

Leetcode Leetcode -19.删除链表的倒数第N个结点Leetcode - 24.两两交换链表中的节点 Leetcode -19.删除链表的倒数第N个结点 题目&#xff1a;给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;he…

软件测试人员在工作中如何运用Linux

从事过软件测试的小伙们就会明白会使用Linux是多么重要的一件事&#xff0c;工作时需要用到&#xff0c;面试时会被问到&#xff0c;简历中需要写到。 对于软件测试人员来说&#xff0c;不需要你多么熟练使用Linux所有命令&#xff0c;也不需要你对Linux系统完全了解&#xff…

vue总线bus的使用和移除注意事项

vue总线bus的使用和移除注意事项 本文目录 vue总线bus的使用和移除注意事项初始化并封装发送事件接收事件移除事件监听实际使用正确测试效果错误测试效果 初始化并封装 在main.js中对bus进行初始化&#xff0c; Bus是一个不具备 DOM 的组件&#xff0c;它具有的仅仅只是它实例…

算法 | 最长回文子串

思路&#xff1a;遍历字符串&#xff0c;对于字符串的每个字符&#xff0c;维持两个游标&#xff08;left&#xff0c;right&#xff09;&#xff0c;找到游标对应字符相等时就同速度向两边扩散。 对于 奇数长度子串&#xff0c;left right 对于偶数成都子串&#xff0c;lef…

RocketMq消息

消息发送 发送同步消息 public class SyncProducer {public static void main(String[] args) throws Exception{DefaultMQProducer producernew DefaultMQProducer(/*please_rename_unique_group_name*/"group1");producer.setNamesrvAddr("localhost:9876&q…