给你一个大小为 m x n
的矩阵 grid
。最初,你位于左上角 (0, 0)
,每一步,你可以在矩阵中 向右 或 向下 移动。
在从左上角 (0, 0)
开始到右下角 (m - 1, n - 1)
结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。
返回 最大非负积 对 ** __109 + 7
** 取余 的结果。如果最大积为 负数 ,则返回 __-1
。
注意, 取余是在得到最大积之后执行的。
示例 1:
**输入:** grid = [[-1,-2,-3],[-2,-3,-3],[-3,-3,-2]]
**输出:** -1
**解释:** 从 (0, 0) 到 (2, 2) 的路径中无法得到非负积,所以返回 -1 。
示例 2:
**输入:** grid = [[1,-2,1],[1,-2,1],[3,-4,1]]
**输出:** 8
**解释:** 最大非负积对应的路径如图所示 (1 * 1 * -2 * -4 * 1 = 8)
示例 3:
**输入:** grid = [[1,3],[0,-4]]
**输出:** 0
**解释:** 最大非负积对应的路径如图所示 (1 * 0 * -4 = 0)
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 15
-4 <= grid[i][j] <= 4
方法一:动态规划 思路与算法
由于矩阵中的元素有正有负,要想得到最大积,我们只存储移动过程中的最大积是不够的,例如当前的最大积为正数时,乘上一个负数后,反而不如一个负数乘上相同的负数得到的积大。
因此,我们需要存储的是移动过程中的积的范围 ,也就是积的最小值 以及最大值 。由于只能向下或者向右走,我们可以考虑使用动态规划的方法解决本题。
设 maxgt}[i][j], \textit{minlt}[i][j] 分别为从坐标 (0, 0) 出发,到达位置 (i, j) 时乘积的最大值与最小值。由于我们只能向下或者向右走,因此乘积的取值必然只与 (i, j-1) 和 (i-1, j) 两个位置有关。
对于乘积的最大值而言:若 grid}[i][j] \ge 0,则 maxgt}[i][j] 的取值取决于这两个位置的最大值,此时
\textit{maxgt}[i][j] = \max(\textit{maxgt}[i][j-1], \textit{maxgt}[i-1][j]) \times \textit{grid}[i][j]
相反地,若 grid}[i][j] \le 0,则 maxgt}[i][j] 的取值取决于这两个位置的最小值,此时
\textit{maxgt}[i][j] = \min(\textit{minlt}[i][j-1], \textit{minlt}[i-1][j]) \times \textit{grid}[i][j]
计算乘积的最小值也是类似的思路。若 grid}[i][j] \ge 0,此时
\textit{mingt}[i][j] = \min(\textit{mingt}[i][j-1], \textit{mingt}[i-1][j]) \times \textit{grid}[i][j]
若 grid}[i][j] \le 0,此时
\textit{mingt}[i][j] = \max(\textit{maxgt}[i][j-1], \textit{maxgt}[i-1][j]) \times \textit{grid}[i][j]
特别地,当 i=0 时,只需要从 (i, j-1) 进行转移;j=0 时,只需要从 (i-1, j) 进行转移;i=0 且 j=0 时,maxgt}[i][j] 与 mingt}[i][j] 的值均为左上角的元素值 grid}[i][j]。
最终的答案即为 maxgt}[m-1][n-1],其中 m 和 n 分别是矩阵的行数与列数。
代码
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution {public : int maxProductPath (vector<vector<int >>& grid) { const int mod = 1000000000 + 7 ; int m = grid.size (), n = grid[0 ].size (); vector<vector<long long >> maxgt (m, vector <long long >(n)); vector<vector<long long >> minlt (m, vector <long long >(n)); maxgt[0 ][0 ] = minlt[0 ][0 ] = grid[0 ][0 ]; for (int i = 1 ; i < n; i++) { maxgt[0 ][i] = minlt[0 ][i] = maxgt[0 ][i - 1 ] * grid[0 ][i]; } for (int i = 1 ; i < m; i++) { maxgt[i][0 ] = minlt[i][0 ] = maxgt[i - 1 ][0 ] * grid[i][0 ]; } for (int i = 1 ; i < m; i++) { for (int j = 1 ; j < n; j++) { if (grid[i][j] >= 0 ) { maxgt[i][j] = max (maxgt[i][j - 1 ], maxgt[i - 1 ][j]) * grid[i][j]; minlt[i][j] = min (minlt[i][j - 1 ], minlt[i - 1 ][j]) * grid[i][j]; } else { maxgt[i][j] = min (minlt[i][j - 1 ], minlt[i - 1 ][j]) * grid[i][j]; minlt[i][j] = max (maxgt[i][j - 1 ], maxgt[i - 1 ][j]) * grid[i][j]; } } } if (maxgt[m - 1 ][n - 1 ] < 0 ) { return -1 ; } else { return maxgt[m - 1 ][n - 1 ] % mod; } } };
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public int maxProductPath (int [][] grid) { final int MOD = 1000000000 + 7 ; int m = grid.length, n = grid[0 ].length; long [][] maxgt = new long [m][n]; long [][] minlt = new long [m][n]; maxgt[0 ][0 ] = minlt[0 ][0 ] = grid[0 ][0 ]; for (int i = 1 ; i < n; i++) { maxgt[0 ][i] = minlt[0 ][i] = maxgt[0 ][i - 1 ] * grid[0 ][i]; } for (int i = 1 ; i < m; i++) { maxgt[i][0 ] = minlt[i][0 ] = maxgt[i - 1 ][0 ] * grid[i][0 ]; } for (int i = 1 ; i < m; i++) { for (int j = 1 ; j < n; j++) { if (grid[i][j] >= 0 ) { maxgt[i][j] = Math.max(maxgt[i][j - 1 ], maxgt[i - 1 ][j]) * grid[i][j]; minlt[i][j] = Math.min(minlt[i][j - 1 ], minlt[i - 1 ][j]) * grid[i][j]; } else { maxgt[i][j] = Math.min(minlt[i][j - 1 ], minlt[i - 1 ][j]) * grid[i][j]; minlt[i][j] = Math.max(maxgt[i][j - 1 ], maxgt[i - 1 ][j]) * grid[i][j]; } } } if (maxgt[m - 1 ][n - 1 ] < 0 ) { return -1 ; } else { return (int ) (maxgt[m - 1 ][n - 1 ] % MOD); } } }
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Solution : def maxProductPath (self, grid: List [List [int ]] ) -> int : mod = 10 **9 + 7 m, n = len (grid), len (grid[0 ]) maxgt = [[0 ] * n for _ in range (m)] minlt = [[0 ] * n for _ in range (m)] maxgt[0 ][0 ] = minlt[0 ][0 ] = grid[0 ][0 ] for i in range (1 , n): maxgt[0 ][i] = minlt[0 ][i] = maxgt[0 ][i - 1 ] * grid[0 ][i] for i in range (1 , m): maxgt[i][0 ] = minlt[i][0 ] = maxgt[i - 1 ][0 ] * grid[i][0 ] for i in range (1 , m): for j in range (1 , n): if grid[i][j] >= 0 : maxgt[i][j] = max (maxgt[i][j - 1 ], maxgt[i - 1 ][j]) * grid[i][j] minlt[i][j] = min (minlt[i][j - 1 ], minlt[i - 1 ][j]) * grid[i][j] else : maxgt[i][j] = min (minlt[i][j - 1 ], minlt[i - 1 ][j]) * grid[i][j] minlt[i][j] = max (maxgt[i][j - 1 ], maxgt[i - 1 ][j]) * grid[i][j] if maxgt[m - 1 ][n - 1 ] < 0 : return -1 return maxgt[m - 1 ][n - 1 ] % mod
复杂度分析