LeetCode 494. Target Sum

问题描述

这里写图片描述

问题分析

  • 一看是统计所有可能性个数问题,便知是用动态规划
  • 先从暴力递归入手,int countWays(int[] nums, int i, int target) 返回 nums[i ~ end] 能否有几种方式可以加出target(基于减法的思想)。对于 nums[i]元素,有加和减两种决策,分别进行递归,两种决策可能性之和即为所求
  • 但改写动态规划时却发现,target 有可能取值为负数,而二维数组的索引不可能为负数,所以只能建立一个映射关系,如果对nums数组求和为sum,那么 target + sum 一定是在[0, sum]之间(先保证了初始target绝对值不能超过sum),所以,将[-sum, sum] 映射为[0, 2*sum+1]的形式即可。具体见实现。

经验教训

  • 暴力递归改写动态规划时,发现坐标有可能取负值怎么办?

代码实现

  • 暴力递归
    public int findTargetSumWays(int[] nums, int S) {
        if(nums == null) {
            return 0;
        }
        return countWays(nums, 0, S);
    }

    //返回 nums[i ~ end] 能否有几种方式可以加出target(基于减法的思想)
    public int countWays(int[] nums, int i, int target) {
        if (i == nums.length) {
            if (target == 0) {
                return 1;
            }
            return 0;
        }
        // + nums[i] 和 -nums[i]
        return countWays(nums, i + 1, target - nums[i]) + countWays(nums, i + 1, target + nums[i]);
    }
  • 动态规划
    public int findTargetSumWays(int[] nums, int S) {
        if(nums == null) {
            return 0;
        }
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        if (sum < Math.abs(S)) {
            return 0;
        }
        int[][] dp = new int[nums.length + 1][2 * sum + 1];
        //初始化:
        dp[nums.length][sum] = 1;
        for (int i = nums.length - 1; i >= 0; --i) {
            for (int j = 0; j < 2 * sum + 1; ++j) {
                //防止越界
                if (j - nums[i] >= 0) {
                  dp[i][j] +=   dp[i + 1][j - nums[i]];
                }
                if (j + nums[i] < 2 * sum + 1) {
                    dp[i][j] +=   dp[i + 1][j + nums[i]];
                }
               // dp[i][j] = dp[i + 1][j - nums[i] + sum] + dp[i + 1][j + nums[i] + sum];
            }
        }
        //因为前面已经判断过,所以 S + sum 不会越界
        return dp[0][S + sum];
    }

猜你喜欢

转载自blog.csdn.net/zjxxyz123/article/details/80255079
今日推荐