我正在努力想出一个强力(天真)解决方案,在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次,但他们谈的是最佳解决方案。我正在寻找的是一个强力解决方案及其复杂性?
答案 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 * f1
和height * f2
次(f1
和f2
是一些常数分数)。算法的其余部分需要恒定的时间,并且不依赖于问题的大小。
因此,复杂度为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。
该系列中最大的术语将接近(m / 2)(n / 2)(m / 2)(n / 2)为O(m 2 n 2 )
系列中共有m * n个术语。
因此,强力溶液的测试阶段将为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。这种技术用于在十年或两年前加速连接组件算法,并且它仍然是一种合理的方法。
无论如何,这不是你问题最直接的答案,但我希望它有所帮助。