[算法][DP]数组任意元素累加和等于目标值

题目

给你一个数组arr,和一个整数aim。如果可以任意选择arr中的数字,能不能累加得到aim,返回true或者false

package basic_class_07;

public class Code_08_Money_Problem {

	//暴力递归版本
	//思路就是,每个数都有可能选也有可能不选,就这两种情况,那么就把这两种情况都穷举了
	public static boolean money1(int[] arr, int aim) {
		//从(i=0,sum=0)起手
		return process1(arr, 0, 0, aim);
	}
	/**
	 * 
	 * @param arr 初始给定的数组
	 * @param i 指的是从i位置开始
	 * @param sum 已经得到的和
	 * @param aim 目标值
	 * @return
	 * 
	 * 举个例子:[1,2,3,4],从1开始执行这个函数,如果1,被选了,那么sum=1;
	 * 进入下一层递归就是(i=1,sum=1);如果没被选,进入下一层递归就是(i=1,sum=0);只有这两条路可选
	 */
	public static boolean process1(int[] arr, int i, int sum, int aim) {
		////尝试改dp版本,以[2,3,7]为例,显而易见,i和sum确定了,return就确定了
		////i的范围(0,n-1)
		////sum取值范围(0,1+2+3+4)当然是离散的,只是最大值是1+2+3+4全部加起来
		////
		//递归出口1
		////
		if (sum == aim) {
			return true;
		}
		//递归出口2
		if (i == arr.length) {
			return false;
		}
		//两种可能性,要么要当前数字,要么不要当前数字
		//这样就全部都穷举了
		////这里可以看出,任意位置的(i,sum)只依赖(i+1,sum)和(i+1,sum+arr[i])
		return process1(arr, i + 1, sum, aim) || process1(arr, i + 1, sum + arr[i], aim);
	}


	//递归改dp版本
	public static boolean money2(int[] arr, int aim) {
		boolean[][] dp = new boolean[arr.length + 1][aim + 1];
		//满足sum=aim的那一列全部置为true
		for (int i = 0; i < dp.length; i++) {
			dp[i][aim] = true;
		}
		for (int i = arr.length - 1; i >= 0; i--) {
			for (int j = aim - 1; j >= 0; j--) {
				//这一行不太清楚什么意思?
				dp[i][j] = dp[i + 1][j];
				if (j + arr[i] <= aim) {
					dp[i][j] = dp[i][j] || dp[i + 1][j + arr[i]];
				}
			}
		}
		return dp[0][0];
	}

	public static void main(String[] args) {
		int[] arr = { 1, 4, 8 };
		int aim = 12;
		System.out.println(money1(arr, aim));
		System.out.println(money2(arr, aim));
	}

}
posted @ 2020-02-25 16:08  KrisTse  阅读(706)  评论(0编辑  收藏  举报