zoukankan      html  css  js  c++  java
  • Leetcode 304 二维区域和检索

    题目定义:

    给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1) ,右下角为 (row2, col2) 。
    
    上图子矩阵左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = (4, 3),该子矩形内元素的总和为 8。
    示例:
    给定 matrix = [
      [3, 0, 1, 4, 2],
      [5, 6, 3, 2, 1],
      [1, 2, 0, 1, 5],
      [4, 1, 0, 1, 7],
      [1, 0, 3, 0, 5]
    ]
    
    sumRegion(2, 1, 4, 3) -> 8
    sumRegion(1, 1, 2, 2) -> 11
    sumRegion(1, 2, 2, 4) -> 12
    
    

    题目解析:

    首先使用 暴力破解 直接求该区域的解,时间复杂度为O(n * m) n为矩阵的行,m为矩阵的列

    方式一(暴力破解):

    class NumMatrix {
        private int[][] matrix;
        public NumMatrix(int[][] matrix) {
            this.matrix = matrix;
        }
        
        public int sumRegion(int row1, int col1, int row2, int col2) {
            int result = 0;
            for(int i = row1; i <= row2; i++){
                for(int j = col1; j <= col2; j++){
                    result += matrix[i][j];
                }
            }
            return result;
        }
    }
    

    可以考虑使用前缀和,前缀和的意思是:假定给个一维数组是:[3, 0, 1, 4, 2], 那么从0开始统计该数组所有的前缀和为:[3,3,4,8,10],方式二在二维数组中统计所有的一维数据前缀和,然后进行累加,这样的时间复杂度缩减到了O(n)次

    在实际的编码过程中,可以创建 matrix.length +1的数组,上述的前缀和变为:[0,3,3,4,8,10]这样就不用考虑初始值为0的情况了

    方式二(一维前缀和):

    class NumMatrix {
        private int[][] sums;
    
        public NumMatrix(int[][] matrix) {
            if(matrix.length == 0 || matrix[0].length == 0)
                return;
            sums = new int[matrix.length][matrix[0].length + 1];
            for(int i = 0; i < matrix.length; i++){
                for(int j = 0; j < matrix[0].length; j++)
                    sums[i][j + 1] = sums[i][j] + matrix[i][j];
            }
        }
        
        public int sumRegion(int row1, int col1, int row2, int col2) {
            int result = 0;
            for(int i = row1; i <= row2; i++)
                result +=(sums[i][col2 + 1] - sums[i][col1]);
            return result;
        }
    }
    
    

    再进行优化,可以直接统计二维数组的前缀和,这样每次查询,只需要一次就能得到结果,时间复杂度就降到了O(1)

    其中,sums[i+1][j+1] = sums[i][j + 1] + sums[i + 1][j] - sums[i][j] + matrix[i][j];原理如下表:

    304.001.jpeg

    S(O,D)=S(O,C)+S(O,B)−S(O,A)+D

    减去 S(O, A)S(O,A) 的原因是 S(O, C)S(O,C) 和 S(O, B)S(O,B) 中都有 S(O, A)S(O,A),即加了两次 S(O, A)S(O,A),所以需要减去一次 S(O, A)S(O,A)就得到了上述的公式。

    求子矩阵的面试: sums[row2 + 1][col2 + 1] - sums[row1][col2 + 1] - sums[row2 + 1][col1] + sums[row1][col1]

    原理如下表:

    304.002.jpeg

    加上子矩形 S(O, G)S(O,G) 面积的原因是 S(O, E)S(O,E) 和 S(O, F)S(O,F) 中都有 S(O, G)S(O,G),即减了两次 S(O, G)S(O,G),所以需要加上一次 S(O, G)S(O,G),就得到了求子矩阵的公式

    方式三(二维前缀和):

    class NumMatrix {
        private int[][] sums;
        public NumMatrix(int[][] matrix) {
            if(matrix.length == 0 || matrix[0].length == 0)
                return;
            sums = new int[matrix.length + 1][matrix[0].length + 1];
            for(int i = 0; i < matrix.length; i++){
                for(int j = 0; j < matrix[0].length; j++){
                    sums[i + 1][j + 1] = sums[i][j + 1] + sums[i + 1][j]  - sums[i][j] + matrix[i][j];
                }
            }
        }
        
        
        public int sumRegion(int row1, int col1, int row2, int col2) {
            return sums[row2 + 1][col2 + 1] - sums[row1][col2 + 1] - sums[row2 + 1][col1] + sums[row1][col1];
        }
    }
    

    参考:

    https://leetcode-cn.com/problems/range-sum-query-2d-immutable/solution/ru-he-qiu-er-wei-de-qian-zhui-he-yi-ji-y-6c21/

  • 相关阅读:
    关于Python安装PIL库失败的原因
    SSH免密登录及配置完成后仍需要输入密码的解决办法
    Github+Hexo博客搭建教程(三)
    Github+Hexo博客搭建教程(二)
    Github+Hexo博客搭建教程(一)
    winform中控件的简单数据绑定
    分享一个跨线程访问控件的很实用的方法
    自定义两个控件,一个是显示图标和文字的矩形,一个是带边框的label(但是不是label)
    写一个给字符串根据长度添加换行符的处理方法
    Winform DataGridView控件在业务逻辑上的简单使用
  • 原文地址:https://www.cnblogs.com/CodingXu-jie/p/14467887.html
Copyright © 2011-2022 走看看