普通视图

发现新文章,点击刷新页面。
今天 — 2026年3月23日LeetCode 每日一题题解

每日一题-矩阵的最大非负积🟡

2026年3月23日 00:00

给你一个大小为 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

记忆化搜索 -> 递推 -> 空间优化(Python/Java/C++/Go)

作者 endlesscheng
2026年3月13日 09:24

前置题目

  1. 152. 乘积最大子数组我的题解
  2. 64. 最小路径和我的题解

状态定义与状态转移方程

思路和 152 题是一样的,除了计算最大路径乘积,还要计算最小路径乘积(因为负负得正)。

定义 $\textit{dfs}(i,j)$ 表示从左上角 $(0,0)$ 到 $(i,j)$ 的最小路径乘积以及最大路径乘积($\textit{dfs}$ 返回两个数)。

设 $x = \textit{grid}[i][j]$。分类讨论如何到达 $(i,j)$:

  • 如果是从上边过来,那么必须先到达 $(i-1,j)$,我们需要知道从 $(0,0)$ 到 $(i-1,j)$ 的最小路径乘积 $\textit{mn}$ 以及最大路径乘积 $\textit{mx}$,这可以从 $\textit{dfs}(i-1,j)$ 获取到。从左上角 $(0,0)$ 到 $(i,j)$ 的最小路径乘积为 $\min(\textit{mn}\cdot x, \textit{mx}\cdot x)$,从左上角 $(0,0)$ 到 $(i,j)$ 的最大路径乘积为 $\max(\textit{mn}\cdot x, \textit{mx}\cdot x)$。理由同 152 题。
  • 如果是从左边过来,那么必须先到达 $(i,j-1)$,我们需要知道从 $(0,0)$ 到 $(i,j-1)$ 的最小路径乘积以及最大路径乘积,这可以从 $\textit{dfs}(i,j-1)$ 获取到。计算方法同上。

两种情况取最小值(最大值),即为 $\textit{dfs}(i,j)$ 的返回值。

递归边界:$\textit{dfs}(0,0) = (x,x)$。

递归入口:$\textit{dfs}(m-1,n-1)$。取返回值中的最大路径乘积作为答案。如果答案是负数,返回 $-1$;否则返回答案模 $10^9+7$ 的结果。

注意:题目要求算完了再取模。如果在中途取模,可能会把一个很大的数模成很小的数,导致计算错误。比如两个数 $10^9+8$ 和 $10^9$,取模之前是 $10^9+8$ 更大,但取模后这两个数分别变成 $1$ 和 $10^9$,后者更大。

###py

class Solution:
    def maxProductPath(self, grid: List[List[int]]) -> int:
        @cache  # 缓存装饰器,避免重复计算 dfs(一行代码实现记忆化)
        def dfs(i: int, j: int) -> Tuple[int, int]:
            x = grid[i][j]
            if i == j == 0:
                return x, x

            res_min, res_max = inf, -inf
            if i > 0:
                mn, mx = dfs(i - 1, j)
                res_min = min(mn * x, mx * x)
                res_max = max(mn * x, mx * x)
            if j > 0:
                mn, mx = dfs(i, j - 1)
                res_min = min(res_min, mn * x, mx * x)
                res_max = max(res_max, mn * x, mx * x)

            return res_min, res_max

        ans = dfs(len(grid) - 1, len(grid[0]) - 1)[1]
        return -1 if ans < 0 else ans % 1_000_000_007

###java

class Solution {
    public int maxProductPath(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        long[][][] memo = new long[m][n][2];
        for (long[][] row : memo) {
            for (long[] p : row) {
                p[0] = p[1] = Long.MIN_VALUE;
            }
        }

        long ans = dfs(m - 1, n - 1, grid, memo)[1];
        return ans < 0 ? -1 : (int) (ans % 1_000_000_007);
    }

    private long[] dfs(int i, int j, int[][] grid, long[][][] memo) {
        long x = grid[i][j];
        if (i == 0 && j == 0) {
            return new long[]{x, x};
        }

        long[] p = memo[i][j];
        if (p[0] != Long.MIN_VALUE) { // 之前计算过
            return p;
        }

        long resMin = Long.MAX_VALUE;
        long resMax = Long.MIN_VALUE;
        if (i > 0) {
            long[] res = dfs(i - 1, j, grid, memo);
            long mn = res[0], mx = res[1];
            resMin = Math.min(mn * x, mx * x);
            resMax = Math.max(mn * x, mx * x);
        }
        if (j > 0) {
            long[] res = dfs(i, j - 1, grid, memo);
            long mn = res[0], mx = res[1];
            resMin = Math.min(resMin, Math.min(mn * x, mx * x));
            resMax = Math.max(resMax, Math.max(mn * x, mx * x));
        }

        p[0] = resMin;
        p[1] = resMax; // 记忆化
        return p;
    }
}

###cpp

class Solution {
public:
    int maxProductPath(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        vector memo(m, vector<array<long long, 2>>(n, {LLONG_MIN, LLONG_MIN}));

        auto dfs = [&](this auto&& dfs, int i, int j) -> array<long long, 2> {
            long long x = grid[i][j];
            if (i == 0 && j == 0) {
                return {x, x};
            }

            auto& res = memo[i][j]; // 注意这里是引用
            if (res[0] != LLONG_MIN) { // 之前计算过
                return res;
            }

            long long res_min = LLONG_MAX;
            long long res_max = LLONG_MIN;
            if (i > 0) {
                auto [mn, mx] = dfs(i - 1, j);
                res_min = min(mn * x, mx * x);
                res_max = max(mn * x, mx * x);
            }
            if (j > 0) {
                auto [mn, mx] = dfs(i, j - 1);
                res_min = min(res_min, min(mn * x, mx * x));
                res_max = max(res_max, max(mn * x, mx * x));
            }

            res = {res_min, res_max}; // 记忆化
            return res;
        };

        long long ans = dfs(m - 1, n - 1)[1];
        return ans < 0 ? -1 : ans % 1'000'000'007;
    }
};

###go

