dp 动态规划 力扣

64. 最小路径和

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

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

示例 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 {
    public int minPathSum(int[][] grid) {
        int dp[][]=new int [grid.length][grid[0].length];
        int sum=0;
        for (int i = 0; i < grid[0].length; i++) {
            sum+=grid[0][i];
            dp[0][i]=sum;
        }
        sum=0;
        for (int i = 0; i < grid.length; i++) {
            sum+=grid[i][0];
            dp[i][0]=sum;
        }
        for (int i = 1; i < grid.length; i++) {
            for (int j = 1; j < grid[0].length; j++) {
                dp[i][j]=Math.min(dp[i-1][j]+grid[i][j],dp[i][j-1]+grid[i][j]);
            }
        }
        return dp[grid.length-1][grid[0].length-1];
    }
}

53. 最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组

是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

以下是错误示范

//这个超出内存限制。。。

class Solution {
    public int maxSubArray(int[] nums) {
        int max=nums[0];
        int dp[][]=new int [nums.length][nums.length];
        for (int i = 0; i < dp.length; i++) {
            dp[i][i]=nums[i];
            max=Math.max(dp[i][i],max);
        }
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {
                dp[i][j]=dp[i-1][j]+nums[i];
                max=Math.max(dp[i][j],max);
            }
        }
        return max;
    }
}
//以为是定义了二维数组dp[][]占内存太大
//改了之后超时。。。

class Solution {
    public int maxSubArray(int[] nums) {
        int max=nums[0];
        for (int t = 0; t < nums.length; t++) {
            int sum=0;
            for (int i = t; i < nums.length; i++) {
                sum+=nums[i];
                max=Math.max(sum,max);
            }
        }
        return max;
    }
}

62. 不同路径

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

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

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

示例 1:

输入: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
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 = 1; 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];
    }
}

LCR 127. 跳跃训练

今天的有氧运动训练内容是在一个长条形的平台上跳跃。平台有 num 个小格子,每次可以选择跳 一个格子 或者 两个格子。请返回在训练过程中,学员们共有多少种不同的跳跃方式。

结果可能过大,因此结果需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:2

示例 2:

输入:n = 5
输出:8

提示:

  • 0 <= n <= 100
class Solution {
    public int trainWays(int num) {
        //到第n个格子的方案为f(n)
        //f(n)=f(n-1)+f(n-2)
        int dp[]=new int [num+1];
        if(num>=0)
        dp[0]=1;
        if(num>=1)
        dp[1]=1;
        for (int i = 2; i <= num; i++) {
            dp[i]=dp[i-1]+dp[i-2];
            dp[i] %= 1000000007;
        }
        return dp[num];
    }
}

以下是错误示范

//超时

//斐波那契
class Solution {
    public int trainWays(int num) {
        //到第n个格子的方案为f(n)
        //f(n)=f(n-1)+f(n-2)
        if(num==0) return 1;
        if(num==1) return 1;
        return trainWays(num-1)+trainWays(num-2);
    }
}
class Solution {
    public int trainWays(int num) {
        //到第n个格子的方案为f(n)
        //f(n)=f(n-1)+f(n-2)
        int dp[]=new int [num+1];
        if(num>=0)
        dp[0]=1;
        if(num>=1)
        dp[1]=1;
        for (int i = 2; i <= num; i++) {
            dp[i]=dp[i-1]+dp[i-2];//后来发现少了一句 dp[i] %= 1000000007;
        }
        return dp[num];
    }
}

746. 使用最小花费爬楼梯

给你一个整数数组 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 {
    static int n;
    public int minCostClimbingStairs(int[] cost) {
        n=cost.length;
        int[]dp=new int[n+1];
        dp[0]=cost[0];
        dp[1]=cost[1];
        for (int i = 2; i <= n; i++) {
            if(i<n)
            dp[i]=Math.min(dp[i-1],dp[i-2])+cost[i];
            else    //i==n
            dp[i]=Math.min(dp[i-1],dp[i-2]);
        }
        return dp[n];
    }
}

以下是错误示范

//超时
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        return f(cost,cost.length);
    }
    public int f(int[] cost,int n){
        if(n==0) return 0;
        if(n==1) return 0;
        return Math.min(f(cost,n-2)+cost[n-2],f(cost,n-1)+cost[n-1]);
    }
}

63. 不同路径 II

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

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

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

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

示例 1:

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

示例 2:

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

提示:

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j] 为 0 或 1
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        if(obstacleGrid[0][0]==1||obstacleGrid[obstacleGrid.length-1][obstacleGrid[0].length-1]==1)
            return 0;
        int dp[][]=new int [obstacleGrid.length][obstacleGrid[0].length];
        int flag=0;
        for (int i = 0; i < obstacleGrid.length; i++) {
            if(obstacleGrid[i][0]==1)
                flag=1;
            if(flag==0) 
                dp[i][0]=1;
            else 
                dp[i][0]=0;
                
        }
        flag=0;
        for (int i = 1; i < obstacleGrid[0].length; i++) {
            if(obstacleGrid[0][i]==1)
                flag=1;
            if(flag==0)
                dp[0][i]=1;
            else 
                dp[0][i]=0;
        }
        for (int i = 1; i < obstacleGrid.length; i++) {
            for (int j = 1; j < obstacleGrid[0].length; j++) {
                if(obstacleGrid[i-1][j]==1&&obstacleGrid[i][j-1]!=1)
                    dp[i][j]=dp[i][j-1];
                else if(obstacleGrid[i][j-1]==1&&obstacleGrid[i-1][j]!=1)
                    dp[i][j]=dp[i-1][j];
                else if(obstacleGrid[i][j-1]!=1&&obstacleGrid[i-1][j]!=1)
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                else dp[i][j]=0;
            }
        }
        return dp[obstacleGrid.length-1][obstacleGrid[0].length-1];
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值