题目:
你要出去旅游,有N元的预算住酒店,有M家酒店供你挑选,这些酒店都有价格X。
需要你正好花完这N元住酒店(不能多,也不能少)最少能住几晚?返回最少住的天数,没有匹配的返回-1* 比如你有1000元,所有酒店都是大于1000的,则返回-1
* 比如你有1000元,有1家1000元的,有1家300,有1家700。则最少能住1晚,最多住2晚(300+700)。返回1
* 比如你有1000元,有1家387元,有1家2元,有一家611,则返回3(3家各住1天)
* 比如你有1000元,有1家1元的,有一家2元的,有一家1001元的,则返回500(1元的1000天,2元的500天)
样例输入
1001 1002 1003 2001 1000
样例输出
-1
题目原型:给定数组a,值都为正数且不重复,每个值代表一种货币,每种货币可以使用任意张
给定一个aim代表要找的钱数,求组成aim的最少货币?
arr:5,2,3 aim=20; 4张5元的可以组成20,且张数最少
时间复杂度O(N*M), 空间复杂度O(N*M)
public static int minCoins(int[] arr, int aim) {
int n = arr.length;
int dp[][] = new int[n][aim + 1]; // dp[i][j]:由arr[0..i]组成j所需的最少货币数
int max = Integer.MAX_VALUE; // 不能组成,则dp=max;
// 初始化,dp[i][0]都为0不需要初始化,dp[0][j]初始化
for (int j = 1; j < aim + 1; j++) {
if (j >= arr[0] && dp[0][j - arr[0]] != max) {
dp[0][j] = dp[0][j - arr[0]] + 1;
} else {
dp[0][j] = max;
}
}
/*
* 另一种初始化方式,除法,求余运算慢,没有动态规划思想
for (int j = 1; j < aim + 1; j++) {
if (j % arr[0] == 0)
{
dp[0][j] = j / arr[0];
} else {
dp[0][j] = max;
}
}
*/
for (int i = 1; i < n; i++) {
for (int j = 1; j < aim + 1; j++) {
if (j >= arr[i] && dp[i][j - arr[i]] != max) {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - arr[i]] + 1);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[n - 1][aim] != max ? dp[n - 1][aim] : -1;
}
public static int minCoins2(int[] arr, int aim) {
int n = arr.length;
int dp[] = new int[aim + 1];// dp[j]:由arr[0..n-1]组成j所需的最少货币数
int max = Integer.MAX_VALUE;
// 初始化dp[j],dp[0]为0
for (int j = 1; j < aim + 1; j++) {
dp[j] = max;
if (j >= arr[0] && dp[j - arr[0]] != max) {
dp[j] = dp[j - arr[0]] + 1;
}
}
for (int i = 1; i < n; i++) {
for (int j = 1; j < aim + 1; j++) {
if (j >= arr[i] && dp[j - arr[i]] != max) {
// 空间压缩,二维变一维数组,按行滚动更新
// dp[j]更新前相当于dp[i-1][j],dp[j-arr[i]]更新前相当于dp[i][j-arr[i]
dp[j] = Math.min(dp[j], dp[j - arr[i]] + 1);
}
}
}
return dp[aim] != max ? dp[aim] : -1;
}
不需要初始化,有点难理解
/*
* 网上参考的解法
*/
public static int minCoins3(int arr[], int aim) {
int n = arr.length;
int[] dp = new int[aim + 1];
for (int i = 1; i <= aim; i++) {
int max = Integer.MAX_VALUE;
for (int j = 0; j < n; j++)
// dp[i - arr(j)] < max 是避免 dp[i] = Integer.MAX_VALUE 这种情况
if (i >= arr[j] && dp[i - arr[j]] < max && dp[i - arr[j]] + 1 < max)
max = dp[i - arr[j]] + 1;
dp[i] = max;
}
if (dp[aim] != Integer.MAX_VALUE)
return dp[aim];
else
return -1;
}