LeetCode 1594 矩阵的最大非负积#
目录#
1. 题目描述#
1.1. Limit#
Time Limit: 2000 ms
Memory Limit: 131072 kB
1.2. Problem Description#
给你一个大小为 rows x cols
的矩阵 grid
。最初,你位于左上角 (0, 0)
,每一步,你可以在矩阵中 向右 或 向下 移动。
在从左上角 (0, 0)
开始到右下角 (rows - 1, cols - 1)
结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。
返回 最大非负积 对 1e9 + 7
取余 的结果。如果最大积为负数,则返回 -1
。
注意,取余是在得到最大积之后执行的。
1 <= rows, cols <= 15
-4 <= grid[i][j] <= 4
1.3. Sample Input 1#
输入:grid = [[-1,-2,-3],
[-2,-3,-3],
[-3,-3,-2]]
1.4. Sample Output 1#
输出:-1
解释:从 (0, 0) 到 (2, 2) 的路径中无法得到非负积,所以返回 -1
1.5. Sample Input 2#
输入:grid = [[1,-2,1],
[1,-2,1],
[3,-4,1]]
1.6. Sample Output 2#
输出:8
解释:最大非负积对应的路径已经用粗体标出 (1 * 1 * -2 * -4 * 1 = 8)
1.7. Source#
2. 解读#
把这道题转化为树形的问题来理解会更好理解,把每条路径看作树上从起点到终点的路径。如图所示。
因为在矩阵中我们只能向右或向左移动,所以图中的蓝色点只有一个入口,从起点到蓝色点的路径最大值在最初就能够被确定。
而蓝色部分的值被确定以后,红色点的路径最大值也能够被确定,以此类推,最终推到终点。
因为矩阵中的值可能为负,所以我们需要保存路径到该点的最大值和最小值。
递推方程为
maxBuffer = grid[i][j] * max(dpMax[i - 1][j], dpMax[i][j - 1]);
minBuffer = grid[i][j] * min(dpMin[i - 1][j], dpMin[i][j - 1]);
dpMax[i][j] = max(maxBuffer, minBuffer);
dpMin[i][j] = min(maxBuffer, minBuffer);
首先初始化第一行和第一列,然后按照递推关系按行顺序或列顺序依次递推,推到终点即可。
3. 代码#
class Solution {
public:
const int MOD = 1e9 + 7;
long long maxBuffer, minBuffer;
int maxProductPath(vector<vector<int>>& grid)
{
const int MAXN = 15 + 1;
long long dpMax[MAXN][MAXN] = { { 0 } };
long long dpMin[MAXN][MAXN] = { { 0 } };
// 初始化起点
dpMax[0][0] = dpMin[0][0] = grid[0][0];
// 初始化列
for (size_t i = 1; i < grid.size(); i++) {
dpMax[i][0] = dpMin[i][0] = grid[i][0] * dpMin[i - 1][0];
}
// 初始化行
for (size_t i = 1; i < grid[0].size(); i++) {
dpMax[0][i] = dpMin[0][i] = grid[0][i] * dpMin[0][i - 1];
}
// DP
for (size_t i = 1; i < grid.size(); i++) {
for (size_t j = 1; j < grid[0].size(); j++) {
// 存储最大最小值和当前方块值的积,因为负号的存在,大小可能翻转
maxBuffer = grid[i][j] * max(dpMax[i - 1][j], dpMax[i][j - 1]);
minBuffer = grid[i][j] * min(dpMin[i - 1][j], dpMin[i][j - 1]);
// 再判断一次大小
dpMax[i][j] = max(maxBuffer, minBuffer);
dpMin[i][j] = min(maxBuffer, minBuffer);
}
}
long long ans = dpMax[grid.size() - 1][grid[0].size() - 1] % MOD;
return ans >= 0 ? ans : -1;
}
};
用 DFS + 剪枝
这题也能通过,不过时间已经到 1900ms
了,如果有更复杂一些的测试用例估计就超时了。
class Solution {
public:
const int mod = 1e9 + 7;
long long ans = -1;
void DFS(vector<vector<int>>& grid, size_t x, size_t y, long long buffer)
{
// 乘积
buffer *= grid[x][y];
// 停止搜索条件
if (y == grid[0].size() - 1 && x == grid.size() - 1) {
ans = max(ans, buffer);
// 不能使用下面的代码在这里取模,因为会将ans的大小削减,从而使原本更小的buffer更新ans
// ans = max(ans, buffer) % mod;
return;
}
// 继续搜索条件
if (buffer == 0) {
ans = max(ans, 0LL);
} else {
// 向行方向扩展
if (x < grid.size() - 1) {
DFS(grid, x + 1, y, buffer);
}
// 向列方向扩展
if (y < grid[0].size() - 1) {
DFS(grid, x, y + 1, buffer);
}
}
}
int maxProductPath(vector<vector<int>>& grid)
{
DFS(grid, 0, 0, 1);
ans %= mod;
return ans >= 0 ? ans : -1;
}
};
联系邮箱:curren_wong@163.com
CSDN:https://me.csdn.net/qq_41729780
知乎:https://zhuanlan.zhihu.com/c_1225417532351741952
公众号:复杂网络与机器学习
欢迎关注/转载,有问题欢迎通过邮箱交流。