Algorithm 查找矩阵中具有特定属性的所有矩形区域

Algorithm 查找矩阵中具有特定属性的所有矩形区域,algorithm,complexity-theory,rectangles,Algorithm,Complexity Theory,Rectangles,给定一个可能值为1、2和null的n*m矩阵: . . . . . 1 . . . 1 . . . . . 1 . . . 2 . . . . . . . . 2 . . . 1 . . . . . 1 . . . . . . . . . . . 1 . . 2 . . 2 . . . . . . 1 我正在寻找所有块B(包含(x0,y0)和(x1,y1)之间的所有值),其: 至少包含一个“1” 不包含“2” 不是具有上述特性的另一块的子集 例如: 红色、

给定一个可能值为1、2和null的n*m矩阵:

  . . . . . 1 . .
  . 1 . . . . . 1
  . . . 2 . . . .
  . . . . 2 . . .
  1 . . . . . 1 .
  . . . . . . . .
  . . 1 . . 2 . .
  2 . . . . . . 1
我正在寻找所有块B(包含(x0,y0)和(x1,y1)之间的所有值),其:

  • 至少包含一个“1”
  • 不包含“2”
  • 不是具有上述特性的另一块的子集
例如:

红色、绿色和蓝色区域都包含一个“1”,没有“2”,并且不是较大区域的一部分。 当然,在这张图片中有超过3个这样的块。我想找到所有这些街区

找到所有这些区域的快速方法是什么


我有一个可行的蛮力解决方案,迭代所有可能的矩形,检查它们是否满足前两个标准;然后迭代所有找到的矩形,删除另一个矩形中包含的所有矩形;我可以通过先删除连续的相同行和列来加快速度。但我相当肯定有一种更快的方法。

你可以在考虑每个矩形和一个适当聪明的解决方案之间找到一个平衡点

例如,从每个
1
开始,您可以创建一个矩形,并在4个方向上逐渐向外扩展其边。当你点击2时停止,如果(a)你必须在所有4个方向上停止,并且(b)你以前没有见过这个矩形,记录这个矩形

然后回溯:您需要能够从左上角附近的
1
开始生成红色矩形和绿色矩形


不过,这种算法有一些非常糟糕的最坏情况。一个由所有
1
s组成的输入突然出现在脑海中。因此,它确实需要与其他一些聪明或对输入的一些约束结合起来。

考虑更简单的一维问题:

查找
.2.1.1…12…2..1.1..2.1..2
的所有子字符串,其中至少包含一个
1
和无
2
,并且不是此类字符串的子字符串。这可以在线性时间内解决,您只需检查两个
2
之间是否存在
1

现在,您可以轻松地将此算法应用于二维问题:

对于
1≤我≤J≤n
使用以下定律对从
i
j
的所有行求和:
+.=.
+1=1
+2=2
1+1=1
1+2=2
,并将一维算法应用于结果行


复杂性:O(n²m)。

我终于找到了一个几乎在线性时间内工作的解决方案(根据找到的区域的数量有一个小因素)。我认为这是最快的解决办法

灵感来源于这个答案:(照片也是从那里拍摄的)

首先,我逐列遍历矩阵,创建一个新的矩阵M1,测量到最后一个“1”的步数,以及一个矩阵M2,测量到最后一个“2”的步数

想象一下上图中任何灰色块中的“1”或“2”

最后我得到了M1和M2,看起来像这样:

不通过M1和M2反向,按行:

我执行以下算法:

 foundAreas = new list()

 For each row y backwards:
     potentialAreas = new List()
     for each column x:
        if M2[x,y]>M2[x-1,y]:
            add to potentialAreas: 
                new Area(left=x,height=M2[x,y],hasOne=M1[x,y],hasTop=false)
        if M2[x,y]<M2[x-1,y]:
            for each area in potentialAreas:
                 if area.hasTop and area.hasOne<area.height:
                        add to foundAreas:
                             new Box(Area.left,y-area.height,x,y)
            if M2[x,y]==0: delete all potentialAreas
            else:
                 find the area in potentialAreas with height=M2[x,y] 
                 or the one with the closest bigger height: set its height to M2[x,y]
                 delete all potentialAreas with a bigger height

            for each area in potentialAreas:
                 if area.hasOne>M1[x,y]: area.hasOne=M1[x,y]
                 if M2[x,y+1]==0: area.hasTop=true
foundAreas=新列表()
对于每行y向后:
潜在区域=新列表()
对于每个列x:
如果M2[x,y]>M2[x-1,y]:
添加到潜在区域:
新区域(左=x,高=M2[x,y],hasOne=M1[x,y],hasTop=false)

如果M2[x,y],这些块的所有边将位于图形的边缘或与“2”相邻。也许你可以做点什么。如果你在这里没有得到好的答案,你也可以问一下。这个解决方案比OP中的朴素算法糟糕得多。@Thomash:严格来说,它并不更糟,例如,对于任何没有
1
的输入,它比HugoRune的要快得多。所以问题是,我想,是否有可能确定好的情况,并有条件地使用它。当然没有,有一些特定的情况下,你的算法更好。我的直觉是,它可以在大部分
N^2*M^2
可能的矩形中有
2
的情况下工作,或者没有
1
。它的主要特点是避免了考虑那些矩形。我认为你可以避免以明显愚蠢的方式在所有4个方向上递归增加矩形,因为“先左后右”与“先右后左”是相同的。也许是我的直觉错了:-)谢谢你的建议。我不确定,但我认为这是O(n³m),因为对于给定的I和j,它已经是O(nm)。但仍然很可能比蛮力更快。@HugoRune不,对于给定的i和j,它是O(m),因为它是一维问题。你可以说它是O(nm),因为你必须计算从i到j的“和”,但事实并非如此,因为你可以重复使用i,j-1的结果。