力扣:494. 目标和(动态规划)(01背包)

题目:

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

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

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

示例 1:

输入:

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

示例 2

输入:

nums = [1], target = 1

输出:

1

提示

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

思路:

本题可以用回溯来解决(但是会超时),也可以用动态规划中的01背包来解决,
如何转化为01背包问题呢。

假设加法的总和为x,那么减法对应的总和就是sum - x。

所以我们要求的是 x - (sum - x) = target

x = (target + sum) / 2

此时问题就转化为,装满容量为x的背包,有几种方法。

这里的x,就是bagSize,也就是我们后面要求的背包容量。

大家看到(target + sum) / 2 应该担心计算的过程中向下取整有没有影响。

这么担心就对了,例如sum 是5,S是2的话其实就是无解的,所以:

        # 如果nums的和与target的和的奇偶性不同,无法得到目标和为target的子集if (sum(nums) + target) % 2 == 1:return 0

同时如果 S的绝对值已经大于sum,那么也是没有方案的。

        # 如果目标和的绝对值大于nums的和,无法得到目标和为target的子集if abs(target) > sum(nums):return 0

再回归到01背包问题,为什么是01背包呢?

因为每个物品(题目中的1)只用一次

这次和之前遇到的背包问题不一样了,之前都是求容量为j的背包,最多能装多少。

本题则是装满有几种方法。其实这就是一个组合问题了。

动态规划五部曲

  1. 确定dp数组以及下标的含义

dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法

  1. 确定递推公式

有哪些来源可以推出dp[j]呢?

只要搞到nums[i],凑成dp[j]就有dp[j - nums[i]] 种方法。

例如:dp[j],j 为5,

  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 dp[5]。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 dp[5]。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 dp[5]。
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 dp[5]。
  • 已经有一个5(nums[i]) 的话,有 dp[0]中方法 凑成 dp[5]。

