zoukankan      html  css  js  c++  java
  • lintcode 中等题:Submatrix sum is 0 和为零的子矩阵

    给定一个整数矩阵,请找出一个子矩阵,使得其数字之和等于0.输出答案时,请返回左上数字和右下数字的坐标。

    样例

    给定矩阵

    [
      [1 ,5 ,7],
      [3 ,7 ,-8],
      [4 ,-8 ,9],
    ]
    

    返回 [(1,1), (2,2)]

    挑战

    O(n3) 时间复杂度

    解题

    直接暴露求解,时间复杂度O(N2*M2 )

    public class Solution {
        /**
         * @param matrix an integer matrix
         * @return the coordinate of the left-up and right-down number
         */
        public int[][] submatrixSum(int[][] matrix) {
            // Write your code here
            int[][] res = new int[2][2];
            int row = matrix.length;
            if(row ==0){
                return res;
            }
            int col = matrix[0].length;
            if(col ==0){
                return res;
            }
            for(int i = 0;i< row ;i++){
                for(int j = 0;j<col;j++){
                    int sum = matrix[i][j];
                    res[0][0]=i;
                    res[0][1]=j;
                    for(int n=i+1;n<row;n++){
                        for(int m=j+1;m<col;m++){
                            sum+=matrix[n][m];
                            if(sum==0){
                                res[1][0] = n;
                                res[1][1] = m;
                                break;
                            }
                        }
                    }
                }
            }
            return res;
        }
    }
    Java Code

    总耗时: 8203 ms

    在编程之美上,看到下面的方法:

    1.先去(0,0)到(i,j)内的子矩阵的部分和,和存放中点(i,j)

    2.根据上面的子矩阵,求解任意两点和为0的子矩阵

    如何求解(0,0)到(i,j)内的子矩阵之和

    (i-1,j-1) (i-1,j)
    (i,j-1) (i,j)

    如上图的子矩阵和的矩阵PS

    PS[i-1][j-1] PS[i-1][j] PS[i][j-1]是已经求出的子矩阵的和

    显然我们知道PS[i][j-1] = PS[i-1][j-1] + A[i][j-1]  这里的A是原始要求的矩阵,A[i][j-1]也就是(i,j-1)点的值

    同理:PS[i-1][j] = PS[i-1][j-1] + A[i-1][j]

    很显然:PS[i][j] = PS[i-1][j-1] + A[i-1][j] + A[i][j-1] + A[i][j]

    将上面的含有A矩阵元素的值消掉就得到下面的矩阵:

    PS[i][j] = PS[i][j-1] + PS[i-1][j] - PS[i-1][j-1]

    对于第0行和第0类,我单独处理的

    PS[0][0] = A[0][0]

    第0行:PS[0][j] =PS[0][j-1] + A[0][j]

    第0列:PS[i][0] =PS[i-1][0] + A[i][0]

    非0行非0列按照上面的迭代求解

    在求解任意两点和为0的子矩阵

    我们求的是(i,j)到(m,n)的子矩阵

    当m 或者n其中一个为0的时候单独考虑

    其他情况 m、n都是非0的时候

    要考虑 i、j是否是0的情况

    如下:

                  int sum = 0;
                            if(i==0 && j==0){
                                sum = PS[m][n]; 
                            }else if(i==0 && j!=0){
                                sum = PS[m][n] - PS[m][j-1];
                            }else if(i!=0 && j==0){
                                sum = PS[m][n] -PS[i-1][n];
                            }else{
                            sum = PS[m][n] - PS[i-1][n] - PS[m][j-1] + PS[i-1][j-1];
                            }

    这样计算的最终时间复杂度还是O(N2*M2)

    最终程序

    public class Solution {
        /**
         * @param matrix an integer matrix
         * @return the coordinate of the left-up and right-down number
         */
        public int[][] submatrixSum(int[][] matrix) {
            // Write your code here
            int[][] res = new int[2][2];
            int row = matrix.length;
            if(row ==0){
                return res;
            }
            int col = matrix[0].length;
            if(col ==0){
                return res;
            }
            // 求解0 0 到i j的部分和
            int PS[][] = new int[row][col];
            PS[0][0] = matrix[0][0];
            for(int i =1;i<row ;i++)
                PS[i][0] =PS[i-1][0] + matrix[i][0];
            for(int j =1;j<col ;j++)
                PS[0][j] =PS[0][j-1] + matrix[0][j];
            for(int i =1;i< row;i++){
                for(int j=1;j<col;j++){
                    PS[i][j] = PS[i-1][j] + PS[i][j-1] - PS[i-1][j-1] + matrix[i][j];
                }
            }
            // for(int i =0;i< row;i++){
            //     for(int j=0;j<col;j++){
                  
            //         System.out.print(PS[i][j] +" ");
            //     }
            //     System.out.println();
            // }
           //对第0行和第0列单独判断
           // 寻找i j 到 m n和为0的数组时间复杂度O(n*n*m*m)
           //对第0行和第0列单独判断
           // 第0列
            for(int i =0;i< row ;i++){
                res[0][0] = i;
                res[0][1] = 0;
                for(int j= i+1;j< row;j++){
                    if(i==0){
                        if(PS[j][0]==0){
                            res[1][0] = j;
                            res[1][1] = 0;
                            return res;
                        }
                    }
                    else if(PS[j][0]-PS[i-1][0] ==0){
                        res[1][0] = j;
                        res[1][1] = 0;
                        return res;
                    }
                }
            }
            // 第0 行
            for(int i =0;i< col ;i++){
                res[0][0] = 0;
                res[0][1] = i;
                for(int j= i+1;j< col;j++){
                    if(i==0){
                        if(PS[0][j]==0){
                        res[1][0] = 0;
                        res[1][1] = j;
                        return res;
                        }
                    }
                    else if(PS[0][j]-PS[0][i-1] ==0){
                        res[1][0] = 0;
                        res[1][1] = j;
                        return res;
                    }
                }
            }
            for(int i =0;i<row ;i++){
                for(int j=0;j<col;j++){
                    res[0][0] = i;
                    res[0][1] = j;
                    for(int m = i+1;m<row; m++){
                        for(int n = j+1;n<col;n++){
                            int sum = 0;
                            if(i==0 && j==0){
                                sum = PS[m][n]; 
                            }else if(i==0 && j!=0){
                                sum = PS[m][n] - PS[m][j-1];
                            }else if(i!=0 && j==0){
                                sum = PS[m][n] -PS[i-1][n];
                            }else{
                            sum = PS[m][n] - PS[i-1][n] - PS[m][j-1] + PS[i-1][j-1];
                            }
                            if(sum==0){
                                res[1][0] = m;
                                res[1][1] = n;
                                return res;
                                
                            }
                        }
                    }
                }
            }
            return res;
        }
    }
    Java Code

    总耗时: 7060 ms

    上面参考的是编程之美

    在九章的程序中,PS矩阵行列比原始的矩阵行列多1,在边界出来上不用那么复杂

    同时在PS矩阵中求解任意两点的子矩阵时候,利用HashMap,对PS矩阵中任意两点的差值判断是否在HashMap中,当存在的时候就是答案了

        public class Solution {
        /**
         * @param matrix an integer matrix
         * @return the coordinate of the left-up and right-down number
         */
        public int[][] submatrixSum(int[][] matrix) {
            int[][] result = new int[2][2];
            int M = matrix.length;
            if (M == 0) return result;
            int N = matrix[0].length;
            if (N == 0) return result;
            // pre-compute: sum[i][j] = sum of submatrix [(0, 0), (i, j)]
            int[][] sum = new int[M+1][N+1];
            for (int j=0; j<=N; ++j) sum[0][j] = 0;
            for (int i=1; i<=M; ++i) sum[i][0] = 0;
            for (int i=0; i<M; ++i) {
                for (int j=0; j<N; ++j)
                    sum[i+1][j+1] = matrix[i][j] + sum[i+1][j] + sum[i][j+1] - sum[i][j];
            }
            for (int l=0; l<M; ++l) {
                for (int h=l+1; h<=M; ++h) {
                    Map<Integer, Integer> map = new HashMap<Integer, Integer>();
                    for (int j=0; j<=N; ++j) {
                        int diff = sum[h][j] - sum[l][j];
                        if (map.containsKey(diff)) {
                            int k = map.get(diff);
                            result[0][0] = l;   result[0][1] = k;
                            result[1][0] = h-1; result[1][1] = j-1;
                            return result;
                        } else {
                            map.put(diff, j);
                        }
                    }
                }
            }
            return result;
        }
    }
    Java Code
  • 相关阅读:
    阿里云乌班图16配置-PHP环境(包括mysql及apache安装)
    mysql主从复制跳过错误
    64位系统下powerdesigner15连接oracle odbc
    解决“指定的服务已经标记为删除”问题
    mysql系列-安装及服务启动
    数据缓存管理
    redis-在乌班图下设置自动启动
    redis-配置文件
    redis安装
    linux-用户建立及权限分配
  • 原文地址:https://www.cnblogs.com/bbbblog/p/4945721.html
Copyright © 2011-2022 走看看