无需显式迭代即可找到满足某些条件的最大矩形块
我有一些大型二维数组,例如:
1 2 3 4 5
--------------
1 | 0 1 1 1 0
2 | 0 1 1 1 0
3 | 0 1 0 1 1
4 | 0 1 0 1 1
因此,满足 ==1
的最大矩形块(按面积)从 (1,2) 开始,其尺寸为 (2,3)。
如何在不显式迭代的情况下使用 Mathematica 找到它?
注意:
为了简化您的测试,这里是我的示例之一:
matrix = ImageData@Binarize@Import@"https://i.sstatic.net/ux7tA.png"
I have a few large 2D arrays like:
1 2 3 4 5
--------------
1 | 0 1 1 1 0
2 | 0 1 1 1 0
3 | 0 1 0 1 1
4 | 0 1 0 1 1
So, the largest rectangular block (by area) satisfying ==1
starts at (1,2) and its dimensions are (2,3).
How to find it with Mathematica without iterating explicitly?
NB:
Just to ease your testing here is one of my samples:
matrix = ImageData@Binarize@Import@"https://i.sstatic.net/ux7tA.png"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是我
对 belisarius 图片使用
BitAnd
结果的尝试:从好的方面来看,这段代码似乎比 David 和 Sjoerd 的代码更快,但由于某种原因,它返回一个矩形,该矩形在两个维度上都比它们的小结果。由于差异正好是一,我怀疑某处存在计数错误,但目前我找不到它。
This is my attempt using
BitAnd
Result for belisarius' picture:
On the plus side this code seems faster than David's and Sjoerd's code, but for some reason it returns a rectangle which is one smaller in both dimensions than their result. Since the difference is exactly one I suspect a counting error somewhere but I can't find it at the moment.
好吧,只是为了证明使用函数式编程是可能的,这是我非常非常低效的强力方法:
首先,我生成所有可能的正方形的列表,按面积降序排序:
对于给定的矩形,我执行
ListCorrelate< /代码>。如果可以在矩阵中找到这一大小的空闲矩形,则结果中应该至少有一个数字与该矩形的面积相对应(假设矩阵仅包含 1 和 0)。我们使用
Max
进行检查。只要我们找不到匹配项,我们就会寻找较小的矩形(LengthWhile
会处理这个问题)。我们最终得到了适合矩阵的最大矩形数:在我的笔记本电脑上,使用贝利撒留的图像,花了 156 秒才找到第 11774+1 个矩形(+1,因为
LengthWhile
返回最后一个不适合的矩形的编号)是适合的最大矩形Well, just to prove it's possible using functional programming here's my terribly, terribly inefficient brute force approach:
First, I generate a list of all possible squares, sorted in order of descending area:
For a given rectangle I do a
ListCorrelate
. If a free rectangle of this size can be found in the matrix there should be at least one number in the result that corresponds to the area of that rectangle (assuming the matrix contains only 1's and 0's). We check that usingMax
. As long as we don't find a match we look for smaller rectangles (LengthWhile
takes care of that). We end up with the largest rectangle number that fits in the matrix:On my laptop, using belisarius' image, it took 156 seconds to find that the 11774+1th rectangle (+1 because the
LengthWhile
returns the number of the last rectangle that doesn't fit) is the largest one that will fit一个可行的选择是忽略该格言以避免迭代。
第一个例程是在给定固定宽度的情况下查找最大长度。在转置矩阵上使用它来反转这些维度。它通过分而治之的方式工作,因此速度相当快。
这是较慢的扫描代码。我们找到最大尺寸,对于其中一个尺寸,我们向下扫描,最大化另一个尺寸,直到我们知道我们无法改进最大面积。我想到的唯一效率是根据先前的下限增加下限,以便使 maxLength 调用稍微快一些。
这比 Sjoerd 的好一个数量级,只是可怕而不是可怕^2。
丹尼尔·利希布劳
A viable option is to ignore the dictum to avoid iteration.
First a routine to find the largest length given a fixed width. Use it on the transposed matrix to reverse those dimensions. It works by divide and conquer, so is reasonably fast.
Here is the slower sweep code. We find the maximal dimensions and for one of them we sweep downward, maximizing the other dimension, until we know we cannot improve on the maximal area. The only efficiency I came up with was to increase the lower bounds based on prior lower bounds, so as to make the maxLength calls slightly faster.
This is better than Sjoerd's by an order of magnitude, being only terrible and not terrible^2.
Daniel Lichtblau
我无法与 Heike 的逻辑竞争,但我可以稍微重构她的代码。
我相信这更干净,而且运行速度快了大约 20%。
I cannot compete with Heike's logic, but I can refactor her code a little.
I believe this is cleaner, and it runs about 20% faster.
您认为卷积是显式迭代吗?如果没有,那么它可以用来做你想做的事。使用简单的内核(例如 3x3 1),您可以快速将那些不连续的 1 归零。
编辑:
Mathematica 有内置的卷积函数,你可以使用它,或者自己编写:
这是伪代码(当然未经测试:)
之后剩下的是 1 的连续正方形区域。您可以进行连通区域分析并从中确定最大区域。
Do you consider convolution as iterating explicitly? If not then it can be used to do what you want. With a simple kernel, say 3x3 1s, you can quickly zero out those non-contiguous 1s.
Edit:
Mathematica has built-in convolution function, you can use that, or brew your own:
Here's the pseudo code (untested of course :)
After that what's left are the contiguous square area of 1s. You can do connected area analysis and determine the biggest area from there.