目标和——动态规划

135 阅读1分钟

image.png

方法——DFS:

代码1

dfs dfs(cur+1, res + nums[cur]),将cur,res都作为函数的参数传递,那么在回溯的时候不需要还原这些值

func findTargetSumWays(nums []int, target int) (ans int) {
    var dfs func(int, int)
    n := len(nums)
    dfs = func(cur int, res int) {
        if cur == n && res == target {
            ans++
            return
        }
        if cur == n {
            return 
        } 
        dfs(cur+1, res + nums[cur])
        dfs(cur+1, res - nums[cur])
    }
    dfs(0, 0)
    return
}

方法二——动态规划:

dp切片的的i和j我们都多开了一个长度,原因是dp[i][j]中 i==0 我们用来表示一个啥也没有的情况,j == 0, 用来表示和为0的情况

代码2

func findTargetSumWays(nums []int, target int) int {
    sum := 0
    for _,v := range nums {
        sum += v
    }
    a := sum - target
    if a < 0 || a % 2 == 1 {
        return 0
    }
    a = a >> 1
    n := len(nums)
    dp := make([][]int, n+1)
    for i := range dp {
        dp[i] = make([]int, a+1)
    }
    dp[0][0] = 1
    for i := 1; i <= n; i++ {
        v := nums[i-1]
        for j := 0; j <= a; j++ {
            if v > j {
                dp[i][j] = dp[i-1][j]
            }else {
                dp[i][j] = dp[i-1][j] + dp[i-1][j-v]
            }
        }
    }
    return dp[n][a]
}

代码3

因为dp状态传递仅于上一层的dp有关所以我们只需要使用一层dp就可以,所以dp二维数组可以简化为一维数组,但如果在传递的时候不想使用临时变量,那么第二层for循环的 j 一定要到这来,以免用到的dp元素不是上一层的,而是这一层最新更新的

func findTargetSumWays(nums []int, target int) int {
    sum := 0
    for _, v := range nums {
        sum += v
    }
    diff := sum - target
    if diff < 0 || diff%2 == 1 {
        return 0
    }
    neg := diff / 2
    dp := make([]int, neg+1)
    dp[0] = 1
    for _, num := range nums {
        for j := neg; j >= num; j-- {
            dp[j] += dp[j-num]
        }
    }
    return dp[neg]
}