简体   繁体   English

试图了解我在 python 中找到的三角形最大路径总和的代码是如何工作的

[英]Trying to understand how this code I found for triangle max path sum in python works

So take a triangle formatted as a nested list.所以取一个格式化为嵌套列表的三角形。 eg例如

t =  [[5],[3, 6],[8, 14, 7],[4, 9, 2, 0],[9, 11, 5, 2, 9],[1, 3, 8, 5, 3, 2]]

and define a path to be the sum of elements from each row of the triangle, moving 1 to the left or right as you go down rows.并将路径定义为三角形每一行的元素之和,在 go 向下行时向左或向右移动 1。 Or in python the second index either stays the same or we add 1 to it.或者在 python 中,第二个索引要么保持不变,要么我们将其加 1。

a_path = [t[0][0],[t[1][1]],t[2][1],t[3][1],t[4][2],t[5][3]] = [5, 6, 14, 9, 5,5] is valid
not_a_path = [t[0][0],[t[1][0]],t[2][2],t[3][1],t[4][0],t[5][4]] = [5, 3, 7, 9, 9, 3] is not valid

For a triangle as small as this example this can obviously be done via brute force.对于像这个例子一样小的三角形,这显然可以通过蛮力来完成。 I wrote a function like that, for a 20 row triangle it takes about 1 minuite.我像这样写了一个 function,对于一个 20 行的三角形,大约需要 1 分钟。 I need a function that can do this for a 100 row triangle.我需要一个可以为 100 行三角形执行此操作的 function。 I found this code on https://rosettacode.org/wiki/Maximum_triangle_path_sum#zkl and it agrees with all the results my terrible function outputs for small triangles I've tried, and using %time in the console it can do the 100 line triangle in 0 ns so relatively quick.我在https://rosettacode.org/wiki/Maximum_triangle_path_sum#zkl上找到了这段代码,它与我尝试过的小三角形的糟糕 function 输出的所有结果一致,并且在控制台中使用 %0time 它可以执行第 1 行0 ns 内的三角形相对较快。

def maxPathSum(rows):
    return reduce(
        lambda xs, ys: [
            a + max(b, c) for (a, b, c) in zip(ys, xs, xs[1:])
        ],
        reversed(rows[:-1]), rows[-1]
    )

So I started taking bits of this, and using print statements and the console to work out what it was doing.所以我开始接受这个,并使用打印语句和控制台来计算它在做什么。 I get that reversed(rows[:-1]), rows[-1] is reversing the triangle so that we can iterate from all possible final values on the last row through the sums of their possible paths to get to that value, and that as a,b,c iterate: a is a number from the bottom row, b is the second from bottom row, c is the third from bottom row.我得到了reversed(rows[:-1]), rows[-1]正在反转三角形,以便我们可以从最后一行上所有可能的最终值通过它们可能路径的总和进行迭代以达到该值,并且作为 a,b,c 迭代:a 是底行的数字,b 是底行的第二个,c 是底行的第三个。 And as they iterate I think a + max(b,c) seems to sum a with the greatest number on b or c, but when I try to find the max of either two lists or a nested list in the console the list returned seems completely arbitrary.当他们迭代时,我认为a + max(b,c)似乎将 a 与 b 或 c 上的最大数字相加,但是当我尝试在控制台中找到两个列表或嵌套列表的最大值时,返回的列表似乎完全任意。

ys = t[-1]
xs = list(reversed(t[:-1]))
for (a, b, c) in zip(ys, xs, xs[1:]):
    print(b)
    print(c)
    print(max(b,c))
    print("")

prints印刷

[9, 11, 5, 2, 9]
[4, 9, 2, 0]
[9, 11, 5, 2, 9]

[4, 9, 2, 0]
[8, 14, 7]
[8, 14, 7]

[8, 14, 7]
[3, 6]
[8, 14, 7]

[3, 6]
[5]
[5]

