动态规划经典例题leetcode思路代码详解

目录

动态规划基础篇例题

leetcode70题.爬楼梯

leetcode746题.使用最小花费爬楼梯

leetcode198题.打家劫舍

leetcode62题.不同路径

leetcode64题.最小路径和

leetcode63题.63不同路径II


动态规划基础篇例题

这一篇的例题解答是严格按照我上一篇写的动态规划三部曲做的,对动态规划不太了解或者比较感兴趣的朋友可以看我上一篇文章。

动态规划算法详解基础篇-CSDN博客

leetcode70题.爬楼梯

70. 爬楼梯 - 力扣(LeetCode)

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

提示:

  • 1 <= n <= 45
class Solution {
    /*动态规划三部曲
        第一步:
        dp[i]数组含义:表示爬到第i个台阶时,一共有dp[i]种爬法。

        第二步:求关系时
        dp[i] dp[i-1] dp[i-2]
        要么是从i-1跳上来 要么就是从i-2跳上来的 
        dp[i] = dp[i-1] + dp[i-2];

        第三步:初始值
        dp[0] = 1;
        dp[1] = 1
        dp[2] = 2;

    */
    public int climbStairs(int n) {

        if(n <= 1){
            return 1;
        }

        int[] dp = new int[n+1];
        dp[0] = 1;
        dp[1] = 1;
        for(int i = 2; i <= n; i++){
            dp[i] = dp[i-1] + dp[i-2];
        }

        return dp[n];
    }
}

leetcode746题.使用最小花费爬楼梯

746. 使用最小花费爬楼梯 - 力扣(LeetCode)

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

示例 1:

输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
- 支付 15 ,向上爬两个台阶,到达楼梯顶部。
总花费为 15 。

示例 2:

输入:cost = [1,100,1,1,1,100,1,1,100,1]
输出:6
解释:你将从下标为 0 的台阶开始。
- 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
- 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
- 支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。

提示:

  • 2 <= cost.length <= 1000
  • 0 <= cost[i] <= 999
class Solution {
    /*
        动态规划三部曲:
        1、dp[i]:我们爬到第 i 层是,需要花费 dp[i] 元。

        2、求关系式
          要跳到 i 层,
        (1)要么从第 i-1 跳上来 dp[i] = dp[i-1] + cost[i]
         (2)要么从第 i-2 跳上来 dp[i] = dp[i-2] + cost[i]。
         dp[i] = min(dp[i-1], dp[i-2]) + cost
            for(i = 2)
         3、初始值
            dp[0] = cost[0]
            dp[1] = cost[1]


    */
    public int minCostClimbingStairs(int[] cost) {
        int n = cost.length;
        int[] dp = new int[n];
        dp[0] = cost[0];
        dp[1] = cost[1];

        for(int i = 2; i < n; i++){
            dp[i] = Math.min(dp[i-1], dp[i-2]) + cost[i];
        }

        return Math.min(dp[n-1], dp[n-2]);
    }
}

leetcode198题.打家劫舍

198. 打家劫舍 - 力扣(LeetCode)

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 400
/*
 1、dp[i]:到达第i个房间时偷到的最高金额是dp[i]
 2、dp[i] = nums[i] + dp[i - 2] 偷当前屋子
    dp[i] = dp[i - 1]  不偷当前屋子
    选一个比较大的

 3、dp[0] = nums[0]
    dp[1] = max(nums[0], nums[1])

*/
class Solution {
    public int rob(int[] nums) {
        if(nums.length <= 1){
            return nums[0];
        }
        if(nums.length <= 2){
            return Math.max(nums[0], nums[1]);
        }
        int[] dp = new int[nums.length];

        // 初始值
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);

        // dp[i] = max(nums[i] + dp[i-2], dp[i-1]);
        for(int i = 2; i < nums.length; i++){
            dp[i] = Math.max(nums[i] + dp[i-2], dp[i-1]);
        }

        return dp[nums.length-1];

    }
}

leetcode62题.不同路径

62. 不同路径 - 力扣(LeetCode)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