func maxProductPath(grid [][]int) int {
m, n := len(grid), len(grid[0])
memo := make([][][2]int, m)
for i := range memo {
memo[i] = make([][2]int, n)
for j := range memo[i] {
memo[i][j] = [2]int{math.MinInt, math.MinInt}
}
}

var dfs func(int, int) (int, int)
dfs = func(i, j int) (int, int) {
x := grid[i][j]
if i == 0 && j == 0 {
return x, x
}

p := &memo[i][j]
if p[0] != math.MinInt { // 之前计算过
return p[0], p[1]
}

resMin := math.MaxInt
resMax := math.MinInt
if i > 0 {
mn, mx := dfs(i-1, j)
resMin = min(mn*x, mx*x)
resMax = max(mn*x, mx*x)
}
if j > 0 {
mn, mx := dfs(i, j-1)
resMin = min(resMin, mn*x, mx*x)
resMax = max(resMax, mn*x, mx*x)
}

p[0], p[1] = resMin, resMax // 记忆化
return resMin, resMax
}

_, ans := dfs(m-1, n-1)
if ans < 0 {
return -1
}
return ans % 1_000_000_007
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(mn)$,其中 $m$ 和 $n$ 分别是 $\textit{grid}$ 的行数和列数。由于每个状态只会计算一次,动态规划的时间复杂度 $=$ 状态个数 $\times$ 单个状态的计算时间。本题状态个数等于 $\mathcal{O}(mn)$,单个状态的计算时间为 $\mathcal{O}(1)$,所以总的时间复杂度为 $\mathcal{O}(mn)$。
  • 空间复杂度:$\mathcal{O}(mn)$。保存多少状态,就需要多少空间。

1:1 翻译成递推

把 $\textit{dfs}(i,j)$ 改成 $f[i][j]$。

###py

class Solution:
    def maxProductPath(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        f = [[None] * n for _ in range(m)]

        for i, row in enumerate(grid):
            for j, x in enumerate(row):
                if i == j == 0:
                    f[0][0] = (x, x)
                    continue

                res_min, res_max = inf, -inf
                if i > 0:
                    mn, mx = f[i - 1][j]
                    res_min = min(mn * x, mx * x)
                    res_max = max(mn * x, mx * x)
                if j > 0:
                    mn, mx = f[i][j - 1]
                    res_min = min(res_min, mn * x, mx * x)
                    res_max = max(res_max, mn * x, mx * x)

                f[i][j] = (res_min, res_max)

        ans = f[-1][-1][1]
        return -1 if ans < 0 else ans % 1_000_000_007

###java

class Solution {
    public int maxProductPath(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        long[][][] f = new long[m][n][2];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                long x = grid[i][j];
                if (i == 0 && j == 0) {
                    f[0][0][0] = x;
                    f[0][0][1] = x;
                    continue;
                }

                long resMin = Long.MAX_VALUE;
                long resMax = Long.MIN_VALUE;
                if (i > 0) {
                    long mn = f[i - 1][j][0], mx = f[i - 1][j][1];
                    resMin = Math.min(mn * x, mx * x);
                    resMax = Math.max(mn * x, mx * x);
                }
                if (j > 0) {
                    long mn = f[i][j - 1][0], mx = f[i][j - 1][1];
                    resMin = Math.min(resMin, Math.min(mn * x, mx * x));
                    resMax = Math.max(resMax, Math.max(mn * x, mx * x));
                }

                f[i][j][0] = resMin;
                f[i][j][1] = resMax;
            }
        }

        long ans = f[m - 1][n - 1][1];
        return ans < 0 ? -1 : (int) (ans % 1_000_000_007);
    }
}

###cpp

class Solution {
public:
    int maxProductPath(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        vector f(m, vector<array<long long, 2>>(n));

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                long long x = grid[i][j];
                if (i == 0 && j == 0) {
                    f[0][0] = {x, x};
                    continue;
                }

                long long res_min = LLONG_MAX;
                long long res_max = LLONG_MIN;
                if (i > 0) {
                    auto [mn, mx] = f[i - 1][j];
                    res_min = min(mn * x, mx * x);
                    res_max = max(mn * x, mx * x);
                }
                if (j > 0) {
                    auto [mn, mx] = f[i][j - 1];
                    res_min = min(res_min, min(mn * x, mx * x));
                    res_max = max(res_max, max(mn * x, mx * x));
                }

                f[i][j] = {res_min, res_max};
            }
        }

        long long ans = f[m - 1][n - 1][1];
        return ans < 0 ? -1 : ans % 1'000'000'007;
    }
};

###go

func maxProductPath(grid [][]int) int {
m, n := len(grid), len(grid[0])
f := make([][][2]int, m)
for i := range f {
f[i] = make([][2]int, n)
}

for i, row := range grid {
for j, x := range row {
if i == 0 && j == 0 {
f[0][0] = [2]int{x, x}
continue
}

resMin := math.MaxInt
resMax := math.MinInt
if i > 0 {
mn, mx := f[i-1][j][0], f[i-1][j][1]
resMin = min(mn*x, mx*x)
resMax = max(mn*x, mx*x)
}
if j > 0 {
mn, mx := f[i][j-1][0], f[i][j-1][1]
resMin = min(resMin, mn*x, mx*x)
resMax = max(resMax, mn*x, mx*x)
}

f[i][j] = [2]int{resMin, resMax}
}
}

ans := f[m-1][n-1][1]
if ans < 0 {
return -1
}
return ans % 1_000_000_007
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(mn)$,其中 $m$ 和 $n$ 分别是 $\textit{grid}$ 的行数和列数。
  • 空间复杂度:$\mathcal{O}(mn)$。

空间优化

原理见 64 题 我的题解

###py

class Solution:
    def maxProductPath(self, grid: List[List[int]]) -> int:
        n = len(grid[0])
        f_min = [0] * n
        f_max = [0] * n

        for i, row in enumerate(grid):
            for j, x in enumerate(row):
                if i == j == 0:
                    f_min[0] = f_max[0] = x
                    continue

                res_min, res_max = inf, -inf
                if i > 0:
                    mn, mx = f_min[j], f_max[j]
                    res_min = min(mn * x, mx * x)
                    res_max = max(mn * x, mx * x)
                if j > 0:
                    mn, mx = f_min[j - 1], f_max[j - 1]
                    res_min = min(res_min, mn * x, mx * x)
                    res_max = max(res_max, mn * x, mx * x)

                f_min[j] = res_min
                f_max[j] = res_max

        ans = f_max[-1]
        return -1 if ans < 0 else ans % 1_000_000_007

###java

class Solution {
    public int maxProductPath(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        long[] fMin = new long[n];
        long[] fMax = new long[n];

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                long x = grid[i][j];
                if (i == 0 && j == 0) {
                    fMin[0] = fMax[0] = x;
                    continue;
                }

                long resMin = Long.MAX_VALUE;
                long resMax = Long.MIN_VALUE;
                if (i > 0) {
                    long mn = fMin[j], mx = fMax[j];
                    resMin = Math.min(mn * x, mx * x);
                    resMax = Math.max(mn * x, mx * x);
                }
                if (j > 0) {
                    long mn = fMin[j - 1], mx = fMax[j - 1];
                    resMin = Math.min(resMin, Math.min(mn * x, mx * x));
                    resMax = Math.max(resMax, Math.max(mn * x, mx * x));
                }

                fMin[j] = resMin;
                fMax[j] = resMax;
            }
        }

        long ans = fMax[n - 1];
        return ans < 0 ? -1 : (int) (ans % 1_000_000_007);
    }
}

###cpp

class Solution {
public:
    int maxProductPath(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        vector<long long> f_min(n), f_max(n);

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                long long x = grid[i][j];
                if (i == 0 && j == 0) {
                    f_min[0] = f_max[0] = x;
                    continue;
                }

                long long res_min = LLONG_MAX;
                long long res_max = LLONG_MIN;
                if (i > 0) {
                    long long mn = f_min[j], mx = f_max[j];
                    res_min = min(mn * x, mx * x);
                    res_max = max(mn * x, mx * x);
                }
                if (j > 0) {
                    long long mn = f_min[j - 1], mx = f_max[j - 1];
                    res_min = min(res_min, min(mn * x, mx * x));
                    res_max = max(res_max, max(mn * x, mx * x));
                }

                f_min[j] = res_min;
                f_max[j] = res_max;
            }
        }

        long long ans = f_max[n - 1];
        return ans < 0 ? -1 : ans % 1'000'000'007;
    }
};

###go

