矩阵中和能被 K 整除的路径
难度:
标签:
题目描述
给你一个下标从 0 开始的 m x n
整数矩阵 grid
和一个整数 k
。你从起点 (0, 0)
出发,每一步只能往 下 或者往 右 ,你想要到达终点 (m - 1, n - 1)
。
请你返回路径和能被 k
整除的路径数目,由于答案可能很大,返回答案对 109 + 7
取余 的结果。
示例 1:
输入:grid = [[5,2,4],[3,0,5],[0,7,2]], k = 3 输出:2 解释:有两条路径满足路径上元素的和能被 k 整除。 第一条路径为上图中用红色标注的路径,和为 5 + 2 + 4 + 5 + 2 = 18 ,能被 3 整除。 第二条路径为上图中用蓝色标注的路径,和为 5 + 3 + 0 + 5 + 2 = 15 ,能被 3 整除。
示例 2:

输入:grid = [[0,0]], k = 5 输出:1 解释:红色标注的路径和为 0 + 0 = 0 ,能被 5 整除。
示例 3:

输入:grid = [[7,3,4,9],[2,3,6,2],[2,3,7,0]], k = 1 输出:10 解释:每个数字都能被 1 整除,所以每一条路径的和都能被 k 整除。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 5 * 104
1 <= m * n <= 5 * 104
0 <= grid[i][j] <= 100
1 <= k <= 50
代码结果
运行时间: 863 ms, 内存: 37.9 MB
// Java Stream Solution
// 思路:此问题不太适合 Java Stream API 的纯函数式风格,因此解决方案与普通 Java 方法类似。
// 使用类似动态规划的方式解决问题,但用 Java Streams 增加代码的可读性。
import java.util.Arrays;
public class Solution {
public int numberOfPaths(int[][] grid, int k) {
final int MOD = 1_000_000_007;
final int m = grid.length;
final int n = grid[0].length;
int[][][] dp = new int[m][n][k];
dp[0][0][grid[0][0] % k] = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
for (int r = 0; r < k; r++) {
if (i > 0) {
dp[i][j][(r + grid[i][j]) % k] = Math.floorMod(dp[i][j][(r + grid[i][j]) % k] + dp[i - 1][j][r], MOD);
}
if (j > 0) {
dp[i][j][(r + grid[i][j]) % k] = Math.floorMod(dp[i][j][(r + grid[i][j]) % k] + dp[i][j - 1][r], MOD);
}
}
}
}
return dp[m - 1][n - 1][0];
}
}
解释
方法:
本题解使用动态规划的方法来解决。首先定义一个二维的 dp 数组,其中 dp[j][p] 表示到达第一行第 j 列时,路径和模 k 余 p 的路径数量。初始化第一行所有可能的路径和,然后基于第一行的结果逐行更新 dp 数组。对于每一行,我们先更新第一列的 dp 值,然后对于每一列,根据左边和上面的列的 dp 值计算当前列的 dp 值。更新规则是,对于每个可能的余数 p,计算包含当前单元格值后的新余数,并更新 dp 数组。最终,dp[n-1][0] 包含了到达右下角且路径和能被 k 整除的路径数。
时间复杂度:
O(m * n * k)
空间复杂度:
O(n * k)
代码细节讲解
🦆
在动态规划解法中,为什么选择使用二维数组dp[j][p]来存储信息,而不是使用一维数组或其他数据结构?
▷🦆
您如何初始化dp数组,并保证这种初始化方式能够正确反映问题的初始状态?
▷🦆
题解中提到更新规则是基于当前单元格的值和之前的dp值,能否详细说明这个更新过程中的数学逻辑和计算步骤?
▷🦆
为什么最终答案是dp[n-1][0],这里的索引0表示什么意义?
▷