Algorithm Styled Question - Max Path Sum
- Programming
- Algorithms
- Math
- Python
NOTE: This is adapted from problem 67 of project euler
By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.
3 7 4 2 4 6 8 5 9 3
That is, 3 + 7 + 4 + 9 = 23.
Find the maximum total from top to bottom of the triangle in the 15Kb text file
NOTE: It is not possible to try every route to solve this problem, as there are altogether! If you could check one trillion () routes every second it would take over twenty billion years to check them all. There is an efficient algorithm to solve it. ;o)
I used recursion because it's the most intuitive and straightforward approach for me, but it's also because it's easier to implement.
Here is the code:
def maxSum(triangle: list[list[int]], layer: int, node: int, memo: dict):
curr = triangle[layer][node]
if layer == len(triangle) - 1:
return curr
key = f"{layer}|{node}"
if memo.get(key):
return memo[key]
res = max(maxSum(triangle, layer + 1, node, memo),
maxSum(triangle, layer + 1, node + 1, memo)) + curr
memo[key] = res
return res
def solve(triangle: list[str]):
integerizedTriangle = list(map(lambda row: list(
map(int, row)), map(lambda x: x.split(" "), triangle)))
memo = {}
return maxSum(integerizedTriangle, 0, 0, memo)
maxSum
Functiondef maxSum(triangle: list[list[int]], layer: int, node: int, memo: dict):
The function takes four arguments, the first oen is the triangle represented as a 2d integer array, where each nested array is the equivalent of a layer in the triangle.
layer
and node
are simply indices used to determine the position of the current node we are looking at. layer
is the row and node
is the ith item in that row (0-indexed).
Lastly, memo
is the dictionary used for optimization with memoization, whereby a key representing the position of a node is mapped to its computed maximum sum.
def maxSum(triangle: list[list[int]], layer: int, node: int, memo: dict):
# get's the value of the current node in the triangle
curr = triangle[layer][node]
# if we are at the bottom layer of the triangle, we reach a base case
if layer == len(triangle) - 1:
# then return the current node as the maximum sum as there's nothing below it
return curr
# define our own representation for the location of the node
key = f"{layer}|{node}"
# check if the maximum sum for this node is already computed and stored in memo
if memo.get(key):
# if so, return the memoized value, avoiding further time-consuming computation
return memo[key]
# if no value is memoized, recursively calculate the maximum sum for the current node
# it works by comparing the *maximum sums* of the two nodes immediately below it
# (which we will have to compute recursively), and adding the greater one to the value
# of the curren node
res = max(maxSum(triangle, layer + 1, node, memo),
maxSum(triangle, layer + 1, node + 1, memo)) + curr
# memoize the value
memo[key] = res
# return that as the result
return res
For this specific input, it took the algorithm about 0.0073 seconds (on average) to run, which, I'm pretty happy with.
Overall, it was a very fun problem to attempt and having the algorithm work on the first try was very exciting.