更好的largestPlus算法

时间:2017-05-01 17:33:08

标签: python algorithm

问题是在矩阵中找到最大的+(加号):

“给定一个只包含字符'0'和'1'的矩阵,找到由1组成的最大加号(+)并返回其等级。在这种情况下,Rank表示加号边缘的长度为了成为有效的加号,边缘的长度必须相等。“

我目前的算法如下。基本上它通过大小为n的矩阵,三次。首先,它通过它并确定其左侧/上方1s的值。第二遍确定向右/向下1s的值。第三个比较生成的4个矩阵并找到最小值。这些值的最大值就是答案。

我想知道如何优化算法。矩阵的长度可以达到1000x1000。有没有办法通过一次矩阵来确定答案?如果是这样,怎么办呢。或者是否有更好的方法来确定与此完全不同的答案?

def biggestPlus(matrix):
    def get_left_up():
        dp_left = [[-1 for _ in row] for row in matrix]
        dp_up = [[ -1 for _ in row ] for row in matrix ]

        for y, row in enumerate(matrix):
            for x, val in enumerate(row):
                if val == '1':
                    #####FOR DP_LEFT
                    if x != 0:
                        dp_left[y][x] = dp_left[y][x-1] + 1
                    else:
                        dp_left[y][x] = 0

                    #####FOR DP_UP
                    if y != 0:
                        dp_up[y][x] = dp_up[y-1][x] + 1
                    else:
                        dp_up[y][x] = 0

        return dp_left, dp_up

    def get_right_down():
        dp_right = [[-1 for _ in row] for row in matrix]
        dp_down = [[-1 for _ in row] for row in matrix]

        for y in range(len(matrix)-1,-1,-1):
            row = matrix[y]
            for x in range(len(row) - 1, -1, -1):
                val = matrix[y][x]
                if val == '1':
                    #####FOR DP_RIGHT
                    if x < len(row)-1:
                        dp_right[y][x] = dp_right[y][x + 1] + 1
                    else:
                        dp_right[y][x] = 0

                    #####FOR DP_DOWN
                    if y < len(matrix)-1:
                        dp_down[y][x] = dp_down[y + 1][x] + 1
                    else:
                        dp_down[y][x] = 0

        return dp_right, dp_down

    def getBiggestPlus(dp_left,dp_up,dp_right,dp_down):
        #####GET MIN OF 4 MATRICES
        result = 0

        for y, row in enumerate(dp_left):
            for x, val in enumerate(row):
                minimum = min(dp_left[y][x],dp_down[y][x],dp_right[y][x],dp_up[y][x])
                result = max(result,minimum)         #####ANSWER IS THE MAX

        return result

    dp_left, dp_up = get_left_up()
    dp_right, dp_down = get_right_down()
    return getBiggestPlus(dp_left,dp_up,dp_right,dp_down)

示例输入:

matrix =   ["0110010",
            "1010101",
            "1111111",
            "0010000",
            "0000000"]
print("Answer:", biggestPlus(matrix))

1 个答案:

答案 0 :(得分:0)

在N行的方阵中,边长 n +必须具有长度 2n + 1 的水平部分,并且该部分无法从 n 行上方或 N - n 行下方开始,否则垂直边缘将不适合。

这个最大的+只能放在矩阵的正中心。

我会开始扫描水平线的矩阵,并为它们寻找匹配的垂直线。考虑到剩余的垂直空间,我有一个变量 k 用于我仍然可以找到的最大加边。我从中间开始, k = N / 2

在每一步中,我都会寻找1 s的横向延伸长度不超过 2k + 1 ;可以有几行。对于他们每个人,我会寻找一个匹配的垂直,扫描中心的列。

寻找最大值的常见想法适用;保持最知名的结果,如果发现更好的结果,请更换。如果 k 变得小于最佳已知结果,则停止是有意义的,并忽略任何小于它的水平延伸。

获得最佳性能的技巧是并行地执行两次扫描,一次向上扫描,一次向下扫描。它们也可以按顺序运行,但是算法可能需要进行完全向上扫描,例如,什么都没有,然后在中间附近找到一个大的加号。通过锁步执行,最快的发现是最快的。

编码取决于你,但我写的第一个函数是:

def find_horizontal_stretches(matrix, line, no_shorter_than=1):  
  """Returns a list of stretches as [(start, length),..],
     each no shorter than indicated.
  """

def has_vertical_stretch(matrix, line, column, size):
  """Returns True iff a column of 1s of given size is present
     at given column, and is centered at given line."""