func maxProductPath(grid [][]int) int {
n := len(grid[0])
fMin := make([]int, n)
fMax := make([]int, n)

for i, row := range grid {
for j, x := range row {
if i == 0 && j == 0 {
fMin[0], fMax[0] = x, x
continue
}

resMin := math.MaxInt
resMax := math.MinInt
if i > 0 {
mn, mx := fMin[j], fMax[j]
resMin = min(mn*x, mx*x)
resMax = max(mn*x, mx*x)
}
if j > 0 {
mn, mx := fMin[j-1], fMax[j-1]
resMin = min(resMin, mn*x, mx*x)
resMax = max(resMax, mn*x, mx*x)
}

fMin[j] = resMin
fMax[j] = resMax
}
}

ans := fMax[n-1]
if ans < 0 {
return -1
}
return ans % 1_000_000_007
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(mn)$,其中 $m$ 和 $n$ 分别是 $\textit{grid}$ 的行数和列数。
  • 空间复杂度:$\mathcal{O}(n)$。

专题训练

见下面动态规划题单的「二、网格图 DP」。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

矩阵的最大非负积

2020年10月9日 11:42

方法一:动态规划

思路与算法

由于矩阵中的元素有正有负,要想得到最大积,我们只存储移动过程中的最大积是不够的,例如当前的最大积为正数时,乘上一个负数后,反而不如一个负数乘上相同的负数得到的积大。

因此,我们需要存储的是移动过程中的积的范围,也就是积的最小值以及最大值。由于只能向下或者向右走,我们可以考虑使用动态规划的方法解决本题。

设 $\textit{maxgt}[i][j], \textit{minlt}[i][j]$ 分别为从坐标 $(0, 0)$ 出发,到达位置 $(i, j)$ 时乘积的最大值与最小值。由于我们只能向下或者向右走,因此乘积的取值必然只与 $(i, j-1)$ 和 $(i-1, j)$ 两个位置有关。

对于乘积的最大值而言:若 $\textit{grid}[i][j] \ge 0$,则 $\textit{maxgt}[i][j]$ 的取值取决于这两个位置的最大值,此时

$$
\textit{maxgt}[i][j] = \max(\textit{maxgt}[i][j-1], \textit{maxgt}[i-1][j]) \times \textit{grid}[i][j]
$$

相反地,若 $\textit{grid}[i][j] \le 0$,则 $\textit{maxgt}[i][j]$ 的取值取决于这两个位置的最小值,此时

$$
\textit{maxgt}[i][j] = \min(\textit{minlt}[i][j-1], \textit{minlt}[i-1][j]) \times \textit{grid}[i][j]
$$

计算乘积的最小值也是类似的思路。若 $\textit{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]
$$

若 $\textit{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$ 时,$\textit{maxgt}[i][j]$ 与 $\textit{mingt}[i][j]$ 的值均为左上角的元素值 $\textit{grid}[i][j]$。

最终的答案即为 $\textit{maxgt}[m-1][n-1]$,其中 $m$ 和 $n$ 分别是矩阵的行数与列数。

代码

###C++

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;
        }
    }
};

###Java

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);
        }
    }
}

###Python

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

###C#

public class Solution {
    public int MaxProductPath(int[][] grid) {
        const int MOD = 1000000007;
        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) {
                    long maxPrev = Math.Max(maxgt[i, j - 1], maxgt[i - 1, j]);
                    long minPrev = Math.Min(minlt[i, j - 1], minlt[i - 1, j]);
                    maxgt[i, j] = maxPrev * grid[i][j];
                    minlt[i, j] = minPrev * grid[i][j];
                } else {
                    long maxPrev = Math.Max(maxgt[i, j - 1], maxgt[i - 1, j]);
                    long minPrev = Math.Min(minlt[i, j - 1], minlt[i - 1, j]);
                    maxgt[i, j] = minPrev * grid[i][j];
                    minlt[i, j] = maxPrev * grid[i][j];
                }
            }
        }
        
        if (maxgt[m - 1, n - 1] < 0) {
            return -1;
        } else {
            return (int)(maxgt[m - 1, n - 1] % MOD);
        }
    }
}

###Go

func maxProductPath(grid [][]int) int {
    const MOD = 1000000007
    m, n := len(grid), len(grid[0])
    
    maxgt := make([][]int64, m)
    minlt := make([][]int64, m)
    for i := range maxgt {
        maxgt[i] = make([]int64, n)
        minlt[i] = make([]int64, n)
    }
    
    maxgt[0][0] = int64(grid[0][0])
    minlt[0][0] = int64(grid[0][0])
    for i := 1; i < n; i++ {
        maxgt[0][i] = maxgt[0][i-1] * int64(grid[0][i])
        minlt[0][i] = maxgt[0][i]
    }
    for i := 1; i < m; i++ {
        maxgt[i][0] = maxgt[i-1][0] * int64(grid[i][0])
        minlt[i][0] = maxgt[i][0]
    }
    for i := 1; i < m; i++ {
        for j := 1; j < n; j++ {
            if grid[i][j] >= 0 {
                maxPrev := max(maxgt[i][j-1], maxgt[i-1][j])
                minPrev := min(minlt[i][j-1], minlt[i-1][j])
                maxgt[i][j] = maxPrev * int64(grid[i][j])
                minlt[i][j] = minPrev * int64(grid[i][j])
            } else {
                maxPrev := max(maxgt[i][j-1], maxgt[i-1][j])
                minPrev := min(minlt[i][j-1], minlt[i-1][j])
                maxgt[i][j] = minPrev * int64(grid[i][j])
                minlt[i][j] = maxPrev * int64(grid[i][j])
            }
        }
    }
    
    if maxgt[m-1][n-1] < 0 {
        return -1
    }
    return int(maxgt[m-1][n-1] % MOD)
}

###C

#define MOD 1000000007

int maxProductPath(int** grid, int gridSize, int* gridColSize) {
    int m = gridSize, n = gridColSize[0];
    long long** maxgt = (long long**)malloc(m * sizeof(long long*));
    long long** minlt = (long long**)malloc(m * sizeof(long long*));
    for (int i = 0; i < m; i++) {
        maxgt[i] = (long long*)malloc(n * sizeof(long long));
        minlt[i] = (long long*)malloc(n * sizeof(long long));
    }
    
    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] = fmax(maxgt[i][j - 1], maxgt[i - 1][j]) * grid[i][j];
                minlt[i][j] = fmin(minlt[i][j - 1], minlt[i - 1][j]) * grid[i][j];
            } else {
                maxgt[i][j] = fmin(minlt[i][j - 1], minlt[i - 1][j]) * grid[i][j];
                minlt[i][j] = fmax(maxgt[i][j - 1], maxgt[i - 1][j]) * grid[i][j];
            }
        }
    }
    
    long long result = maxgt[m - 1][n - 1];
    for (int i = 0; i < m; i++) {
        free(maxgt[i]);
        free(minlt[i]);
    }
    free(maxgt);
    free(minlt);
    
    if (result < 0) {
        return -1;
    } else {
        return result % MOD;
    }
}

###JavaScript

