在不使用numpy的情况下检查矩阵内的算术排序

时间:2016-11-13 03:55:15

标签: python python-3.x matrix

我只是想知道如何编写一个函数,可以确定矩阵中任何方向上是否存在任何长度(此时为4)的算术序列,如果它是“#”; s True,函数返回列表中包含4个坐标(y,x)的列表。否则,它什么都不返回。请参阅下面的测试以获得澄清。

在数学中,算术级数(AP)或算术序列是一系列数字,使得连续项之间的差异是恒定的。例如,序列5,7,9,11,13,15 ......是一个算术级数,差异为2。

P.S。对于位置,组件首先以垂直位置开始,然后以水平为0,作为两个组件的初始位置,就像在索引中一样。

这是测试函数的方法。函数下面的名称为as1。

>>> as1([[1,  10, 18,  29, 2],
        [2,   7, 5,  6, 34], 
        [21,   4, 3,  5, 2], 
        [9,   1, 6, 10, 3], 
        [16, -9, 9, 17, 4], 
        [32, -6, 0, 26, 5]])

[[0, 1],[1, 1], [2, 1], [3, 1]]

我的尝试只是成功使用了列表,而不是矩阵:

def as1(l):
    list = []
    delta = l[1] - l[0]
    for index in range(len(l) - 1):
        if (l[index + 1] - l[index] == delta):
            list.append(index)

    return list

我不知道如何为矩阵中的每个值和每个值识别长度为4的算术序列。此外,我不知道如何使函数识别并附加算术序列发生位置的2D位置。

聪明的程序员如何处理这样的问题?

欢迎任何提示。

我建议不要使用numpy,因为我在shell中安装它时遇到问题。

1 个答案:

答案 0 :(得分:0)

这是使用动态编程的解决方案。它遍历矩阵,并为每个元素更新4个可能方向的传入序列的长度。迭代完矩阵之后,它会找到最大序列并回溯以生成结果:

def as1(matrix):
    # Each element has 4 slots for incoming directions:
    # 0: x - 1
    # 1: y - 1, x - 1
    # 2: y - 1
    # 3: y - 1, x + 1
    # Each slot is a pair two numbers: difference to parent and sequence length
    cache = [[[[0, 0] for _ in range(4)] for _ in row] for row in matrix]

    def update(y_0, x_0, y_1, x_1, slot):
        if y_1 < len(matrix) and x_1 < len(matrix[y_1]):
            diff = matrix[y_0][x_0] - matrix[y_1][x_1]
            prev_diff, prev_len = cache[y_0][x_0][slot]
            if prev_diff == diff:
                length = prev_len + 1
            else:
                length = 1
            cache[y_1][x_1][slot] = [diff, length]

    # Populate working memory
    for i in range(len(matrix)):
        for j in range(len(matrix[i])):
            update(i, j, i, j + 1, 0)
            update(i, j, i + 1, j + 1, 1)
            update(i, j, i + 1, j, 2)
            update(i, j, i + 1, j - 1, 3)

    # Find coordinate & slot for maximum sequence
    y, x, slot = max(((i, j, s)
                      for i in range(len(matrix))
                      for j in range(len(matrix[i]))
                      for s in range(4)
                     ),
                     key=lambda x: cache[x[0]][x[1]][x[2]][1])

    # Backtrack to generate the result
    length = cache[y][x][slot][1]
    result = []
    if length >= 3:
        for _ in range(4):
            result.append((y, x))
            if slot == 0:
                x -= 1
            elif slot == 1:
                x -= 1
                y -= 1
            elif slot == 2:
                y -= 1
            else:
                y -= 1
                x += 1

    return list(reversed(result))

res = as1([[0,  10, 1,  1, 0],
        [1,   7, 2,  2, 1],
        [4,   4, 3,  5, 2],
        [9,   1, 4, 10, 3],
        [16, -2, 5, 17, 4],
        [25, -5, 6, 26, 5]])

print(res)

输出:

[(2, 1), (3, 1), (4, 1), (5, 1)]

它具有线性运行时间,并且将始终返回最长序列的最后4项。如果你只需要第一个长度为4的序列,那么一旦找到这样的序列就可以改进终止算法。

更新:这是一个版本,只要找到长度为4的序列就会终止:

SLOTS = [
    [0, -1],
    [-1, -1],
    [-1, 0],
    [-1, 1]
]

def as2(matrix):
    state = [[[[0, 0] for _ in range(4)] for _ in range(len(matrix[0]))] for _ in range(2)]

    def update(y, x, d_y, d_x, slot):
        if (y + d_y) >= 0 and 0 <= (x + d_x) < len(matrix[0]):
            prev_diff, prev_len = state[1+d_y][x+d_x][slot]
            diff = matrix[y+d_y][x+d_x] - matrix[y][x]
            length = prev_len + 1 if diff == prev_diff else 1
            state[1][x][slot] = [diff, length]

    for y in range(len(matrix)):
        for x in range(len(matrix[0])):
            for slot, (d_y, d_x) in enumerate(SLOTS):
                update(y, x, d_y, d_x, slot)
                if state[1][x][slot][1] == 3:
                    return [(y + d_y * i, x + d_x * i) for i in range(3, -1, -1)]

        state = state[::-1]
    return []

当应用于与第一个版本相同的输入时,输出如下:

[(0, 1), (1, 1), (2, 1), (3, 1)]