Intuition
As for brute force solution, we need to iterate every single possible submatrics and sum each submatix to see if it equals to target. This will take \(O(n^4)\) time complexity.
Now we need to think about a trick to solve it and its prefix-sum.
Approach
Prefix Sum matrix的构建
Prefix sum, 这个trick可以减少很多重复的计算,定义一个prefix_sum[i][j],
prefix_sum[i][j]= sum of all elements in the submatrix from(0,0)to(i,j)(top left to bottom right)
甚至在计算prefix_sum时,可以用到这个trick,
Hashmap的构建
首先还是要延伸一下560 subarray sum equals K中的prefix sum + hash思路for array, 这里是其2D延伸.
在一个矩阵当中,任何一个submatrix都可以由两个其它submatrix的差值来构建出来.
也就是说,任何一个submatrix的和,都可以由其它两个submatrix的和的差值来构建出来. 这也是prefix sum的基本理论. 但我们看看这两个submatix有什么要求呢?
For a matrix with (r1,c1) as top left corner and (r2,c2) as bottom right corner, 我们只能用,
- matrix 1: 以(0,c1)为左上角,(r2,c2)为右下角的matrix (大的那个)
- matrix 2: 以(r1-1,c1)为左上角,(r1,c2)为右下角的matrix (小的那个)
from collections import defaultdict
class Solution:
def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int:
# prefix_sum矩阵: 储存以(i,j)为bottom right corner, (0,0)为top left corner为定义的矩阵之和
#
ROWS,COLS = len(matrix), len(matrix[0])
prefix_sum = [[0 for _ in range(COLS)] for _ in range(ROWS)]
# O(m*n)
for r in range(ROWS):
for c in range(COLS):
top = prefix_sum[r-1][c] if r > 0 else 0
left = prefix_sum[r][c-1] if c > 0 else 0
top_left = prefix_sum[r-1][c-1] if c > 0 and r > 0 else 0
prefix_sum[r][c] = matrix[r][c] + top + left - top_left
res = 0
for r1 in range(ROWS):
for r2 in range(r1,ROWS):
# initialize an empty hashmap with base case 0 -> 1
# the hashmap count is only valid for matrix with r1, r2 锁死了row, 但是col可以变的情况
count = defaultdict(int)
count[0] = 1
for c in range(COLS):
# cur_sum:以(r1,0)为左上角,(r2,c)为右下角的matrix的值
cur_sum = prefix_sum[r2][c] - (
prefix_sum[r1-1][c] if r1 > 0 else 0
)
diff = cur_sum - target
res += count[diff]
# update accumulative sum
count[cur_sum] += 1
return res