动态规划编程实例——LeetCode 494.Target Sum

问题描述

You are given a list of non-negative integers, a1, a2, …, an, and a target, S.
Now you have 2 symbols + and -. For each integer, you should choose one from + and – as its new symbol.

Find out how many ways to assign symbols to make sum of integers equal to target S.

Example 1:

Input: nums is [1, 1, 1, 1, 1], S is 3. 
Output: 5
Explanation: 

-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 There are 5 ways to assign symbols to make the sum of nums be target 3.

问题分析及算法求解:

1.将数组的值求和得到sum,若sum-S可被2整除,则商即为所有负加数的和,问题可被转化为:
求解数组nums中有多少种组合数的和为目标值target。
否则,返回0;
若sum < abs(S) , 返回0.

2.利用动态规划求解新问题:
2.1 创建一个大小为sum+1的整型数组dp,初始化dp[0]=1,其余为0.
2.2 对于nums中的每一个元素,更改dp数组中相应索引的值。(注意这里需要先将原数组dp拷贝出来)
数组的值即:和为index的组合个数。
2.3 返回dp[target]的值,即为所求。

代码实现

class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int res=0;
        int sum=0;
        for(int x:nums){
            sum+=x;
        }
        int[] dp=new int[sum+1];
        dp[0] = 1;
        //判断是否有解
        if((sum-S)%2 != 0 || sum<Math.abs(S) )
            return 0;
        int target = (sum-S)/2;//目标值
        for(int num:nums){
            //需要拷贝原数组,避免多加
            int[] array = Arrays.copyOf(dp, dp.length);
            for(int i=0;i<array.length;i++){
                if(array[i]>0 && i+num<dp.length)
                    //若已有array[i]种方法可以获得i,现在就有array[i+num]+array[i]种方法获得i+num
                    dp[i+num] = array[i+num]+array[i];                  
            }
        }
        return dp[target];
    }
}
点赞