查看原文
其他

566,DFS解目标和问题

博哥 数据结构和算法 2022-05-01

We went through a lot, but we stayed together.

我们经历了各种风风雨雨,但依然团结一心。

问题描述



来源:LeetCode第494题

难度:中等


给你一个整数数组nums和一个整数target


向数组中的每个整数前添加'+'或'-',然后串联起所有整数,可以构造一个表达式 :

  • 例如,nums=[2,1],可以在2之前添加'+',在1之前添加'-',然后串联起来得到表达式"+2-1"。

返回可以通过上述方法构造的、运算结果等于target的不同表达式的数目。


示例 1:

输入:nums = [1,1,1,1,1], target = 3

输出:5

解释:一共有 5 种方法让最终目标和为 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

+1 + 1 + 1 + 1 - 1 = 3

示例 2:

输入:nums = [1], target = 1

输出:1


提示:

  • 1<=nums.length<=20

  • 0<=nums[i]<=1000

  • 0<=sum(nums[i])<=1000

  • -1000<=target<=100


DFS解决



这题让在数组中每个元素前面添加'+'或'-',组成算术表达式并且他的和等于target,问有多少种方式。每个元素只能有两种选择,要么添加'+'要么添加'-',所以我们很容易想到的是二叉树。假如使用数组[1,1,1,1]中的所有元素通过'+'或'-'符号构成2,如下图所示

我们让每个节点的左子节点选择'-'右子节点选择'+',计算从根节点到叶子节点所有元素的和是否等于target,如果等于,说明找到了一个满足条件的表达式,只需要计算所有满足条件的个数即可,来看下代码

1//不同表达式的数目
2int count = 0;
3
4public int findTargetSumWays(int[] nums, int target) {
5    dfs(nums, target, 00);
6    return count;
7}
8
9//从根节点开始往下累加,到叶子节点的时候如果累加值等于target,
10//说明找到了一条符合条件的表达式
11private void dfs(int[] nums, int target, int sum, int index) {
12    //判断从根节点到当前叶子节点这条路径是否走完了
13    if (index == nums.length) {
14        //如果当前累加值等于target,说明找到了一条符号条件的表达式
15        if (target == sum)
16            count++;
17        return;
18    }
19    //左子树数负数,要减去
20    dfs(nums, target, sum - nums[index], index + 1);
21    //右子树是正数,要加上
22    dfs(nums, target, sum + nums[index], index + 1);
23}

这题我们还可以修改一下,上面计算的时候是从根节点到叶子节点的累加,其实我们还可以从根节点到叶子节点往下减,根节点默认值是target,到叶子节点计算完的时候如果值为0,说明找到了一个满足条件的表达式,原理都差不多,来看下代码

1//不同表达式的数目
2int count = 0;
3
4public int findTargetSumWays(int[] nums, int target) {
5    dfs(nums, target, 0);
6    return count;
7}
8
9//从更节点开始往下减
10private void dfs(int[] nums, int target, int index) {
11    //判断当前路径是否走完了
12    if (index == nums.length) {
13        //如果走完了,减到最后等于0,说明找到了一条符号条件的表达式
14        if (target == 0)
15            count++;
16        return;
17    }
18    dfs(nums, target - nums[index], index + 1);
19    dfs(nums, target + nums[index], index + 1);
20}

或者还可以这样写,直接通过dfs返回

1public int findTargetSumWays(int[] nums, int target) {
2    return dfs(nums, target, 0);
3}
4
5private int dfs(int[] nums, int target, int index) {
6    if (index == nums.length) {
7        return target == 0 ? 1 : 0;
8    }
9    int res = 0;
10    res += dfs(nums, target - nums[index], index + 1);
11    res += dfs(nums, target + nums[index], index + 1);
12    return res;
13}


总结



这题还一种解决方式就是使用动态规划,解题思路和组合总和 Ⅳ以及背包问题很类似,太晚了这个先放到下次在讲。


这种类似的题估计大家很常见,就是连续的几个数通添加一些符号让他等于一个特定的值,但这题简化了,只能添加'+'或'-,没有其他符号。


507,BFS和DFS解二叉树的层序遍历 II

455,DFS和BFS解被围绕的区域

557,动态规划解戳气球

553,动态规划解分割回文串 II


截止到目前我已经写了500多道算法题了,为了方便大家阅读,我把部分算法题整理成了pdf文档,目前有1000多页,大家可以在公众号中回复关键字“pdf”即可获取下载链接。


你点的每个赞,我都认真当成了喜欢

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存