📜  计算总和可整除“k”的子矩阵(1)

📅  最后修改于: 2023-12-03 14:57:30.403000             🧑  作者: Mango

计算总和可整除"k"的子矩阵

在某些算法竞赛问题中,我们需要计算矩阵中总和可整除“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是矩阵的行数。