计算二维数组中的最大路径和

Calculate the Maximum Path Sum in a 2D array

在准备编码面试时,我发现了这个问题,但正在努力解决它。我非常确定需要使用递归,但我似乎无法正确使用它。

二维数组表示城市地图,其中索引处的值表示该城市的宝藏数量。数组中有些值为零(表示不能交叉)

目标:给定一个二维数组,return一个整数,表示您从一个城市到另一个城市可以收集的最大宝藏数量。

规则:

  1. 可以从数组中的任意位置开始
  2. 避免零(即不能交叉)
  3. 您一次可以在 1 个索引处上下左右移动
  4. 不同途径可能获得相同数量的宝物
  5. 一张空地图应该return 0
  6. 如果映射包含正整数以外的任何值,函数应该return -1

例如。地图 1:
[[ 3, 0, 0, 1, 2],
[ 0, 1, 4, 0, 0],
[ 5, 0, 0, 3, 3]]

最高奖励为 6 件物品 (3,3)

我尝试过的:
我尝试创建两个 for 循环来访问每个索引: 首先,我检查当前索引不为零或 -1。 如果不是,那么我将当前索引处的值添加到一个空数组,其中每个路径指示不同的位置。 IE。左 = arr[0],右 = arr[1],等等。 然后找到可能的路径并重复相同的过程 直到我的数组索引值为零(对于所有路径)。

如果有人能在 python 中提供解决方案,将不胜感激。

下面是一个使用简单递归来解决这个问题的天真的方法。但是,如果有更智能的解决方案(最好是不使用递归),我不会感到惊讶。

import numpy as np

reward_map = np.array(
    [[ 3, 0, 0, 1, 2],
     [ 0, 1, 4, 0, 0],
     [ 5, 0, 0, 3, 3]])

print("Reward map:")
print(reward_map)

# This function checks if [i,j] are valid indices for the matrix "mat"
def are_valid_idcs(mat, i, j):
    return i >= 0 and j >= 0 and i < mat.shape[0] and j < mat.shape[1]

# This is the recursive function that computes the value given a starting point
def get_cell_value(reward_map, i, j):
    if ( not are_valid_idcs(reward_map, i, j) ) or reward_map[i,j] == 0.:
        return 0.
    else:
        # If we are in a "city", we want to check the connected squares. 
        # However, from there, we do not want to walk back.
        # That's why I copy the whole map and set [i,j] = 0, meaning this coordinate has already been handled.
        # This is important. If we do not do this, the recursion will not stop.
        submap = np.array(reward_map)
        submap[i,j] = 0.
        
        # Now we compute the value of our neighbors
        value_left = get_cell_value(submap, i-1, j)
        value_right = get_cell_value(submap, i+1, j)
        value_top = get_cell_value(submap, i, j-1)
        value_bottom = get_cell_value(submap, i, j+1)
        
        # And add everything together
        return value_left + value_right + value_top + value_bottom + reward_map[i,j]


# Here, we will remember the value and the coordinates where we started
values_per_idcs = []

# Loop over all cells and compute which value we can get if we start at that point
for i in range(reward_map.shape[0]):
    for j in range(reward_map.shape[1]):
        values_per_idcs += [ [ get_cell_value(reward_map, i, j), i, j] ]

# Now we build a numpy [n,3]-array over the results, where n is the total amount of elements in the map
# The 3 components in the 1-axis correspond to [value, i, j].
values_per_idcs = np.array(values_per_idcs, dtype=np.int64)

# Check if there are negative values in the map
if np.any(reward_map < 0):
    print(f" Value is -1 (due to negative values in reward map)")
# Check if all values are integer
elif not issubclass(reward_map.dtype.type, np.integer):
    print(f" Value is -1 (due to non-integer values in reward map)")
# If the input is OK, we can output the actual results
else:
    # in the [n,3]-result-array, find the n which has the maximum value (i.e. at position 0 on axis 1)
    best = np.argmax( values_per_idcs[...,0], axis=0 )
    
    # Print the best coordinate
    print(f"Maximum value is {values_per_idcs[best,0]} at indices {values_per_idcs[best,1], values_per_idcs[best,2]}")
    
    # Plot the suggested starting point which is easier for humans to read than the coordinates
    print("Suggested start-point:")
    starter = np.zeros_like(reward_map, dtype=np.int8)
    starter[values_per_idcs[best,1], values_per_idcs[best,2]] = 1
    print(starter)

输出:

Reward map:
[[3 0 0 1 2]
 [0 1 4 0 0]
 [5 0 0 3 3]]
Maximum value is 6 at indices (2, 3)
Suggested start-point:
[[0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 0 1 0]]

适合您的练习任务:

请注意,此方法是 sub-optimal,因为它会为集群中的每个城市重新计算该集群的值。因此,如果我们的 reward_map 是一个仅包含 1[n,m] 矩阵,它将开始 所有 n*m 的完整递归 坐标,这很糟糕。对您来说,一个好的做法是通过更新递归内部的 reward_map 来解决此问题,这样 reward_map[i,j]=0. 对于递归中曾经处理过的每个 [i,j]

如果您对此回答满意,请不要忘记采纳。