换钱的方法数
换钱的方法数
http://www.nowcoder.com/questionTerminal/39cb6c6e2b844a8cba382c8e26951e0a
话不多说上代码。解释书上有。
import java.util.Scanner;
public class Main{
public static final int mod = 1_000_000_007;
public static int coins1(int[] arr, int aim){
if(arr.length == 0 || arr == null || aim < 0){
return 0;
}
int[][] map = new int[arr.length+1][aim+1];
return process1(arr, 0, aim, map);
}
//暴力递归的方法
public static int process(int[] arr, int index, int aim){
int res = 0;
//base case
if(index == arr.length){
res = aim == 0 ? 1 : 0;
}else{
for(int k = 0; k * arr[index] <= aim; k ++){
res += process(arr, index+1, aim - k * arr[index]);
}
}
return res;
}
//记忆搜索的方法
public static int process1(int[] arr, int index, int aim, int[][] map){
int res = 0;
//base case
if(index == arr.length){
res = aim == 0 ? 1 : 0;
}else{
int mapValue = 0;
for(int k = 0; k * arr[index] <= aim; k ++){
mapValue = map[index+1][aim - k * arr[index]];
if(mapValue != 0){
res += mapValue == -1 ? 0 : mapValue;
}else{
res += process(arr, index+1, aim - k * arr[index]);
}
}
}
map[index][aim] = res == 0 ? -1 : res;
return res;
}
//暴力递归——动态规划
public static int coins3(int[] arr, int aim){
if(arr.length == 0 || arr == null || aim < 0){
return 0;
}
//dp[i][j]:钱arr[0...i],目标j 有多少做法
int[][] dp = new int[arr.length][aim+1];
//base case
for(int i = 0; i < arr.length; i++){
dp[i][0] = 1;
}
for(int j = 1; arr[0] * j <= aim; j++){
dp[0][arr[0] * j] = 1;
}
int num = 0;
//遍历dp数组
for(int i = 1; i < arr.length; i++){
for(int j = 1; j <= aim; j ++){
num = 0;
//如何求dp[i][j]?
for(int k = 0; j - k*arr[i] >= 0 ; k++){
num = (num + dp[i-1][j - k*arr[i]]) % mod;
}
dp[i][j] = num;
}
}
return dp[arr.length-1][aim];
}
//动态规划O(N aim)
public static int coins4(int[] arr, int aim){
if(arr.length == 0 || arr == null || aim < 0){
return 0;
}
//dp[i][j]:钱arr[0...i],目标j 有多少做法
int[][] dp = new int[arr.length][aim+1];
//base case
for(int i = 0; i < arr.length; i++){
dp[i][0] = 1;
}
for(int j = 1; arr[0] * j <= aim; j++){
dp[0][arr[0] * j] = 1;
}
//遍历dp数组
for(int i = 1; i < arr.length; i++){
for(int j = 1; j <= aim; j ++){
dp[i][j] = dp[i-1][j] % mod;
dp[i][j] = (dp[i][j] + (j - arr[i] >= 0 ? dp[i][j-arr[i]] : 0) )% mod;
}
}
return dp[arr.length-1][aim];
}
//本题的最优解 时间O(N aim) 空间O(aim)
public static int coins5(int[] arr, int aim){
if(arr.length == 0 || arr == null || aim < 0){
return 0;
}
//dp[i][j]:钱arr[0...i],目标j 有多少做法
int[] dp = new int[aim+1];
//dp[0] = 1;
for(int j = 0; arr[0] * j <= aim; j++){
dp[arr[0] * j] = 1;
}
//遍历dp数组
for(int i = 1; i < arr.length; i++){
for(int j = 1; j <= aim; j ++){
dp[j] = dp[j] % mod;
dp[j] = (dp[j] + (j - arr[i] >= 0 ? dp[j-arr[i]] : 0) )% mod;
}
}
return dp[aim];
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int aim = sc.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; i++){
arr[i] = sc.nextInt();
}
System.out.println(coins5(arr, aim));
}}
