巩固动态规划

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);
  }

三、改动态规划

回顾我们的步骤:

  1. 找递归函数的可变参数,几个就是几维表

  2. 确定最终状态(目标)

  3. 根据base-case确定初始状态(直接能算并没有依赖的状态)

  4. 分析依赖(递归如何调用),递归的返回值确定了数组中的状态变化

  5. 根据依赖的顺序,逆序求表。

改:

  1. 此题目中可变参数是i与sum,所以是个二维表

  2. 最终目标是求i=0,sum=0时,能不能保证累加得到aim

  3. 根据base-case,我们知道当i==arr.length时,在sum==aim的位置一定是true,其他位置一定是false

  4. 一个普通位置(i,sum),根据递归调用,它依赖于(i+1, sum)和(i+1, sum+arr[i])这两个位置的状态,但其实不难发现,依赖的位置,总是这个普通位置的下一行

  5. 根据分析出来的依赖顺序,逆序求表

四、代码

 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动态规划题

LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)

LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)

20210822-周总结

动态 Rstudio 代码片段

是否可以动态编译和执行 C# 代码片段?