494.目标和

'''
Description: 494.目标和
Autor: 365JHWZGo
Date: 2021-11-23 09:17:29
LastEditors: 365JHWZGo
LastEditTime: 2021-11-23 20:24:54
'''
在看到题目时的想法:
        一、在没有到达target之前都在相加,在超过之后回退到恰好比它小的数的位置,当时当你实际运用起来时,你会发现它行不通!
        二、分为两个数组,一个是在数字之前添加+号,另一个数组是在数字之前添加-号
            那么只需要知道有多少种组合能组合为差值,结果就为多少
            假设‘➕’一组为A,’➖‘号一组为B
            A+B=sum(nums)
            A-B=target
            所以:
            A=(sum(nums)+target)//2
            同时也知道,当A无法整除时,则不存在这样一种组合,适合A-B=target,所以结果为0
            并且当A<0时,情况同上
思路:
    1.确定dp数组以及含义
        dp[j]表示在和为j的情况下,有dp[j]种方法
    2.确定递推公式
        dp[j]+=dp[j-nums[i]]
    3.初始化dp数组
        在和为0的情况下,要取决于是否数组中含有0,如果有的话则dp[0]=2^n(n为0的个数)
        若是没有0的话,则dp[0]=2^0
    4.dp数组的遍历顺序
        一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序
    5.举例推导
        EG:nums=[1,2,1],target=2
            j	        0   1   2
        nums[0]	        1   1   0	
        nums[1].        1   1   1
        nums[2].        1   2   2  	
        

class Solution(object):
    def findTargetSumWays(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        totalSum = sum(nums)
        if (totalSum+target) % 2 != 0 or totalSum+target<0:
            return 0
        newTarget = (totalSum+target)//2
        dp = [0 for _ in range(newTarget+1)]
        #因为dp[j]的含义是当和为j时的有dp[j]种组合
        #所以在初始化dp[0]时,需要考虑0的情况,因为0比较特殊,它+0和-0均不会影响最后的结果
        dp[0] = 2**(nums.count(0))
        for i in range(len(nums)):
        #当nums[i]==0时,需要跳过,因为dp[j]+=dp[j-nums[i]]不需要再加自己
            if nums[i]==0:
                continue
            else:
            #因为已经考虑过0的情况了,所以只需要遍历[1,newTarget]
                for j in range(newTarget,0,-1):
                    if j-nums[i]<0:
                        continue
                    dp[j]+=dp[j-nums[i]]
        #print(dp)
        return dp[-1]

494.目标和_第1张图片
另一种简洁版本,不需要考虑太多外在因素。

class Solution(object):
    def findTargetSumWays(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        totalSum = sum(nums)
        if (totalSum+target) % 2 != 0 or totalSum+target<0:
            return 0
        newTarget = (totalSum+target)//2
        dp = [0 for _ in range(newTarget+1)]
        dp[0]=1
        for i in range(len(nums)):
            for j in range(newTarget,nums[i]-1,-1):
                dp[j]+=dp[j-nums[i]]
        print(dp)
        return dp[-1]

494.目标和_第2张图片
感悟:
这道题今天耗费了很长时间,主要是一直没推出来递推公式,思路什么的倒是好想,看了解题思路后,豁然开朗.

在面对背包问题时要是问求解方案,则使用dp[j]+=dp[j-nums[i]]

要是问最大容量【或最大价值】则dp[j]=max(dp[j],dp[j-nums[i]]+nums[i])

你可能感兴趣的:(leetcode,算法,动态规划)