From 27718a4dfca99b25ceda3ee2946130c29261be71 Mon Sep 17 00:00:00 2001 From: asnpro <920569392@qq.com> Date: Fri, 24 Jan 2025 22:51:46 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E4=B8=BA=200494.=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E5=92=8C.md=20=E5=AE=8C=E5=96=84=20JavaDoc=20=E6=B3=A8?= =?UTF-8?q?=E9=87=8A,=20=E6=B7=BB=E5=8A=A0=E5=8A=A8=E8=A7=84=E4=BA=94?= =?UTF-8?q?=E9=83=A8=E6=9B=B2=E6=B3=A8=E9=87=8A,=20=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F,=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86=E5=8F=98=E9=87=8F=E5=90=8D?= =?UTF-8?q?=E4=BB=A5=E5=A2=9E=E5=BC=BA=E4=BB=A3=E7=A0=81=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0494.目标和.md | 59 +++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index 4a1fc6ab..c38ba7e4 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -825,30 +825,69 @@ func abs(x int) int { ### JavaScript ```javascript +/** + * 题目来源: {@link https://leetcode.cn/problems/target-sum/} + * + * 题解来源: {@link https://programmercarl.com/0494.%E7%9B%AE%E6%A0%87%E5%92%8C.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE} + * + * 时间复杂度: O(n * C), C 为数组元素总和与目标值之和的一半 + * + * 空间复杂度: O(C) + * + * @param { number[] } nums + * @param { number } target + * @return { number } + */ const findTargetSumWays = (nums, target) => { + // 原题目可转化为: + // + // 将所有元素划分为 2 个集合, + // 一个集合中包含所有要添加 "+" 号的元素, 一个集合中包含所有要添加 "-" 号的元素 + // + // 设两个集合的元素和分别为 positive 和 negative, 所有元素总和为 sum, 那么有如下等式: + // positive + negative = sum (1) + // positive - negative = target (2) + // (1) 与 (2) 联立可得: positive = (sum + target) / 2, + // 所以如果能从原数组中取出若干个元素形成 1 个元素总和为 (sum + target) / 2 的集合, + // 就算得到了 1 种满足题意的组合方法 + // + // 因此, 所求变为: 有多少种取法, 可使得容量为 (sum + target) / 2 的背包被装满? - const sum = nums.reduce((a, b) => a+b); + const sum = nums.reduce((a, b) => a + b); - if(Math.abs(target) > sum) { + if (Math.abs(target) > sum) { return 0; } - if((target + sum) % 2) { + if ((target + sum) % 2) { return 0; } - const halfSum = (target + sum) / 2; - - let dp = new Array(halfSum+1).fill(0); + const bagWeight = (target + sum) / 2; + + // 1. dp 数组的含义 + // dp[j]: 装满容量为 j 的背包, 有 dp[j] 种方法 + let dp = new Array(bagWeight + 1).fill(0); + + // 2. 递推公式 + // dp[j] = Σ(dp[j - nums[j]]), (j ∈ [0, j] 且 j >= nums[j]) + // 因为 dp[j - nums[j]] 表示: 装满容量为 j - nums[j] 背包有 dp[j - nums[j]] 种方法 + // 而容量为 j - nums[j] 的背包只需要再将 nums[j] 放入背包就能使得背包容量达到 j + // 因此, 让背包容量达到 j 有 Σ(dp[j - nums[j]]) 种方法 + + // 3. dp 数组如何初始化 + // dp[0] = 1, dp[1 ~ bagWeight] = 0 dp[0] = 1; - - for(let i = 0; i < nums.length; i++) { - for(let j = halfSum; j >= nums[i]; j--) { + + // 4. 遍历顺序 + // 先物品后背包, 物品从前往后遍历, 背包容量从后往前遍历 + for (let i = 0; i < nums.length; i++) { + for (let j = bagWeight; j >= nums[i]; j--) { dp[j] += dp[j - nums[i]]; } } - return dp[halfSum]; + return dp[bagWeight]; }; ```