var maxProductPath = function(grid) {
    const MOD = 1000000007;
    const m = grid.length, n = grid[0].length;
    const maxgt = new Array(m).fill(0).map(() => new Array(n).fill(0));
    const minlt = new Array(m).fill(0).map(() => new Array(n).fill(0));
    
    maxgt[0][0] = minlt[0][0] = grid[0][0];
    for (let i = 1; i < n; i++) {
        maxgt[0][i] = minlt[0][i] = maxgt[0][i - 1] * grid[0][i];
    }
    for (let i = 1; i < m; i++) {
        maxgt[i][0] = minlt[i][0] = maxgt[i - 1][0] * grid[i][0];
    }
    for (let i = 1; i < m; i++) {
        for (let 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 maxgt[m - 1][n - 1] % MOD;
    }
};

###TypeScript

function maxProductPath(grid: number[][]): number {
    const MOD = 1000000007;
    const m = grid.length, n = grid[0].length;
    
    const maxgt: number[][] = new Array(m).fill(0).map(() => new Array(n).fill(0));
    const minlt: number[][] = new Array(m).fill(0).map(() => new Array(n).fill(0));
    
    maxgt[0][0] = minlt[0][0] = grid[0][0];
    for (let i = 1; i < n; i++) {
        maxgt[0][i] = minlt[0][i] = maxgt[0][i - 1] * grid[0][i];
    }
    for (let i = 1; i < m; i++) {
        maxgt[i][0] = minlt[i][0] = maxgt[i - 1][0] * grid[i][0];
    }
    for (let i = 1; i < m; i++) {
        for (let 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 maxgt[m - 1][n - 1] % MOD;
    }
}

###Rust

impl Solution {
    pub fn max_product_path(grid: Vec<Vec<i32>>) -> i32 {
        const MOD: i64 = 1_000_000_007;
        let m = grid.len();
        let n = grid[0].len();
        let mut maxgt = vec![vec![0i64; n]; m];
        let mut minlt = vec![vec![0i64; n]; m];
        maxgt[0][0] = grid[0][0] as i64;
        minlt[0][0] = grid[0][0] as i64;
        
        for i in 1..n {
            maxgt[0][i] = maxgt[0][i-1] * grid[0][i] as i64;
            minlt[0][i] = maxgt[0][i];
        }
        for i in 1..m {
            maxgt[i][0] = maxgt[i-1][0] * grid[i][0] as i64;
            minlt[i][0] = maxgt[i][0];
        }
        for i in 1..m {
            for j in 1..n {
                let grid_val = grid[i][j] as i64;
                if grid_val >= 0 {
                    let max_prev = maxgt[i][j-1].max(maxgt[i-1][j]);
                    let min_prev = minlt[i][j-1].min(minlt[i-1][j]);
                    maxgt[i][j] = max_prev * grid_val;
                    minlt[i][j] = min_prev * grid_val;
                } else {
                    let max_prev = maxgt[i][j-1].max(maxgt[i-1][j]);
                    let min_prev = minlt[i][j-1].min(minlt[i-1][j]);
                    maxgt[i][j] = min_prev * grid_val;
                    minlt[i][j] = max_prev * grid_val;
                }
            }
        }
        
        let result = maxgt[m-1][n-1];
        if result < 0 {
            -1
        } else {
            (result % MOD) as i32
        }
    }
}

复杂度分析

  • 时间复杂度:$O(mn)$,其中 $m$ 和 $n$ 为矩阵的行数与列数。我们需要遍历矩阵的每一个元素,而处理每个元素时只需要常数时间。

  • 空间复杂度:$O(mn)$。我们开辟了两个与原矩阵等大的数组。

动态规划注意预初始化

2020年9月20日 21:55

大家常见的最大路径动态规划问题,比赛时傻傻的惯性思维导致一些细节没处理好,最后换了一下预处理就过了,
由于乘积有正负,最大整数下一秒就能成为最小负数,最小负数下一步也能成为最大正数,所以设置两个DP数组分别记录路劲最大值dp1和路径最小值dp2,即递推过程:
dp1[i][j] = max({dp1[i-1][j]*grid[i][j], dp1[i][j-1]*grid[i][j],dp2[i-1][j]*grid[i][j], dp2[i][j-1]*grid[i][j]});
dp2[i][j] = min({dp1[i-1][j]*grid[i][j], dp1[i][j-1]*grid[i][j],dp2[i-1][j]*grid[i][j], dp2[i][j-1]*grid[i][j]});
初始化:for(int i = 1 ; i < row; i++) dp1[i][0] =dp1[i-1][0] * grid[i][0];dp2同理

class Solution {
public:
    int maxProductPath(vector<vector<int>>& grid) {
        int row = grid.size();
        int col = grid[0].size();
        vector<vector<long long>>dp1(row,vector<long long>(col));
        vector<vector<long long>>dp2(row,vector<long long>(col));
        dp1[0][0] = grid[0][0];
        dp2[0][0] = grid[0][0];
        for(int i = 1 ; i < row; i++){
            dp1[i][0] =dp1[i-1][0] * grid[i][0];
            dp2[i][0] =dp2[i-1][0] * grid[i][0];
        }
        for(int i = 1 ; i < col; i++){
            dp1[0][i] =dp1[0][i-1] * grid[0][i];
            dp2[0][i] =dp2[0][i-1] * grid[0][i];

        }
        for(int i = 1; i < grid.size();i++){
            for(int j = 1; j < grid[0].size();j++){
                dp1[i][j]=max({dp1[i-1][j]*grid[i][j], dp1[i][j-1]*grid[i][j],dp2[i-1][j]*grid[i][j], dp2[i][j-1]*grid[i][j]});
                dp2[i][j]=min({dp1[i-1][j]*grid[i][j], dp1[i][j-1]*grid[i][j],dp2[i-1][j]*grid[i][j], dp2[i][j-1]*grid[i][j]});
            }
        }
        if(dp1[row-1][col-1] < 0) return -1;
        else return dp1[row-1][col-1]%1000000007;
    }
};
昨天 — 2026年3月22日LeetCode 每日一题题解

每日一题-判断矩阵经轮转后是否一致🟢

2026年3月22日 00:00

给你两个大小为 n x n 的二进制矩阵 mattarget 。现 以 90 度顺时针轮转 矩阵 mat 中的元素 若干次 ,如果能够使 mat 与 target 一致,返回 true ;否则,返回 false

 

示例 1:

输入:mat = [[0,1],[1,0]], target = [[1,0],[0,1]]
输出:true
解释:顺时针轮转 90 度一次可以使 mat 和 target 一致。

示例 2:

输入:mat = [[0,1],[1,1]], target = [[1,0],[0,1]]
输出:false
解释:无法通过轮转矩阵中的元素使 equal 与 target 一致。

示例 3:

输入:mat = [[0,0,0],[0,1,0],[1,1,1]], target = [[1,1,1],[0,1,0],[0,0,0]]
输出:true
解释:顺时针轮转 90 度两次可以使 mat 和 target 一致。

 

提示:

  • n == mat.length == target.length
  • n == mat[i].length == target[i].length
  • 1 <= n <= 10
  • mat[i][j]target[i][j] 不是 0 就是 1

枚举四种情况进行比较即可

作者 qyaaaa
2021年6月6日 12:52
public boolean findRotation(int[][] mat, int[][] target) {
        int n = mat.length;
        boolean b1 = true,b2 = true,b3 = true,b4 = true;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < n;j++){
                //旋转90度
                if(mat[n - j - 1][i] != target[i][j]){
                    b1 = false;
                }
                //旋转180度
                if (mat[n - i - 1][n - j - 1] != target[i][j]){
                    b2 = false;
                }
                //旋转270度
                if (mat[j][n- i- 1] != target[i][j]){
                    b3 = false;
                }
                //旋转360度
                if (mat[i][j] != target[i][j]){
                    b4 = false;
                }
            }
        }
        return b1 || b2 || b3 || b4;
    }

[Python] 判断顺时针转0度,90度,180度和270度是否一样

作者 himymBen
2021年6月6日 12:50

解题思路

该用户太懒了见代码

代码

###python3

class Solution:
    def findRotation(self, mat: List[List[int]], target: List[List[int]]) -> bool:
        def rotate(matrix):
            m,n = len(matrix),len(matrix[0])
            new = [[0] * m for _ in range(n)]
            for i in range(m):
                for j in range(n):
                    new[j][m-1-i] = matrix[i][j]
            return new
        
        if mat == target:
            return True
        
        for i in range(3):
            mat = rotate(mat)
            if mat == target:
                return True
        return False

两种方法:先旋转再比较 / 直接比较(Python/Java/C++/Go)

作者 endlesscheng
2021年6月6日 12:34

方法一:先旋转再比较

枚举 $\textit{mat}$ 旋转 $0,1,2,3$ 次,判断旋转后的 $\textit{mat}$ 是否等于 $\textit{target}$。

旋转方阵有原地算法,见 48. 旋转图像我的题解

