LeetCode 1594 矩阵的最大非负积 动态规划 DFS

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

LeetCode 1594 矩阵的最大非负积

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

公众号:复杂网络与机器学习

欢迎关注/转载,有问题欢迎通过邮箱交流。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值