给出一个n * m矩阵,其可能的值为1,2和null:
. . . . . 1 . .
. 1 . . . . . 1
. . . 2 . . . .
. . . . 2 . . .
1 . . . . . 1 .
. . . . . . . .
. . 1 . . 2 . .
2 . . . . . . 1
我正在寻找所有块B(包含(x0,y0)和(x1,y1)之间的所有值):
示例:
红色,绿色和蓝色区域都包含'1',没有'2',并且不是更大区域的一部分。 当然,在这张图片中有超过3个这样的块。我想找到所有这些块。
找到所有这些区域的快速方法是什么?
我有一个工作强力解决方案,迭代所有可能的矩形,检查它们是否符合前两个标准;然后迭代所有找到的矩形,删除另一个矩形中包含的所有矩形;我可以通过先删除连续相同的行和列来加快速度。但我相当确定有更快的方法。
答案 0 :(得分:1)
你可以在考虑每个矩形和一个适当聪明的解决方案之间找到它。
例如,从每个1
开始,您可以创建一个矩形,并逐渐向四个方向向外扩展其边缘。当你点击2时停止,如果(a)你必须在所有4个方向停止,并且(b)你之前没有看过这个矩形,则记录这个矩形。
然后回溯:你需要能够从左上角附近的1
开始生成红色矩形和绿色矩形。
但是,这个算法有一些非常糟糕的最坏情况。我想到了一个由所有1
组成的输入。所以它确实需要与其他一些聪明或输入的约束相结合。
答案 1 :(得分:1)
考虑更简单的一维问题:
查找.2.1.1...12....2..1.1..2.1..2
的所有子字符串,其中包含至少一个1
且不包含2
,并且不是此字符串的子字符串。这可以在线性时间内解决,您只需要检查两个1
之间是否有2
。
现在,您可以轻松地将此算法应用于二维问题:
1≤i≤j≤n
使用以下法律对i
到j
的所有行进行求和:.+.=.
,.+1=1
,.+2=2
,{{1} }},1+1=1
,1+2=2
并将一维算法应用于结果行。
复杂性:O(n²m)。
答案 2 :(得分:1)
我终于找到了几乎在线性时间内工作的解决方案(取决于找到的区域数量,这个因素很小)。我认为这是最快的解决方案。
受到这个答案的启发:https://stackoverflow.com/a/7353193/145999(图片也从那里拍摄)
首先,我按列选择矩阵,创建一个新矩阵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
now foundAreas包含具有所需属性的所有矩形。