其他分享
首页 > 其他分享> > 动态规划-2-1

动态规划-2-1

作者:互联网

最大子序和

  1. public int crossSum(int[] nums, int left, int righ, int p){
        if(left == right) return nums[left];
        
        int leftSubsum = Integer.MIN_VALUE;
        int currSum = 0;
        for(int i=p;i > left -1; --i){
            currSum += nums[i];
            leftSubsum = Math.max(leftSubsum, currSum);
        }
        
        int rightSubsum = Integer.MIN_VALUE;
        currSum = 0;
        for(int i = p +1;i<right + 1;++i){
    		currSum += nums[i];
            rightSubsum = Math.max(rightSubsum, currSum);
        }
        return leftSubsum + rightSubsum;
    }
    
    public int helper(int[] nums, int left, int right){
        if(left == right) return nums[left];
        
        int p = (left + right) / 2;
        
        int leftSum = helper(nums, left, p);
        int rightSum = helper(nums, p + 1, right);
        int crossSum = crossSum(nums, left, right, p);
        
        return Math.max(Math.max(leftSum, rightSum), crossSum);
    }
    
    public int maxSubArray(int[] nums){
        return helper(nums, 0, nums.lenght - 1);
    }
    

    爬楼梯

    每步只能爬1或2个台阶,总共多少种方法。

    1. 暴力法:把所有可能爬的阶数进行组合,也就是1和2.

    2. climbStairs(i,n)=(i+1,n)+climbStairs(i+2,n) climbStairs(i,n) = (i+1, n) + climbStairs(i+2,n) climbStairs(i,n)=(i+1,n)+climbStairs(i+2,n)

其中i定义了当前阶数,而n定义了目标阶数。

public class Solution{
    public int climbStairs(int n){
        climb_Stairs(0,n);
    }
    
    public int climb_Stairs(int i, int n){
        if(i > n){
            return 0;
        }
        if(i == n){
            return 1;
        }
        return climb_Stairs(i+1, n) + climb_Stairs(i+2, n);
    }
}
  1. 记忆化递归

  2. 思路:把每一步的结果存储在memo数组之中,当函数每次被调用,我们就直接从memo数组中返回结果。在memo数组的帮助下,可以得到一个修复的递归树,其大小减小到n。

  3. public class Solution{
        public int climbStairs(int n){
            int memo[] = new int[n + 1];
            return climb_Stairs(0,n,memo);
        }
        public int climb_Stairs(int i, int n, int memo[]){
            if(i > n){
                return 0;
            }
            if(i == n){
                return 1;
            }
            if(memo[i] > 0){
                return memo[i];
            }
            memo[i] = climb_Stairs(i + 1, n, memo) + climb_Stairs(i + 2, n, memo);
            return memo[i];
        }
    }
    
  4. 时间和空间复杂度为:O(n)

    1. 动态规划

    2. 思路:可以被分解为一些包含最优子结构的子问题。即他的最优解可以从其子问题的最优解来有效构建。

      在i阶可以由以下的两种方法得到:
      	1. 在第(i-1)阶后向上爬一阶
      	2. 在第(i - 2)阶后向上爬2阶。
      
      public class Solution{
          public int climbStairs(int n){
              if(n == 1){
                  return 1;
              }
              int[] dp = new int[n + 1];
              dp[1] = 1;
              dp[2] = 2;
              for(int i = 3;i <= n; i++){
                  dp[i] = dp[i-1]+dp[i-2];
              }
              return dp[n];
          }
      }
      

      方法四:斐波那契数,

      public class Solution{
          public climbStairs(int n){
              if(n==1){
                  return 1;
              }
              int first = 1;
              int second = 2;
              for(int i=3;i<=n;i++){
                  int third = first + second;
                  first = second;
                  second = third;
              }
              return second;
          }
      }
      

      方法五:Binets方法,两种方式初始化数组,第一种,将斐波那契数列的初始项修改为2和1来代替原来的1和0. 第二种,使用相同的初始化矩阵Q并使用result = Qn[0,0]得到最后的结果。

      public class Solution{
          public int climbStairs(int n){
              int[][] q = {{1,1},{1,0}};
              int res = pow(q, n);
              return res[0][0];
          }
          public int[][] pow(int[][] p, int n){
              int[][] ret = {{1,0},{0,1}};
              while(n > 0){
                  if((n & 1) == 1){ //判断n是否是奇数
                      ret = multiply(ret,a);
                  }
                  n >>= 1;//n的二进制数向右移动一位
                  a = multiply(a, a);
              }
              return ret;
          }
          public int[][] multiply(int[][] a, int[][] b){
              int[][] c = new int[2][2];
              for(int i=0; i<2;i++){
                  for(int j=0;j<2;j++){
                      c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
                  }
              }
              return c;
          }
      }
      

      不同路径

      这是个杨辉三角形,每个位置的路径=该位置左边的路径+该位置上边的路径。

      二维数组的动态规划

      class Solution{
          public int uniquePaths(int m, int n){
              int[][] dp = new int[m][n];
              for(int i=0;i<m;i++) dp[0][i]=1;
              for(int j=0;j<n;j++) dp[j][0]=1;
              for(int i=1;i<m;i++){
                  for(int j=1;j<n;j++){
                      dp[i][j] = dp[i-1][j] + dp[i][j-1];
                  }
              }
              return dp[m-1][n-1];
          }
      }
      

      空间压缩

      public static int uniquePaths(int m, int n){
          if(m<=0||n<=0){
              return 0;
          }
          int less = Math.min(m,n);
          int more = Math.max(m,n);
          
          int[] dp = new int[less];//空间压缩,就是利用了dp暂存上一轮的值,在这一次的赋值中循环利用第一行或第一列的值都是1,因为第一行的路径只能是从左侧走过来。
          Arrays.fill(dp,1);
          
          for(int i=1;i<more;i++){//转换成了一位数组
              for(int j=1;j<less;j++){
                  dp[j] = dp[j-1] + dp[j];
              }
          }
          return dp[less-1];
      }
      
jjxwj 发布了46 篇原创文章 · 获赞 13 · 访问量 1万+ 私信 关注

标签:return,int,Stairs,memo,climbStairs,动态,规划,public
来源: https://blog.csdn.net/qq_31900497/article/details/104130215