题解:leetcode—494目标和

745 阅读3分钟

题目描述:

给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。返回可以使最终数组和为目标数 S 的所有添加符号的方法数。

示例 1:

输入: nums: [1, 1, 1, 1, 1], S: 3

输出: 5

解释:
    -1+1+1+1+1 = 3
    +1-1+1+1+1 = 3
    +1+1-1+1+1 = 3
    +1+1+1-1+1 = 3
    +1+1+1+1-1 = 3
    
    一共有5种方法让最终目标和为3。

注意:

数组非空,且长度不会超过20。
初始的数组的和不会超过1000。
保证返回的最终结果能被32位整数存下。

解题思路:

本题目是一个标准动态规划思想,可以每次进行加减时记录当时的状态(加减和及对应的方案数)。下一次加减一个数字时的状态可以参考上个状态计算得出,再下一次加减一个数字这个状态又变成。最后根据最终状态输出目标和S的方案数。

样例:输入nums=[0,1,0,1], S=0;输出方案数ans

image.png

python3 Solution:

class Solution:
    def findTargetSumWays(self, nums: List[int], S: int) -> int:
        # 若列表为空,和为0就返回方案数1
        if not nums and S == 0:
            return 1
        # 若列表为空,和不为0就返回方案数0
        elif not nums:
            return 0
        # 若列表不为空,和不为0的情况
        else:
            # 数组长度后面遍历使用
            length = len(nums)
            # 初始化第一个数字的状态,res代表上一个状态,因为后面我们从第二个数开始遍历
            if nums[0]==0:
                # 若第一个数字是0,那就初始化字典为{"0":2},此时和为0有两个方案:+0和-0
                res = {nums[0]:2}
            else:
                # 若第一个数字不是0,假设是1,那就初始化字典为{"1":1, "-1":1}
                res = {nums[0]:1, -nums[0]:1}
            # 遍历后面每一个数字
            for i in range(1, length):
                # 临时字典,存储当前状态
                tmp = {}
                # 遍历上个状态
                keys = res.keys()
                for key in keys:
                    # 上个状态的和加减当前数,代表当前某个状态和
                    tmp_add = int(key) + nums[i]
                    tmp_sub = int(key) - nums[i]
                    # 若当前这个状态和在当前状态字典tmp中,那就把当前方案数加上上个状态中key状态的方案数
                    '''
                    例如res = {"1":4,"-1":4},当前数为1,res的第一个key("1")加上1,减去1放到当前状态中,此时tmp = {"2":4, "0":4},res的第二个key("-1")加上1等于0,tmp里面已经有0了,所以现在用res["-1"]+tmp["0"]更新tmp["0"](ps:最开始的tmp的状态和"0"来自res的状态和"1"减1,现在的0来自于res的状态和"-1"加1)
                    '''
                    if tmp_add in tmp:
                        tmp[tmp_add] += res[key]
                    # 若当前这个状态和不在当前状态字典tmp中,就把上个状态中的key状态和的方案数当作当前这个方案和的方案数,更新到当前状态的字典中
                    else:
                        tmp.update({tmp_add:res[key]})
                    
                    # 和上面相同,这个是减去该数
                    if tmp_sub in tmp:
                        tmp[tmp_sub] += res[key]
                    else:
                        tmp.update({tmp_sub:res[key]})
                # 把当前状态赋值给上个状态,开始遍历下个数
                res = tmp
        # 若最后状态中存在该加减和,则取出方案数,否则方案数为0
        return res.get(S, 0)

复杂度分析

    时间复杂度:O(N∗sum),其中 N 是数组 nums 的长度。
    空间复杂度:O(sum),sum为状态字典的长度。

写在最后:

本方法是自己看到这道题想到的解题方法(代码方面还有优化空间),写该文章主要是记录自己的思路,同时和需要的朋友进行分享。当然还有更精简的标准答案,就不在这里一一列出。

题目来源:力扣(LeetCode)题目链接