背包问题VI Lintcode 564
已知:
给出一个都是正整数的数组 nums,其中没有重复的数。从中找出所有的和为 target 的组合个数。
- 一个数可以在组合中出现多次。
- 数的顺序不同则会被认为是不同的组合。
示例:
给出 nums = [1, 2, 4], target = 4
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[2, 1, 1]
[2, 2]
[4]
则返回6
思路:
注意题目描述中的“数的顺序不同则会被认为是不同的组合",也就是典型的动态规划问题。
以{1,2,4}为例, 要使得和为4, 则结果为第一个数为1的排列组合数 + 第一个数为2的排列组合数 + 第一个数为4的排列组合数。 终止条件是和小于数组的当前的数字(如果两者相同则返回1).
代码如下:
public class Solution {
public int backPackVI(int[] nums, int target) {
if (target == 0) {
return 1;
}
if (target < 0) {
return 0;
}
int ret = 0;
for (int i : nums) {
temp[target - i] = backPackVI(nums, target - i);
}
return ret;
}
}
以上代码通过了大部分数据,但是最后两个数据的处理时间极长,但是数组长度仅仅为13. 其原因也很简单,动态规划本身只能作为一种思路,包含了诸多重复计算的内容,我们只需要用数组存储计算过的内容,如果未初始化,则先初始化,如果有值,则直接用来计算即可。
优化后的代码如下:
public class Solution {
//因为测试样例的target最大值为35,这个数组大小可以根据target进行改变
int[] temp = new int[100];
public int backPackVI(int[] nums, int target) {
if (target == 0) {
return 1;
}
if (target < 0) {
return 0;
}
//初始化为-1是因为默认为0
//如果数组为3,5 则1,2,4等数永远取不到,默认为0则不知道是否初始化过
for (int i = 0; i < temp.length; i++) {
temp[i] = -1;
}
int ret = 0;
for (int i : nums) {
//如果target - i小于0,不处理会出现数组越界异常
if (target - i < 0) {
continue;
}
//未初始化则进行初始化
if (temp[target - i] == -1) {
temp[target - i] = backPackVI(nums, target - i);
}
ret += temp[target - i];
}
return ret;
}
}
运行速度大增,直接通过了所有测试案例.
谢谢您的阅读,希望对您有所帮助…φ(๑˃∀˂๑)♪