JavaScript|LeetCode|动态规划/递归|494. 目标和

该博客探讨了LeetCode 494题的解决方案,通过动态规划和递归法来找到数组中元素组合成目标和的方法数。动态规划思路是将数组分为正负两部分,计算各自和,然后求解装满背包的方案数。递归法则是利用递归结束条件和当前元素对目标和的影响,寻找所有可能的路径。
摘要由CSDN通过智能技术生成

法1:动态规划
看了题解
想法:

  1. 思考:什么是背包?什么是物品?
  • 将nums分为P(加+)和N(加-)两部分
  • sums( P ) + sums( N ) = sums(nums)
  • sums( P ) - sums( N ) = S
  • => sums( P ) = (sums(nums) + S) / 2
  • 则只需要选取数组中元素加入背包(这些数前面加+),使得背包正好被装满;求装满的方法数
  1. 数组dp表示:选取nums中元素加入背包中,元素之和等于 i 的选取的方法数
/** 
* @param {number[]} nums 
* @param {number} S 
* @return {number} 
*/
var findTargetSumWays = function(nums, S) {    
    // 思考:什么是背包?什么是物品?    
    // 将nums分为P(加+)和N(加-)两部分    
    // sums(P) + sums(N) = sums(nums)    
    // sums(P) - sums(N) = S    
    // => sums(P) = (sums(nums) + S) / 2    
    // 则只需要选取数组中元素加入背包(这些数前面加+),使得背包正好被装满;求装满的方法数
    var dp = [], i = 0, j = 0, sum = 0, W = 0; 
    // dp表示有几种方式使得和为i;W为背包容量    

    for(i = 0; i < nums.length; i++) {        
        sum += nums[i];    
    }    
    W = (sum + S) / 2;
    
    // 如果W不是整数,则方法数为0    
    // 若目标和大于全部整数为正时候的和,则方法数为0    
    if(Math.floor(W) != W || S > sum) {         
        return 0;    
    }    
    for(i = 0; i <= W; i++) {        
        dp[i] = 0;    
    }    
    dp[0] = 1; // 容量为0的背包:不在背包里放东西,则能够使得背包“装满” => 一种方法数
    
    for(i = 0; i < nums.length; i++) { // 对于nums中每个数字(物品)        
        for(j = W; j >= nums[i]; j--) {            
            dp[j] += dp[j - nums[i]]; // dp[j - nums[i]]:将当前物品装入之后,剩余空间的可能组合数        
        }    
    }    
    return dp[W];
};

法2:递归
看了题解
想法:

  1. 递归结束条件:若数组为空,则:S == 0时,方法数为1,否则方法数为0
  2. 对于数组的第一个数nums[0],有可能在前面加 - 或 +,则:
  • S = -nums[0] + 剩余的数 => S + nums[0] = 剩余的数
  • S = +nums[0] + 剩余的数 => S - nums[0] = 剩余的数
    上面两种可能性,表示父节点的两个子节点(两种走向)
/** 
* @param {number[]} nums 
* @param {number} S 
* @return {number} 
*/
var findTargetSumWays = function(nums, S) {    
    // 递归结束条件:若数组为空,则:S == 0时,方法数为1,否则方法数为0    
    // 对于数组的第一个数nums[0],有可能在前面加 - 或 +,则:    
    // S = -nums[0] + 剩余的数    
    // S + nums[0] = 剩余的数    
    // S = +nums[0] + 剩余的数    
    // S - nums[0] = 剩余的数    
    // 上面两种可能性,表示父节点的两个子节点(两种走向)    
    return findTargetSumWays2(nums, 0, S);
};

function findTargetSumWays2(nums, start, S) {    
    if(start == nums.length) {        
        return S == 0 ? 1 : 0;    
    }    
    return findTargetSumWays2(nums, start + 1, S + nums[start]) +         
        findTargetSumWays2(nums, start + 1, S - nums[start]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值