首页 > 其他分享 >二维前缀和知识讲解+例题

二维前缀和知识讲解+例题

时间:2024-03-16 21:03:33浏览次数:26  
标签:前缀 int 矩阵 getValue 正方形 二维 grid 例题

1.二维前缀和

二维前缀和是一种数组处理技术,它在处理二维数据(如矩阵)时非常有用。它的概念源自于一维前缀和,但扩展到了两个维度。二维前缀和的主要思想是将矩阵中的每个元素与其上方和左方的元素进行累加,从而快速计算出矩阵中任意子矩阵的元素和。

定义如下:

设有一个二维矩阵 A,其大小为 m x n,即包含 m 行和 n 列。矩阵 A 的元素表示为 A[i][j],其中 i 表示行索引,j 表示列索引。

二维前缀和矩阵 P 也具有相同的大小 m x n,并且定义如下:

  • 对于第一行和第一列的元素,P[i][j] 等于 A[i][j]i = 0j = 0)。
  • 对于其他位置的元素,P[i][j] 计算为其下方元素 A[i-1][j]、左方元素 A[i][j-1] 以及左下方对角线元素 A[i-1][j-1] 的和,即 P[i][j] = A[i][j] + A[i-1][j] + A[i][j-1] - A[i-1][j-1]i > 0j > 0)。
  • 要求右下角下标为i,j的前缀和(红色框),只需用蓝色框的前缀和加上绿色框的前缀和,再减去重复部分,最后加上A[i][j]位置。

通过这种方式,我们可以快速地计算出矩阵中任意子矩阵的和,而不需要进行逐个元素的累加。这是因为对于子矩阵 (i, j, k, l)(其中 i <= kj <= l),其和可以通过以下公式计算得到:

Sum = P[k][l] - P[i-1][l] - P[k][j-1] + P[i-1][j-1]

这种技术在很多算法问题中都非常有用,特别是在需要频繁计算子矩阵和的场景中,如动态规划、图像处理和数据流问题等。通过预处理二维前缀和,可以将原本复杂度较高的计算简化,提高算法的效率。

2.例题(leetcode-1139.最大的以 1 为边界的正方形)

给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0。

示例 1:

输入:grid = [[1,1,1],[1,0,1],[1,1,1]]
输出:9
示例 2:

输入:grid = [[1,1,0,0]]
输出:1

思路

这个问题可以通过构建一个二维前缀和矩阵来高效解决。

代码中定义了一个 Solution 类,其中包含了解决这个问题的主要方法和辅助方法:

  1. largest1BorderedSquare 方法:这是公共接口方法,它接收一个二维数组 grid 作为输入,并返回最大边界正方形的边长。它首先初始化 mn 为网格的行数和列数,然后调用 build 方法来执行实际的计算。

  2. build 方法:这是私有的辅助方法,它负责构建二维前缀和矩阵,并在此基础上寻找最大的边界正方形。它首先通过嵌套循环遍历整个网格,使用 getValue 方法来计算每个元素的前缀和。然后,它检查网格的右下角元素,如果为 0,则直接返回 0,表示没有边界正方形。否则,它继续寻找最大的边界正方形。

  3. getSum 方法:这是另一个私有的辅助方法,用于计算给定的子矩阵(由坐标 a, b, c, d 确定)的元素和。它使用前缀和矩阵 grid 来快速得到子矩阵的和。

  4. getValue 方法:这也是一个私有的辅助方法,用于获取网格中位置 (i, j) 的元素值。如果索引超出范围,则返回 0。

build 方法中,代码使用了一个双层循环来遍历网格,并尝试找到最大的边界正方形。对于每个位置 (i, j),它尝试扩展一个正方形,直到正方形的边界上出现 0。在尝试扩展正方形时,它使用 getSum 方法来计算当前正方形的元素和,并与预期的和((k - 1) << 2,其中 k 是正方形的边长)进行比较。如果两者相等,说明找到了一个边界正方形,并且更新最大边长 ans

最后,build 方法返回最大边界正方形的边长的平方,这是因为题目要求的是边长,而不是面积。

整体上,这段代码通过构建和利用二维前缀和矩阵,以及一系列的边界检查和子矩阵和计算,高效地解决了寻找最大边界正方形的问题。

3.代码

class Solution {
    public int m;
    public int n;

    public int largest1BorderedSquare(int[][] grid) {
        m = grid.length;
        n = grid[0].length;
        return build(grid);
    }

