## 题目描述
给定一个包含非负整数的 \( m \times n \) 网格 `grid`,找出一条从左上角到右下角的路径,使得路径上的数字总和最小。每次只能向下或向右移动一步。
## 解题思路
动态规划是解决此类问题的经典方法。核心思路是:
1. **定义状态**:`dp[i][j]` 表示从左上角到 `(i,j)` 位置的最小路径和。
2. **初始化**:起点的值 `dp[0][0] = grid[0][0]`。第一行和第一列的值只能通过单一方向累加。
3. **状态转移**:对于其他位置 `(i,j)`,路径和为左边或上边的最小值加上当前值:
`dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]`。
4. **结果**:返回 `dp[m-1][n-1]`。
## 原代码问题分析
以下是用户提供的错误代码中的关键问题:
### 1. 未正确初始化起点
```java
int[][] dp = new int[m][n];
// 缺少 dp[0][0] = nums[0][0];
```
起点必须初始化为网格的第一个值,否则后续计算全部错误。
### 2. 未累加当前网格的值
```java
// 错误代码示例:未加当前值
dp[i][0] += dp[i-1][0];
// 正确应为:dp[i][0] = dp[i-1][0] + nums[i][0];
```
第一行和第一列的初始化必须包含当前网格的值,否则路径和会遗漏当前格。
### 3. 数组越界问题
```java
// 错误示例:循环条件错误
for (int j = 1; j < nums[m].length; j++) {
```
`nums[m]` 会导致越界(数组索引最大为 `m-1`)。应使用 `n`(列数)作为循环条件。
### 4. 循环变量递增错误
```java
// 内层循环变量错误
for (int j = 1; j < n; i++) {
```
`i++` 会导致 `j` 不变化,引发死循环或越界。应改为 `j++`。
---
## 修正后的代码
```java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
int[][] grid = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
grid[i][j] = sc.nextInt();
}
}
System.out.println(minPathSum(grid));
}
public static int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = grid[0][0]; // 初始化起点
// 初始化第一列
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i-1][0] + grid[i][0];
}
// 初始化第一行
for (int j = 1; j < n; j++) {
dp[0][j] = dp[0][j-1] + grid[0][j];
}
// 填充其他位置
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
}
}
return dp[m-1][n-1];
}
}
```
---
## 易错点总结
1. **起点未初始化**:必须显式设置 `dp[0][0] = grid[0][0]`。
2. **路径和未累加当前值**:第一行和第一列的每个位置都需要加上当前网格的值。
3. **数组越界**:确保循环条件正确,尤其是对二维数组的索引。
4. **循环变量错误**:注意 `for` 循环的变量名和递增逻辑。
5. **边界条件处理**:当 `m=0` 或 `n=0` 时需单独处理(题目中网格为非负整数,但实际可能需要返回0)。
通过修正这些问题,代码可以正确计算最小路径和。