优美的递归,华丽的动规。

优美的递归,华丽的动规。

  1. 递归:实质是自顶向下。

  2. DP: 实质是自低向上,依次填表,以空间换时间。

    1. 一维DP 斐波那契 递归重叠 子元素问题。
    2. 二维DP就是填表。

    1. 选还是不选?问题

      1. 第一题 题目描述:选出不重叠的最长线段和。

        解题思路:

        1. 就是找到最后一个线段:考虑他的状态

        2. 选还是不选?

          1. 选择:OPT(8)=等于它本身的值 + 他前面可选最后一个的最优解

          2. 不选:OPT(8)= OPT(7)

          3. 所以需要 3个值来记录

            1. i : 当前下标
            2. pre(i):用于记录前面最后一个可选的最优解.
            3. opt(i) : 用于记录当前下标最优解.
          4. 状态转移:如果opt(i)= A(选择)>B(不选择)?A:B

          5. 初始化:OPT(0) = arr[0] ; Pre[0] = 0;

          递归:

                 public int theLongRC(int[][] qujian,int n,int[] pre){
                  if(n==-1){
                      return 0;
                  }
                  if(n==0){
                      return qujian[0][1]-qujian[0][0];
                  }
                  int A = qujian[n][1]-qujian[n][0] + theLongRC(qujian,pre[n],pre);  //选
                  int B = theLongRC(qujian,n-1,pre); //不选
                  return A>B?A:B;
              }
          }
          

          DP:

                 public int theLongDp(int[][] qujian,int n,int[] pre){
                  int dp[] = new int[qujian.length];
          
                  dp[0] = qujian[0][1]-qujian[0][0];
                  dp[1] = dp[0];
                  for(int i =2;i<n;i++){
                      int A = qujian[i][1]-qujian[i][0] + (pre[i]>=0?dp[pre[i]]:0);//选
                      int B = dp[i-1];//不选;
                      dp[i]  = A>B?A:B;
                  }
                  return dp[n-1];
                  }
          

      2. 第二题:选出不相邻的数字组成的最大值:4,1,1,9,3 最大为13

        解题思路:

        1. 选还是不选?

          1. 选 : opt[i] = opt[i-2] + arr[i];
          2. 不选:opt[i] = opt[i-1];
        2. 状态转移:

          ​ 如果opt(i)= A(选择)>B(不选择)?A:B

        3. 初始化:

          ​ opt[0] = 4 opt[1] = 4

        递归:

            public int RECtest(int[] arr,int i) {    
                int max =0;
                if(i<0){
                    return max;
                }else{
                    int A = arr[i] +  RECtest(arr,i-2);
                    int B = RECtest(arr,i-1);
                    return A>B?A:B;
                }
            }
        

        DP:

          public int DPtest(int[] arr) {     //不相邻的最大值
                int[] dp = new int[arr.length];
                int[] pre = new int[arr.length];
                pre[0] = 0;
                dp[0] = arr[0];
        
                for(int i=1;i<arr.length;i++){
                    int A = arr[i] + pre[i-1];  //选
                    int B = dp[i-1];
                    if(A>B){
                        dp[i] = A;
                    }else{
                        dp[i] = B;
                    }
                    pre[i] = dp[i-1];
                }
                return dp[arr.length-1];
            }
        

      3. 第三题给一个数列 如果 有数字相加等于k 则返回True (二位填表)

        ​ 解题思路: 往前面找,直到找到刚好为K的数。

        1. 选还是不选?

        2. 选:

        3. 不选:

        4. 状态转移?

        5. 初始化

          1. subset(arr[5],9);
        6. 出口:

          1. if(s==0) return true;
          2. if(i0) return arr[0]s;
          3. 剪枝操作:如果此 arr[i] > s 那直接跳过选择的阶段,直接不选。

        7. 递归

          public boolean RECtest2(int arr[],int k,int i){   //递归,选出数字之和等于x,如果有,返回true。
            if(i<0){
                return false;
            }else if(arr[i]==k){
                return true;
            }else if(arr[i]>k){// 剪枝 直接不选 。
                return RECtest2(arr,k,i-1);
            }else{
                return RECtest2(arr,k-arr[i],i-1)|| RECtest2(arr,k,i-1);
            }
          }
          
          
        8. DP

            public boolean DPtest2(int arr[],int k){   //非递归,选出数字之和等于x,如果有,返回true。
            boolean dp[][] = new boolean[arr.length][k+1]; //注意看表
            for(int i=0;i<arr.length;i++){  //初始化。
                dp[i][0] = (arr[i] ==k);
                dp[0][i] = true;
            }
            for(int i =1;i<arr.length;i++){
                for(int j=1;j<k+1;j++){
                    if(arr[i]>j){
                        dp[i][j] = dp[i-1][j];
                    }else{
                        dp[i][j] = dp[i-1][j-arr[i]] || dp[i-1][j];
                    }
                }
            }
            return dp[arr.length-1][k];
              }
          
          

posted @ 2020-09-24 00:07  逆风微笑的魔法师  阅读(45)  评论(0)    收藏  举报