暴力递归到动态规划

import java.util.HashMap;

/*
 * 给定数组arr, arr中所有的值都为正数且不重复。 每个值代表一种面值的货币, 
 * 每种面值的货币可以使用任意张, 再给定一个整数aim代表要找的钱数, 求换钱有多少种方法。
 * 
 * 举例:
 * arr=[5,10,25,1], aim=0。组成0元的方法有1种, 就是所有面值的货币都不用。 所以返回1。
 * arr=[5,10,25,1], aim=15。组成15元的方法有6种, 分别为3张5元、 1张10元+1张5元、 
 * 1张10元+5张1元、 10张1元+1张5元、 2张5元+5张1元和15张1元。 所以返回6。
 * arr=[3,5], aim=2。任何方法都无法组成2元。 所以返回0。
 */
public class FindAimInArr {
    
    

	public static void main(String[] args) {
    
    
		int[] arr = new int[] {
    
     25, 20, 10, 5, 1 };
		System.out.println(coins(arr, 50));----打印71
		System.out.println(coins2(arr, 50));----打印71
		System.out.println(coins3(arr, 50));----打印71
	}

	// 例子:arr[200,100,50,20,5,1] aim=100
	// 方法一:暴力递归、
	// 方法二:通过一个Map缓存优化暴力递归、
	// 方法三:动态规划--------------解决子问题重叠问题

	// 方法一:暴力递归、
	public static int coins(int[] arr, int aim) {
    
    
		if (arr == null || arr.length == 0 || aim < 0) {
    
    
			return 0;
		}
		return process(arr, 0, aim);
	}

	// int[] arr:不变的变量,面试数组
	// index:可以任意自由使用index及其之后所有的钱
	// aim:目标钱数
	// 返回值:方法数
	public static int process(int[] arr, int index, int aim) {
    
    
		int res = 0;
		if (index == arr.length) {
    
    
			res = aim == 0 ? 1 : 0;
		} else {
    
    
			for (int zhang = 0; arr[index] * zhang <= aim; zhang++) {
    
    
				res += process(arr, index + 1, aim - zhang * arr[index]);
			}
		}
		return res;
	}

	// 方法二:通过一个Map缓存优化暴力递归---记忆化搜索方法
	public static int coins2(int[] arr, int aim) {
    
    
		if (arr == null || arr.length == 0 || aim < 0) {
    
    
			return 0;
		}
		return process_map(arr, 0, aim);
	}

	// key:"index_aim"
	// value:返回值
	public static HashMap<String, Integer> map = new HashMap<>();

	public static int process_map(int[] arr, int index, int aim) {
    
    
		int res = 0;
		if (index == arr.length) {
    
    
			res = aim == 0 ? 1 : 0;
		} else {
    
    
			for (int zhang = 0; arr[index] * zhang <= aim; zhang++) {
    
    
				int nextAim = aim - arr[index] * zhang;
				String key = String.valueOf(index + 1) + "_" + String.valueOf(nextAim);
				if (map.containsKey(key)) {
    
    
					res += map.get(key);
				} else {
    
    
					res += process_map(arr, index + 1, nextAim);
				}
			}
		}
		map.put(String.valueOf(index) + "_" + String.valueOf(aim), res);
		return res;
	}

	// 方法三:动态规划--------------解决子问题重叠问题
	public static int coins3(int[] arr, int aim) {
    
    
		if (arr == null || arr.length == 0 || aim < 0) {
    
    
			return 0;
		}
		return process_dp(arr, aim);
	}

	public static int process_dp(int[] arr, int aim) {
    
    
		int[][] dp = new int[arr.length][aim + 1];

		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;
		}
		for (int i = 1; i < arr.length; i++) {
    
    
			for (int j = 1; j <= aim; j++) {
    
    
				dp[i][j] = dp[i - 1][j];
				dp[i][j] += j - arr[i] >= 0 ? dp[i][j - arr[i]] : 0;
			}
		}

		return dp[arr.length - 1][aim];
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_44374871/article/details/98209949