自己搭建一个网站我做钓鱼网站自首了

算法思路(62)
-
状态表示:
在解决“路径类”问题时,常见的状态表示形式有两种:- 形式一:从位置 [i,j] 出发的路径计数。
- 形式二:从起始位置到达位置 [i,j] 的路径计数。
本文选择第二种形式来定义状态:设 dp[i][j] 表示到达位置 [i,j] 的路径总数。
-
状态转移方程:
根据状态的定义,若 dp[i][j] 表示到达位置 [i,j] 的路径数,考虑到达该位置的方式,可以得到以下两种可能情况:- 从上方位置 [i−1,j] 向下移动一格;
- 从左方位置 [i,j−1] 向右移动一格。
因此,状态转移方程可表示为:
dp[i][j]=dp[i−1][j]+dp[i][j−1] -
初始化:
为了便于后续的状态填表,建议在状态表的前面添加一行和一列作为辅助节点。这里有两个关键点需注意:- 值的设置:确保辅助节点的值正确,以保证后续的填表结果正确。
- 下标映射:添加行列后,实际填表时需注意对应的下标映射。
在本题中,我们可以在状态表中插入一行和一列,并将 dp[0][1] 初始化为 1,以确保后续填表过程顺利进行。
-
填表顺序:
根据状态转移方程的推导,填表顺序应为:- 从上到下逐行填充;
- 在填充每一行时,从左到右逐列填充。
-
返回值:
最终结果即为到达位置 [m,n] 的路径数量,返回 dp[m][n] 的值即可。
C++:
class Solution
{
public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); // 创建⼀个 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];}
};
Java:
class Solution
{public int uniquePaths(int m, int n) {// 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回值 int[][] dp = new int[m + 1][n + 1];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)
本题为不同路径问题的变种,需考虑障碍物的影响,稍加修改即可求解。以下是详细的算法思路:
-
状态表示:
在解决“路径类”问题时,常见的状态表示形式有两种:- 形式一:从位置 [i,j] 出发的路径数量。
- 形式二:从起始位置到达位置 [i,j] 的路径数量。
本文采用第二种形式来定义状态:令 dp[i][j] 表示到达位置 [i,j] 的路径总数。
-
状态转移:
通过分析可得,若dp[i][j]表示达到位置[i,j]的路径数量,则可通过以下两种方式到达该位置:- 从上方位置 [i−1,j] 向下移动;
- 从左侧位置 [i,j−1] 向右移动。
然而,需注意如果上方或左侧位置存在障碍物,则无法到达 [i,j][i,j] 位置,此时对应的路径数应设为0。因此我们可以得出结论:
- 如果位置 [i,j] 有障碍物,那么 dp[i][j]=0;否则,状态转移方程为:
-
初始化:
为了便于后续状态表的填充,建议在表的前面添加一行和一列以作为辅助节点。以下是需注意的要点:- 辅助节点值的设置:确保辅助节点值的设置能够保证后续计算的正确性。
- 下标映射:添加的行列后,需特别关注下标的正确映射。
在本题中,添加一行和一列后,将 dp[1][0] 初始化为 1,表示从起始位置出发的路径数。
-
填表顺序:
根据状态转移公式的推导,填表应按照以下顺序进行:- 从上到下逐行填充;
- 在填充每一行时,从左到右逐列填充。
-
返回值:
最后,返回 dp[m][n] 的值,以获取结束位置的路径数量。
C++:
class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& ob) {// 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回值 int m = ob.size(), n = ob[0].size();vector<vector<int>> dp(m + 1, vector<int>(n + 1));dp[1][0] = 1;for(int i = 1; i <= m; i++)for(int j = 1; j <= n; j++)if(ob[i - 1][j - 1] == 0)dp[i][j] = dp[i - 1][j] + dp[i][j - 1];return dp[m][n];}
};
Java:
class Solution
{public int uniquePathsWithObstacles(int[][] ob) {// 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回值 int m = ob.length, n = ob[0].length;int[][] dp = new int[m + 1][n + 1];dp[1][0] = 1;for(int i = 1; i <= m; i++)for(int j = 1; j <= n; j++)if(ob[i - 1][j - 1] == 0)dp[i][j] = dp[i - 1][j] + dp[i][j - 1];return dp[m][n];}
}

算法思路(166)
-
状态表示:
在处理这类“路径类”问题时,状态表示通常有两种形式:
- 形式一:从位置 [i,j] 出发的路径数。
- 形式二:从起始位置出发到达位置 [i,j] 的路径数。
本题中,我们采用第二种形式进行状态定义,即:
dp[i][j] 表示到达位置 [i,j] 时所能获得的最大价值。 -
状态转移方程:
当我们考虑 dp[i][j] 的值时,可以得出以下两种到达 [i,j] 位置的方式:
- 从上方:通过位置 [i−1,j] 向下移动,能获得的礼物价值为:dp[i−1][j]+grid[i][j]
- 从左侧:通过位置 [i,j−1] 向右移动,能获得的礼物价值为:dp[i][j−1]+grid[i][j]
因此,为了获得最大价值,状态转移方程可以表示为:
dp[i][j]=max(dp[i−1][j],dp[i][j−1])+grid[i][j] -
初始化:
为了初始化状态表,可以在状态表的前方添加一行及一列作为辅助节点。在进行此操作时,应注意以下两个关键点:
- 辅助节点值的设置:确保辅助节点内的值能够保证后续填表时的正确性。
- 下标映射关系:添加行列后,务必关注下标映射的变化。
在本题中,添加一行和一列后,可以将所有值初始化为 0。
-
填表顺序:
根据状态转移方程,填表的顺序为:
- 逐行从上到下进行填充;
- 逐列从左到右进行填充。
-
返回值:
根据状态表的定义,最终返回的结果为:
dp[m][n]该值表示从起始位置到达位置 [m,n] 时能够获得的最大价值。
C++:
class Solution
{
public:int maxValue(vector<vector<int>>& grid) {// 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回结果 int m = grid.size(), n = grid[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 - 1][j], dp[i][j - 1]) + grid[i - 1][j -
1];return dp[m][n];}
};
Java:
class Solution
{public int maxValue(int[][] grid) {// 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回值 int m = grid.length, n = grid[0].length;int[][] dp = new int[m + 1][n + 1];for(int i = 1; i <= m; i++)for(int j = 1; j <= n; j++)dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]) + grid[i - 1]
[j - 1];return dp[m][n];}
}

算法思路(931)
对于这类路径问题,由于我们先前已处理过类似题型,因此“状态表示”和“状态转移”相对容易分析。相对而言,比较复杂的地方在于“边界条件”的处理。以下是详细的算法思路:
-
状态表示:
在解决此类“路径类”问题时,通常采用两种状态表示形式:
- 形式一:从位置 [i,j] 出发,到达目标位置的路径数量。
- 形式二:从起始位置出发,到达位置 [i,j] 的路径数量。
本题选择第二种形式进行状态定义:
dp[i][j] 表示到达位置 [i,j] 时,所有下降路径中的最小和。 -
状态转移方程:
对于一般位置 [i,j],根据题意,达到该位置可能有三种情况:
- 从正上方位置 [i−1,j] 转移到 [i,j];
- 从左上方位置 [i−1,j−1] 转移到 [i,j];
- 从右上方位置 [i−1,j+1] 转移到 [i,j]。
为了找到到达 [i,j][i,j] 的最小值,我们需要对这三种情况的最小值进行比较,然后加上矩阵中 [i,j][i,j] 位置的值。因此,状态转移方程为:
dp[i][j]=min(dp[i−1][j],min(dp[i−1][j−1],dp[i−1][j+1]))+matrix[i][j] -
初始化:
在状态表的前面添加辅助节点以便初始化。在进行此操作时,需要注意以下两个要点:
- 辅助节点值的设置:确保辅助节点中的值能保证后续填表时的正确性。
- 下标映射关系:在本题中,需要添加一行和两列作为辅助节点。所有新位置的值初始设为无穷大(∞),而第一行的值则初始化为0。
-
填表顺序:
根据状态表示,我们需按顺序以“从上到下”的方式填充状态表。
-
返回值:
请注意,题目并不要求返回 dp[m][n] 的值。题意是要求到达最后一行即可,因此我们需要返回“状态表中最后一行的最小值”,即:
min(dp[最后一行][j])
C++:
class Solution
{
public:int minFallingPathSum(vector<vector<int>>& matrix) {// 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回结果 int n = matrix.size();vector<vector<int>> dp(n + 1, vector<int>(n + 2, INT_MAX));// 初始化第⼀⾏ for(int j = 0; j < n + 2; j++) dp[0][j] = 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 j = 1; j <= n; j++)ret = min(ret, dp[n][j]);return ret;}
};
Java:
class Solution
{public int minFallingPathSum(int[][] matrix) {// 1. 创建 dp 表 // 2. 初始化 // 3. 填表 // 4. 返回结果 int n = matrix.length;int[][] dp = new int[n + 1][n + 2];for(int i = 1; i <= n; i++) dp[i][0] = dp[i][n + 1] =
Integer.MAX_VALUE;for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i - 1][j - 1],
dp[i - 1][j + 1])) + matrix[i - 1][j - 1];int ret = Integer.MAX_VALUE;for(int j = 1; j <= n; j++)ret = Math.min(ret, dp[n][j]);return ret;}