class Solution:
    # 48. 旋转图像
    def rotate(self, matrix: List[List[int]]) -> None:
        n = len(matrix)
        for i, row in enumerate(matrix):
            for j in range(i + 1, n):  # 遍历对角线上方元素,做转置
                row[j], matrix[j][i] = matrix[j][i], row[j]
            row.reverse()  # 行翻转

    def findRotation(self, mat: List[List[int]], target: List[List[int]]) -> bool:
        for _ in range(4):
            if mat == target:
                return True
            self.rotate(mat)
        return False
class Solution {
    public boolean findRotation(int[][] mat, int[][] target) {
        for (int i = 0; i < 4; i++) {
            if (Arrays.deepEquals(mat, target)) {
                return true;
            }
            rotate(mat);
        }
        return false;
    }

    // 48. 旋转图像
    public void rotate(int[][] matrix) {
        int n = matrix.length;
        for (int i = 0; i < n; i++) {
            int[] row = matrix[i];
            for (int j = i + 1; j < n; j++) { // 遍历对角线上方元素,做转置
                int tmp = row[j];
                row[j] = matrix[j][i];
                matrix[j][i] = tmp;
            }
            for (int j = 0; j < n / 2; j++) { // 遍历左半元素,做行翻转
                int tmp = row[j];
                row[j] = row[n - 1 - j];
                row[n - 1 - j] = tmp;
            }
        }
    }
}
class Solution {
    // 48. 旋转图像
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) { // 遍历对角线上方元素,做转置
                swap(matrix[i][j], matrix[j][i]);
            }
            ranges::reverse(matrix[i]); // 行翻转
        }
    }

public:
    bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
        for (int i = 0; i < 4; i++) {
            if (mat == target) {
                return true;
            }
            rotate(mat);
        }
        return false;
    }
};
// 48. 旋转图像
func rotate(matrix [][]int) {
n := len(matrix)
for i, row := range matrix {
for j := i + 1; j < n; j++ { // 遍历对角线上方元素,做转置
row[j], matrix[j][i] = matrix[j][i], row[j]
}
slices.Reverse(row) // 行翻转
}
}

func findRotation(mat, target [][]int) bool {
for range 4 {
if slices.EqualFunc(mat, target, slices.Equal[[]int]) {
return true
}
rotate(mat)
}
return false
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(n^2)$,其中 $n$ 是 $\textit{mat}$ 的行数和列数。
  • 空间复杂度:$\mathcal{O}(1)$。

方法二:直接比较

顺时针旋转 $90^\circ$ 后,位于 $(i,j)$ 的元素去哪了?

根据 48 题 我的题解,结论如下:

$$
(i,j)\xrightarrow{旋转\ 90^\circ} (j,n-1-i) \xrightarrow{旋转\ 90^\circ} (n-1-i,n-1-j) \xrightarrow{旋转\ 90^\circ} (n-1-j,i)
$$

所以对于 $\textit{mat}[i][j]$,它需要比较四个位置上的值:

  • 旋转 $0$ 次:比较 $\textit{target}[i][j]$。
  • 旋转 $1$ 次:比较 $\textit{target}[j][n-1-i]$。
  • 旋转 $2$ 次:比较 $\textit{target}[n-1-i][n-1-j]$。
  • 旋转 $3$ 次:比较 $\textit{target}[n-1-j][i]$。

如果对于某个旋转次数,所有的比较都为真,那么返回 $\texttt{true}$。否则返回 $\texttt{false}$。

class Solution:
    def findRotation(self, mat: List[List[int]], target: List[List[int]]) -> bool:
        ok = (1 << 4) - 1  # ok = [True] * 4
        for i, row in enumerate(mat):
            for j, x in enumerate(row):
                if x != target[i][j]:
                    ok &= ~(1 << 0)  # ok[0] = False
                if x != target[j][-1 - i]:
                    ok &= ~(1 << 1)  # ok[1] = False
                if x != target[-1 - i][-1 - j]:
                    ok &= ~(1 << 2)  # ok[2] = False
                if x != target[-1 - j][i]:
                    ok &= ~(1 << 3)  # ok[3] = False
                if ok == 0:  # 所有的 ok[i] 都是 False
                    return False
        return True  # 至少有一个 ok[i] 是 True
class Solution {
    public boolean findRotation(int[][] mat, int[][] target) {
        int n = mat.length;
        int ok = (1 << 4) - 1; // boolean[] ok = {true, true, true, true};
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int x = mat[i][j];
                if (x != target[i][j]) {
                    ok &= ~(1 << 0); // ok[0] = false
                }
                if (x != target[j][n - 1 - i]) {
                    ok &= ~(1 << 1); // ok[1] = false
                }
                if (x != target[n - 1 - i][n - 1 - j]) {
                    ok &= ~(1 << 2); // ok[2] = false
                }
                if (x != target[n - 1 - j][i]) {
                    ok &= ~(1 << 3); // ok[3] = false
                }
                if (ok == 0) { // 所有的 ok[i] 都是 false
                    return false;
                }
            }
        }
        return true; // 至少有一个 ok[i] 是 true
    }
}
class Solution {
public:
    bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
        int n = mat.size();
        int ok = (1 << 4) - 1; // bool ok[4] = {true, true, true, true}
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int x = mat[i][j];
                if (x != target[i][j]) {
                    ok &= ~(1 << 0); // ok[0] = false
                }
                if (x != target[j][n - 1 - i]) {
                    ok &= ~(1 << 1); // ok[1] = false
                }
                if (x != target[n - 1 - i][n - 1 - j]) {
                    ok &= ~(1 << 2); // ok[2] = false
                }
                if (x != target[n - 1 - j][i]) {
                    ok &= ~(1 << 3); // ok[3] = false
                }
                if (ok == 0) { // 所有的 ok[i] 都是 false
                    return false;
                }
            }
        }
        return true; // 至少有一个 ok[i] 是 true
    }
};
func findRotation(mat, target [][]int) bool {
n := len(mat)
ok := 1<<4 - 1 // ok := [4]bool{true, true, true, true}
for i, row := range mat {
for j, x := range row {
if x != target[i][j] {
ok &^= 1 << 0 // ok[0] = false
}
if x != target[j][n-1-i] {
ok &^= 1 << 1 // ok[1] = false
}
if x != target[n-1-i][n-1-j] {
ok &^= 1 << 2 // ok[2] = false
}
if x != target[n-1-j][i] {
ok &^= 1 << 3 // ok[3] = false
}
if ok == 0 { // 所有的 ok[i] 都是 false
return false
}
}
}
return true // 至少有一个 ok[i] 是 true
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(n^2)$,其中 $n$ 是 $\textit{mat}$ 的行数和列数。
  • 空间复杂度:$\mathcal{O}(1)$。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

昨天以前LeetCode 每日一题题解

每日一题-垂直翻转子矩阵🟢

2026年3月21日 00:00

给你一个 m x n 的整数矩阵 grid,以及三个整数 xyk

整数 xy 表示一个 正方形子矩阵 的左上角下标,整数 k 表示该正方形子矩阵的边长。

你的任务是垂直翻转子矩阵的行顺序。

返回更新后的矩阵。

 

示例 1:

输入: grid = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]], x = 1, y = 0, k = 3

输出: [[1,2,3,4],[13,14,15,8],[9,10,11,12],[5,6,7,16]]

解释:

上图展示了矩阵在变换前后的样子。

示例 2:

输入: grid = [[3,4,2,3],[2,3,4,2]], x = 0, y = 2, k = 2

输出: [[3,4,4,2],[2,3,2,3]]

解释:

上图展示了矩阵在变换前后的样子。

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 50
  • 1 <= grid[i][j] <= 100
  • 0 <= x < m
  • 0 <= y < n
  • 1 <= k <= min(m - x, n - y)

