Backpack VI 564

Question

Given an integer array nums with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.

Notice

The different sequences are counted as different combinations.

Example

Given nums = [1, 2, 4], target = 4

The possible combination ways are:

[1, 1, 1, 1]

[1, 1, 2]

[1, 2, 1]

[2, 1, 1]

[2, 2]

[4]

return 6

Solution

dp[j]表示背包容量为j时,数组nums能装满j的方法数量。

可以想到的方法是对于当前背包容量j,假设最后加入的元素为当前遍历的元素i,则将i元素最后加入的方法数量为dp[j - nums[i]](此时要求j - nums[i] >= 0),将数组元素全部遍历当过i为止。其中,初始化dp[0]=1,表示数组元素将容量为0的背包装满的方法数为1(即什么元素都不取这一种方法)。

这道题并不难,但需要注意要和IV,V的区别。IV,V中的方法和元素位置有关系,元素的相对位置不能变化,不能先取后面的元素再取前面的元素,即相同元素组成的方法被视为一种方法(就算排列不同),其dp[j]的含义为前i件物品装满容量j的方法数,因此只和i之前的物品相关,而和i之后的物品无关。这道题则说明不同的顺序被认为是不同的方法,因此和元素位置无关,可以先取后面的元素再取前面的元素,即相同元素的不同排列被视为不同的方法,其dp[j]表示的是数组nums装满容量j的方法数,是和数组中所有元素有关。

之前几题能够用一维dp表示的本质其实是因为当前行的值只和上一行有关,因此用动态数组两行就行,如果直接在上一行更新当前行的状态则只需要一行即可,因此其本质就是还是二维dp。但是这道题真的是一维dp,即当前容量的填装数量只和之前容量填装的结果有关,只不过每次填装都要遍历整个nums数组来寻找相关的之前容量的状态,因此要用两重for循环。

代码如下:

public class Solution {
    /**
     * @param nums an integer array and all positive numbers, no duplicates
     * @param target an integer
     * @return an integer
     */
    public int backPackVI(int[] nums, int target) {
        // Write your code here
        int[] dp = new int[target + 1];
        dp[0] = 1;

        for(int i = 1; i <= target; i++){
            for(int j = 0; j < nums.length; j++){
                if(i - nums[j] >= 0){
                    dp[i] += dp[i - nums[j]];
                }
            }
        }
        return dp[target];
    }
}

results matching ""

    No results matching ""