目录
动态规划基础篇例题
leetcode70题.爬楼梯
leetcode746题.使用最小花费爬楼梯
leetcode198题.打家劫舍
leetcode62题.不同路径
leetcode64题.最小路径和
leetcode63题.63不同路径II
这一篇的例题解答是严格按照我上一篇写的动态规划三部曲做的,对动态规划不太了解或者比较感兴趣的朋友可以看我上一篇文章。
动态规划算法详解基础篇-CSDN博客
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];
}
}
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]);
}
}
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];
}
}
62. 不同路径 - 力扣(LeetCode)
一个机器人位于一个
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
/*
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];
}
}
64. 最小路径和 - 力扣(LeetCode)
给定一个包含非负整数的
*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 {
/*动态规划三部曲
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];
}
}
63. 不同路径 II - 力扣(LeetCode)
一个机器人位于一个
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 {
/*
第一步:
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];
}
}