- 元素和为目标值的子矩阵数量 难度[困难]
给出矩阵 matrix 和目标值 target,返回元素总和等于目标值的非空子矩阵的数量。
子矩阵 x1, y1, x2, y2 是满足 x1 <= x <= x2 且 y1 <= y <= y2 的所有单元 matrix[x][y] 的集合。
如果 (x1, y1, x2, y2) 和 (x1’, y1’, x2’, y2’) 两个子矩阵中部分坐标不同(如:x1 != x1’),那么这两个子矩阵也不同。
示例 1:
输入:matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0
输出:4
解释:四个只含 0 的 1x1 子矩阵。
示例 2:
输入:matrix = [[1,-1],[-1,1]], target = 0
输出:5
解释:两个 1x2 子矩阵,加上两个 2x1 子矩阵,再加上一个 2x2 子矩阵。
示例 3:
输入:matrix = [[904]], target = 0
输出:0
提示:
- 1 <= matrix.length <= 100
- 1 <= matrix[0].length <= 100
- -1000 <= matrix[i] <= 1000
- -10^8 <= target <= 10^8
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法一:前缀和解
class Solution {
public int numSubmatrixSumTarget(int[][] matrix, int target) {
int m=matrix.length;
int n=matrix[0].length;
int ans=0;
int[][] sum=new int [m+1][n+1];
//求出矩阵前缀和
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+matrix[i-1][j-1];
}
}
//(i,j)作为目标矩阵的右下角,(p,q)作为目标矩阵的左上角形成目标矩阵
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
for(int p=1;p<=i;p++){
for(int q=1;q<=j;q++){
//目标矩阵的矩阵和 = target 则 ans++
if((sum[i][j]-sum[p-1][j]-sum[i][q-1]+sum[p-1][q-1])==target) ans++;
}
}
}
}
return ans;
}
}
解法二:优化枚举 + 哈希表
class Solution {
public int numSubmatrixSumTarget(int[][] matrix, int target) {
int m=matrix.length;
int n=matrix[0].length;
int ans=0;
int[][] sum=new int [m+1][n+1];
//求出矩阵前缀和
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+matrix[i-1][j-1];
}
}
//确定上下边界
for(int top=1;top<=m;top++){
for(int bot=top;bot<=m;bot++){
//用来存储已经遍历过的矩阵和
Map<Integer,Integer> map = new HashMap<>();
//用来存储当前遍历的矩阵和
int cur=0;
//在确定上下边界的情况下遍历右边界,以原矩阵左边界形成一个子矩阵
for(int r=1;r<=n;r++){
cur = sum[bot][r]-sum[top-1][r];
//如果形成的子矩阵等于target,则ans++
if(cur==target) ans++;
//如果map中存在矩阵和位x ,且满足 cur-x=target,则 ans+= map中矩阵和为x的矩阵个数
if(map.containsKey(cur-target)) ans+=map.get(cur-target);
//将当前遍历的矩阵和存入map
map.put(cur,map.getOrDefault(cur,0)+1);
}
}
}
return ans;
}
}
解法三:最大化「二分」效益
class Solution {
public int numSubmatrixSumTarget(int[][] matrix, int target) {
int m=matrix.length;
int n=matrix[0].length;
int ans=0;
int[][] sum=new int [m+1][n+1];
//求出矩阵前缀和
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+matrix[i-1][j-1];
}
}
if(m<=n){
//确定上下边界
for(int top=1;top<=m;top++){
for(int bot=top;bot<=m;bot++){
//用来存储已经遍历过的矩阵和
Map<Integer,Integer> map = new HashMap<>();
//用来存储当前遍历的矩阵和
int cur=0;
//在确定上下边界的情况下遍历右边界,以原矩阵左边界形成一个子矩阵
for(int r=1;r<=n;r++){
cur = sum[bot][r]-sum[top-1][r];
//如果形成的子矩阵等于target,则ans++
if(cur==target) ans++;
//如果map中存在矩阵和位x ,且满足 cur-x=target,则 ans+= map中矩阵和为x的矩阵个数
if(map.containsKey(cur-target)) ans+=map.get(cur-target);
//将当前遍历的矩阵和存入map
map.put(cur,map.getOrDefault(cur,0)+1);
}
}
}
}else{
for(int left=1;left<=n;left++){
for(int right=left;right<=n;right++){
Map<Integer,Integer> map = new HashMap<>();
int cur=0;
for(int bot=1;bot<=m;bot++){
cur = sum[bot][right]-sum[bot][left-1];
if(cur==target) ans++;
if(map.containsKey(cur-target)) ans+=map.get(cur-target);
map.put(cur,map.getOrDefault(cur,0)+1);
}
}
}
}
return ans;
}
}
今天这题其实和
这题的解法差不多
此文章创于本人学习时的记录,如有错误或更优解还请指出