    public int build(int[][] grid) {
        //获取前缀和
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                grid[i][j] = getValue(i - 1, j, grid) + getValue(i, j - 1, grid) - getValue(i - 1, j - 1, grid) + getValue(i, j, grid);
            }
        }
        if (grid[m - 1][n - 1] == 0) {
            return 0;
        }
        int ans = 1;
        for (int a = 0; a < m; a++) {
            for (int b = 0; b < n; b++) {
                //左上角遍历
                for (int c = a + ans, d = b + ans, k = ans + 1; c < m && d < n; c++, d++, k++) {
                    if (getSum(a, b, c, d, grid) - getSum(a + 1, b + 1, c - 1, d - 1, grid) == ((k - 1) << 2)) {
                        ans = k;
                    }
                }
            }
        }
        return ans * ans;
    }

    public int getSum(int a, int b, int c, int d, int[][] grid) {
        if (a > c) return 0;
        return grid[c][d] - getValue(c, b - 1, grid) - getValue(a - 1, d, grid) + getValue(a - 1, b - 1, grid);
    }

    public int getValue(int i, int j, int[][] grid) {
        return i < 0 || j < 0 ? 0 : grid[i][j];
    }
}

标签:前缀,int,矩阵,getValue,正方形,二维,grid,例题
From: https://blog.csdn.net/qq_47778153/article/details/136716359

相关文章

  • 节点异常检测-二维高斯分布
    所以一个样本是一个椭圆曲线吗?不完全是这样。在二维高斯分布的上下文中,单个样本是分布中的一个点,而不是一个椭圆曲线。椭圆曲线实际上表示的是等高线,也就是概率密度函数在不同值下的轮廓线。每条椭圆曲线上的点具有相同的概率密度,这些椭圆反映了数据的分布特性,如集中趋势和变异情......
  • 【C++算法模板】图论-拓扑排序,超详细注释带例题
    文章目录0)概述1)Kahn算法1:数据结构2:建图3:Kanh算法2)DFS染色1:数据结构2:建图3:DFS3)算法对比【例题】洛谷B3644推荐视频链接:D01拓扑排序0)概述给定一张有向无环图,排出所有顶点的一个序列A......
  • KMP字符串(解释+例题)
    题目描述:  思路: 数据结构KMP算法配图详解(超详细)_kmp算法流程图-CSDN博客AcWing831.字符串查找---用16幅图从暴力一步步优化到KMP-AcWing推荐以上两篇大佬的文章kmp算法步骤(p子串和s串下标从1开始):1、kmp匹配过程首先需要了解什么是前缀和后缀(只针对p子串去......
  • Java中二维数组全部赋成同一个值
    有以下几种方法可以将二维数组全部赋成同一个值:1. 使用双重循环遍历二维数组,逐个元素赋值。int[][]arr=newint[3][3];intvalue=5;for(inti=0;i<arr.length;i++){for(intj=0;j<arr[i].length;j++){arr[i][j]=value;}}2. 使用Arrays.......
  • 动态规划背包问题(01、二维、完全背包)
    背包问题01背包dfs#include<bits/stdc++.h>usingnamespacestd;constintN=1009;intn,m,v[N],w[N];intdfs(intx,intspV){//当前枚举到哪个物品,背包剩余容量 if(x>n)return0; elseif(spV<v[x])returndfs(x+1,spV); elsereturnmax(dfs(x+1,spV),dfs(x+......
  • 14. 最长公共前缀c
    char*longestCommonPrefix(char**strs,intstrsSize){intindex=1,min=INT_MAX;if(strsSize==1)returnstrs[0];while(index<strsSize){inti=0;while(strs[index-1][i]!=0&&strs[index][i]!=0&&strs[index-1][......
  • 二维逆运动学 – 代码
    介绍在本系列的前一部分中,我们讨论了具有两个自由度的机械臂的反向运动学问题;如下图所示。在这种情况下,机械臂的长度和 通常是已知的。如果我们必须到达的点是 ,那么配置就变成了一个三角形,其中所有边都是已知的。然后,我们推导出了角度和的方程,它控制着机械臂关节的旋转:(1......
  • 稀疏数组与二维数组之间的转换
    稀疏数组介绍:稀疏数组:当一个数组中大部分元素为同一个值时,就可以考虑使用稀疏数组来保存数据节省空间。稀疏数组的原理:1)稀疏数组一共三列,第一行的第一列保存原二维数组的行数,第一行第二列保存原二维数组的列数,第一行第三列保存原二维数组非0数据的个数;2)稀疏数组一共有【原二维......
  • 二维逆运动学 – 数学
    如果您已经关注此博客一段时间,您可能已经注意到一些反复出现的主题。逆向运动学绝对是其中之一,我已经专门写了一整套关于如何将其应用于机械臂和触手的系列文章。如果您还没有读过它们,请不要担心:这个新系列将是独立的,因为它从一个新的角度回顾了逆运动学的问题。您可以在此处阅......
  • LeetCodeHot100 73. 矩阵置零 54. 螺旋矩阵 48. 旋转图像 240. 搜索二维矩阵 II
    73.矩阵置零https://leetcode.cn/problems/set-matrix-zeroes/description/?envType=study-plan-v2&envId=top-100-likedpublicvoidsetZeroes(int[][]matrix){inttop=0,bottom=matrix.length,left=0,right=matrix[0].length;int[][]flag......