【问题标题】:Maximum subarray of size HxW within a big 2D bit matrix大 2D 位矩阵中大小为 HxW 的最大子数组
【发布时间】:2020-11-13 01:21:20
【问题描述】:

我有一个包含 K 个 1 的大 NxN 位数组(其他都为零)。所有非零点的坐标都是已知的 - 换句话说,这个 NxN 数组可以表示为 K 对数组,每对包含一个非零点的 x 和 y 坐标。

给定一个 HxW 大小的子矩阵,我需要将它放在我原来的 NxN 数组中,这样它就可以覆盖大多数非零点。

输入:子矩阵的高度H和宽度W

输出: xy HxW 子数组的坐标,其中包含最多的子数组

之前回答过类似的问题:Maximum subarray of size HxW within a 2D matrix 但在我的问题中,由于 N 很大,所以问题有点复杂,在我的情况下: N=60000, K

即使是位数组,创建 60000x60000 数组也会导致内存消失。这就是为什么我想出了用所有非零点表示该数组的想法:K 对的一维数组。

我能想出的一切都是超级内存和时间效率低下,我正在寻找任何不会吃掉我所有内存的解决方案。 它的含义如下:输出将是点 (4,3),因为从该点开始的 HxW 子数组包含最多的点。

【问题讨论】:

  • 如果有多个解决方案,返回哪个重要吗?
  • 不是真的,如果每次运行程序时都返回相同的解决方案会很好,但也没有必要。
  • 我认为你至少需要查看所有矩阵,所以也许 O(n²) 是你能做的更好?

标签: arrays algorithm max submatrix


【解决方案1】:

这里的算法应该是O(k<sup>2</sup>*h)(它可能被优化为O(k*h*w))并且对空间要求很轻O(k)。它的原理是,任何具有最高非零和的子矩阵必须在其左边缘有一个点(否则,在这个子矩阵的右侧可能有一个总和更高的子矩阵) .因此,为了找到最大的和,我们遍历每个非零点并找到在其左边缘具有该点的所有子矩阵,将 W 内的所有非零点求和到当前点的右侧子矩阵中的每一行。

下面是该算法的 python 实现。它首先创建每行中的点的字典,然后按所述迭代每个点,将非零点的总和存储在该行的右侧,然后基于该点计算每个子矩阵的总和。如果总和大于当前最大值,则存储该值及其位置。请注意,这使用 0 索引列表,因此对于您的示例数据,最大值为 (2, 3)

from collections import defaultdict

def max_subarray(n, nzp, h, w):
    maxsum = 0
    maxloc = (0, 0)
    # create a dictionary of points in a row
    nzpd = defaultdict(list)
    for p in nzp:
        nzpd[p[0]].append(p[1])
    # iterate over each of the non-zero points, looking at all
    # submatrixes that have the point on the left side
    for p in nzp:
        y, x = p
        pointsright = [0] * n
        for r in range(max(y-(h-1), 0), min(y+h, n)):
            # points within w to the right of this column on this row
            pointsright[r] = len([p for p in nzpd[r] if x <= p <= x+(w-1)])
        # compute the sums for each of the possible submatrixes
        for i in range(-h+1, h):
            thissum = sum(pointsright[max(y+i, 0):min(y+i+h, n)])
            if thissum > maxsum:
                maxsum = thissum
                maxloc = (y, x)
    # adjust the position in case the submatrix would extend beyond the last row/column
    maxloc = (min(n-h, maxloc[0]), min(n-w, maxloc[1]))
    # print the max sum
    print(f'{maxsum} found at location {maxloc}')

示例用法:

nzp = [(0, 6), (1, 9), (2, 3), (2, 4), (2, 5), 
       (3, 1), (3, 4), (3, 6), (4, 3), (4, 3), 
       (4, 10), (5, 5), (6, 4), (6, 8), (7, 5), 
       (8, 3), (10, 2), (10, 8), (11, 4), (11, 10)
       ]
  
max_subarray(12, nzp, 2, 4)

输出:

5 found at location (2, 3)

Demo on rextester

【讨论】:

  • 适用于中等大小的数据(尝试 N=6000),将用 C++ 重写它,我希望这会提高效率。谢谢!
  • @Igor 很酷 - 我很高兴听到它。这是一个非常有趣的问题(我确实对 Q 投了赞成票)。
猜你喜欢
  • 2017-02-17
  • 2013-01-20
  • 2012-04-16
  • 1970-01-01
  • 1970-01-01
  • 2015-03-02
  • 2022-06-14
  • 1970-01-01
相关资源
最近更新 更多