leetcode [377] 组合总和

错误思路:
一开始是按完全背包问题去解决,即外层循环为数组,内层循环为target,结果不对,因为每一个target可以以数组中任何数字结尾。题目中虽然写着组合,但其实这是一个排列问题,与顺序有关。
错误代码如下:
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
for (int num : nums) {
for (int t = num; t <= target; t++) {
dp[t] = dp[t] + dp[target - t];
}
}
return dp[target];
}
正确解法:
1、记忆搜索法
我们可以使用递归的方式查找到target对应的排序数
f(target) = f(target - num1) + f(target - num2) + .... f(target - numn)
注意f(0) = 1,总和为0时只有一种组合结果。
可以写出如下递归函数:
int dfs(int target, int[] nums) {
if (target == 0) {
return 1;
}
int r = 0;
for (int num : nums) {
if (target >= num) {
r += dfs(target - num, nums);
}
}
return r;
}
该递归函数有很多重复调用的情况,可以使用数组来将每一次的结果进行缓存,改进后代码:
int dfs(int target, int[] nums, int[] dp) {
if (target == 0) {
return 1;
}
if (dp[target] != -1) {
return dp[target];
}
int r = 0;
for (int num : nums) {
if (target >= num) {
r += dfs(target - num, nums, dp);
}
}
dp[target] = r;
return r;
}
完整代码:
class Solution {
public static void main(String[] args) {
System.out.println(new Solution().combinationSum4(new int[]{1, 2, 3}, 4));
}
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
Arrays.fill(dp, -1);
return dfs(target, nums, dp);
}
int dfs(int target, int[] nums, int[] dp) {
if (target == 0) {
return 1;
}
if (dp[target] != -1) {
return dp[target];
}
int r = 0;
for (int num : nums) {
if (target >= num) {
r += dfs(target - num, nums, dp);
}
}
dp[target] = r;
return r;
}
}
2、递推法
递归法是自顶向下的,递推法是自底向上,动态规划
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
dp[0] = 1;
for (int i = 1; i <= target; i++) {
for (int num : nums) {
if (i >= num) {
dp[i] += dp[i - num];
}
}
}
return dp[target];
}

浙公网安备 33010602011771号