巩固动态规划
Posted 不做油腻的中年大叔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了巩固动态规划相关的知识,希望对你有一定的参考价值。
一、题目
给你一个数组arr,和一个整数aim。如果可以任意选择arr中的 数字,能不能累加得到aim,返回true或者false
二、分析
根据昨天的文章内容,我们需要先写出递归版本,再改为动态规划。
此题目的递归方法非常简单,就是在遇到一个数时,选择要或不要,然后看下一个数要或不要。代码如下:
public static boolean money1(int[] arr, int aim){
return process1(arr, 0, 0, aim);
}
public static boolean process1(int[] arr, int i, int sum, int aim){
if(i == arr.length){//base-case:arr中所有数字检查完了,看有没有等于aim的情况
return sum == aim;
}
//要或不要
return process1(arr, i + 1, sum, aim) || process1(arr, i+1, sum+arr[i], aim);
}
三、改动态规划
回顾我们的步骤:
找递归函数的可变参数,几个就是几维表
确定最终状态(目标)
根据base-case确定初始状态(直接能算并没有依赖的状态)
分析依赖(递归如何调用),递归的返回值确定了数组中的状态变化
根据依赖的顺序,逆序求表。
改:
此题目中可变参数是i与sum,所以是个二维表
最终目标是求i=0,sum=0时,能不能保证累加得到aim
根据base-case,我们知道当i==arr.length时,在sum==aim的位置一定是true,其他位置一定是false
一个普通位置(i,sum),根据递归调用,它依赖于(i+1, sum)和(i+1, sum+arr[i])这两个位置的状态,但其实不难发现,依赖的位置,总是这个普通位置的下一行
根据分析出来的依赖顺序,逆序求表
四、代码
public static boolean money2(int[] arr, int aim){
int sum = 0;
for(int cur : arr){
sum += cur;
}
boolean[][] dp = new boolean[arr.length+1][sum + 1];
for(int i = 0; i < dp[0].length; i++){
if(i == aim){
dp[arr.length][i] = true;
}else{
dp[arr.length][i] = false;
}
}
for(int i = arr.length - 1; i >= 0; i--){
for(int j = 0; j < dp[0].length; j++){
if(j + arr[i] > sum){
dp[i][j] = dp[i + 1][j];
}else{
dp[i][j] = dp[i+1][j] || dp[i+1][j+arr[i]];
}
}
}
return dp[0][0];
}
以上是关于巩固动态规划的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)
LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)