📅  最后修改于: 2023-12-03 14:57:30.403000             🧑  作者: Mango
在某些算法竞赛问题中,我们需要计算矩阵中总和可整除“k”的子矩阵的数量。一个典型的应用是LeetCode第560题“Subarray Sum Equals K”。
下面介绍两种算法:前缀和+哈希表 和 前缀和+二分查找。
这是一种基于前缀和和哈希表的算法,时间复杂度为O(n),其中n是矩阵中元素的个数。具体思路是:对于每个列的左右边界,计算出该列之间所有行的数字和能否被k整除。如果不能,那么更新一下哈希表,否则我们需要计算总和可整除"k"的子矩阵数量。时间复杂度为O(n)。
def sub_array_sum(matrix, k):
m, n = len(matrix), len(matrix[0])
count, prefix = 0, [0] * m
for left in range(n):
prefix = [0] * m
for right in range(left, n):
for i in range(m):
prefix[i] += matrix[i][right]
h = {0: 1}
total = 0
for i in range(m):
total = (total + prefix[i]) % k
count += h.get(total, 0)
h[total] = h.get(total, 0) + 1
return count
时间复杂度:O(n),其中n是矩阵中元素的个数。
空间复杂度:O(m),其中m是矩阵的行数。
这是一种基于前缀和和二分查找的算法,时间复杂度为O(nlog n)。具体思路是:对于每个列的左右边界,计算出该列之间所有行的数字和并把这些数字和保存在数组sums[i]中。接下来,对于任意两个下标i和j(i<j),如果sums[i]和sums[j]模k相等,那么所有介于i和j之间的下标k,sums[i+1]+…+sums[k]和sums[j+1]+…+sums[k]的模k也相等。因此,我们可以把数组sums模k的值放在一个哈希表中。接下来,对于任意两个下标i和j(i<j),如果sums[j]-sums[i]在哈希表中存在,那么就会有一个或多个子数组的总和是可被k整除的。使用这种方法,每个列都会被处理一次,从而总复杂度为O(nlog n)。注意:如果k是负数,那么需要在代码中进行一些调整。
def sub_array_sum(matrix, k):
m, n = len(matrix), len(matrix[0])
count, prefix, sum_set = 0, [0] * m, set()
for left in range(n):
prefix = [0] * m
for right in range(left, n):
sum_set.add(0)
cur_sum = 0
for i in range(m):
prefix[i] += matrix[i][right]
cur_sum += prefix[i]
mod = cur_sum % k
count += sum_set.count(mod)
sum_set.add(mod)
return count
时间复杂度:O(n*log n),其中n是矩阵中元素的个数。
空间复杂度:O(m),其中m是矩阵的行数。