我正在创建一个游戏,其中机器人遍历一个2D阵列的地图。 2D阵列中的每个点都有一个"宝贝"那是一些硬币。我希望能够从机器人当前位置向上,向下,向右和向左添加最多4个位置的所有元素(制作"加"符号)。所以,如果我们有一个数组:
a = [[1, 2, 3, 4]
[5, 6, 7 ,8]
[9, 10, 11, 12]
[13, 14, 15, 16]
如果机器人站在a[0][0]
(在1位置),总和将返回1+2+3+4+5+9+13
。如果他站在a[1][2]
(7点),它将返回(7+3)+(8)+(5+6)+(11+15)
。但我希望它最多只返回4个地方。最后,我想找到机器人的最佳位置。
这是我的代码:
def the_place_to_be(a):
maximum = 0
for i in range(len(a)):
# Looping through columns
for j in range(len(a[i])):
# Looping through rows
sum_at_ij = a[i][j]
for x in range(i - max_steps_in_direction(a, i, "up"), i):
sum_at_ij += a[x][j]
for x in range(j - max_steps_in_direction(a[i], j, "left"), j):
sum_at_ij += a[i][x]
for x in range(i, i + max_steps_in_direction(a, i, "down")):
sum_at_ij += a[x+1][j]
for x in range(j, j + max_steps_in_direction(a[i], j, "right")):
sum_at_ij += a[i][x+1]
if sum_at_ij >= maximum:
maximum = sum_at_ij
coordinates = "(" + str(i) + ", " + str(j) + ")"
return maximum, coordinates
def max_steps_in_direction(a, idx, direction):
if direction == "up" or direction == "left":
return min(idx, 4)
elif direction == "down" or direction == "right":
return min(len(a) - idx - 1, 4)
这可能是最疯狂的时间复杂性。我正在查看整个阵列,然后循环遍历所有元素,距离机器人站立的坐标,顶部,底部,右侧和左侧方向最多四个位置。
在每一步中,我都在计算超过我的价值。有没有办法缓解这种情况?我想也许我的变量sum_at_ij
可以保存。我基本上是在多列表中的每个列表中移动。在列表中的每个点,我实际上只计算与前一个坐标不同的一些值。所以,再次说,当我移动到a[2][2]
或者坐标12时,我处于坐标a[2][3]
或坐标11处,差异在于:
sum_at_22:11 + 7 + 3 + 15 + 12 + 10 + 9
sum_at_23:12 + 8 + 4 + 16 + 11 + 10 + 9
我正在计算总共3个新值(顶部和底部的值不同)。如果这是一个8x8矩阵,则新值将是最高值,最低值,右侧是一个新值,左侧是一个较小值。如果我保存了每个值(可能在某个hashmap中),那么也许我可以找到一些公式......说实话,我不知道。也许这是一个math.stackexchange问题。
任何想法如何节省计算时间(是的,没关系)内存费用?
答案 0 :(得分:1)
我建议使用与输入矩阵完全相同的 2个辅助矩阵。
现在让第一个为行,第二个为列。行矩阵填充为:
row[i][j] = sum of(a[i][0] + a[i][1] +....a[i][j-1])
你可以通过遍历行主要顺序遍历输入数组,轻松地及时做到 O(N * N)。列矩阵填充为:
column[i][j] = sum of(a[0][j] + a[1][j] +....a[i-1][j])
您也可以通过按列主要顺序遍历输入数组,轻松地及时 O(N * N)。
现在通过遍历输入数组获得您的位置,总复杂度为:
时间复杂度= O(N * N)
空间复杂度= O(N * N)
答案 1 :(得分:1)
你在求和过程中所做的实际上是一个+形滤波器的卷积。如果你用一个调用scipy的convolve2d
函数替换你的显式循环,你可以更快地得到这个,它将为你做所有必要的循环,但不是在python中,而是在C:
import numpy as np
from scipy.signal import convolve2d
# Your original array:
a = np.asarray([[1, 2, 3, 4],
[5, 6, 7 ,8],
[9, 10, 11, 12],
[13, 14, 15, 16]])
# Building a filter that is essentially a + with arms of length 4
mask = np.zeros((2*4+1, 2*4+1))
mask[4, :] = 1
mask[:, 4] = 1
# Apply that filter to your array
sums = convolve2d(a, mask, mode="same")
# Find the maximum and its position in the sums array:
np.max(sums), np.unravel_index(np.argmax(sums), sums.shape)
最后,sums是给出原始数组中每个位置的求和过程值的数组。您只需找到最大值及其位置。
虽然复杂性可能不会比你的解决方案更好,但它仍然会快得多,因为python循环非常慢,而numpy和scipy中的很多机器都是用C / Fortran编写的,加快了计算速度
在100x100阵列上定时解决这个问题的解决方案可以提供大约的加速因子。在我的机器上40(78.7ms vs 2.06ms)。
答案 2 :(得分:1)
使用numpy slicing -
的解决方案import numpy as np
def get_sum(matrix, row, col):
# Get the sum of 4 numbers to the left
sum_left_4_numbers = matrix[row, max(col - 4, 0):col].sum()
# Get the sum of 4 numbers to the right
sum_right_4_numbers = matrix[row, col:col + 4].sum()
# Get the sum of 4 numbers above
sum_top_4_numbers = matrix[max(row - 4, 0):row, col].sum()
# Get the sum of 4 numbers below
sum_bottom_4_numbers = matrix[row + 1: row + 4, col].sum()
return sum_left_4_numbers + sum_right_4_numbers + sum_top_4_numbers + sum_bottom_4_numbers
matrix = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print get_sum(matrix, 1, 2)
# Output - 55