力扣记录:动态规划1基础题目——509 斐波那契数,70 爬楼梯,746 使用最小花费爬楼梯,62 不同路径,63 不同路径II,343 整数拆分,96 不同的二叉搜索树

本次题目

  • 509 斐波那契数
  • 70 爬楼梯
  • 746 使用最小花费爬楼梯
  • 62 不同路径
  • 63 不同路径II
  • 343 整数拆分
  • 96 不同的二叉搜索树

动态规划(DP)

  • 针对同一问题的多个重叠子问题。
  • 步骤:
    1. 确定dp数组及其下标的定义
    2. 确定递推公式
    3. 初始化dp数组
    4. 确定遍历顺序
    5. 举例推导dp数组

509 斐波那契数

  • DP:
    1. 定义一维dp数组保存递归的结果,dp[i]为第i个斐波那契数;
    2. 递推公式(状态转移方程):dp[i] = dp[i-1] + dp[i-2];
    3. 初始化dp数组:dp[0] = 0,dp[1] = 1;
    4. 确定遍历顺序,i递增;
    5. 举例。
  • 注意:dp数组实际存储两个值即可。
class Solution {
    public int fib(int n) {
        //判断特殊情况
        if (n <= 1) return n; 
        //定义一维dp数组保存递归的结果,dp[i]为第i个斐波那契数
        int[] dp = new int[n + 1];
        //dp数组实际存储两个值即可
        //int[] dp = new int[2];
        //初始化dp数组:dp[0] = 0,dp[1] = 1;
        dp[0] = 0;
        dp[1] = 1;
        //递推公式
        //确定遍历顺序,i递增
        for(int i = 2; i <= n; i++){
            dp[i] = dp[i - 1] + dp[i - 2];
            //dp数组实际存储两个值即可
            //int sum = dp[0] + dp[1];
            //dp[0] = dp[1];
            //dp[1] = sum;
        }
        return dp[n];
    }
}

70 爬楼梯

  • DP:
    1. dp[i]为爬到第i层楼梯的方法数量;
    2. dp[i] = dp[i-1] + dp[i-2];
    3. dp[1] = 1,dp[2] = 2;
    4. i递增遍历;
    5. 举例。注意:同斐波那契数列,不考虑i=0。
class Solution {
    public int climbStairs(int n) {
        //判断特殊情况
        if (n <= 1) return n; 
        //定义一维dp数组保存递归的结果,dp[i]为爬到第i层楼梯的方法数量
        //dp数组实际存储两个值即可
        int[] dp = new int[3];
        //初始化dp数组
        dp[1] = 1;
        dp[2] = 2;
        //递推公式
        //确定遍历顺序,i递增
        for(int i = 3; i <= n; i++){
            //dp数组实际存储两个值即可
            int sum = dp[1] + dp[2];
            dp[1] = dp[2];
            dp[2] = sum;
        }
        return dp[2];
    }
}

746 使用最小花费爬楼梯

  • DP:
    1. dp[i]为到达第i个台阶所花费的最少体力;
    2. dp[i] = min(dp[i-1], dp[i-2]) + cost[i];
    3. dp[0]=cost[0],dp[1] = cost[1];
    4. i递增遍历;
    5. 举例。
  • 注意:dp数组记录两位即可。最后一步到达顶层不用花费。
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        //dp[i]为到达第i个台阶所花费的最少体力
        int[] dp = new int[cost.length];
        //初始化
        dp[0] = cost[0];
        dp[1] = cost[1];
        //递推遍历
        for(int i = 2; i < cost.length; i++){
            dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
        }
        //返回结果
        return Math.min(dp[cost.length - 1], dp[cost.length - 2]);
    }
}

62 不同路径

  • DP:
    1. 定义二维dp数组,dp[i][j]为从起点到点(i,j)的路径个数;
    2. dp[i][j] = dp[i-1][j] + dp[i][j-1];
    3. dp[0][j] = 1,dp[i][0] = 1;
    4. 从左到右从上到下i,j递增;
    5. 举例。
  • 注意:使用一位dp数组即可。
  • 补充:数论方法C_(m+n-2)^(m-1)
class Solution {
    public int uniquePaths(int m, int n) {
        //定义二维dp数组,dp[i][j]为从起点到点(i,j)的路径个数
        int[][] dp = new int[m][n];
        //初始化
        for(int j = 0; j < n; j++) dp[0][j] = 1;
        for(int i = 0; i < m; i++) dp[i][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];
    }
}

63 不同路径II

  • 同上,但是路径上增加了障碍。DP:
    1. 定义二维dp数组,dp[i][j]为从起点到点(i,j)的路径个数;
    2. dp[i][j] = dp[i-1][j] + dp[i][j-1],如果(i,j)为障碍则无法到达(dp[i][j] = 0);
    3. dp[0][j] = 1,dp[i][0] = 1,如果有障碍则为0,并且停止后面的赋值;
    4. 从左到右从上到下i,j递增;
    5. 举例。
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        //定义二维dp数组,dp[i][j]为从起点到点(i,j)的路径个数
        int[][] dp = new int[obstacleGrid.length][obstacleGrid[0].length];
        //初始化dp[0][j] = 1,dp[i][0] = 1,如果有障碍则为0,并且停止后面的赋值
        for(int i = 0; i < obstacleGrid.length; i++){
            if(obstacleGrid[i][0] == 1) break;
            dp[i][0] = 1;
        }
        for(int j = 0; j < obstacleGrid[0].length; j++){
            if(obstacleGrid[0][j] == 1) break;
            dp[0][j] = 1;
        }
        //递推遍历
        for(int i = 1; i < obstacleGrid.length; i++){
            for(int j = 1; j < obstacleGrid[0].length; j++){
                if(obstacleGrid[i][j] != 1) dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        //返回结果
        return dp[obstacleGrid.length - 1][obstacleGrid[0].length - 1];
    }
}

343 整数拆分

  • DP:
    1. dp[i]为数字i拆分后得到的最大乘积;
    2. j递增,取两数相乘,两数以上相乘的最大值,dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});
    3. dp[2] = 1;
    4. i从3开始递增递增;
    5. 举例。
  • 补充:贪心算法,将数字分为n个3,剩下4则保留并乘4。
class Solution {
    public int integerBreak(int n) {
        //dp[i]为数字i拆分后得到的最大乘积
        int[] dp = new int[n + 1];
        //初始化
        dp[2] = 1;
        //递推遍历
        for(int i = 3; i <= n; i++){
            for(int j = 1; j < i - 1; j++){
                dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
            }
        }
        //返回结果
        return dp[n];
    }
}

96 不同的二叉搜索树

  • DP:
    1. dp[i]为1到i节点组成的二叉搜索树的数量;
    2. dp[i] += dp[j - 1] * dp[i - j];
    3. dp[0] = 1;
    4. i,j递增;
    5. 举例。
class Solution {
    public int numTrees(int n) {
        //dp[i]为1到i节点组成的二叉搜索树的数量
        int[] dp = new int[n + 1];
        //初始化
        dp[0] = 1;
        //递推遍历
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= i; j++){
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        //返回结果
        return dp[n];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值