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
原文地址:https://www.cnblogs.com/theskulls/p/4945721.html