给定数组arr,arr中所有的值都为正数且不重复。每个值代表一种面值的货币,没中面值的货币可以使用人一丈,再给定一个正数aim代表要找的钱数,求换钱有多少种方法。
解法一:暴力递归
1 |
|
解法二:记忆搜索。使用map记录已经计算过的值,当使用0张5元和1张10元情况和使用2张5元和0张10元的情况是一样的。所以记录index和aim-arr[index]*i值
1 | public int cosins1(int[] arr, int aim){ |
解法三:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public int coins3(int[] arr, int aim){
if(arr == null || arr.length == 0 || aim < 0){
return -1;
}
int[][] dp = new int[arr.length][aim+1];
for(int i=0; i< arr.length; i++){
dp[i][0] = 1;
}
for (int j = 1; arr[0] * j<=aim; j++){
dp[0][j] = 1;
}
int num = 0;
for(int i = 1; i< arr.length; i++){
for(int j=1; j <=aim; j++){
num = 0;
for(int k = 0; j-arr[i] * k>=0; k++){
num += dp[i-1][j-arr[i] * k];
}
dp[i][j] = num;
}
}
return dp[arr.length][aim];
}
解法三:动态规划
1 | public int coins3(int[] arr, int aim){ |
解法四:动态规划+空间压缩
1 | public int coins3(int[] arr, int aim){ |
通过本题目的优化过程,可以梳理出暴力递归通用的优化过程。一般先想到暴力递归的过程,在通过查看函数中有哪些参数是不发生变化的,忽略不变化的,只看变化的,并且可以表示递归过程的参数,找到这些参数之后,记忆搜索的方法就可以写出来,将计算完成的记录保存到map中,并在下次直接拿来使用。之后看每个位置是通过哪个位置求出来的,先求出被依赖的位置,就能写出动态规划,如果依赖的位置