494. 目标和(中等)

422 阅读2分钟

494. 目标和(中等)

这是我参与更文挑战的第 3 天,活动详情查看: 更文挑战

题目描述

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/ta…

给你一个整数数组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

题目解析

构建二叉树

假设有nums数组是{1,2,3},它的所有情况是一共是23有8种,分别是+1+2+3,+1+2-3,+1-2+3,+1-2-3一直到-1-2-3

我可以构建这样一棵二叉树,从根节点到每个叶子节点的路径就代表其中一种情况,比如第一个叶子节点是+3,从根节点0到叶子节点+3之间所有节点是0,+1,+2,+3,他就代表8种情况之一+1+2+3。这样通过一棵二叉树就表示了所有可能的情况

image-20210608115639682

右边的二叉树表示的是计算后的结果,还是对0,+1,+2,+3这几个节点,根节点是0不变,下一个节点原本是+1,与上一个节点相加0+11,再下一个节点原本是+2,与上一个节点相加1+23,最后原本是+3,与上一个节点相加3+36

所以右边这棵二叉树的叶子节点就是每种情况计算后的值,把每个值跟target比较就可以了

public class Solution {
  public int findTargetSumWays(int[] nums, int target) {
    int result = 0;
    int len = nums.length;
      // 用数组表示二叉数,sumLen是二叉树的节点个数
    int sumLen = (int) Math.pow(2, len + 1) - 1;
    int[] sum = new int[sumLen];
    for (int i = 0; i < len; i++) {
        // j表示二叉树每行第一个节点的下标
      int j = (int) (Math.pow(2, i + 1) - 1);
        // k表示二叉树每行最后一个节点的下标
      int k = 2 * j;
      for (; j <= k; j++) {
          // 左子节点等于父节点加上当前元素
        if (j % 2 == 1) {
          sum[j] = sum[j / 2] + nums[i];
        } else {
            // 右子节点等于父节点减去当前元素
          sum[j] = sum[j / 2 - 1] - nums[i];
        }
        if(i == len -1 && sum[j] == target){
          result++;
        }
      }
    }
    return result;
  }
}

总结

构建二叉树这个方法并不是很好,相当于暴力法了,而且代码中jk两个变量的值要找规律才容易看出来

总结一下二叉树的部分性质

  • 满二叉树,每层的节点都达到了最大值,上图中就是满二叉树。层数是n,总节点数是2n-1,第k层上的结点数是2k-1
  • 完全二叉树,除了最后一次,其他每层的节点都达到最大值
  • 用一维数组保存二叉树的话,nums[i]的左孩子是nums[2*i+1],右孩子是nums[2*i+2]。同样的,nums[i]是左节点的话,他的父节点是nums[i/2]nums[i]是右节点的话,他的父节点是nums[i/2-1]