62. 不同路径
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
以[i, j]为结尾,走到[i, j]位置时,一共有多少方式。
最近的一步,划分问题。
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
向左侧和上侧分别加一列和一行虚拟节点实现简化初始化。虚拟节点里的值要保证后面填表的数是正确的且注意保证下标的映射。
dp[0][1] = 1;
从上往下,从左往右。
return dp[m][n];
class Solution{
public:
int uniquePaths(int m, int n){
//创建dp表
//初始化
//填表
//返回值
vector<vector<int>> dp(m + 1, vector<int>(n + 1));//创建dp表
dp[0][1] = 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][n];
}
};
63. 不同路径 II
给定一个 m x n
的整数数组 grid
。一个机器人初始位于 左上角(即 grid[0][0]
)。机器人尝试移动到 右下角(即 grid[m - 1][n - 1]
)。机器人每次只能向下或者向右移动一步。
网格中的障碍物和空位置分别用 1
和 0
来表示。机器人的移动路径中不能包含 任何 有障碍物的方格。
返回机器人能够到达右下角的不同路径数量。
测试用例保证答案小于等于 2 * 109
。
以[i, j]为结尾,走到[i, j]位置时,一共有多少方式。
dp[i] [j]
//无障碍物
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
向左侧和上侧分别加一列和一行虚拟节点实现简化初始化。虚拟节点里的值要保证后面填表的数是正确的且注意保证下标的映射。
dp[0][1] = 1;
从上往下从左往右
return dp[n][m]
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& ob) {
size_t m = ob.size(), n = ob[0].size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
dp[0][1] = 1;
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++)
if(ob[i - 1][j - 1] == 0)//无障碍物时,填表;有障碍时,保持默认数值0。
{
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m][n];
}
};
LCR 166. 珠宝的最高价值
现有一个记作二维矩阵 frame
的珠宝架,其中 frame[i][j]
为该位置珠宝的价值。拿取珠宝的规则为:
注意:珠宝的价值都是大于 0 的。除非这个架子上没有任何珠宝,比如 frame = [[0]]
。
经验+题目要求:dp[i] [j]表示:到达[i, j]位置时,此时的最大价值。
dp[i][j] = max(dp[i - 1][j] + g[i][j], dp[i][j - 1] + g[i][j]);
即全部初始化为0
从上往下,从左往右。
return dp[m][n];
class Solution{
public:
int jewelleryValue(vector<vector<int>>& frame) {
int m = frame.size(), n = frame[0].size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) + frame[i - 1][j - 1];
return dp[m][n];
}
};
931. 下降路径最小和
给你一个 n x n
的 方形 整数数组 matrix
,请你找出并返回通过 matrix
的下降路径 的 最小和 。
下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col)
的下一个元素应当是 (row + 1, col - 1)
、(row + 1, col)
或者 (row + 1, col + 1)
。
经验+题目要求,以dp[i] [j]为结尾,考虑dp[i] [i]为抵达[i, j]的最小下降路径。
dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j + 1]) + matrix[i][j];
初始化左右两列虚位置时,为保证其不被选择,因此第一行初始为0,其余初始为MAX_INT。
for(int i = 0; i <= n + 1; i++) dp[0][i] = 0;
从上往下。
return min()
class Solution{
public:
int minFallingPathSum(vector<vector<int>>& matrix){
int n = matrix.size();
vector<vector<int>> dp(n + 1, vector<int>(n + 2, INT_MAX));
//初始化
for(int i = 0; i <= n + 1; i++) dp[0][i] = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i - 1][j + 1])) + matrix[i - 1][j - 1];
int ret = INT_MAX;
for(int i = 1; i <= n; i++)
ret = min(ret, dp[n][i]);
return ret;
}
};
LCR 099. 最小路径和
给定一个包含非负整数的 *m* x *n*
网格 grid
,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
**说明:**一个机器人每次只能向下或者向右移动一步。
经验+题目要求,dp[i] [j] 表示以[i, j] 为结尾时,从起点到此处的最小路径和。
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
dp[0][1] = dp[1][0] = 0;
从左往右,从上往下。
return dp[m][n];
class Solution{
public:
int minPathSum(vector<vector<int>>& grid){
int m = grid.size(), n = grid[0].size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));
dp[0][1] = dp[1][0] = 0;
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];
return dp[m][n];
}
};
174. 地下城游戏
恶魔们抓住了公主并将她关在了地下城 dungeon
的 右下角 。地下城是由 m x n
个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。
返回确保骑士能够拯救到公主所需的最低初始健康点数。
**注意:**任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。
经验+题目要求:
若以[i, j]为结尾,dp[i] [j]表示到到[i, j]时候所需的最低的初始健康点数。
由于最低初始健康点数不但受到最终健康点数的影响,也受到路径过程中选择的影响。
以[i, j]为起点,dp[i] [j]表示到[i, j]位置时所需的最低的初始健康点数。
dp[i][j] = min(dp[i][j + 1], dp[i + 1][j]) - dungeon[i][j];
dp[i][j] = max(1, dp[i][j]);//与失败思路的区别的关键所在!避免在中途产生负血量!
//在最下方和最右方添加虚位置,故不用考虑下标映射。
//所有位置初始为无穷大。
dp[m][n - 1] = dp[m - 1][n] = 1;
从下往上,从右往左。
return dp[0][0];
class Solution {
public:
int calculateMinimumHP(vector<vector<int>>& dungeon) {
int m = dungeon.size();
int n = dungeon[0].size();
vector<vector<int>> dp(m + 1, vector(n + 1, INT_MAX));
dp[m][n - 1] = dp[m - 1][n] =1;
for(int i = m - 1; i >= 0; i--){
for(int j = n - 1; j >= 0; j--){
dp[i][j] = min(dp[i][j + 1], dp[i + 1][j]) - dungeon[i][j];
dp[i][j] = max(1, dp[i][j]);
}
}
return dp[0][0];
}
};