题目
级别: 中等
给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例:
输入: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 位整数存下。
思路
-
拿到题目的第一想法,没有思路~~excuse me?
-
仔细想了想,看下能否使用递归的方式分解问题
-
每次先拿数组第一个元素
-
如果数组长度为1,判断
S==num[0]和S==1num[0]最开始的时候,没有考虑到0的情况,导致少算了1次
-
数组长度-1,得到一个子数组
-
获取
S-num[0]和S+num[0]的情况下的有多少种可能,相加即为最终结果
-
code
-
方案一
只判断数组长度为1是,数组的第一个元素和S的关系;
然后递归寻找加号和减号时的结果;
注意如果
a==S && -a==S,需要返回2;主要是因为可能有0存在public int findTargetSumWays(int[] nums, int S) { int a = nums[0]; if (nums.length == 1) { return a == S && -a == S ? 2 : a == S ? 1 : -a == S ? 1 : 0; } else { int[] nums1 = new int[nums.length - 1]; for (int i = 1; i < nums.length; i++) { nums1[i - 1] = nums[i]; } return findTargetSumWays(nums1, S - a) + findTargetSumWays(nums1, S + a); } } -
方案二(同方案一,通过添加一个递归的方法去掉了数组复制的过程)
class Solution { public int findTargetSumWays(int[] nums, int S) { return find(0, nums, S); } private int find(int t, int[] nums, int S) { int a = nums[t]; if (nums.length - t == 1) { return a == S && -a == S ? 2 : a == S ? 1 : -a == S ? 1 : 0; } else { return find(t + 1, nums, S - a) + find(t + 1, nums, S + a); } } }
截图
- 本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情