那么凑整dp[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起来。

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

这个跟爬楼梯(力扣:70爬楼梯)和不同路径(力扣:62.不同路径)的思路有点类似,现在在重新分析一下:
现在有dp[4]种方法凑成4,你手上还有一个数字1,那么凑成5的话有几种方法? 还是dp[4]种方法!为什么不是dp[4] + 1 种方法呢?因为这个数字1是确定只能是+1,而不能是-1,只有一种方法使4变成5。可以这样理解,这里的方法数量最后是dp[4] * 1,
如果这里1可以是+1也可以是-1的话那方法数量应该是dp[4] * 2

同理,有dp[3]种方法凑成3,现在手上还有一个2,那么有几种方法凑成5?还是dp[3]种!

  1. dp数组如何初始化

从递推公式可以看出,在初始化的时候dp[0] 一定要初始化为1,因为dp[0]是在公式中一切递推结果的起源,如果dp[0]是0的话,递推结果将都是0。

这里有录友可能认为从dp数组定义来说 dp[0] 应该是0,也有录友认为dp[0]应该是1。

其实不要硬去解释它的含义,咱就把 dp[0]的情况带入本题看看应该等于多少。

如果数组[0] ,target = 0,那么 bagSize = (target + sum) / 2 = 0。 dp[0]也应该是1, 也就是说给数组里的元素 0 前面无论放加法还是减法,都是 1 种方法。

所以本题我们应该初始化 dp[0] 为 1。

  1. 确定遍历顺序

毋庸置疑,对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。

  1. 举例推导dp数组

输入:nums: [1, 1, 1, 1, 1], S: 3

bagSize = (S + sum) / 2 = (3 + 5) / 2 = 4

dp数组状态变化如下:
在这里插入图片描述

代码及详细注释:

一维dp数组:

class Solution:def findTargetSumWays(self, nums: List[int], target: int) -> int:# 如果nums的和与target的和的奇偶性不同,无法得到目标和为target的子集if (sum(nums) + target) % 2 == 1:return 0# 如果目标和的绝对值大于nums的和,无法得到目标和为target的子集if abs(target) > sum(nums):return 0# 计算S,S为目标和S = (target + sum(nums)) // 2# 创建一个长度为S+1的数组dp,用于记录可以得到和为i的子集的个数dp = [0] * (S + 1)dp[0] = 1  # 初始化dp[0]为1# 遍历nums中的每个数字for i in range(len(nums)):# 从S到nums[i]遍历,更新dp数组for j in range(S, nums[i] - 1, -1):# 更新dp[j]的值dp[j] += dp[j - nums[i]]# 返回dp[S],表示可以得到和为S的子集的个数return dp[S]
  • 时间复杂度:O(n × m),n为正数个数,m为背包容量
  • 空间复杂度:O(m),m为背包容量

回溯版本:

class Solution:def backtracking(self, candidates, target, total, startIndex, path, result):if total == target:result.append(path[:])  # 将当前路径的副本添加到结果中# 如果 sum + candidates[i] > target,则停止遍历for i in range(startIndex, len(candidates)):if total + candidates[i] > target:breaktotal += candidates[i]path.append(candidates[i])self.backtracking(candidates, target, total, i + 1, path, result)total -= candidates[i]path.pop()def findTargetSumWays(self, nums: List[int], target: int) -> int:total = sum(nums)if target > total:return 0  # 此时没有方案if (target + total) % 2 != 0:return 0  # 此时没有方案,两个整数相加时要注意数值溢出的问题bagSize = (target + total) // 2  # 转化为组合总和问题,bagSize就是目标和# 以下是回溯法代码result = []nums.sort()  # 需要对nums进行排序self.backtracking(nums, bagSize, 0, 0, [], result)return len(result)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git学习笔记(第2章):Git安装

官网地址&#xff1a;Githttps://git-scm.com/ Step1&#xff1a;查看Git的GNU协议 → 点击“Next” Step2&#xff1a;设置Git的安装位置(非中文、无空格的目录) → 点击“Next” Step3&#xff1a;选择Git的选项配置(推荐默认设置) → 点击“Next” Step4&#xff1a;设置Git…

chatgpt国内使用网站(免费收藏级)

如果您认为本文对你有帮助&#xff0c;希望可以点赞收藏&#xff01;感谢您的支持 下面我为你推荐我自己在用的gpt类工具&#xff0c;帮你在工作学习生活上解决一些大小问题 &#x1f389;智能GPT 地址&#xff1a; https://meet.adminjs.net 在他的详情中有详细的使用介绍&am…

SSE[Server-Sent Events]实现页面流式数据输出(模拟ChatGPT流式输出)

文章目录 前言SSE 简介应用场景区分浏览器支撑性 实现过程Web VUE核心解析数据代码实例demo参考 前言 服务端向客户端推送消息&#xff0c;除了用WebSocket可实现&#xff0c;还有一种服务器发送事件(Server-Sent Events)简称 SSE&#xff0c;这是一种服务器端到客户端(浏览器)…

为vs code配置unity开发环境

1.安装.NET.Core SDK 我们可以访问官网下载安装SDK及tool&#xff08;https://www.microsoft.com/net/download/core&#xff09;下载。有的系统只提供了执行文件&#xff0c;没有提供安装包&#xff0c;需要自己做一些配置。 下载好对应的版本就可以安装了&#xff0c;安装好以…

Lua 快速入门 · 教程笔记

Lua语言快速入门 教程笔记 前言1. Lua 语言介绍2. Lua 语言基础之基本语法声明变量声明方法使用 if - else使用 for使用 while 3. Lua 语言基础之表4. Lua 语言基础之数组插入元素移除元素获取表的长度全局表 5. Lua 语言面向对象之复制表的方式面向对象实现继承和重写父类方法…

SpringMVC基础知识学习笔记

Universe Infinity Inc. 目录 一、学习SpringMVC主要是学什么1、SpringMVC的基本原理2、SpringMVC学习串联 二、快速体验SpringMVC的开发1、新建项目&#xff0c;转成web项目2、引入依赖3、编写Spring的配置类4、配置web启动类&#xff0c;替代web.xml5、编写Handler&#xff…

智能助手的巅峰对决:ChatGPT对阵文心一言

在人工智能的世界里&#xff0c;ChatGPT与文心一言都是备受瞩目的明星产品。它们凭借先进的技术和强大的性能&#xff0c;吸引了大量用户的关注。但究竟哪一个在智能回复、语言准确性、知识库丰富度等方面更胜一筹呢&#xff1f;下面就让我们一探究竟。 首先来谈谈智能回复能力…

VUE表单中多个el-upload上传组件共享回调函数解决方案

产品需求界面&#xff1a; 在产品配置页面表单中需要上传多个图片&#xff0c;项目中上传组件采用Element Plus 中的 el-upload&#xff0c;目前问题是每个上传组件都需要实现自己的回调&#xff0c;比如:on-change&#xff0c;采用官方推荐标准代码如下&#xff1a; <el-fo…

[C#]winform部署openvino调用padleocr模型

【官方框架地址】 https://github.com/PaddlePaddle/PaddleOCR 【算法介绍】 OpenVINO和PaddleOCR都是用于计算机视觉应用的工具&#xff0c;但它们有不同的特点和用途。OpenVINO是一个由Intel开发的开源工具套件&#xff0c;主要用于加速深度学习推理&#xff0c;而PaddleOC…

修复uni-simple-router@2.0.7版本query参数null的bug

问题&#xff1a;query参数为null或者为空时&#xff0c;插件内部参数校验问题导致的会报错&#xff1a;TypeError: Cannot convert undefined or null to object at Function.keys 源码修改如下&#xff1a; 通过打补丁的方式修复query参数类型校验问题 1. 安装patch-packag…

黑色金属厂房3d数据可视化综合平台进一步保障生产效率

在当今的数字化时代&#xff0c;钢铁厂面临着降本增效、绿色环保、安全第一等发展问题&#xff0c;亟需寻找更有效的解决方案&#xff0c;数字孪生公司深圳华锐视点利用先进的数字孪生可视化、web3D开发和VR虚拟仿真技术制作数字孪生钢铁厂可视化管控平台&#xff0c;实现对钢铁…

循环神经网络-单变量序列预测详解(pytorch)

参考博客 文章目录 &#xff08;1&#xff09;导入所需要的包&#xff08;2&#xff09;读取数据并展示&#xff08;3&#xff09;数据预处理&#xff08;4&#xff09;划分训练集和测试集&#xff08;5&#xff09;构建RNN回归模型&#xff08;6&#xff09;构造训练函数&…