给定一个整型数组arr,arr中的值为正数且不重复,每个值代表一种面值的货币,每种货币可以使用任意张。
给定一个整数target,代表要换的钱数,求换钱的方法数。
该题有暴力递归法、记忆搜索法、动态规划法,本文介绍在解题时最容易想到的暴力递归
暴力递归在计算时会有大量的重复计算,但在笔试面试中暴力递归是解题的思路,记忆搜索和动态规划都是基于暴力递归的优化手段。
arr=[5,10,25,1],target=0
组成0元的方法有1种,就是所有货币都不用,则返回0;
arr=[5,10,25,1],target=15
组成15元的方法有6种,分别是:3张5元,1张5元+1张10元,1张10元+5张1元,10张1元+1张5元,2张5元+5张1元,15张1元,所以返回6。
arr=[5,10,25,1],target=1000
**1.**用0张5元的货币,让[10,25,1]组成剩下的1000,最终方法数记为res1。
**2.**用1张5元的货币,让[10,25,1]组成剩下的995,最终方法数记为res2。
**3.**用2张5元的货币,让[10,25,1]组成剩下的990,最终方法数记为res3。
…
**201.**用200张5元的货币,让[10,25,1]组成剩下的0,最终方法数记为res201。
则res1+res2+res3+…+res201为最终总方法数。
1.时间复杂度为O(N),遍历数组,最差情况下时间复杂度为O(target的N次方)
2.额外空间复杂度O(N),递归栈的深度即为数组长度。
3.递归:递归就是程序运行时自己调用自己,一个递归过程就是出入栈的过程。
import java.util.Scanner;
/**
* @author hkd
*
* 问题:换钱的方法数
暴力递归法
*
*/
public class ExchangeMoney {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.nextLine();
String[] str = s.split(",");
int target = in.nextInt();
int[] arr = new int[str.length];
for (int i = 0; i < arr.length; i++) {
arr[i] = Integer.parseInt(str[i]);
}
int result = getResult(arr, 0, target);
System.out.println(result);
}
public static int getResult(int[] arr, int index, int target) {
if (arr.length == 0 || arr == null || target < 0) {
return 0;
} else {
return process(arr, index, target);
}
}
//实现(暴力递归)
public static int process(int[] arr, int index, int target) {
// res记录结果数
int res = 0;
// 递归终止条件,index是否已经到达数组最后
// 此时当target为0时,表示此方法可行,res置1
if (index == arr.length) {
res = target == 0 ? 1 : 0;
} else {
for (int i = 0; arr[index] * i <= target; i++) {
res += process(arr, index + 1, target - arr[index] * i);
}
}
return res;
}
}