lintcode---和为零的子矩阵

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

样例:
给定矩阵

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

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

思路讲解:
首先我们看一下题,发现是和为0的子矩阵,返回的是左上点和右下点,这样我们就可以直接利用四层循环,来循环找出不同的左上点和右下点,然后看其是否为0,如果为0,就将这两个点的坐标返回,但是如何求其之间的和呢?第一种就是暴力求解,直接循环求和,这样的方法简单,但是最后的时间估计会超时,仔细分析一下超时的原因,就是由于我们每一次重复计算了很多次的加法,例如计算matrix[x1][y1]–matrix[x2][y2],下一次计算matrix[x1+1][y1+1]–matrix[x2][y2],有重复计算了他们之间的一些加法,所以,我考虑将这些重复计算的提前算出来,这个时候我就考虑提前计算出每一个点到位置00的和,这样我们在计算某个子矩阵的时候,就可以使用其进行加减得到想要区域子矩阵的和。
举个栗子:
例如:

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

其的和矩阵sum为

[
  [1 ,6 ,13],
  [4 ,16 ,15],
  [8 ,12 ,20],
]

比如我们求(1,1)到(2,2)子矩阵的和,我们只需要将sum[2][2]-sum[0][2]-sum[2][0]+sum[0][0]这样我们就得到了我们想要的和。
这里写图片描述
上图中假如每一个区域都是该点到(0,0)的子矩阵和,所以我们要求(i,j)这个区域的和,我们就可以通过sum[i][j]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1]得到我们想要的子矩阵和。
这里还有一个需要解释的点就是关于如何求和矩阵的方法,我们通过上面类似的方法,就是sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+matrix[i][j],这样我们就不用重复计算了,这里需要将第一行和第一列特殊处理,然后就利用上面的方法求解就好了。

代码详解:

class Solution {
public:
    /*
     * @param matrix: an integer matrix
     * @return: the coordinate of the left-up and right-down number
     */
    vector<vector<int>> submatrixSum(vector<vector<int>> &matrix) {
        // write your code here
        int m=matrix.size();
        int n=matrix[0].size();
        cout<<m<<" "<<n<<endl;
        int **map=new int*[m];
        for(int i=0;i<m;i++){
            map[i]=new int[n];
        }

        map[0][0] = matrix[0][0];//生成和矩阵
        for(int i =1;i<m ;i++)
            map[i][0] =map[i-1][0] + matrix[i][0];
        for(int j =1;j<n ;j++)
            map[0][j] =map[0][j-1] + matrix[0][j];
        for(int i =1;i<m;i++){
            for(int j=1;j<n;j++){
                map[i][j] = map[i-1][j] + map[i][j-1] - map[i-1][j-1] + matrix[i][j];
            }
        }

        vector<vector<int>>res(2);
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                for(int x=i;x<m;x++){
                    for(int y=j;y<n;y++){
                        if(judge_is_zero(map,i,j,x,y)==0){
                            res[0].push_back(i);
                            res[0].push_back(j);
                            res[1].push_back(x);
                            res[1].push_back(y);
                            return res;
                        }
                    }
                }
            }
        }

    }
    int judge_is_zero(int **map,int x1,int y1,int x2,int y2){//通过和矩阵计算子矩阵的和
        int a=0,b=0,c=0,d=0;
        int a1=x1-1,a2=y1-1;
        int b1=x1-1,b2=y2;
        int c1=x2,c2=y1-1;
        int d1=x2,d2=y2;

        if(a1<0||a2<0){
            a=0;
        }else{
            a=map[a1][a2];
        }
        if(b1<0||b2<0){
            b=0;
        }else{
            b=map[b1][b2];
        }
        if(c1<0||c2<0){
            c=0;
        }else{
            c=map[c1][c2];
        }if(d1<0||d2<0){
            d=0;
        }else{
            d=map[d1][d2];
        }

        return a+d-b-c;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值