10-9 LeetCode 494. Target Sum
Description
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.
给你一个列表和一个目标整数 S,列表元素都是非负整数,你有+和-两个符号,对列表里的每一个整数,你需要选择其中一个符号作为他的符号。
找出一共有多少种方法来分配符号是列表元素的和等于目标整数S。
Example 1:
Input: nums is [1, 1, 1, 1, 1], S is 3.
Output: 5
Explanation:
-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
There are 5 ways to assign symbols to make the sum of nums be target 3.
Note:
The lengThe 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.
Solution 1():
几乎所有题目都可以使用蛮力法,我用递归和循环两种方式去使用蛮力法,结果都没有解决,都超时了。。。。。
超时代码如下:
`class Solution(object):
def findTargetSumWays(self, nums, S):
"""
:type nums: List[int]
:type S: int
:rtype: int
"""
if not nums:
return 0
front = [nums[0], -nums[0]]
for i in range(len(nums))[1:]:
length = len(front)
for j in range(length):
front.append(front[j]-nums[i])
front[j] = front[j] + nums[i]
count = 0
for num in front:
if num == S:
count += 1
return count`
然后就想着如何优化这种方法,于是用字典这种数据结构代替列表,这样就可以在循环的过程中直接求出方法数,省去最后一个for sum in front
循环,毕竟这个数据非常大。
改进代码如下:
`class Solution(object):
def findTargetSumWays(self, nums, S):
"""
:type nums: List[int]
:type S: int
:rtype: int
"""
if not nums:
return 0
dic = {nums[0]: 1, -nums[0]: 1} if nums[0] != 0 else {0 : 2}
for i in range(1, len(nums)):
temp_dic = {}
for d in dic:
temp_dic[d + nums[i]] = temp_dic.get(d + nums[i], 0) + dic.get(d, 0)
temp_dic[d - nums[i]] = temp_dic.get(d - nums[i], 0) + dic.get(d, 0)
dic = temp_dic
return dic.get(S, 0)`
Solution 2
这是参考了大神的做法。
Java (15 ms) C++ (3 ms) O(ns) iterative DP solution using subset sum with explanation
先根据数学的关系,将问题优化。
集合P包括所有符号为正的整数,集合N包括所有符号为负的整数。可以得出如下关系:
sum(P) - sum(N) = target
sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
2*sum(P) = target + sum(nums)
于是这题目就变成求有多少中子集合的和为 (target + sum(nums))/2。 具体过程参考链接。
感想
这是第一次写,写的不是很好。主要是时间紧,对问题没有那么多时间分析,也是一个摸索的阶段,在摸索如何写的精简和易懂,毕竟大家都很忙。谢谢阅读!