问题:
给定一个二维数组,求子数组之和为target的子数组个数。
Example 1: Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0 Output: 4 Explanation: The four 1x1 submatrices that only contain 0. Example 2: Input: matrix = [[1,-1],[-1,1]], target = 0 Output: 5 Explanation: The two 1x2 submatrices, plus the two 2x1 submatrices, plus the 2x2 submatrix. Note: 1 <= matrix.length <= 300 1 <= matrix[0].length <= 300 -1000 <= matrix[i] <= 1000 -10^8 <= target <= 10^8
解法:
是上述题目的延展,思想一致。
一个数列:Target = Sum(i~j) =Sum(0~j)-Sum(0~i) =Sum(j)-Sum(i)
所以:Sum(i) = Sum(j)-Target
那么 直到 第j个元素:和为target的子数组个数cout(sum=target) = cout(sum=当前sum(j)-Target) 到j为止,前缀和(0~x)为(sum(j)-Target)的子数组个数。
再考虑:二维数组->降维
固定列(or行,这里我们选择列),
从内部看:对于每一组列(j,k)<第j列到第k列为一组>,幻化成单列,内部进行上面的算法操作。
★幻化成单列:单列里的每个元素=matrix[..][j]+...+matrix[..][k]=Sum(matrix[..][k])-Sum(matrix[..][j-1])
从外部看:要求的子数组,即是将每一组列看作一个整体,各自得出的子数组数,累加即可
每一组列:左右(j,k)两个bound来界定,00,01,02,03,...,0m, 11,12,13,...,1m,...,(m-1)m, mm
为了求★的Sum(matrix[..][k]),进行第一轮for循环,
1 for(i=0; i<n; i++){ 2 for(j=1; j<m; j++){ 3 matrix[i][j]+=matrix[i][j-1]; 4 } 5 }
然后,固定列,排列组合各种组列:
(每一组列:左右(j,k)两个bound来界定,00,01,02,03,...,0m, 11,12,13,...,1m,...,(m-1)m, mm)
1 for(j=0; j<m; j++){ 2 for(k=j; k<m; k++){ 3 sumhash={{0,1}}; 4 int presum=0; 5 ...... 6 } 7 } 8 }
对每一组列,遍历每个元素(row压缩为一个:matrix[..][k]-matrix[..][j-1])
累加,计算前缀和presum。并保存前缀和计数map:sumhash中。
1 for(i=0; i<n; i++){ 2 presum+=(matrix[i][k]-(j>0?matrix[i][j-1]:0)); 3 ...... 4 sumhash[presum]++; 5 }
对于到目前的 i,为止,sum=target的子数列数目= 前缀和为 当前总和-target 的前缀数组个数。
1 res+=sumhash.find(presum - target) != sumhash.end() ? sumhash[presum - target] : 0;
代码参考:
⚠️注意:不用●的写法,而使用count判断存在与否,在进行赋值,减少运算时间。
1 class Solution { 2 public: 3 int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) { 4 int i=0, j=0, k=0; 5 int n=matrix.size(), m=matrix[0].size(); 6 int res=0; 7 // |0| 1 | 2 | 3 | 8 //->|0|0+1|0+1+2|0+1+2+3|★ 9 for(i=0; i<n; i++){ 10 for(j=1; j<m; j++){ 11 matrix[i][j]+=matrix[i][j-1]; 12 } 13 } 14 unordered_map<int,int>sumhash; 15 for(j=0; j<m; j++){ 16 for(k=j; k<m; k++){ 17 sumhash={{0,1}}; 18 int presum=0; 19 // col-j ~ col-k fixed. move row 20 // cause ★, so only to see → value.(matrix[..][k]) 21 // remove 0~j-1 cols, so -matrix[..][j-1] 22 for(i=0; i<n; i++){ 23 presum+=(matrix[i][k]-(j>0?matrix[i][j-1]:0)); 24 res+=sumhash.find(presum - target) != sumhash.end() ? sumhash[presum - target] : 0; 25 //●sumhash[presum-target];//k:sum(x), v:cout(sum(x)) 26 //target=sum(i~j)=sum(j)-sum(i) 27 //sum(i)=sum(j)-target 28 //until j: cout(sum=target)=cout(sum=sum(i)) 29 sumhash[presum]++; 30 } 31 } 32 } 33 return res; 34 } 35 };