If max(b,c) returned the list containing max(max(b),max(c)) then b = [3, 6], c = [5] would return b, so not that.如果 max(b,c) 返回包含 max(max(b),max(c)) 的列表,则 b = [3, 6], c = [5] 将返回 b,所以不是这样。 If max(b,c) returned the list with the greatest sum, max(sum(b),sum(c)), then the same example contradicts it.如果 max(b,c) 返回总和最大的列表,max(sum(b),sum(c)),那么同一个示例与之矛盾。 It doesn't return the list containg minimum value or the one with the greatest mean, so my only guess is that the fact that I set xs = list(reversed(t[:-1])) is the problem and that it works fine if its an iterator inside the lambda function but not in console.它不会返回包含最小值或平均值最大的列表,所以我唯一的猜测是我设置xs = list(reversed(t[:-1]))的事实是问题所在并且它有效如果它是 lambda function 但不在控制台中的迭代器,则很好。

Also trying to find a + max (b,c) gives me this error, which makes sense.还试图找到a + max (b,c)给我这个错误,这是有道理的。

TypeError: unsupported operand type(s) for +: 'int' and 'list'

My best guess is again that the different definition of xs as a list is the problem.我最好的猜测再次是 xs 作为列表的不同定义是问题所在。 If true I would like to know how this all works in the context of being iterators in the lambda function.如果属实,我想知道这一切在 lambda function 中的迭代器上下文中是如何工作的。 I think I get what reduce() and zip() are doing, so mostly just the lambda function is what's confusing me.我想我知道 reduce() 和 zip() 正在做什么,所以大多数情况下只是 lambda function 让我感到困惑。

Thanks in advance for any help提前感谢您的帮助

We can simplify the expression a bit by including all the rows in the second argument to reduce - there's no reason to pass the last row as third parameter (the starting value) of reduce .我们可以通过在 reduce 的第二个参数中包含所有行来稍微简化表达式 - 没有理由将最后一行作为reduce的第三个参数(起始值)传递。

Then, it really helps to give your variables meaningful names, which the original code badly fails to do.然后,为变量赋予有意义的名称确实很有帮助,而原始代码却未能做到这一点。

So, this becomes:所以,这就变成了:

from functools import reduce

def maxPathSum(rows):
    return reduce(
        lambda sums, upper_row: [cell + max(sum_left, sum_right) 
                                 for (cell, sum_left, sum_right) 
                                 in zip(upper_row, sums, sums[1:])],
        reversed(rows)
    )

On the first iteration, sums will be the last row, and upper_row the one over it.在第一次迭代中, sums将是最后一行, upper_row在它上面。

The lambda will calculate the best possible sums by adding each value of the upper row with the largest value of sums to its left or right. sums将通过将上行的每个值加上其左侧或右侧的最大值来计算可能的最佳和。

It zips the upper row with the sums (the last sum won't be used, as there is one too much), and the sums shifted by one value.它用总和压缩上一行(不会使用最后一个总和,因为有一个太多),总和移动一个值。 So, zip will provide us with a triplet (value from upper row ( cell ), sum underneath to its left ( sum_left ), sum underneath to its right ( sum_right ). The best possible sum at this point is our current cell + the largest of theses sums.因此,zip 将为我们提供一个三元组(来自上排的值( cell ),在其左侧下方求和( sum_left ),在其右侧下方求和( sum_right )。此时最好的总和是我们当前的单元格 + 最大的论文总和。

The lambda returns this new row of sums, which will be used as the first parameter of reduce ( sums ) on the next iteration, while upper_row becomes the next row in reversed(rows) . lambda 返回这一新的 sum 行,它将在下一次迭代中用作 reduce ( sums ) 的第一个参数,而upper_row成为reversed(rows)的下一行。

In the end, reduce returns the last row of sums, which contains only one value, our best possible total:最后, reduce返回最后一行总和,它只包含一个值,即我们最好的总和:

[53]

you can spell out the lambda function so it can print.您可以拼出 lambda function 以便打印。 does this help you understand?这有助于你理解吗?

t =  [[5],[3, 6],[8, 14, 7],[4, 9, 2, 0],[9, 11, 5, 2, 9],[1, 3, 8, 5, 3, 2]]
def g( xs, ys):
    ans=[a + max(b, c) for (a, b, c) in zip(ys, xs, xs[1:])]
    print(ans)
    return ans
def maxPathSum(rows):
    return reduce(
        g,
        reversed(rows[:-1]), rows[-1]
    )
maxPathSum(t)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM