1074. 元素和为目标值的子矩阵数量

1074. 元素和为目标值的子矩阵数量

1074. 元素和为目标值的子矩阵数量

我的思路

暴力枚举

确定矩形的四个边界: t o p , b o t t o m , l e f t , r i g h t top, bottom, left, right top,bottom,left,right, 求该区域内数字的和 s u m sum sum,判断 s u m sum sum 和 t a r g e t target target 的关系。

显然,该算法的时间复杂度为: O ( n 4 ⋅ n 2 ) O(n^4 \cdot n^2) O(n4⋅n2),确定四个边界需要 O ( n 4 ) O(n^4) O(n4), 求和需要 O ( n 2 ) O(n^2) O(n2)。

会TLE。

想个办法降低时间复杂度

如果数组只有一维呢?按照上述思路,确定边界需要 O ( n 2 ) O(n^2) O(n2),求和需要 O ( n ) O(n) O(n),共需要 O ( n 3 ) O(n^3) O(n3)。

求和的时间复杂度可以省掉,如果我们先对数组 预处理,将数组变成 前缀和 的形式,设前缀和的数组为 S S S,那么,求和可以在 O ( 1 ) O(1) O(1) 的时间复杂度内实现,总的时间复杂度变成了 O ( n + n 2 ) O(n + n^2) O(n+n2), 也就是 O ( n 2 ) O(n^2) O(n2)。

有没有什么办法,把 O ( n 2 ) O(n^2) O(n2) 变成 O ( n ) O(n) O(n) 呢?

上述 O ( n 2 ) O(n^2) O(n2) 的思路,用数学语言来解释就是: ∑ 0 ≤ i < j ≤ n − 1 ( S j − S i = t a r g e t ) \sum_{0\le i \lt j \le n-1}(S_j - S_i = target) ∑0≤i<j≤n−1​(Sj​−Si​=target), 当我们遍历到 j j j 的时候,因为 i < j i \lt j i<j, 那么每一个 S i S_i Si​ 的大小这一信息我们是可以知晓的。

我们用一个unordered_map<int, int> 存放 S i S_i Si​ 和它对应的数量,这样,我们就可以使用一层循环,遍历 j j j,我们每次查找unordered_map中键为 S j − t a r g e t S_j -target Sj​−target 的, 将该值加入到结果上。

这样,只需要遍历一次即可解决一维的问题。(其实一维的情况就是560. 和为K的子数组的思路)

对于二维

降维,我们枚举上下边界 t o p , b o t t o m ( t o p ≤ b o t t o m ) top, bottom(top \le bottom) top,bottom(top≤bottom),确定 t o p top top 后,枚举 b o t t o m bottom bottom, 将列向量的元素累次相加,这样便可以将二维降维到一维。

AC代码

class Solution {
public:
    int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) {
        int m = matrix.size();  // 行大小
        int n = matrix[0].size();   // 列大小

        int ret = 0;    // 返回值

        for (int x = 0; x < m; x ++){   // 枚举上边界
            vector<int> tmp(n, 0);  // 数组用于存放martix[x:y]的列向量相加的和
            for (int y = x; y < m; y ++){   // 枚举下边界
                for (int k = 0; k < n; k ++){   // 将当前的matrix[y]的列累加到tmp上。
                    tmp[k] += matrix[y][k];
                }
                // 一维情况处理
                unordered_map<int, int> umap;  
                umap[0] = 1;    // 初始值,可以模拟获得
                int sum = 0;
                for (int i = 0; i < n; i ++){
                    sum += tmp[i];
                    if (umap.find(sum - target) != umap.end()){
                        ret += umap[sum-target];
                    }
                    umap[sum] += 1;
                }
            }
        }
        return ret;
    }
};

时间复杂度: O ( m 2 ⋅ n ) O(m^2 \cdot n) O(m2⋅n),实际的为 O ( m 2 ⋅ ( n + n ) ) O(m^2 \cdot (n + n)) O(m2⋅(n+n)),看循环层数即可。
空间复杂度: O ( n ) O(n) O(n),需要使用tmpumap


2021.10.5 10:45

今天是国庆假期的第5天。前三天在宿舍当了三天宅男,玩了三天的的王者荣耀。昨天毅然来到天际大厦学习,决定摆脱自甘堕落的行为。

9月29号去玉泉校医院看了左耳流不明液体的病症,总共49元,医保后14元。用左氧氟沙星滴耳液浴耳、糠酸莫米松软膏涂耳几日后,便觉得痊愈了。

昨日本想到晚上八点归的,奈何下午四点双耳便奇痒难耐,于是乎便早早回去用药了。

今日便又觉得痊愈了。

现在写杂感,咋感觉像是在写流水账?

流水账就流水账吧,有记录的日子,就算是流水账,某年某月突然看到,或许会感慨一下。

上一篇:ios socket编程


下一篇:什么是Spring Profiles以及如何使用