004-目标和-2020.03.10|刷题打卡

223 阅读2分钟

题目

级别: 中等

给定一个非负整数数组,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 位整数存下。

思路

  1. 拿到题目的第一想法,没有思路~~excuse me?

  2. 仔细想了想,看下能否使用递归的方式分解问题

    • 每次先拿数组第一个元素

    • 如果数组长度为1,判断S==num[0]S==1num[0]

      最开始的时候,没有考虑到0的情况,导致少算了1次

    • 数组长度-1,得到一个子数组

    • 获取S-num[0]S+num[0]的情况下的有多少种可能,相加即为最终结果

code

  1. 方案一

    只判断数组长度为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);
            }
        }
    
  2. 方案二(同方案一,通过添加一个递归的方法去掉了数组复制的过程)

    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);
            }
        }
    }
    

截图

image-20210310224711468.png

  • 本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情