动态规划
时间复杂度为O(n * aim), 空间复杂度为O(aim),n是arr数组的长度
/**
* 最少货币数
* 动态规划:
* 状态: dp[i],凑成i元需要的货币数
*
* @param arr int整型一维数组 the array
* @param aim int整型 the target
* @return int整型
*/
public int minMoney (int[] arr, int aim) {
// write code here
int len = arr.length;
int[] dp = new int[aim + 1];
dp[0] = 0;
/*
初始化,aim + 1是一个不可能达到的最大货币数,
因为不会有小于1面值的货币
*/
for (int i = 1; i < aim + 1; i++)
dp[i] = aim + 1;
// 外层循环是面值,内层循环更新要找的钱数。
for (int value : arr) {
// 初始化,value钱数需要的最小货币数就是一个value面值的货币
dp[value] = 1;
for (int j = 0; j <= aim; j++) {
if (j - value < 0)
continue;
/*
凑成j元需要的货币数是
使用value面值的货币数和不使用value面值的货币数取较小值
*/
dp[j] = Math.min(dp[j - value] + 1, dp[j]);
}
}
return dp[aim] == aim + 1 ? -1 : dp[aim];
}
递归 时间复杂度过高
例:arr = [5, 2, 3], (5, 2, 2), (2, 5, 2), (2, 2, 5)都会遍历到,而这几个组合其实是一样的,arr越长,重复遍历的组合就越多。时间复杂度为(n ^ m),n是 arr 的长度,m 与 aim和arr[i]的商 有关。
public int minMoney (int[] arr, int aim) {
return dfs(arr, aim, arr.length, Integer.MAX_VALUE, 0);
}
/**
* 深度遍历
* @param arr
* @param aim 目标钱数
* @param len 数组长度
* @param min 最小货币数
* @param num 当前使用的货币数
* @return
*/
private int dfs(int[] arr, int aim, int len, int min, int num) {
if (aim == 0)
return num;
else if (aim < 0)
return Integer.MAX_VALUE;
for (int i = 0; i < len; i++){
min = Math.min(min, dfs(arr, aim - arr[i], len, min, num + 1));
}
return min == Integer.MAX_VALUE ? -1 : min;
}