今天,小编在力扣去找寻一些动态规划的题目尝试,感受动态规划的神奇之处,那就废话不多说,直接上题。
题目描述:
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
链接:https://leetcode-cn.com/problems/combination-sum-iv
举例:
- 输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
大家通过题目分析,很容易发现这是一道背包问题,与01背包的区别在于,数组的数是可重复利用的,老实说一开始我便掉入坑中。还记得我之前说过动态规划的题目是需要三个过程的分析,不懂的小伙伴可以看看我的主页关于动态规划与暴力递归这块的总结。
首先 ,暴力递归思路:因为要达到targert的数大小,(别像我一样从0开始累加到targert,会发现有许多序列是多算的),分析入手其实从targert一直减下去,会比较简单,而且容易分析,所以在这种类题目我们要注意从哪开始入手很重要。(这样倒着思路就无需多考虑数组中的各个数到底加多少次)
-
判空条件
1.targert<0;
2.targert==0;递归代码:
public static int combin(int[] arr, int targe) {
if (targe < 0)
return 0;
if (targe == 0)
return 1;
int res = 0;
for (int index : arr) {
res += combin(arr, targe - index);
}
return res;
}
同样我们会发现有的会多算:
于是引入一个数组记录引入的值:
public static int combin1(int[] arr, int targe, int[] dp) {
if (targe < 0)
return 0;
if (dp[targe] != -1)
return dp[targe];
int res = 0;
for (int i = 0; i < arr.length; i++) {
res += combin1(arr, targe - arr[i], dp);
dp[targe] = res;
}
return dp[targe];
}
最后就是通过递归改动态规划了
*需要注意的是赋予初值dp[0]=1*
因为我们在递归的时候遇到targert==0 return 1;
public static int DPCombin(int[] arr, int targe) {
int[] dp = new int[targe + 1];
dp[0] = 1;
for (int j = 1; j <= targe; j++) {
for (int i = 0; i < arr.length; i++) {
if (j >= arr[i]) {
dp[j] += dp[j - arr[i]];
}
}
}
return dp[targe];
}
谢谢大家的阅读,希望大佬们多多指点