题目
给你一个数组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));
}
}