天真的方式找到1和0的矩形中的最大块

时间:2013-10-26 18:03:43

标签: algorithm

我正在努力想出一个强力(天真)解决方案,在1和0的矩形中找到1或0的最大块。我知道在O(n)时间内可以做到的最佳方法n是矩形的总大小。

1 1 0 1 0 1
1 0 0 0 1 1
1 0 0 0 1 1
1 1 0 1 1 0

在上面的矩形中,它是从大小为6的(第2行,第2列)开始的矩形。我在想这个..

  

浏览每个元素,然后通过迭代找到它所做的大小   在它的各个方向。

是暴力吗?复杂性会是什么?我正在浏览所有n元素,但后来我向所有方向迭代,那将是多少?

我知道这个问题已被问过100次,但他们谈的是最佳解决方案。我正在寻找的是一个强力解决方案及其复杂性?

3 个答案:

答案 0 :(得分:3)

您描述的算法在某种程度上看起来像这个C代码:

//for each entry
for(int x = 0; x < width; ++x)
    for(int y = 0; y < height; ++y)
    {
        char lookFor = entries[x][y];
        int area = 0;
        for(int row = y; row < height; ++row)
        {
            if(entries[x, row] != lookFor)
                break;
            for(int col = x; col < width; ++col)
            {
                if(entries[col, row] != lookFor)
                    break;
                int currentArea = (col - x + 1) * (row - y + 1);
                if(currentArea > area)
                {
                    //save the current rect
                }
            }
        }
    }

有四个嵌套循环。外部循环将完全迭代n次(n是条目数)。内部循环将平均迭代width * f1height * f2次(f1f2是一些常数分数)。算法的其余部分需要恒定的时间,并且不依赖于问题的大小。

因此,复杂度为O(n * f1 * width * f2 * height) = O(n^2),这实际上意味着“转到每个条目并从那里再次访问每个条目”,无论是否真正需要检查所有条目,或者只是增加的常量分数问题的大小。

修改

上述解释假设条目不是随机分布的,而对于较大的字段,它更有可能找到更大的同质子区域。如果不是这种情况,并且内部循环的平均迭代计数根本不依赖于字段大小(例如,对于随机分布的条目),则得到的时间复杂度为O(n)

答案 1 :(得分:0)

Brute force通常分为两个(有时是连续的)部分。第一部分是为解决问题产生所有可能的候选人。第二部分是测试它们,看它们是否真的是解决方案。

蛮力:假设你的矩形是m x n。生成大小为a x b的所有子矩形,其中a在{1..m}中,b在{1..n}中。将maximum变量设置为0.测试所有子矩形以查看它是否全为0和1。如果是,请maximum = max(maximum, size(sub-rectangle)。或者,简单地从测试较大的子矩形开始,然后转向测试较小的子矩形。一旦找到一个全0或1的子矩形,就停止。时间复杂度将是相同的,因为在两种方法的最坏情况下,您仍然必须遍历所有子矩形。

时间复杂度:

让我们计算每一步生成的子矩形的数量

有大小为1 x 1的m * n个子矩形。

有(m-1)* n个子矩形,大小为2 x 1.

有大小为1 x 2的m *(n-1)个子矩形。

有大小为2 x 2的(m-1)*(n-1)个子矩形。

...&lt;等等&gt;

有(m-(m-1))*(n-(n-1))子矩形,大小为m x n。

因此,从一个大小为m x n的较大矩形中计算大小为a x b的子矩形数的公式就是:

number_of_subrectangles_of_size_a_b = (m-a) * (m-b)

如果我们想象这些数字在算术系列中列出,我们得到

1*1 + 1*2 + ... + 1*n + 2*1 + ... + m*n

这可以考虑到:

(1 + 2 + ... + m) * (1 + 2 + ... + n)

这两个算术级数分别收敛到O(m 2 )和O(n 2 )的阶数。因此,生成m * n矩形的所有子矩形是O(m 2 n 2 )。现在我们来看看测试阶段。

在生成所有子矩形之后,测试大小为a x b的每个子矩形是全0还是全1都是O(a * b)。与上一步生成尺寸为a x b的子矩形不同,x b随着x b的减小而向上扩展,此步骤与x b的大小成比例增加。

例如:有一个大小为m x n的子矩形。但是测试该矩形是全0还是全1需要O(m * n)时间。相反,存在大小为1的m * n个子矩形。但是测试这些矩形是全是0还是全1只需要每个矩形O(1)个时间。

你最终得到的时间复杂性是这样一个系列:

O( (m-(m-1))(n-(n-1))*(mn) + (m-(m-1))(n-(n-2))*m(n-1)... + mn*(m-(m-1))(n-(n-1)) )

注意事项2。

  1. 该系列中最大的术语将接近(m / 2)(n / 2)(m / 2)(n / 2)为O(m 2 n 2

  2. 系列中共有m * n个术语。

  3. 因此,强力溶液的测试阶段将为O(mn * m 2 n 2 )= O(m < SUP> 3 名词 3 )。

    总时间复杂度为:

    O(generating) + O(testing) = O(m2n2 + m3n3) = O(m3n3)

    如果给定矩形的面积为N,我们将具有O(N 3 )时间复杂度。

答案 2 :(得分:0)

查看“连接组件”算法以获取其他想法。您作为二维值的二维数组呈现的内容看起来就像二进制黑色&amp;白色图像。一个重要的例外是在图像处理中我们通常允许连接的组件(0或1的blob)具有非矩形形状。对现有的多通道和单通道算法的一些调整应该易于实现。

http://en.wikipedia.org/wiki/Connected-component_labeling

虽然这是一个比您需要的更通用的解决方案,但您也可以运行连通组件算法来查找所有连接区域(0或1,背景或前景),然后过滤生成的组件(a.k.a.blob)。我还要提到的是,对于前景组件,最好选择“4连接”而不是“8连接”,前者意味着只允许在中心像素的上方,下方,左侧和右侧的像素处进行连接,后者意味着允许连接中心像素周围的八个像素中的任何一个。

更远的地方,对于非常大的2D阵列,它可能(可能)通过创建我们称之为“图像金字塔”的方式来帮助首先减少搜索空间,这意味着一堆逐渐变小的阵列:1 / 2每个维度(根据需要填充),1 / 4,1 / 8,依此类推。在降低分辨率的图像中可检测的矩形是非常大的图像(或2D比特阵列)中的最大矩形的良好候选者。虽然对于您正在考虑的任何情况,这可能不是最佳解决方案,但它可以扩展。当然,需要付出一些努力来确定缩放阵列/图像的成本与在原始大图像中维护相对较大的候选矩形列表的成本。

运行长度编码也可以帮助您,特别是因为您处理的是矩形而不是任意形状的连接组件。行程编码将每行表示为拉伸或“运行长度”为0或1。这种技术用于在十年或两年前加速连接组件算法,并且它仍然是一种合理的方法。

无论如何,这不是你问题最直接的答案,但我希望它有所帮助。