3643. 垂直翻转子矩阵

作者 navi-hex
2025年9月24日 20:39

Problem: 3643. 垂直翻转子矩阵

[TOC]

思路

模拟

Code

###Rust

impl Solution {
    pub fn reverse_submatrix(mut grid: Vec<Vec<i32>>, x: i32, y: i32, k: i32) -> Vec<Vec<i32>> {
        let (x, y, k) = (x as usize, y as usize, k as usize);
        for u in x..x + k / 2 {
            let d = x + k - 1 - u + x;
            for i in y..y + k {
                let p1 = &mut grid[u][i] as *mut i32;
                let p2 = &mut grid[d][i] as *mut i32;
                unsafe { std::ptr::swap(p1, p2); }
            }
        }

        grid
    }
}

双指针(Python/Java/C++/Go)

作者 endlesscheng
2025年8月10日 13:44

根据题意,交换的范围是行号 $[x,x+k-1]$,列号 $[y,y+k-1]$。

类似 344. 反转字符串,用双指针实现:

  • 初始化 $l=x$,$r=x+k-1$。
  • 循环直到 $l\ge r$。
  • 每次循环,对于 $[y,y+k-1]$ 中的每个整数 $j$,交换 $\textit{grid}[l][j]$ 和 $\textit{grid}[r][j]$。

具体请看 视频讲解,欢迎点赞关注~

###py

class Solution:
    def reverseSubmatrix(self, grid: List[List[int]], x: int, y: int, k: int) -> List[List[int]]:
        l, r = x, x + k - 1
        while l < r:
            for j in range(y, y + k):
                grid[l][j], grid[r][j] = grid[r][j], grid[l][j]
            l += 1
            r -= 1
        return grid

###py

class Solution:
    def reverseSubmatrix(self, grid: List[List[int]], x: int, y: int, k: int) -> List[List[int]]:
        l, r = x, x + k - 1
        while l < r:
            grid[l][y: y + k], grid[r][y: y + k] = grid[r][y: y + k], grid[l][y: y + k]
            l += 1
            r -= 1
        return grid

###java

class Solution {
    public int[][] reverseSubmatrix(int[][] grid, int x, int y, int k) {
        int l = x;
        int r = x + k - 1;
        while (l < r) {
            for (int j = y; j < y + k; j++) {
                int tmp = grid[l][j];
                grid[l][j] = grid[r][j];
                grid[r][j] = tmp;
            }
            l++;
            r--;
        }
        return grid;
    }
}

###cpp

class Solution {
public:
    vector<vector<int>> reverseSubmatrix(vector<vector<int>>& grid, int x, int y, int k) {
        int l = x, r = x + k - 1;
        while (l < r) {
            for (int j = y; j < y + k; j++) {
                swap(grid[l][j], grid[r][j]);
            }
            l++;
            r--;
        }
        return grid;
    }
};

###go

func reverseSubmatrix(grid [][]int, x, y, k int) [][]int {
l, r := x, x+k-1
for l < r {
for j := y; j < y+k; j++ {
grid[l][j], grid[r][j] = grid[r][j], grid[l][j]
}
l++
r--
}
return grid
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(k^2)$。
  • 空间复杂度:$\mathcal{O}(1)$。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、二叉树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA/一般树)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

模拟

作者 tsreaper
2025年8月10日 12:11

解法:模拟

按题意模拟即可。复杂度 $\mathcal{O}(nm)$。

参考代码(c++)

class Solution {
public:
    vector<vector<int>> reverseSubmatrix(vector<vector<int>>& grid, int x, int y, int k) {
        for (int i = x, ii = x + k - 1; i < ii; i++, ii--) for (int j = y; j < y + k; j++)
            swap(grid[i][j], grid[ii][j]);
        return grid;
    }
};

每日一题-子矩阵的最小绝对差🟡

2026年3月20日 00:00

给你一个 m x n 的整数矩阵 grid 和一个整数 k

对于矩阵 grid 中的每个连续的 k x k 子矩阵,计算其中任意两个 不同值 之间的 最小绝对差 

返回一个大小为 (m - k + 1) x (n - k + 1) 的二维数组 ans,其中 ans[i][j] 表示以 grid 中坐标 (i, j) 为左上角的子矩阵的最小绝对差。

注意:如果子矩阵中的所有元素都相同,则答案为 0。

子矩阵 (x1, y1, x2, y2) 是一个由选择矩阵中所有满足 x1 <= x <= x2y1 <= y <= y2 的单元格 matrix[x][y] 组成的矩阵。

 

示例 1:

输入: grid = [[1,8],[3,-2]], k = 2

输出: [[2]]

解释:

  • 只有一个可能的 k x k 子矩阵:[[1, 8], [3, -2]]
  • 子矩阵中的不同值为 [1, 8, 3, -2]
  • 子矩阵中的最小绝对差为 |1 - 3| = 2。因此,答案为 [[2]]

示例 2:

输入: grid = [[3,-1]], k = 1

输出: [[0,0]]

解释:

  • 每个 k x k 子矩阵中只有一个不同的元素。
  • 因此,答案为 [[0, 0]]

示例 3:

输入: grid = [[1,-2,3],[2,3,5]], k = 2

输出: [[1,2]]

解释:

  • 有两个可能的 k × k 子矩阵:
    • (0, 0) 为起点的子矩阵:[[1, -2], [2, 3]]
      • 子矩阵中的不同值为 [1, -2, 2, 3]
      • 子矩阵中的最小绝对差为 |1 - 2| = 1
    • (0, 1) 为起点的子矩阵:[[-2, 3], [3, 5]]
      • 子矩阵中的不同值为 [-2, 3, 5]
      • 子矩阵中的最小绝对差为 |3 - 5| = 2
  • 因此,答案为 [[1, 2]]

 

提示:

  • 1 <= m == grid.length <= 30
  • 1 <= n == grid[i].length <= 30
  • -105 <= grid[i][j] <= 105
  • 1 <= k <= min(m, n)

3567. 子矩阵的最小绝对差

作者 stormsunshine
2025年6月1日 15:26

解法

思路和算法

矩阵 $\textit{grid}$ 的大小是 $m \times n$,需要计算每个 $k \times k$ 的子矩阵中的任意两个不同值之间的最小绝对差。为了得到最小绝对差,需要得到 $k \times k$ 的子矩阵中的所有元素值,由于最小绝对差一定出现在排序后的两个相邻的不同元素值的差值中,因此需要将子矩阵中的元素值排序,然后计算最小绝对差。

创建 $(m - k + 1) \times (n - k + 1)$ 的二维数组 $\textit{ans}$,计算 $\textit{ans}[i][j]$ 的方法如下。

  1. 遍历矩阵 $\textit{grid}$ 的行下标范围 $[i, i + k - 1]$ 和列下标范围 $[j, j + k - 1]$ 中的 $k^2$ 个元素,使用长度为 $k^2$ 的数组存储。

  2. 将长度为 $k^2$ 的数组按升序排序,排序之后遍历数组中的每一对相邻元素,如果相邻元素不相等则计算绝对差。遍历结束之后即可得到当前子矩阵中的不同值之间的最小绝对差,填入 $\textit{ans}[i][j]$。

分别计算所有 $k \times k$ 的子矩阵的不同值之间的最小绝对差之后,二维数组 $\textit{ans}$ 即为答案。

代码

###Java

class Solution {
    public int[][] minAbsDiff(int[][] grid, int k) {
        int m = grid.length, n = grid[0].length;
        int[][] ans = new int[m - k + 1][n - k + 1];
        for (int i = 0; i < m - k + 1; i++) {
            for (int j = 0; j < n - k + 1; j++) {
                ans[i][j] = getMinAbsDiff(grid, k, i, j);
            }
        }
        return ans;
    }

