diff --git a/solution/0400-0499/0494.Target Sum/README.md b/solution/0400-0499/0494.Target Sum/README.md index 2d1ae7f9d5841..79680b9b0202b 100644 --- a/solution/0400-0499/0494.Target Sum/README.md +++ b/solution/0400-0499/0494.Target Sum/README.md @@ -69,11 +69,29 @@ tags: ### 方法一:动态规划 -题目可以转换为 `0-1` 背包问题。 +我们记数组 $\text{nums}$ 所有元素的和为 $s$,添加负号的元素之和为 $x$,则添加正号的元素之和为 $s - x$,则有: -设整数数组总和为 `s`,添加 `-` 号的元素之和为 `x`,则添加 `+` 号的元素之和为 `s - x`,那么 `s - x - x = target`,`2x = s - target`。左式成立需要满足 `s - target` 一定大于等于 0,并且能够被 2 整除。在此前提下,我们可以将问题抽象为: 从数组中选出若干个数,使得选出的元素之和为 x。显然这是一个 `0-1` 背包问题。 +$$ +(s - x) - x = \text{target} \Rightarrow x = \frac{s - \text{target}}{2} +$$ -定义 `dp[i][j]` 表示从前 i 个数中选出若干个数,使得所选元素之和为 j 的所有方案数。 +由于 $x \geq 0$,且 $x$ 为整数,所以 $s \geq \text{target}$ 且 $s - \text{target}$ 为偶数。如果不满足这两个条件,则直接返回 $0$。 + +接下来,我们可以将问题转化为:在数组 $\text{nums}$ 中选取若干元素,使得这些元素之和等于 $\frac{s - \text{target}}{2}$,问有多少种选取方法。 + +我们可以使用动态规划来解决这个问题。定义 $f[i][j]$ 表示在数组 $\text{nums}$ 的前 $i$ 个元素中选取若干元素,使得这些元素之和等于 $j$ 的选取方案数。 + +对于 $\text{nums}[i - 1]$,我们有两种选择:选取或不选取。如果我们不选取 $\text{nums}[i - 1]$,则 $f[i][j] = f[i - 1][j]$;如果我们选取 $\text{nums}[i - 1]$,则 $f[i][j] = f[i - 1][j - \text{nums}[i - 1]]$。因此,状态转移方程为: + +$$ +f[i][j] = f[i - 1][j] + f[i - 1][j - \text{nums}[i - 1]] +$$ + +其中,选取的前提是 $j \geq \text{nums}[i - 1]$。 + +最终答案即为 $f[m][n]$。其中 $m$ 为数组 $\text{nums}$ 的长度,而 $n = \frac{s - \text{target}}{2}$。 + +时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。 @@ -83,17 +101,17 @@ tags: class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: s = sum(nums) - if s < target or (s - target) % 2 != 0: + if s < target or (s - target) % 2: return 0 m, n = len(nums), (s - target) // 2 - dp = [[0] * (n + 1) for _ in range(m + 1)] - dp[0][0] = 1 - for i in range(1, m + 1): + f = [[0] * (n + 1) for _ in range(m + 1)] + f[0][0] = 1 + for i, x in enumerate(nums, 1): for j in range(n + 1): - dp[i][j] = dp[i - 1][j] - if nums[i - 1] <= j: - dp[i][j] += dp[i - 1][j - nums[i - 1]] - return dp[-1][-1] + f[i][j] = f[i - 1][j] + if j >= x: + f[i][j] += f[i - 1][j - x] + return f[m][n] ``` #### Java @@ -101,26 +119,23 @@ class Solution: ```java class Solution { public int findTargetSumWays(int[] nums, int target) { - int s = 0; - for (int v : nums) { - s += v; - } + int s = Arrays.stream(nums).sum(); if (s < target || (s - target) % 2 != 0) { return 0; } int m = nums.length; int n = (s - target) / 2; - int[][] dp = new int[m + 1][n + 1]; - dp[0][0] = 1; + int[][] f = new int[m + 1][n + 1]; + f[0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { - dp[i][j] = dp[i - 1][j]; - if (nums[i - 1] <= j) { - dp[i][j] += dp[i - 1][j - nums[i - 1]]; + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; } } } - return dp[m][n]; + return f[m][n]; } } ``` @@ -132,17 +147,23 @@ class Solution { public: int findTargetSumWays(vector& nums, int target) { int s = accumulate(nums.begin(), nums.end(), 0); - if (s < target || (s - target) % 2 != 0) return 0; - int m = nums.size(), n = (s - target) / 2; - vector> dp(m + 1, vector(n + 1)); - dp[0][0] = 1; + if (s < target || (s - target) % 2) { + return 0; + } + int m = nums.size(); + int n = (s - target) / 2; + int f[m + 1][n + 1]; + memset(f, 0, sizeof(f)); + f[0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { - dp[i][j] += dp[i - 1][j]; - if (nums[i - 1] <= j) dp[i][j] += dp[i - 1][j - nums[i - 1]]; + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } } } - return dp[m][n]; + return f[m][n]; } }; ``` @@ -152,27 +173,50 @@ public: ```go func findTargetSumWays(nums []int, target int) int { s := 0 - for _, v := range nums { - s += v + for _, x := range nums { + s += x } if s < target || (s-target)%2 != 0 { return 0 } m, n := len(nums), (s-target)/2 - dp := make([][]int, m+1) - for i := range dp { - dp[i] = make([]int, n+1) + f := make([][]int, m+1) + for i := range f { + f[i] = make([]int, n+1) } - dp[0][0] = 1 + f[0][0] = 1 for i := 1; i <= m; i++ { for j := 0; j <= n; j++ { - dp[i][j] = dp[i-1][j] - if nums[i-1] <= j { - dp[i][j] += dp[i-1][j-nums[i-1]] + f[i][j] = f[i-1][j] + if j >= nums[i-1] { + f[i][j] += f[i-1][j-nums[i-1]] } } } - return dp[m][n] + return f[m][n] +} +``` + +#### TypeScript + +```ts +function findTargetSumWays(nums: number[], target: number): number { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const [m, n] = [nums.length, ((s - target) / 2) | 0]; + const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + f[0][0] = 1; + for (let i = 1; i <= m; i++) { + for (let j = 0; j <= n; j++) { + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } + } + } + return f[m][n]; } ``` @@ -180,39 +224,24 @@ func findTargetSumWays(nums []int, target int) int { ```rust impl Solution { - #[allow(dead_code)] pub fn find_target_sum_ways(nums: Vec, target: i32) -> i32 { - let mut sum = 0; - for e in &nums { - sum += *e; - } - - // -x + (sum - x) = target <-> -2 * x + sum = target <-> 2 * x = sum - target - if sum < target || (sum - target) % 2 != 0 { - // There is no way to get any expression in this case + let s: i32 = nums.iter().sum(); + if s < target || (s - target) % 2 != 0 { return 0; } - let n = nums.len(); - let m = (sum - target) / 2; - - let mut dp: Vec> = vec![vec![0; m as usize + 1]; n + 1]; - - // Initialize the dp vector - dp[0][0] = 1; - - // Begin the actual dp phase - for i in 1..=n { - for j in 0..=m as usize { - // nums[i - 1] is not included - dp[i][j] = dp[i - 1][j]; - if nums[i - 1] <= (j as i32) { - // nums[i - 1] is included - dp[i][j] += dp[i - 1][j - (nums[i - 1] as usize)]; + let m = nums.len(); + let n = ((s - target) / 2) as usize; + let mut f = vec![vec![0; n + 1]; m + 1]; + f[0][0] = 1; + for i in 1..=m { + for j in 0..=n { + f[i][j] = f[i - 1][j]; + if j as i32 >= nums[i - 1] { + f[i][j] += f[i - 1][j - nums[i - 1] as usize]; } } } - - dp[n][m as usize] + f[m][n] } } ``` @@ -226,23 +255,22 @@ impl Solution { * @return {number} */ var findTargetSumWays = function (nums, target) { - let s = 0; - for (let v of nums) { - s += v; - } - if (s < target || (s - target) % 2 != 0) { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { return 0; } - const m = nums.length; - const n = (s - target) / 2; - let dp = new Array(n + 1).fill(0); - dp[0] = 1; - for (let i = 1; i <= m; ++i) { - for (let j = n; j >= nums[i - 1]; --j) { - dp[j] += dp[j - nums[i - 1]]; + const [m, n] = [nums.length, ((s - target) / 2) | 0]; + const f = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + f[0][0] = 1; + for (let i = 1; i <= m; i++) { + for (let j = 0; j <= n; j++) { + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } } } - return dp[n]; + return f[m][n]; }; ``` @@ -252,7 +280,11 @@ var findTargetSumWays = function (nums, target) { -### 方法二 +### 方法二:动态规划(空间优化) + +我们可以发现,方法一中的状态转移方程中,$f[i][j]$ 的值只和 $f[i - 1][j]$ 以及 $f[i - 1][j - \text{nums}[i - 1]]$ 有关,因此我们去掉第一维空间,只使用一维数组即可。 + +时间复杂度 $O(m \times n)$,空间复杂度 $O(n)$。 @@ -262,15 +294,15 @@ var findTargetSumWays = function (nums, target) { class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: s = sum(nums) - if s < target or (s - target) % 2 != 0: + if s < target or (s - target) % 2: return 0 n = (s - target) // 2 - dp = [0] * (n + 1) - dp[0] = 1 - for v in nums: - for j in range(n, v - 1, -1): - dp[j] += dp[j - v] - return dp[-1] + f = [0] * (n + 1) + f[0] = 1 + for x in nums: + for j in range(n, x - 1, -1): + f[j] += f[j - x] + return f[n] ``` #### Java @@ -278,22 +310,19 @@ class Solution: ```java class Solution { public int findTargetSumWays(int[] nums, int target) { - int s = 0; - for (int v : nums) { - s += v; - } + int s = Arrays.stream(nums).sum(); if (s < target || (s - target) % 2 != 0) { return 0; } int n = (s - target) / 2; - int[] dp = new int[n + 1]; - dp[0] = 1; - for (int v : nums) { - for (int j = n; j >= v; --j) { - dp[j] += dp[j - v]; + int[] f = new int[n + 1]; + f[0] = 1; + for (int num : nums) { + for (int j = n; j >= num; --j) { + f[j] += f[j - num]; } } - return dp[n]; + return f[n]; } } ``` @@ -305,14 +334,19 @@ class Solution { public: int findTargetSumWays(vector& nums, int target) { int s = accumulate(nums.begin(), nums.end(), 0); - if (s < target || (s - target) % 2 != 0) return 0; + if (s < target || (s - target) % 2) { + return 0; + } int n = (s - target) / 2; - vector dp(n + 1); - dp[0] = 1; - for (int& v : nums) - for (int j = n; j >= v; --j) - dp[j] += dp[j - v]; - return dp[n]; + int f[n + 1]; + memset(f, 0, sizeof(f)); + f[0] = 1; + for (int x : nums) { + for (int j = n; j >= x; --j) { + f[j] += f[j - x]; + } + } + return f[n]; } }; ``` @@ -322,21 +356,41 @@ public: ```go func findTargetSumWays(nums []int, target int) int { s := 0 - for _, v := range nums { - s += v + for _, x := range nums { + s += x } if s < target || (s-target)%2 != 0 { return 0 } n := (s - target) / 2 - dp := make([]int, n+1) - dp[0] = 1 - for _, v := range nums { - for j := n; j >= v; j-- { - dp[j] += dp[j-v] + f := make([]int, n+1) + f[0] = 1 + for _, x := range nums { + for j := n; j >= x; j-- { + f[j] += f[j-x] } } - return dp[n] + return f[n] +} +``` + +#### TypeScript + +```ts +function findTargetSumWays(nums: number[], target: number): number { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const n = ((s - target) / 2) | 0; + const f = Array(n + 1).fill(0); + f[0] = 1; + for (const x of nums) { + for (let j = n; j >= x; j--) { + f[j] += f[j - x]; + } + } + return f[n]; } ``` @@ -344,61 +398,47 @@ func findTargetSumWays(nums []int, target int) int { ```rust impl Solution { - #[allow(dead_code)] pub fn find_target_sum_ways(nums: Vec, target: i32) -> i32 { - let mut sum = 0; - for e in &nums { - sum += *e; - } - - if sum < target || (sum - target) % 2 != 0 { - // Just directly return + let s: i32 = nums.iter().sum(); + if s < target || (s - target) % 2 != 0 { return 0; } - - let n = ((sum - target) / 2) as usize; - let mut dp: Vec = vec![0; n + 1]; - - // Initialize the dp vector - dp[0] = 1; - - // Begin the actual dp phase - for e in &nums { - for i in (*e as usize..=n).rev() { - dp[i] += dp[i - (*e as usize)]; + let n = ((s - target) / 2) as usize; + let mut f = vec![0; n + 1]; + f[0] = 1; + for x in nums { + for j in (x as usize..=n).rev() { + f[j] += f[j - x as usize]; } } - - dp[n] + f[n] } } ``` - - - - - - -### 方法三 - - - -#### Python3 +#### JavaScript -```python -class Solution: - def findTargetSumWays(self, nums: List[int], target: int) -> int: - @cache - def dfs(i, t): - if i == n: - if t == target: - return 1 - return 0 - return dfs(i + 1, t + nums[i]) + dfs(i + 1, t - nums[i]) - - ans, n = 0, len(nums) - return dfs(0, 0) +```js +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var findTargetSumWays = function (nums, target) { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const n = (s - target) / 2; + const f = Array(n + 1).fill(0); + f[0] = 1; + for (const x of nums) { + for (let j = n; j >= x; j--) { + f[j] += f[j - x]; + } + } + return f[n]; +}; ``` diff --git a/solution/0400-0499/0494.Target Sum/README_EN.md b/solution/0400-0499/0494.Target Sum/README_EN.md index 4ebe6d0754338..776a50a943237 100644 --- a/solution/0400-0499/0494.Target Sum/README_EN.md +++ b/solution/0400-0499/0494.Target Sum/README_EN.md @@ -65,7 +65,31 @@ tags: -### Solution 1 +### Solution 1: Dynamic Programming + +Let's denote the sum of all elements in the array $\text{nums}$ as $s$, and the sum of elements to which we assign a negative sign as $x$. Therefore, the sum of elements with a positive sign is $s - x$. We have: + +$$ +(s - x) - x = \text{target} \Rightarrow x = \frac{s - \text{target}}{2} +$$ + +Since $x \geq 0$ and $x$ must be an integer, it follows that $s \geq \text{target}$ and $s - \text{target}$ must be even. If these two conditions are not met, we directly return $0$. + +Next, we can transform the problem into: selecting several elements from the array $\text{nums}$ such that the sum of these elements equals $\frac{s - \text{target}}{2}$. We are asked how many ways there are to make such a selection. + +We can use dynamic programming to solve this problem. Define $f[i][j]$ as the number of ways to select several elements from the first $i$ elements of the array $\text{nums}$ such that the sum of these elements equals $j$. + +For $\text{nums}[i - 1]$, we have two choices: to select or not to select. If we do not select $\text{nums}[i - 1]$, then $f[i][j] = f[i - 1][j]$; if we do select $\text{nums}[i - 1]$, then $f[i][j] = f[i - 1][j - \text{nums}[i - 1]]$. Therefore, the state transition equation is: + +$$ +f[i][j] = f[i - 1][j] + f[i - 1][j - \text{nums}[i - 1]] +$$ + +This selection is based on the premise that $j \geq \text{nums}[i - 1]$. + +The final answer is $f[m][n]$, where $m$ is the length of the array $\text{nums}$, and $n = \frac{s - \text{target}}{2}$. + +The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. @@ -75,17 +99,17 @@ tags: class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: s = sum(nums) - if s < target or (s - target) % 2 != 0: + if s < target or (s - target) % 2: return 0 m, n = len(nums), (s - target) // 2 - dp = [[0] * (n + 1) for _ in range(m + 1)] - dp[0][0] = 1 - for i in range(1, m + 1): + f = [[0] * (n + 1) for _ in range(m + 1)] + f[0][0] = 1 + for i, x in enumerate(nums, 1): for j in range(n + 1): - dp[i][j] = dp[i - 1][j] - if nums[i - 1] <= j: - dp[i][j] += dp[i - 1][j - nums[i - 1]] - return dp[-1][-1] + f[i][j] = f[i - 1][j] + if j >= x: + f[i][j] += f[i - 1][j - x] + return f[m][n] ``` #### Java @@ -93,26 +117,23 @@ class Solution: ```java class Solution { public int findTargetSumWays(int[] nums, int target) { - int s = 0; - for (int v : nums) { - s += v; - } + int s = Arrays.stream(nums).sum(); if (s < target || (s - target) % 2 != 0) { return 0; } int m = nums.length; int n = (s - target) / 2; - int[][] dp = new int[m + 1][n + 1]; - dp[0][0] = 1; + int[][] f = new int[m + 1][n + 1]; + f[0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { - dp[i][j] = dp[i - 1][j]; - if (nums[i - 1] <= j) { - dp[i][j] += dp[i - 1][j - nums[i - 1]]; + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; } } } - return dp[m][n]; + return f[m][n]; } } ``` @@ -124,17 +145,23 @@ class Solution { public: int findTargetSumWays(vector& nums, int target) { int s = accumulate(nums.begin(), nums.end(), 0); - if (s < target || (s - target) % 2 != 0) return 0; - int m = nums.size(), n = (s - target) / 2; - vector> dp(m + 1, vector(n + 1)); - dp[0][0] = 1; + if (s < target || (s - target) % 2) { + return 0; + } + int m = nums.size(); + int n = (s - target) / 2; + int f[m + 1][n + 1]; + memset(f, 0, sizeof(f)); + f[0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { - dp[i][j] += dp[i - 1][j]; - if (nums[i - 1] <= j) dp[i][j] += dp[i - 1][j - nums[i - 1]]; + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } } } - return dp[m][n]; + return f[m][n]; } }; ``` @@ -144,27 +171,50 @@ public: ```go func findTargetSumWays(nums []int, target int) int { s := 0 - for _, v := range nums { - s += v + for _, x := range nums { + s += x } if s < target || (s-target)%2 != 0 { return 0 } m, n := len(nums), (s-target)/2 - dp := make([][]int, m+1) - for i := range dp { - dp[i] = make([]int, n+1) + f := make([][]int, m+1) + for i := range f { + f[i] = make([]int, n+1) } - dp[0][0] = 1 + f[0][0] = 1 for i := 1; i <= m; i++ { for j := 0; j <= n; j++ { - dp[i][j] = dp[i-1][j] - if nums[i-1] <= j { - dp[i][j] += dp[i-1][j-nums[i-1]] + f[i][j] = f[i-1][j] + if j >= nums[i-1] { + f[i][j] += f[i-1][j-nums[i-1]] } } } - return dp[m][n] + return f[m][n] +} +``` + +#### TypeScript + +```ts +function findTargetSumWays(nums: number[], target: number): number { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const [m, n] = [nums.length, ((s - target) / 2) | 0]; + const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + f[0][0] = 1; + for (let i = 1; i <= m; i++) { + for (let j = 0; j <= n; j++) { + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } + } + } + return f[m][n]; } ``` @@ -172,39 +222,24 @@ func findTargetSumWays(nums []int, target int) int { ```rust impl Solution { - #[allow(dead_code)] pub fn find_target_sum_ways(nums: Vec, target: i32) -> i32 { - let mut sum = 0; - for e in &nums { - sum += *e; - } - - // -x + (sum - x) = target <-> -2 * x + sum = target <-> 2 * x = sum - target - if sum < target || (sum - target) % 2 != 0 { - // There is no way to get any expression in this case + let s: i32 = nums.iter().sum(); + if s < target || (s - target) % 2 != 0 { return 0; } - let n = nums.len(); - let m = (sum - target) / 2; - - let mut dp: Vec> = vec![vec![0; m as usize + 1]; n + 1]; - - // Initialize the dp vector - dp[0][0] = 1; - - // Begin the actual dp phase - for i in 1..=n { - for j in 0..=m as usize { - // nums[i - 1] is not included - dp[i][j] = dp[i - 1][j]; - if nums[i - 1] <= (j as i32) { - // nums[i - 1] is included - dp[i][j] += dp[i - 1][j - (nums[i - 1] as usize)]; + let m = nums.len(); + let n = ((s - target) / 2) as usize; + let mut f = vec![vec![0; n + 1]; m + 1]; + f[0][0] = 1; + for i in 1..=m { + for j in 0..=n { + f[i][j] = f[i - 1][j]; + if j as i32 >= nums[i - 1] { + f[i][j] += f[i - 1][j - nums[i - 1] as usize]; } } } - - dp[n][m as usize] + f[m][n] } } ``` @@ -218,23 +253,22 @@ impl Solution { * @return {number} */ var findTargetSumWays = function (nums, target) { - let s = 0; - for (let v of nums) { - s += v; - } - if (s < target || (s - target) % 2 != 0) { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { return 0; } - const m = nums.length; - const n = (s - target) / 2; - let dp = new Array(n + 1).fill(0); - dp[0] = 1; - for (let i = 1; i <= m; ++i) { - for (let j = n; j >= nums[i - 1]; --j) { - dp[j] += dp[j - nums[i - 1]]; + const [m, n] = [nums.length, ((s - target) / 2) | 0]; + const f = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + f[0][0] = 1; + for (let i = 1; i <= m; i++) { + for (let j = 0; j <= n; j++) { + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } } } - return dp[n]; + return f[m][n]; }; ``` @@ -244,7 +278,11 @@ var findTargetSumWays = function (nums, target) { -### Solution 2 +### Solution 2: Dynamic Programming (Space Optimization) + +We can observe that in the state transition equation of Solution 1, the value of $f[i][j]$ is only related to $f[i - 1][j]$ and $f[i - 1][j - \text{nums}[i - 1]]$. Therefore, we can eliminate the first dimension of the space and use only a one-dimensional array. + +The time complexity is $O(m \times n)$, and the space complexity is $O(n)$. @@ -254,15 +292,15 @@ var findTargetSumWays = function (nums, target) { class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: s = sum(nums) - if s < target or (s - target) % 2 != 0: + if s < target or (s - target) % 2: return 0 n = (s - target) // 2 - dp = [0] * (n + 1) - dp[0] = 1 - for v in nums: - for j in range(n, v - 1, -1): - dp[j] += dp[j - v] - return dp[-1] + f = [0] * (n + 1) + f[0] = 1 + for x in nums: + for j in range(n, x - 1, -1): + f[j] += f[j - x] + return f[n] ``` #### Java @@ -270,22 +308,19 @@ class Solution: ```java class Solution { public int findTargetSumWays(int[] nums, int target) { - int s = 0; - for (int v : nums) { - s += v; - } + int s = Arrays.stream(nums).sum(); if (s < target || (s - target) % 2 != 0) { return 0; } int n = (s - target) / 2; - int[] dp = new int[n + 1]; - dp[0] = 1; - for (int v : nums) { - for (int j = n; j >= v; --j) { - dp[j] += dp[j - v]; + int[] f = new int[n + 1]; + f[0] = 1; + for (int num : nums) { + for (int j = n; j >= num; --j) { + f[j] += f[j - num]; } } - return dp[n]; + return f[n]; } } ``` @@ -297,14 +332,19 @@ class Solution { public: int findTargetSumWays(vector& nums, int target) { int s = accumulate(nums.begin(), nums.end(), 0); - if (s < target || (s - target) % 2 != 0) return 0; + if (s < target || (s - target) % 2) { + return 0; + } int n = (s - target) / 2; - vector dp(n + 1); - dp[0] = 1; - for (int& v : nums) - for (int j = n; j >= v; --j) - dp[j] += dp[j - v]; - return dp[n]; + int f[n + 1]; + memset(f, 0, sizeof(f)); + f[0] = 1; + for (int x : nums) { + for (int j = n; j >= x; --j) { + f[j] += f[j - x]; + } + } + return f[n]; } }; ``` @@ -314,21 +354,41 @@ public: ```go func findTargetSumWays(nums []int, target int) int { s := 0 - for _, v := range nums { - s += v + for _, x := range nums { + s += x } if s < target || (s-target)%2 != 0 { return 0 } n := (s - target) / 2 - dp := make([]int, n+1) - dp[0] = 1 - for _, v := range nums { - for j := n; j >= v; j-- { - dp[j] += dp[j-v] + f := make([]int, n+1) + f[0] = 1 + for _, x := range nums { + for j := n; j >= x; j-- { + f[j] += f[j-x] } } - return dp[n] + return f[n] +} +``` + +#### TypeScript + +```ts +function findTargetSumWays(nums: number[], target: number): number { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const n = ((s - target) / 2) | 0; + const f = Array(n + 1).fill(0); + f[0] = 1; + for (const x of nums) { + for (let j = n; j >= x; j--) { + f[j] += f[j - x]; + } + } + return f[n]; } ``` @@ -336,61 +396,47 @@ func findTargetSumWays(nums []int, target int) int { ```rust impl Solution { - #[allow(dead_code)] pub fn find_target_sum_ways(nums: Vec, target: i32) -> i32 { - let mut sum = 0; - for e in &nums { - sum += *e; - } - - if sum < target || (sum - target) % 2 != 0 { - // Just directly return + let s: i32 = nums.iter().sum(); + if s < target || (s - target) % 2 != 0 { return 0; } - - let n = ((sum - target) / 2) as usize; - let mut dp: Vec = vec![0; n + 1]; - - // Initialize the dp vector - dp[0] = 1; - - // Begin the actual dp phase - for e in &nums { - for i in (*e as usize..=n).rev() { - dp[i] += dp[i - (*e as usize)]; + let n = ((s - target) / 2) as usize; + let mut f = vec![0; n + 1]; + f[0] = 1; + for x in nums { + for j in (x as usize..=n).rev() { + f[j] += f[j - x as usize]; } } - - dp[n] + f[n] } } ``` - - - - - - -### Solution 3 - - - -#### Python3 +#### JavaScript -```python -class Solution: - def findTargetSumWays(self, nums: List[int], target: int) -> int: - @cache - def dfs(i, t): - if i == n: - if t == target: - return 1 - return 0 - return dfs(i + 1, t + nums[i]) + dfs(i + 1, t - nums[i]) - - ans, n = 0, len(nums) - return dfs(0, 0) +```js +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var findTargetSumWays = function (nums, target) { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const n = (s - target) / 2; + const f = Array(n + 1).fill(0); + f[0] = 1; + for (const x of nums) { + for (let j = n; j >= x; j--) { + f[j] += f[j - x]; + } + } + return f[n]; +}; ``` diff --git a/solution/0400-0499/0494.Target Sum/Solution.cpp b/solution/0400-0499/0494.Target Sum/Solution.cpp index 10446d089898e..61491ff0faa15 100644 --- a/solution/0400-0499/0494.Target Sum/Solution.cpp +++ b/solution/0400-0499/0494.Target Sum/Solution.cpp @@ -2,16 +2,22 @@ class Solution { public: int findTargetSumWays(vector& nums, int target) { int s = accumulate(nums.begin(), nums.end(), 0); - if (s < target || (s - target) % 2 != 0) return 0; - int m = nums.size(), n = (s - target) / 2; - vector> dp(m + 1, vector(n + 1)); - dp[0][0] = 1; + if (s < target || (s - target) % 2) { + return 0; + } + int m = nums.size(); + int n = (s - target) / 2; + int f[m + 1][n + 1]; + memset(f, 0, sizeof(f)); + f[0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { - dp[i][j] += dp[i - 1][j]; - if (nums[i - 1] <= j) dp[i][j] += dp[i - 1][j - nums[i - 1]]; + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } } } - return dp[m][n]; + return f[m][n]; } }; \ No newline at end of file diff --git a/solution/0400-0499/0494.Target Sum/Solution.go b/solution/0400-0499/0494.Target Sum/Solution.go index e7e7df99f3e59..ac41cfd2049fb 100644 --- a/solution/0400-0499/0494.Target Sum/Solution.go +++ b/solution/0400-0499/0494.Target Sum/Solution.go @@ -1,24 +1,24 @@ func findTargetSumWays(nums []int, target int) int { s := 0 - for _, v := range nums { - s += v + for _, x := range nums { + s += x } if s < target || (s-target)%2 != 0 { return 0 } m, n := len(nums), (s-target)/2 - dp := make([][]int, m+1) - for i := range dp { - dp[i] = make([]int, n+1) + f := make([][]int, m+1) + for i := range f { + f[i] = make([]int, n+1) } - dp[0][0] = 1 + f[0][0] = 1 for i := 1; i <= m; i++ { for j := 0; j <= n; j++ { - dp[i][j] = dp[i-1][j] - if nums[i-1] <= j { - dp[i][j] += dp[i-1][j-nums[i-1]] + f[i][j] = f[i-1][j] + if j >= nums[i-1] { + f[i][j] += f[i-1][j-nums[i-1]] } } } - return dp[m][n] + return f[m][n] } \ No newline at end of file diff --git a/solution/0400-0499/0494.Target Sum/Solution.java b/solution/0400-0499/0494.Target Sum/Solution.java index 72d225b158cdc..3aac226e0957a 100644 --- a/solution/0400-0499/0494.Target Sum/Solution.java +++ b/solution/0400-0499/0494.Target Sum/Solution.java @@ -1,24 +1,21 @@ class Solution { public int findTargetSumWays(int[] nums, int target) { - int s = 0; - for (int v : nums) { - s += v; - } + int s = Arrays.stream(nums).sum(); if (s < target || (s - target) % 2 != 0) { return 0; } int m = nums.length; int n = (s - target) / 2; - int[][] dp = new int[m + 1][n + 1]; - dp[0][0] = 1; + int[][] f = new int[m + 1][n + 1]; + f[0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { - dp[i][j] = dp[i - 1][j]; - if (nums[i - 1] <= j) { - dp[i][j] += dp[i - 1][j - nums[i - 1]]; + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; } } } - return dp[m][n]; + return f[m][n]; } } \ No newline at end of file diff --git a/solution/0400-0499/0494.Target Sum/Solution.js b/solution/0400-0499/0494.Target Sum/Solution.js index 0025fbf517ac6..88cc9b0c49b35 100644 --- a/solution/0400-0499/0494.Target Sum/Solution.js +++ b/solution/0400-0499/0494.Target Sum/Solution.js @@ -4,21 +4,20 @@ * @return {number} */ var findTargetSumWays = function (nums, target) { - let s = 0; - for (let v of nums) { - s += v; - } - if (s < target || (s - target) % 2 != 0) { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { return 0; } - const m = nums.length; - const n = (s - target) / 2; - let dp = new Array(n + 1).fill(0); - dp[0] = 1; - for (let i = 1; i <= m; ++i) { - for (let j = n; j >= nums[i - 1]; --j) { - dp[j] += dp[j - nums[i - 1]]; + const [m, n] = [nums.length, ((s - target) / 2) | 0]; + const f = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + f[0][0] = 1; + for (let i = 1; i <= m; i++) { + for (let j = 0; j <= n; j++) { + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } } } - return dp[n]; + return f[m][n]; }; diff --git a/solution/0400-0499/0494.Target Sum/Solution.py b/solution/0400-0499/0494.Target Sum/Solution.py index 1f7739d83dadb..1db438fd5d130 100644 --- a/solution/0400-0499/0494.Target Sum/Solution.py +++ b/solution/0400-0499/0494.Target Sum/Solution.py @@ -1,14 +1,14 @@ class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: s = sum(nums) - if s < target or (s - target) % 2 != 0: + if s < target or (s - target) % 2: return 0 m, n = len(nums), (s - target) // 2 - dp = [[0] * (n + 1) for _ in range(m + 1)] - dp[0][0] = 1 - for i in range(1, m + 1): + f = [[0] * (n + 1) for _ in range(m + 1)] + f[0][0] = 1 + for i, x in enumerate(nums, 1): for j in range(n + 1): - dp[i][j] = dp[i - 1][j] - if nums[i - 1] <= j: - dp[i][j] += dp[i - 1][j - nums[i - 1]] - return dp[-1][-1] + f[i][j] = f[i - 1][j] + if j >= x: + f[i][j] += f[i - 1][j - x] + return f[m][n] diff --git a/solution/0400-0499/0494.Target Sum/Solution.rs b/solution/0400-0499/0494.Target Sum/Solution.rs index 919c419e567f2..21770d6b88322 100644 --- a/solution/0400-0499/0494.Target Sum/Solution.rs +++ b/solution/0400-0499/0494.Target Sum/Solution.rs @@ -1,36 +1,21 @@ impl Solution { - #[allow(dead_code)] pub fn find_target_sum_ways(nums: Vec, target: i32) -> i32 { - let mut sum = 0; - for e in &nums { - sum += *e; - } - - // -x + (sum - x) = target <-> -2 * x + sum = target <-> 2 * x = sum - target - if sum < target || (sum - target) % 2 != 0 { - // There is no way to get any expression in this case + let s: i32 = nums.iter().sum(); + if s < target || (s - target) % 2 != 0 { return 0; } - let n = nums.len(); - let m = (sum - target) / 2; - - let mut dp: Vec> = vec![vec![0; m as usize + 1]; n + 1]; - - // Initialize the dp vector - dp[0][0] = 1; - - // Begin the actual dp phase - for i in 1..=n { - for j in 0..=m as usize { - // nums[i - 1] is not included - dp[i][j] = dp[i - 1][j]; - if nums[i - 1] <= (j as i32) { - // nums[i - 1] is included - dp[i][j] += dp[i - 1][j - (nums[i - 1] as usize)]; + let m = nums.len(); + let n = ((s - target) / 2) as usize; + let mut f = vec![vec![0; n + 1]; m + 1]; + f[0][0] = 1; + for i in 1..=m { + for j in 0..=n { + f[i][j] = f[i - 1][j]; + if j as i32 >= nums[i - 1] { + f[i][j] += f[i - 1][j - nums[i - 1] as usize]; } } } - - dp[n][m as usize] + f[m][n] } } diff --git a/solution/0400-0499/0494.Target Sum/Solution.ts b/solution/0400-0499/0494.Target Sum/Solution.ts new file mode 100644 index 0000000000000..34861934590ba --- /dev/null +++ b/solution/0400-0499/0494.Target Sum/Solution.ts @@ -0,0 +1,18 @@ +function findTargetSumWays(nums: number[], target: number): number { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const [m, n] = [nums.length, ((s - target) / 2) | 0]; + const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + f[0][0] = 1; + for (let i = 1; i <= m; i++) { + for (let j = 0; j <= n; j++) { + f[i][j] = f[i - 1][j]; + if (j >= nums[i - 1]) { + f[i][j] += f[i - 1][j - nums[i - 1]]; + } + } + } + return f[m][n]; +} diff --git a/solution/0400-0499/0494.Target Sum/Solution2.cpp b/solution/0400-0499/0494.Target Sum/Solution2.cpp index d0a2ab7c1e599..d4e32384d01db 100644 --- a/solution/0400-0499/0494.Target Sum/Solution2.cpp +++ b/solution/0400-0499/0494.Target Sum/Solution2.cpp @@ -2,13 +2,18 @@ class Solution { public: int findTargetSumWays(vector& nums, int target) { int s = accumulate(nums.begin(), nums.end(), 0); - if (s < target || (s - target) % 2 != 0) return 0; + if (s < target || (s - target) % 2) { + return 0; + } int n = (s - target) / 2; - vector dp(n + 1); - dp[0] = 1; - for (int& v : nums) - for (int j = n; j >= v; --j) - dp[j] += dp[j - v]; - return dp[n]; + int f[n + 1]; + memset(f, 0, sizeof(f)); + f[0] = 1; + for (int x : nums) { + for (int j = n; j >= x; --j) { + f[j] += f[j - x]; + } + } + return f[n]; } }; \ No newline at end of file diff --git a/solution/0400-0499/0494.Target Sum/Solution2.go b/solution/0400-0499/0494.Target Sum/Solution2.go index ef5a7a7612059..b735717676a2c 100644 --- a/solution/0400-0499/0494.Target Sum/Solution2.go +++ b/solution/0400-0499/0494.Target Sum/Solution2.go @@ -1,18 +1,18 @@ func findTargetSumWays(nums []int, target int) int { s := 0 - for _, v := range nums { - s += v + for _, x := range nums { + s += x } if s < target || (s-target)%2 != 0 { return 0 } n := (s - target) / 2 - dp := make([]int, n+1) - dp[0] = 1 - for _, v := range nums { - for j := n; j >= v; j-- { - dp[j] += dp[j-v] + f := make([]int, n+1) + f[0] = 1 + for _, x := range nums { + for j := n; j >= x; j-- { + f[j] += f[j-x] } } - return dp[n] + return f[n] } \ No newline at end of file diff --git a/solution/0400-0499/0494.Target Sum/Solution2.java b/solution/0400-0499/0494.Target Sum/Solution2.java index 159e8e8bf201c..3231f0275ae6e 100644 --- a/solution/0400-0499/0494.Target Sum/Solution2.java +++ b/solution/0400-0499/0494.Target Sum/Solution2.java @@ -1,20 +1,17 @@ class Solution { public int findTargetSumWays(int[] nums, int target) { - int s = 0; - for (int v : nums) { - s += v; - } + int s = Arrays.stream(nums).sum(); if (s < target || (s - target) % 2 != 0) { return 0; } int n = (s - target) / 2; - int[] dp = new int[n + 1]; - dp[0] = 1; - for (int v : nums) { - for (int j = n; j >= v; --j) { - dp[j] += dp[j - v]; + int[] f = new int[n + 1]; + f[0] = 1; + for (int num : nums) { + for (int j = n; j >= num; --j) { + f[j] += f[j - num]; } } - return dp[n]; + return f[n]; } } \ No newline at end of file diff --git a/solution/0400-0499/0494.Target Sum/Solution2.js b/solution/0400-0499/0494.Target Sum/Solution2.js new file mode 100644 index 0000000000000..c8d0f7b091dc4 --- /dev/null +++ b/solution/0400-0499/0494.Target Sum/Solution2.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var findTargetSumWays = function (nums, target) { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const n = (s - target) / 2; + const f = Array(n + 1).fill(0); + f[0] = 1; + for (const x of nums) { + for (let j = n; j >= x; j--) { + f[j] += f[j - x]; + } + } + return f[n]; +}; diff --git a/solution/0400-0499/0494.Target Sum/Solution2.py b/solution/0400-0499/0494.Target Sum/Solution2.py index 359016a473817..9db940be4a370 100644 --- a/solution/0400-0499/0494.Target Sum/Solution2.py +++ b/solution/0400-0499/0494.Target Sum/Solution2.py @@ -1,12 +1,12 @@ class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: s = sum(nums) - if s < target or (s - target) % 2 != 0: + if s < target or (s - target) % 2: return 0 n = (s - target) // 2 - dp = [0] * (n + 1) - dp[0] = 1 - for v in nums: - for j in range(n, v - 1, -1): - dp[j] += dp[j - v] - return dp[-1] + f = [0] * (n + 1) + f[0] = 1 + for x in nums: + for j in range(n, x - 1, -1): + f[j] += f[j - x] + return f[n] diff --git a/solution/0400-0499/0494.Target Sum/Solution2.rs b/solution/0400-0499/0494.Target Sum/Solution2.rs index fc185741e04ef..51f704aef1bec 100644 --- a/solution/0400-0499/0494.Target Sum/Solution2.rs +++ b/solution/0400-0499/0494.Target Sum/Solution2.rs @@ -1,29 +1,17 @@ impl Solution { - #[allow(dead_code)] pub fn find_target_sum_ways(nums: Vec, target: i32) -> i32 { - let mut sum = 0; - for e in &nums { - sum += *e; - } - - if sum < target || (sum - target) % 2 != 0 { - // Just directly return + let s: i32 = nums.iter().sum(); + if s < target || (s - target) % 2 != 0 { return 0; } - - let n = ((sum - target) / 2) as usize; - let mut dp: Vec = vec![0; n + 1]; - - // Initialize the dp vector - dp[0] = 1; - - // Begin the actual dp phase - for e in &nums { - for i in (*e as usize..=n).rev() { - dp[i] += dp[i - (*e as usize)]; + let n = ((s - target) / 2) as usize; + let mut f = vec![0; n + 1]; + f[0] = 1; + for x in nums { + for j in (x as usize..=n).rev() { + f[j] += f[j - x as usize]; } } - - dp[n] + f[n] } } diff --git a/solution/0400-0499/0494.Target Sum/Solution2.ts b/solution/0400-0499/0494.Target Sum/Solution2.ts new file mode 100644 index 0000000000000..62262964f4469 --- /dev/null +++ b/solution/0400-0499/0494.Target Sum/Solution2.ts @@ -0,0 +1,15 @@ +function findTargetSumWays(nums: number[], target: number): number { + const s = nums.reduce((a, b) => a + b, 0); + if (s < target || (s - target) % 2) { + return 0; + } + const n = ((s - target) / 2) | 0; + const f = Array(n + 1).fill(0); + f[0] = 1; + for (const x of nums) { + for (let j = n; j >= x; j--) { + f[j] += f[j - x]; + } + } + return f[n]; +} diff --git a/solution/0400-0499/0494.Target Sum/Solution3.py b/solution/0400-0499/0494.Target Sum/Solution3.py deleted file mode 100644 index 36ad4e2f7b43a..0000000000000 --- a/solution/0400-0499/0494.Target Sum/Solution3.py +++ /dev/null @@ -1,12 +0,0 @@ -class Solution: - def findTargetSumWays(self, nums: List[int], target: int) -> int: - @cache - def dfs(i, t): - if i == n: - if t == target: - return 1 - return 0 - return dfs(i + 1, t + nums[i]) + dfs(i + 1, t - nums[i]) - - ans, n = 0, len(nums) - return dfs(0, 0)