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),需要使用tmp
和umap
。
2021.10.5 10:45
今天是国庆假期的第5天。前三天在宿舍当了三天宅男,玩了三天的的王者荣耀。昨天毅然来到天际大厦学习,决定摆脱自甘堕落的行为。
9月29号去玉泉校医院看了左耳流不明液体的病症,总共49元,医保后14元。用左氧氟沙星滴耳液浴耳、糠酸莫米松软膏涂耳几日后,便觉得痊愈了。
昨日本想到晚上八点归的,奈何下午四点双耳便奇痒难耐,于是乎便早早回去用药了。
今日便又觉得痊愈了。
现在写杂感,咋感觉像是在写流水账?
流水账就流水账吧,有记录的日子,就算是流水账,某年某月突然看到,或许会感慨一下。