    public int getMinAbsDiff(int[][] grid, int k, int startRow, int startCol) {
        int total = k * k;
        int[] values = new int[total];
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < k; j++) {
                values[i * k + j] = grid[startRow + i][startCol + j];
            }
        }
        Arrays.sort(values);
        int minAbsDiff = Integer.MAX_VALUE;
        for (int i = 1; i < total; i++) {
            if (values[i] > values[i - 1]) {
                minAbsDiff = Math.min(minAbsDiff, values[i] - values[i - 1]);
            }
        }
        return minAbsDiff != Integer.MAX_VALUE ? minAbsDiff : 0;
    }
}

###C#

public class Solution {
    public int[][] MinAbsDiff(int[][] grid, int k) {
        int m = grid.Length, n = grid[0].Length;
        int[][] ans = new int[m - k + 1][];
        for (int i = 0; i < m - k + 1; i++) {
            ans[i] = new int[n - k + 1];
            for (int j = 0; j < n - k + 1; j++) {
                ans[i][j] = GetMinAbsDiff(grid, k, i, j);
            }
        }
        return ans;
    }

    public int GetMinAbsDiff(int[][] grid, int k, int startRow, int startCol) {
        int total = k * k;
        int[] values = new int[total];
        for (int i = 0; i < k; i++) {
            for (int j = 0; j < k; j++) {
                values[i * k + j] = grid[startRow + i][startCol + j];
            }
        }
        Array.Sort(values);
        int minAbsDiff = int.MaxValue;
        for (int i = 1; i < total; i++) {
            if (values[i] > values[i - 1]) {
                minAbsDiff = Math.Min(minAbsDiff, values[i] - values[i - 1]);
            }
        }
        return minAbsDiff != int.MaxValue ? minAbsDiff : 0;
    }
}

复杂度分析

  • 时间复杂度:$O(mnk^2 \log k)$,其中 $m$ 和 $n$ 分别是矩阵 $\textit{grid}$ 的行数和列数,$k$ 是给定的子矩阵边长。需要计算的子矩阵个数是 $O(mn)$,对于每个子矩阵遍历 $k^2$ 个元素存入数组的时间是 $O(k^2)$,将数组排序的时间是 $O(k^2 \log k^2) = O(k^2 \log k)$,因此每个子矩阵的计算时间是 $O(k^2 \log k)$,时间复杂度是 $O(mnk^2 \log k)$。

  • 空间复杂度:$O(k^2)$,其中 $k$ 是给定的子矩阵边长。对于每个子矩阵计算差值时需要创建长度为 $k^2$ 的数组,将数组排序的空间是 $O(\log k^2) = O(\log k)$,因此空间复杂度是 $O(k^2)$。

暴力枚举(Python/Java/C++/Go)

作者 endlesscheng
2025年6月1日 13:51

暴力枚举所有子矩形。把子矩形中的所有元素添加到一个数组 $a$ 中,然后把 $a$ 排序。排序后,不同元素之差的最小值一定来自 $a$ 的相邻元素,计算相邻不同元素之差的最小值。

本题视频讲解,欢迎点赞关注~

###py

class Solution:
    def minAbsDiff(self, grid: List[List[int]], k: int) -> List[List[int]]:
        m, n = len(grid), len(grid[0])
        ans = [[0] * (n - k + 1) for _ in range(m - k + 1)]
        for i in range(m - k + 1):
            sub_grid = grid[i: i + k]
            for j in range(n - k + 1):
                a = []
                for row in sub_grid:
                    a += row[j: j + k]
                a.sort()

                res = inf
                for x, y in pairwise(a):
                    if x < y:  # 题目要求相减的两个数必须不同
                        res = min(res, y - x)
                if res < inf:
                    ans[i][j] = res
        return ans

###java

class Solution {
    public int[][] minAbsDiff(int[][] grid, int k) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] ans = new int[m - k + 1][n - k + 1];
        int[] a = new int[k * k];
        for (int i = 0; i <= m - k; i++) {
            for (int j = 0; j <= n - k; j++) {
                int idx = 0;
                for (int x = 0; x < k; x++) {
                    for (int y = 0; y < k; y++) {
                        a[idx++] = grid[i + x][j + y];
                    }
                }
                Arrays.sort(a);

                int res = Integer.MAX_VALUE;
                for (int p = 1; p < a.length; p++) {
                    if (a[p] > a[p - 1]) { // 题目要求相减的两个数必须不同
                        res = Math.min(res, a[p] - a[p - 1]);
                    }
                }
                if (res < Integer.MAX_VALUE) {
                    ans[i][j] = res;
                }
            }
        }
        return ans;
    }
}

###cpp

class Solution {
public:
    vector<vector<int>> minAbsDiff(vector<vector<int>>& grid, int k) {
        int m = grid.size(), n = grid[0].size();
        vector ans(m - k + 1, vector<int>(n - k + 1));
        for (int i = 0; i <= m - k; i++) {
            for (int j = 0; j <= n - k; j++) {
                vector<int> a;
                for (int x = 0; x < k; x++) {
                    for (int y = 0; y < k; y++) {
                        a.push_back(grid[i + x][j + y]);
                    }
                }
                ranges::sort(a);

                int res = INT_MAX;
                for (int p = 1; p < a.size(); p++) {
                    if (a[p] > a[p - 1]) { // 题目要求相减的两个数必须不同
                        res = min(res, a[p] - a[p - 1]);
                    }
                }
                if (res < INT_MAX) {
                    ans[i][j] = res;
                }
            }
        }
        return ans;
    }
};

###go

func minAbsDiff(grid [][]int, k int) [][]int {
m, n := len(grid), len(grid[0])
ans := make([][]int, m-k+1)
arr := make([]int, k*k)
for i := range ans {
ans[i] = make([]int, n-k+1)
for j := range ans[i] {
a := arr[:0] // 避免反复 make
for _, row := range grid[i : i+k] {
a = append(a, row[j:j+k]...)
}
slices.Sort(a)

res := math.MaxInt
for p := 1; p < len(a); p++ {
if a[p] > a[p-1] { // 题目要求相减的两个数必须不同
res = min(res, a[p]-a[p-1])
}
}
if res < math.MaxInt {
ans[i][j] = res
}
}
}
return ans
}

复杂度分析

  • 时间复杂度:$\mathcal{O}((m-k)(n-k)k^2\log k)$,其中 $m$ 和 $n$ 分别为 $\textit{grid}$ 的行数和列数。
  • 空间复杂度:$\mathcal{O}(k^2)$。返回值不计入。

:考虑用定长滑动窗口 + 有序集合 + 懒删除堆,用有序集合维护窗口(子矩阵)元素,用懒删除堆维护相邻不同元素之差。添加删除的时候更新相邻不同元素之差。

这样可以做到 $\mathcal{O}((m-k)nk\log k)$,但常数比较大。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

枚举

作者 tsreaper
2025年6月1日 12:12

解法:枚举

元素互不相同的序列中,两个元素的最小差值,就是序列排序后,相邻元素差值的最小值。

枚举所有子矩阵,将子矩阵里的元素排序并去重,求相邻元素差值的最小值即可。复杂度 $\mathcal{O}((n - k)(m - k)k^2\log k)$。

参考代码(c++)

