funcfindTargetSumWays(nums []int, target int)int { count := 0 var dfs func(int ,int) dfs = func(index, left int) { if index == len(nums) { if left == 0 { count++ } } else { dfs(index + 1, left + nums[index]) dfs(index + 1, left - nums[index]) } } dfs(0, target) return count }
b. Dynamic Programming
dp[i][j] refers to the number of assignments which can lead to a sum of j up to the ith items in the Array. We can get the state transition function: dp[i][j] = dp[i - 1][j + nums[i]] + dp[i - 1][j - nums[i]]
funcfindTargetSumWays(nums []int, target int)int { sum := 0 for _, num := range nums { sum += num } if sum < target || -sum > target || (sum + target) % 2 != 0 { return0 } n := len(nums) dp := make([][]int, n) for i := 0; i < n; i++ { dp[i] = make([]int, 2 * sum + 1) } dp[0][sum + nums[0]] = 1 dp[0][sum - nums[0]] += 1 for i := 1; i < n; i++ { for j := -sum; j <= sum; j++ { if j + nums[i] < sum + 1 { dp[i][j + sum + nums[i]] += dp[i - 1][j + sum] } if j + sum - nums[i] >= 0 { dp[i][j + sum - nums[i]] += dp[i - 1][j + sum] } } } return dp[n - 1][sum + target] }
c. Knapsack solution (subset sum)
Based on the problem description, we will have two subsets. One with positive symbol (s1) and another one with negative symbol (s2). So s1 + s2 = sum and s1 - s2 = target. We can convert this problem to a 0-1 knapsack problem — find a subset which subtotal is s1 = (sum + target) / 2.
funcrob(nums []int)int { n := len(nums) dp := make([]int, n + 1) dp[1] = nums[0] max := func(a, b int)int { if a > b { return a } return b } for i := 2; i <= n; i++ { dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1]) } return dp[n] }
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcrob(root *TreeNode)int { cache := make(map[*TreeNode]int) var dfs func(*TreeNode)int dfs = func(root *TreeNode)int { if root == nil { return0 } if value, ok := cache[root]; ok { return value } rootValue := root.Val if root.Left != nil { rootValue += dfs(root.Left.Left) + dfs(root.Left.Right) } if root.Right != nil { rootValue += dfs(root.Right.Left) + dfs(root.Right.Right) } childValue := dfs(root.Left) + dfs(root.Right) maxValue := childValue if rootValue > childValue { maxValue = rootValue } cache[root] = maxValue return maxValue } return dfs(root) }
b. Dynamic Programming to cache more calculation results.
Since each node has two values, with or without its own value. The above one only caches the maxValue, if we cache both of those in an array, it will speed up the calculating.