在0-1阵列中找到矩形坐标的有效方法

时间:2017-01-07 03:07:41

标签: python arrays algorithm numpy

假设我有一个0' s和1的MxN矩阵。它可能稀疏也可能不稀疏。

我想要一个函数来有效地找到数组中的矩形,其中矩形是指:

  

一组4个元素,它们都是创建a的4个角的1个元素   矩形,使得矩形的边与其正交   阵列轴。换句话说,矩形是一组4个1的元素   坐标[行索引,列索引]如下:[r1,c1],[r1,c2],   [r2,c2],[r2,c1]。

E.g。此设置有一个矩形:

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

对于给定的MxN数组,我想要一个Python函数F(A),它返回一个子数组的数组L,其中每个子数组是矩形一角的坐标对(并包含矩形的所有4个角) )。对于阵列的相同元素是多个矩形的角的情况,可以复制这些坐标。

到目前为止,我的想法是:

1)找到数组中每个直角三角形顶点的坐标

2)检查每个直角三角形顶点坐标,看它是否是矩形的一部分

步骤1)可以通过找到那些1的元素并且在列总和> = 2的列中,并且在行和>&2的行中来实现。

然后,步骤2)将遍历确定为直角三角形的顶点的每个坐标。对于给定的直角三角形坐标对,它将遍历该列,查看该列中1)的每个其他直角三角形坐标。对于列中任何一对2个直角三角形点,它将检查哪一行具有较小的行总和,以便知道哪一行将更快地迭代。然后它将迭代该行中的所有直角三角形列坐标,并查看另一行是否在该列中也有一个直角三角形点。如果是这样,那4个点形成一个矩形。

我认为这会有效,但会有重复,总的来说这个程序似乎是合理的计算密集型。有哪些更好的方法可以检测0-1阵列中的矩形角?

2 个答案:

答案 0 :(得分:0)

这是我的头顶,并在洛杉矶国际机场停留5小时。以下是我的算法:

第1步:搜索所有行至少两个

 |  0 0 0 1 0 1 0
 |  0 0 0 0 0 0 0
 |  0 1 0 0 0 0 0
\|/ 1 0 0 1 0 1 0
    0 0 0 0 0 0 0
    0 0 0 1 0 0 1

输出:

 -> 0 0 0 1 0 1 0
    0 0 0 0 0 0 0
    0 1 0 0 0 0 0
 -> 1 0 0 1 0 1 0
    0 0 0 0 0 0 0
 -> 0 0 0 1 0 0 1

第2步:对于每一行一对,获取与其对应的列中的一个的索引,让我们说第一行行:

 -> 0 0 0 1 0 1 0

您检查以下列中的内容:

       |   | 
      \|/ \|/

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

第3步:如果两个索引匹配;返回所有四个指数。这可以很容易地访问,因为您知道所有步骤中的行和索引。在我们的例子中,第3列,第5列的搜索将返回3,假设您从0开始索引。所以我们得到以下的指标:

 0 0 0 ->1 0 ->1 0
 0 0 0 0 0 0 0
 0 1 0 0 0 0 0
 1 0 0 ->1 0 ->1 0
 0 0 0 0 0 0 0
 0 0 0 1 0 0 1

第4步:对所有对重复

算法复杂度 我知道您需要搜索columns * rows * number of pairs,但您始终可以使用哈希映射来优化搜索O(1)。这将使复杂性与对的数量相关联。如有任何问题,请随时发表评论。

答案 1 :(得分:0)

这是一个类似于@PseudoAj解决方案的Python实现。它将在构造dict时从顶部开始处理行,其中键是x坐标,值是各自y坐标的集合。

对于以下步骤的每一行:

  1. 从当前行
  2. 生成一个x坐标列表,其中包含1秒
  3. 如果列表长度小于2,则移至下一行
  4. 对所有坐标对left, right进行迭代,其中left < right
  5. 对于每个坐标对,从包含已处理行的dict开始交叉
  6. 对于交叉点中的每个y坐标,添加矩形到结果
  7. 最后使用当前行的坐标
  8. 更新dict

    代码:

    from collections import defaultdict
    from itertools import combinations
    
    arr = [
        [0, 0, 0, 1, 0, 1, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 1, 0, 0, 0, 0, 0],
        [1, 0, 0, 1, 0, 1, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 1, 0, 0, 1]
    ]
    
    # List corner coords
    result = []
    
    # Dict {x: set(y1, y2, ...)} of 1s in processed rows
    d = defaultdict(set)
    
    for y, row in enumerate(arr):
        # Find indexes of 1 from current row
        coords = [i for i, x in enumerate(row) if x]
    
        # Move to next row if less than two points
        if len(coords) < 2:
            continue
    
        # For every pair on this row find all pairs on previous rows
        for left, right in combinations(coords, 2):
            for top in d[left] & d[right]:
                result.append(((top, left), (top, right), (y, left), (y, right)))
    
        # Add coordinates on this row to processed rows
        for x in coords:
            d[x].add(y)
    
    print(result)
    

    输出:

    [((0, 3), (0, 5), (3, 3), (3, 5))]