leetcode(494). Target Sum
来源:互联网 发布:云计算与大数据 idc 编辑:程序博客网 时间:2024/06/01 09:20
problem
You are given a list of non-negative integers, a1, a2, …, an, and a
target, S. Now you have 2 symbols + and -. For each integer, you
should choose one from + and - as its new symbol.Find out how many ways to assign symbols to make sum of integers equal
to target S.Note:
The length of the given array is positive and will not exceed 20.
The sum of elements in the given array will not exceed 1000.
Your output answer is guaranteed to be fitted in a 32-bit integer.
分析
这个问题可以使用穷举法来求解,但是时间复杂度为指数级,代码如下:
class Solution(object): def findTargetSumWays(self, nums, S): """ :type nums: List[int] :type S: int :rtype: int """ if len(nums) == 0: return 0 elif len(nums) == 1: if nums[0] == S and nums[0] == -S: return 2 elif nums[0] == S or nums[0] == -S: return 1 else: return 0 else: return self.findTargetSumWays(nums[1:], S-nums[0])+self.findTargetSumWays(nums[1:], S+nums[0])
但是注意题目中要求所有的数字都是非负整数,数组长度不超过20,最大的和不超过2000,这样就可以使用动态规划来求解。
动态规划解法
动态规划的本质就是把求解原问题转化为求解规模由小到大的子问题,而且这些子问题之间还有联系,也就是大的问题可以利用上小的问题的答案,这样就从初始子问题逐步递推为原始问题了。
那么如何对这个问题进行子问题划分呢?这里把把子问题设置为前i个数字所有可能组合的和的个数,也就是f(i, m)表示前i个数字可能结果为m的组合数,这样f(n, target)就是原始问题的解。
ps:这个问题很像求解图的最短路径问题,即使只需要两点的最短路径还是要求所有点的最短路径。
时间复杂度:一共有n个子问题,每个子问题最大可能数为4000,
ps:发现在二维dp问题中使用hash表可以节省一些空间和不必要的判断,只不过在代码上有一些处理,例如需要判断之前是否存在这个key,不能直接全都初始化。
下面是使用hash表的二维dp代码,超越了68%的提交。(注意在dict中整数可能为+0和-0都映射到一个key上)
class Solution(object): def findTargetSumWays(self, nums, S): """ :type nums: List[int] :type S: int :rtype: int """ n = len(nums) d = [{} for _ in range(n)] d[0][nums[0]] = 1 if -nums[0] not in d[0]: d[0][-nums[0]] = 1 else: d[0][-nums[0]] += 1 for i, num in enumerate(nums[1:], start=1): for pre in d[i-1].keys(): if pre + num not in d[i]: d[i][pre+num] = d[i-1][pre] else: d[i][pre+num] += d[i-1][pre] if pre - num not in d[i]: d[i][pre-num] = d[i-1][pre] else: d[i][pre-num] += d[i-1][pre] return d[n-1][S] if S in d[n-1] else 0
下面是使用数组而不是hash表的代码,可以看到由于全部初始化所以不用像dict一样需要考虑key是否存在直接赋值即可,并且由于python支持负数索引所以不用像Java和c++一样进行索引的映射,所以python实现的非常简洁,不过由于之前所提到的,使用数组实现的话需要一些不必要的比较,所以只超过了10%的提交。
class Solution(object): def findTargetSumWays(self, nums, S): """ :type nums: List[int] :type S: int :rtype: int """ n = len(nums) d = [[0 for _ in range(2001)] for _ in range(20)] d[0][nums[0]] += 1 d[0][-nums[0]] += 1 for i, num in enumerate(nums[1:], start=1): for j in range(-1000, 1001): #直接使用负数索引即可,非常方便 if d[i-1][j] > 0: d[i][j + num] += d[i-1][j] d[i][j - num] += d[i-1][j] if S>1000 or S<-1000: return 0 return d[n-1][S]
总结
对于这种解空间有限制的题目可以使用二维动态规划解法(解空间有限制保证了dp可以优于暴力解法,如果是浮点数的话也可以使用dict,dp方法来求解,但是时间复杂度也是指数级,其实就相当于把递归算法调过来),另外对于二维规划问题在规模较小时使用list(dict)可能会好于二维list。
- leetcode[494]:Target Sum
- LeetCode 494:Target Sum
- leetcode 494 Target sum
- leetcode(494). Target Sum
- LeetCode 494 Target Sum 题解
- 【Leetcode-Medium-494】Target Sum
- LeetCode#494 Target Sum (week14)
- Leetcode 494 - Target Sum(01背包)
- LeetCode 494. Target Sum
- [LeetCode]494. Target Sum
- [leetcode]494. Target Sum
- Leetcode 494. Target Sum
- LeetCode: Target Sum
- leetCode---Target Sum
- Leetcode-494. Target Sum
- Leetcode 494. Target Sum
- leetcode-494. Target Sum
- [LeetCode OJ]Target Sum
- 竞赛题目讲解-【Greater New York 2001】最大子矩阵
- 我是如何学会英语的
- jQuery中实现表格的增、删、改操作
- 泛型通配符
- 极大似然和交叉熵 | 深度学习
- leetcode(494). Target Sum
- ZCMU新人训练赛F
- SQLyog恢复数据库报错解决方法【Error Code: 2006
- 函数式编程简单记忆
- 选择排序
- 安装ssh -server 完不能启动服务的问题
- 404. Sum of Left Leaves
- HDU 2476 区间DP--转移思考方向
- 实时计算 流数据处理系统简单分析