class Solution {
public:
    vector<vector<int>> minAbsDiff(vector<vector<int>>& grid, int K) {
        int n = grid.size(), m = grid[0].size();

        // 求以 (SI, SJ) 为左上角的子矩阵的不同元素最小差值
        auto calc = [&](int SI, int SJ) {
            // 将子矩阵里的元素排序并去重
            vector<int> vec;
            for (int i = 0; i < K; i++) for (int j = 0; j < K; j++) vec.push_back(grid[SI + i][SJ + j]);
            sort(vec.begin(), vec.end());
            vec.resize(unique(vec.begin(), vec.end()) - vec.begin());
            // 特殊情况:只有一种元素
            if (vec.size() == 1) return 0;
            // 求i相邻元素差值的最小值
            int ret = 1e9;
            for (int i = 1; i < vec.size(); i++) ret = min(ret, vec[i] - vec[i - 1]);
            return ret;
        };

        vector<vector<int>> ans;
        // 枚举子矩阵的左上角
        for (int i = 0; i + K <= n; i++) {
            ans.push_back({});
            for (int j = 0; j + K <= m; j++) ans.back().push_back(calc(i, j));
        }
        return ans;
    }
};

每日一题-元素和小于等于 k 的子矩阵的数目🟡

2026年3月18日 00:00

给你一个下标从 0 开始的整数矩阵 grid 和一个整数 k

返回包含 grid 左上角元素、元素和小于或等于 k子矩阵的数目。

 

示例 1:

输入:grid = [[7,6,3],[6,6,1]], k = 18
输出:4
解释:如上图所示,只有 4 个子矩阵满足:包含 grid 的左上角元素,并且元素和小于或等于 18 。

示例 2:

输入:grid = [[7,2,9],[1,5,0],[2,6,6]], k = 20
输出:6
解释:如上图所示,只有 6 个子矩阵满足:包含 grid 的左上角元素,并且元素和小于或等于 20 。

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= n, m <= 1000
  • 0 <= grid[i][j] <= 1000
  • 1 <= k <= 109

元素和小于等于 k 的子矩阵的数目

2026年3月10日 12:43

方法一:二维前缀和

思路与算法

题目要求统计包含矩阵 $\textit{grid}$ 左上角元素的所有子矩阵中,元素和不超过 $k$ 的子矩阵个数。

我们从左上角出发,按行优先顺序遍历矩阵,将当前访问位置 $(i, j)$ 视为子矩阵的右下角。为了在一次遍历中高效计算子矩阵的和,我们维护一个数组 $\textit{cols}[j]$,用于记录当前行之前第 $j$ 列所有元素的和。在遍历第 $i$ 行时,按列从左到右遍历 $j$,将 $\textit{grid}[i][j]$ 累加到 $\textit{cols}[j]$后,并将 $\textit{cols}[j]$ 累加起来,若当前累加和 $\le k$,则答案加 $1$。

代码

###C++

class Solution {
public:
    int countSubmatrices(vector<vector<int>>& grid, int k) {
        int n = grid.size(), m = grid[0].size();
        vector<int> cols(m);
        int res = 0;
        for (int i = 0; i < n; i++) {
            int rows = 0;
            for (int j = 0; j < m; j++) {
                cols[j] += grid[i][j];
                rows += cols[j];
                if (rows <= k) {
                    res++;
                }
            }
        }
        return res;
    }
};

###Python

class Solution:
    def countSubmatrices(self, grid: List[List[int]], k: int) -> int:
        n, m = len(grid), len(grid[0])
        cols = [0] * m
        res = 0
        
        for i in range(n):
            row_sum = 0
            for j in range(m):
                cols[j] += grid[i][j]
                row_sum += cols[j]
                if row_sum <= k:
                    res += 1
        
        return res

###Rust

impl Solution {
    pub fn count_submatrices(grid: Vec<Vec<i32>>, k: i32) -> i32 {
        let n = grid.len();
        let m = grid[0].len();
        let mut cols = vec![0; m];
        let mut res = 0;
        
        for i in 0..n {
            let mut row_sum = 0;
            for j in 0..m {
                cols[j] += grid[i][j];
                row_sum += cols[j];
                if row_sum <= k {
                    res += 1;
                }
            }
        }
        
        res
    }
}

###Java

class Solution {
    public int countSubmatrices(int[][] grid, int k) {
        int n = grid.length, m = grid[0].length;
        int[] cols = new int[m];
        int res = 0;
        
        for (int i = 0; i < n; i++) {
            int rows = 0;
            for (int j = 0; j < m; j++) {
                cols[j] += grid[i][j];
                rows += cols[j];
                if (rows <= k) {
                    res++;
                }
            }
        }
        
        return res;
    }
}

###C#

public class Solution {
    public int CountSubmatrices(int[][] grid, int k) {
        int n = grid.Length, m = grid[0].Length;
        int[] cols = new int[m];
        int res = 0;
        
        for (int i = 0; i < n; i++) {
            int rows = 0;
            for (int j = 0; j < m; j++) {
                cols[j] += grid[i][j];
                rows += cols[j];
                if (rows <= k) {
                    res++;
                }
            }
        }
        
        return res;
    }
}

###Go

func countSubmatrices(grid [][]int, k int) int {
    n := len(grid)
    m := len(grid[0])
    cols := make([]int, m)
    res := 0
    
    for i := 0; i < n; i++ {
        rows := 0
        for j := 0; j < m; j++ {
            cols[j] += grid[i][j]
            rows += cols[j]
            if rows <= k {
                res++
            }
        }
    }
    
    return res
}

###C

int countSubmatrices(int** grid, int gridSize, int* gridColSize, int k) {
    int n = gridSize;
    int m = *gridColSize;
    int* cols = (int*)calloc(m, sizeof(int));
    int res = 0;
    
    for (int i = 0; i < n; i++) {
        int rows = 0;
        for (int j = 0; j < m; j++) {
            cols[j] += grid[i][j];
            rows += cols[j];
            if (rows <= k) {
                res++;
            }
        }
    }
    
    free(cols);
    return res;
}

###JavaScript

var countSubmatrices = function(grid, k) {
    const n = grid.length;
    const m = grid[0].length;
    const cols = new Array(m).fill(0);
    let res = 0;
    
    for (let i = 0; i < n; i++) {
        let rows = 0;
        for (let j = 0; j < m; j++) {
            cols[j] += grid[i][j];
            rows += cols[j];
            if (rows <= k) {
                res++;
            }
        }
    }
    
    return res;
};

###TypeScript

function countSubmatrices(grid: number[][], k: number): number {
    const n: number = grid.length;
    const m: number = grid[0].length;
    const cols: number[] = new Array(m).fill(0);
    let res: number = 0;
    
    for (let i = 0; i < n; i++) {
        let rows: number = 0;
        for (let j = 0; j < m; j++) {
            cols[j] += grid[i][j];
            rows += cols[j];
            if (rows <= k) {
                res++;
            }
        }
    }
    
    return res;
}

复杂度分析

  • 时间复杂度:$O(mn)$,其中 $m$ 是 $\textit{grid}$ 的行数,$n$ 是 $\textit{grid}$ 的列数。

  • 空间复杂度:$O(n)$。

C++二位前缀和

作者 thdlrt
2024年3月3日 17:52

Problem: 100237. 元素和小于等于 k 的子矩阵的数目

思路

  • 非常标准的二位前缀和,处理之后对每个位置都可以在$O(1)$的时间完成一次查询,暴力即可

Code

###C++

class Solution {
public:
    int countSubmatrices(vector<vector<int>>& grid, int k) {
        int n=grid.size(),m=grid[0].size();
        vector<vector<int>>arr(n+1,vector<int>(m+1));
        int res=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                arr[i][j]=arr[i-1][j]+arr[i][j-1]-arr[i-1][j-1]+grid[i-1][j-1];
                if(arr[i][j]<=k)
                    res++;
            }
        }
        return res;
    }
};
❌
❌