剑指 Offer II 102. 加减的目标值(494. 目标和)

题目:

 

思路:

【1】回溯的方式:

【2】动态规划的方式:

记数组的元素和为 sum,添加 - 号的元素之和为 neg,则其余添加 + 的元素之和为 sum−neg,得到的表达式的结果为
(sum−neg)−neg=sum−2*neg=target 
即
neg=(sum−target)/2 

所以转变成了在数组中多个元素组合累加成为neg的问题

 

代码展示:

动态规划的方式:

//时间5 ms击败53.59%
//内存41.1 MB击败24%
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
           //根据neg=(sum−target)/2,所以sum−target必须是偶数,否则条件不成立,且neg是正整数
        int diff = sum - target;
        if (diff < 0 || diff % 2 != 0) {
            return 0;
        }
        int n = nums.length, neg = diff / 2;
        int[][] dp = new int[n + 1][neg + 1];
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            int num = nums[i - 1];
            for (int j = 0; j <= neg; j++) {
                dp[i][j] = dp[i - 1][j];
                if (j >= num) {
                    dp[i][j] += dp[i - 1][j - num];
                }
            }
        }
        return dp[n][neg];
    }
}

//优化空间复杂度
//由于 dp的每一行的计算只和上一行有关,因此可以使用滚动数组的方式,去掉 dp的第一个维度,将空间复杂度优化到 O(neg)。
//时间1 ms击败100%
//内存39 MB击败85.20%
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        int diff = sum - target;
        if (diff < 0 || diff % 2 != 0) {
            return 0;
        }
        int neg = diff / 2;
        int[] dp = new int[neg + 1];
        dp[0] = 1;
        for (int num : nums) {
            for (int j = neg; j >= num; j--) {
                dp[j] += dp[j - num];
            }
        }
        return dp[neg];
    }
}

 

回溯的方式:

//时间564 ms击败10.54%
//内存39.1 MB击败73.31%
//首先回溯是能解决这个问题的,但是有点不太合适,因为数组的一个元素就代表着一层
//所以数组很大的时候层数很深,代价很大
//其次,剪枝优化部分,先看例子[1,1,1],这种数据大部分都是集中在中间部分的,剪枝的情况其实不太理想
//                  0
//           +1             -1
//        +1      -1       +1      -1
//   +1   -1  +1  -1  +1   -1  +1   -1
//    3    1   1  -1   1   -1  -1   -3
class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = Arrays.stream(nums).sum();
        if (target > sum || target < -sum) return 0;
        return dfsSum(0,0,nums,target);
    }

    private int dfsSum(int index, int sum, int[] nums, int target) {
        if (index == nums.length) return sum == target ? 1 : 0;

        return dfsSum(index+1,sum+nums[index],nums,target) + dfsSum(index+1,sum-nums[index],nums,target);
    }
}

 

posted @ 2023-04-06 16:26  忧愁的chafry  阅读(19)  评论(0编辑  收藏  举报