通过不同面值的硬币,求出组合出n有多少种组合情况
本题的一个具体情况如下
给定n,求出使用给定的1,5,10,25的硬币组合出n 的组合方式有多少种
第一种:迭代法
思路分析:
例如 15
-
不使用10面值
a. 不使用5面值 res = 1;
b. 使用1个5面值 res = 1
c. 使用2个5面值 res = 1;
d. 使用3个5面值的 res = 1; -
使用一个10面值
a. 不使用5面值 res = 1;
b.使用一个5面值 res = 1;
sum = 6
由上述例子可以想到,n的组合方式由两个维度决定
- 可使用面值的个数
- 使用面值之后所剩的 n - x(x为使用次数)*面值
所以本题的迭代方法需要使用到二维数组
图解如下
/**
* 迭代写法,使用二维数组的形式模型结果描述
*/
public static int[][] countWays1(int n, int[] arr) {
//规定数组大小 行:代表可用的面值 列代表 n
int[][] res = new int[arr.length][n+1];
//初始化 n为0时,res 1; arr【1】 = 1时, res = 1;
for (int i = 0; i < res[0].length; i++) {
res[0][i] = 1;
}
for (int i = 0; i < res.length; i++) {
res[i][0] = 1;
res[i][1] = 1;
}
//填数组空缺的值
for (int i = 1; i < res.length; i++) {
for (int j = 2; j < res[0].length; j++) {
//计数组合进行求和
int sum = 0;
//对最大的可用面值 进行计数 循环
int times = j / arr[i];
//通过对 可用最大面值的情况, 分类, 取上一层数组进行 计算 组合数
for (int k = times; k >= 0; k--) {
int surplus = j - arr[i]*k ;
sum += res[i-1][surplus];
}
res[i][j] = sum;
}
}
for (int i = 0; i <= n; i++) {
System.out.print(i +" ");
if (i == n) {
System.out.println();
}
}
for (int[] is : res) {
for (int is2 : is) {
System.out.print(is2+" ");
}
System.out.println();
}
return res;
}
递归写法
public static int countWay(int n) {
if (n <= 0) {
return 0;
}
return countWays(n, new int[]{1,5,10,25}, 3);
}
/**
* 递归写法
* @param n 需要组合的数
* @param arr 给定的硬币数值
* @param cur 能使用的最大面值硬币
* @return
*/
public static int countWays(int n, int[] arr, int cur ) {
// TODO Auto-generated method stub
if (cur == 0) {
return 1;
}
//返回的结果
int res = 0;
//多分枝递归,通过规定能够使用最大面值的个数进行 递归
//例如 15 1. 不使用10面值 a. 不使用5面值 res = 1; b. 使用1个5面值 res = 1 c. 使用2个5面值 res = 1; d. 使用3个5面值的 res = 1;
// 2. 使用一个10面值 a. 不使用5面值 res = 1; b.使用一个5面值 res = 1;
// sum = 6;
for (int i = 0; i * arr[cur] <= n; i++) {
int surplus = n - i * arr[cur];
res += countWays(surplus, arr, cur-1);
}
return res;
}