python编程动态
我最近遇到了一个困难的编程挑战,该挑战涉及如何在矩阵中获取最大或最小的和。 这类问题有多种变体,但每种挑战都相似。 以下面的三角形为例:
其中一些问题涉及网格,而不是三角形,但概念相似。 在上面的示例中,从顶部(3)移到底部,最大路径总和是多少? 这个问题之所以具有挑战性,是因为对于较大的矩阵或三角形,无法采用强力方法。 至少对我而言,自然的本能是从顶部开始,然后逐步下降。 基本上,您将通过选择从顶部到底部的最佳路径来解决此问题,如下所示:
但是,这种方法不仅需要在每个路口选择最大的数字,而且还需要将此选择与当前位置以下的选择进行比较。 例如,如果当前的最大选择是7,但是将此路径移到底部将消除相邻路径中的较大数字,则需要比较两个路径以查看哪个路径的值更大。 这样的小三角形当然是可行的,但更大的三角形并非易事。 例如,让我们假设三角形有四行,而不是四行。 不可能尝试每条路线来解决这个问题,因为总共会有2分! 如果您每秒可以检查一万亿(10 12)条路线,那么要花掉全部200亿年的时间。 因此,我着手要做的是以对任何大小的三角形都适用的方式解决三角形问题。 即使算法良好,对100行的函数进行硬编码也将非常耗时。 但是,让我们不要超越自己。
解决类似问题的方法的基本概念是从底部开始,然后逐步提高。
我们将从最下面一行开始,然后将每个数字添加到其上方的行中,如下所示:
现在,我们将使用上一步中的最大和替换倒数第二行,如下所示:
现在,我们重复步骤1,将底行添加到其上方的行中。
我们将重复步骤2,将第二行替换为最后一行中的最大和。
现在我们只剩下三个数字,我们只是从第1行和第2行中取最大的和,在这种情况下,我们剩下的是23。
现在,如前所述,我想编写一个函数来解决此问题,而不管三角形的大小如何。 这是我关于如何执行此操作的思考过程:
如果我的三角形是一个数字数组,那么我只想处理最后一个数字,倒数第二个数字,然后是它上面一行的数字。 我将找出该组的最大和,然后删除每行末尾的最后两个数字。 但是,总和最大的是,我将插入一个临时数组,并将其从当前数组中删除。 现在,我可以使用新的三个数字组重复相同的步骤,因为先前的数字已删除,而结尾的数组数字是新的。 如果在任何时候,我的最后一行的长度为0,则将最后一行替换为我创建的临时数组。 这样,无论三角形的大小如何,该功能将始终循环显示。 从视觉上看,这可能是这样:
在这一点上,当我得到2和8以及2和5的总和后,我不再需要这个组。 我的最后一行的长度为零,因此第4步将用tempArr替换最后一行:
我的想法是,一开始,我通常会拥有一个数组,但是为了简化起见,我希望每一行都是它在更大的数组容器中的自己的数组。 为了做到这一点,我首先创建一个函数,该函数采用给定的任意三角形大小,并将其分解为单独的数组。 在这种情况下,我知道我需要四行。 因此,对于较大的数组,如果给定一个较大的三角形开头,则可以更改所需的行:
arr = [3, 7, 4, 2, 4, 6, 8, 5, 9, 3]
arr2 = []
start = 0
endVar = 1
end = 1
while len(arr2) is not 4:
arr2.append(arr[start:end])
start = end
endVar = endVar + 1
end = end + endVar
基本上,只要我的数组没有4行(子数组),它就会继续执行while循环。 它从零开始,以1结束,然后将该组推入数组。 然后,新的起始组将成为最后一组的末尾。 为了确定第二组的结尾,我有一个endVar,它在每个循环中递增。 每个组的结尾将是end变量加上endVar变量。
执行之后,我应该得到一个看起来像下面的结构:
[[3], [7, 4], [2, 4, 6], [8, 5, 9, 3]]
现在,我将遍历这些并做一些魔术。 首先:
tempArr = []
while len(arr2) is not 1:
# --- Do stuff -----
打破while循环的条件是数组长度不为1。如果为1,则很明显,我找到了答案,并且循环将停止,因为该数字应为最大求和路径。 tempArr将存储每一行的最大和。
首先要弄清楚两个结尾数组元素总和中哪一个最大。 这是我的处理方式:
tempArr = []
while len(arr2) is not 1:
if arr2[-2][-1] + arr2[-1][-1] > arr2[-2][-1] + arr2[-1][-2]:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-1]
else:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-2]
在这一点上,我将数组元素的值设置在最后一行的最后一行。 现在,我可以从每个数组的末尾删除这两个元素,然后将总和推入tempArr。
tempArr = []
while len(arr2) is not 1:
if arr2[-2][-1] + arr2[-1][-1] > arr2[-2][-1] + arr2[-1][-2]:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-1]
else:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-2]
tempArr.insert(0, arr2[-2][-1])
del arr2[-1][-1]
del arr2[-2][-1]
现在,我们将在这里遇到一个问题,最终最后一行的下一个将是一个空数组,并且将破坏我们的功能。 我们只删除数组中的值,而不删除数组本身。 因此,我想添加一个条件,如果数组的长度达到零,则将完全删除该数组。
tempArr = []
while len(arr2) is not 1:
if arr2[-2][-1] + arr2[-1][-1] > arr2[-2][-1] + arr2[-1][-2]:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-1]
else:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-2]
tempArr.insert(0, arr2[-2][-1])
del arr2[-1][-1]
del arr2[-2][-1]
if len(arr2[-2]) == 0:
arr2[-1] = tempArr
del arr2[-2]
这个效果很好。 但是由于缺乏数学技能,我遇到了一个问题。 一旦数组的长度变为2,它将停止工作。 我可能还要花30分钟来尝试解决问题。 但是我很懒。 因此,我在开头添加了一条if语句来捕获错误。 如果容器数组的长度为2,则仅获取底部数组的最大值,然后将其添加到顶部数组。 然后将其保存为我创建的名为“ total”的新变量。 这应该是我最大的总和。
total = 0
tempArr = []
print arr2
while len(arr2) is not 1:
if len(arr2) == 2:
print max(arr2[-1])
print arr2[0][0]
total = max(arr2[-1]) + arr2[0][0]
if arr2[-2][-1] + arr2[-1][-1] > arr2[-2][-1] + arr2[-1][-2]:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-1]
else:
arr2[-2][-1] = arr2[-2][-1] + arr2[-1][-2]
tempArr.insert(0, arr2[-2][-1])
del arr2[-1][-1]
del arr2[-2][-1]
if len(arr2[-2]) == 0:
arr2[-1] = tempArr
del arr2[-2]
print arr2
print tempArr
print total
以下是python如何执行while循环以及循环的每次迭代中每个数组中包含的内容:
arr2 (starting): [[3], [7, 4], [2, 4, 6], [8, 5, 9, 3]]
arr2 (after first pass): [[3], [7, 4], [2, 4], [8, 5, 9]]
tempArr: [15]
arr2 (after second pass): [[3], [7, 4], [2], [8, 5]]
tempArr: [13, 15]
arr2 (after third pass): [[3], [7, 4], [10, 13, 15]]
tempArr: [10, 13, 15]
arr2 (after fourth pass): [[3], [7], [19, 10, 13]]
tempArr: [19, 10, 13]
arr2 (after fifth pass): [[3], [20, 19, 10]]
tempArr: [20, 19, 10]
max value : 20
remaining array value: 3
total: 23
无论如何,我希望这会有所帮助。 让我知道您是否有任何反馈意见。 谢谢!
翻译自: https://hackernoon.com/dynamic-programming-python-80f944aa6e6c
python编程动态