示例 1:

img

输入:m = 3, n = 7
输出:28

示例 2:

输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下

示例 3:

输入:m = 7, n = 3
输出:28

示例 4:

输入:m = 3, n = 3
输出:6

提示:

  • 1 <= m, n <= 100
  • 题目数据保证答案小于等于 2 * 109
/*

1、定义:dp[i][j]:到达[i, j]时,一共有dp[i, j]个路径
2、关系式:dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
3、初始化
   dp[0][0...m - 1] = 1
   dp[0...n - 1][0] = 1

*/

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];

        // 初始值
        //最左边的一列
        for(int i = 0; i < m; i++){
            dp[i][0] = 1;
        }
        //最上边的一行
        for(int i = 0; i < n; i++){
            dp[0][i] = 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];

    }
}

leetcode64题.最小路径和

64. 最小路径和 - 力扣(LeetCode)

给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例 1:

动态规划经典例题leetcode思路代码详解_第1张图片

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

示例 2:

输入:grid = [[1,2,3],[4,5,6]]
输出:12

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 200
class Solution {
    /*动态规划三部曲

    1、定义数组含义
    dp[i][j]:当到达 (i,j) 这个位置时,最小路径和为 dp[i][j]。

    2、关系式
    dp[i][j]. dp[i-1][j] dp[i][j-1]
    如何才能到达 (i,j)
    (1)要么从 (i-1,j) 这个位置向下走一步=>dp[i][j] = dp[i-1][j] + grid[i][j]
    (2)要么是从(i,j-1)这个位置向右走一步=>dp[i][j] = dp[i][j-1] + grid[i][j]

    dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]

    3、初始值
    dp[0][0~m-1]
    dp[0~n-1][0]

    */
    public int minPathSum(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;
        int[][] dp = new int[n][m];
        // 求初始值
        dp[0][0] = grid[0][0];
        for(int j = 1; j < m; j++){
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }
        for(int i = 1; i < n; i++){
            dp[i][0] = dp[i-1][0] + grid[i][0];
        }

        for(int i = 1; i < n; i++){
            for(int j = 1; j < m; j++){
                dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[n-1][m-1];
    }
}

leetcode63题.63不同路径II

63. 不同路径 II - 力扣(LeetCode)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

示例 1:

动态规划经典例题leetcode思路代码详解_第2张图片

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

示例 2:

动态规划经典例题leetcode思路代码详解_第3张图片

输入:obstacleGrid = [[0,1],[0,0]]
输出:1

提示:

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j] 为 0 或 1
class Solution {
    /*
        第一步:
        dp[i][j]:表示走到(i,j)这个地方一共有 dp[i][j]条路径
        第二步:找关系式
        if(obstacleGrid[i][j] == 1){
            dp[i][j] = 0
        }else{
            dp[i][j] = dp[i-1][j] + dp[i][j-1]
        }

        第三步:初始值
        dp[0][0] = obstacleGrid[0][0] == 1? 0 : 1; 
        dp[0][j] = dp[0][j-1]
        dp[i][0] = dp[i-1][0];


    */
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int n = obstacleGrid.length;
        int m = obstacleGrid[0].length;
        int[][] dp = new int[n][m];

        dp[0][0] = obstacleGrid[0][0] == 1 ? 0 : 1;
        // 最上面一行
        for(int j = 1; j < m; j++){
            dp[0][j] = obstacleGrid[0][j] == 1 ? 0 : dp[0][j-1];
        }
        // 最左边一列
        for(int i = 1; i < n; i++){
            dp[i][0] = obstacleGrid[i][0] == 1 ? 0 : dp[i-1][0];
        }

        for(int i = 1; i < n; i++){
            for(int j = 1; j < m; j++){
                if(obstacleGrid[i][j] == 1){
                    dp[i][j] = 0;
                }else{
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }
        return dp[n-1][m-1];

    }
}

你可能感兴趣的:(leetcode刷题练习,动态规划,leetcode,算法,数据结构,java,开发语言)