LintCode 405: Submatrix Sum (matrix处理经典题!)

  1. Submatrix Sum

Given an integer matrix, find a submatrix where the sum of numbers is zero. Your code should return the coordinate of the left-up and right-down number.

If there are multiple answers, you can return any of them.

Example
Example 1:

Input:
[
[1, 5, 7],
[3, 7, -8],
[4, -8 ,9]
]
Output: [[1, 1], [2, 2]]
Example 2:

Input:
[
[0, 1],
[1, 0]
]
Output: [[0, 0], [0, 0]]
Challenge
O(n3) time.

解法1:
思路:基于LintCode138. Subarray Sum。遍历i行和j行的组合,将其中的行都累加起来,然后就可以用LintCode 138里面的解法来判断是不是有某段元素累加起来等于0了。
但我感觉这题调通并不容易。主要有两个地方要注意:
1)当输入是类似
[[-1,-1]
[-1,3]]

[[-1,-1,-1]
[-1,-1,-1]
[-1,-1,8]]
这样的matrix时,必须要考虑整个矩阵,这样,返回结果的左上方点一定在第0行。
2) 还要考虑在单独某行就会出现sum为0的情况,比如说本来就有0元素,或该行连续某段和为0(即LintCode 138情形)。所以我们要考虑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) {
        int m = matrix.size();
        int n = matrix[0].size();
        
        vector<vector<int>> rowSums(m, vector<int> (n, 0));
        for (int i = 0; i < n; ++i) {
            rowSums[0][i] = matrix[0][i];
        }
        
        for (int i = 1; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                rowSums[i][j] = rowSums[i - 1][j] + matrix[i][j];
            }
        }
        
        vector<int> tempList(n, 0);
        vector<vector<int>> result(2, vector<int>(2, 0));
        for (int i = 0; i < m; ++i) {
            for (int j = i; j < m; ++j) {
                vector<int> tempResult = subArraySum(rowSums[j]);
                if (tempResult.size() != 0) { //考虑整个矩阵
                        result[0][0] = 0;
                        result[0][1] = tempResult[0];
                        result[1][0] = j;
                        result[1][1] = tempResult[1];
                        return result;
                }
                
                for (int k = 0; k < n; ++k) {
                    if (j == i) {
                        tempList[k] = rowSums[j][k];
                    } else {
                        tempList[k] = rowSums[j][k] - rowSums[i][k];    
                    }
                }
                tempResult = subArraySum(tempList);
                if (tempResult.size() != 0) {
                    if (j == i)
                        result[0][0] = i;
                    else
                        result[0][0] = i + 1;
                    result[0][1] = tempResult[0];
                    result[1][0] = j;
                    result[1][1] = tempResult[1];
                    return result;
                }
                       
            }
        }
        return vector<vector<int>>(2, vector<int>(2));
    }
    
private:
    vector<int> subArraySum(vector<int> &list) {
        int n = list.size();
        vector<int> result;
        if (n == 0) return vector<int>();
        long long sum = 0;
        
        unordered_map<long long, int> preSums; //presum, index
        for (int i = 0; i < n; ++i) {
            sum += list[i];
            if (sum == 0) return vector<int>{0, i};
            if (preSums.find(sum) != preSums.end()) {
                result.push_back(preSums[sum] + 1);
                result.push_back(i);
                break;
            }
            preSums[sum] = i;
        }
        return result;
    } 
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值