In the last article, we studied the analysis methods of DP (dynamic programming) in online relationships by using the topics “Longest ascending subsequence” and “maximum suborder sum”. This analysis method is also known as “linear dynamic programming” in operations research, which specifically refers to “linear functions with specific variables as the objective function, linear inequalities or equations of these variables as constraints, and the purpose is to find the maximum or minimum value of the objective function”. This point as we can understand, do not need to remember, not to copy!
In this section, we will continue to analyze a slightly different from the previous topic type, hope to be able to compare this topic with the previous topic demonstration, and then smooth solution!
01. Topic analysis
Problem 120: sum of minimum paths of a triangle |
---|
Given a triangle, find the minimum sum of paths from top to bottom. Each step can only move to the next node in the next row. |
For example, given a triangle:
[[2], [3,4], [6,5,7], [4,1,8,3]Copy the code
The minimum sum of paths from top to bottom is 11 (that is, 2 + 3 + 5 + 1 = 11).
This problem has certain difficulty oh! If you do not have ideas, please review the last learning content!
It is not recommended to read the problem directly!
02. Title Diagram
So first of all, we’re going to look for the sum of minimum paths of a triangle, what does that mean? Suppose we have a triangle: [[2], [3,4], [6,5,7],
,1,8,3 [4]]
So the minimum sum of paths from top to bottom is 2-3-5-1, which is 11.
Since we are using an array to define a triangle for our analysis, we change the triangle slightly:
So we’re stretching the whole triangle. In this case, according to the conditions given in the problem: each step can only move to the next row adjacent
At the node of. This is essentially the same thing as saying, for every step we can only move one down or one down to the right. Convert it to code, let’s say 2 is in the element
If the prime position is [0,0], then we can only move down to [1,0] or [1,1]. If 5 is in position [2,1], it can also move
To the positions [3,1] and [3,2]. As shown below:
Now that the problem is clear, let’s start the analysis. The problem is obviously a problem of finding the optimal solution, and can be derived from the optimal solution of the subproblem
Line build. So we solve it by dynamic programming. First, we define the state:
Dp [I][j] : represents the minimum path sum of elements containing the ith row and j column
It’s easy to think of top-down analysis. And, whatever the final path is, it must go through the topmost element, which is [0,0]. So we need to initialize dp[0][0].
Dp [0][0] = the value of the element at position [0]
Further analysis, if we ask dp[I][j], then it must move from the two elements above its head.
The minimum path sum at 5, for example, is either 2-3-5 or 2-4-5. Then take the smaller of the sum of the two paths. Into the
And we get the state transition equation:
dp[i][j] = min(dp[i-1][j-1],dp[i-1][j]) + triangle[i][j]
However, we have a problem here! Except for the element at the top,
The element on the left can only come from above. (2-3-6-4)
The rightmost element can only come from its upper left corner. (2-4-7-3)
Then, we observe that the elements in line 2 are special elements (because they can only come from the element [0,0])
We can directly treat it specially and get:
dp[1][0] = triangle[1][0] + triangle[0][0]
dp[1][1] = triangle[1][1] + triangle[0][0]
In the end, we just have to find the smallest path sum in the last row, and that’s our answer. That is:
L: dp array length
Result = min(dp[l-1,0], dp[l-1,1], dp[l-1,1]….)
To sum up, we have finished the analysis. We have carried out 4 steps in total:
- Define state
- Summarize the state transition equation
- Analyze the special case where the state transition equation cannot be satisfied.
- Get the final solution
03. Examples of Go language
According to the above analysis, the code can be obtained as follows:
func minimumTotal(triangle [][]int) int {
if len(triangle) < 1 {
return 0
}
if len(triangle) == 1 {
return triangle[0] [0]
}
dp := make([] []int.len(triangle))
for i, arr := range triangle {
dp[i] = make([]int.len(arr))
}
result := 1<<31 - 1
dp[0] [0] = triangle[0] [0]
dp[1] [1] = triangle[1] [1] + triangle[0] [0]
dp[1] [0] = triangle[1] [0] + triangle[0] [0]
for i := 2; i < len(triangle); i++ {
for j := 0; j < len(triangle[i]); j++ {
if j == 0 {
dp[i][j] = dp[i- 1][j] + triangle[i][j]
} else if j == (len(triangle[i]) - 1) {
dp[i][j] = dp[i- 1][j- 1] + triangle[i][j]
} else {
dp[i][j] = min(dp[i- 1][j- 1], dp[i- 1][j]) + triangle[i][j]
}
}
}
for _,k := range dp[len(dp)- 1] {
result = min(result, k)
}
return result
}
func min(a, b int) int {
if a > b {
return b
}
return a
}
Copy the code
Running results:
Running the above code, we find that we are using too much memory. Is there any way we can compress memory? Through observation we find that in our
In the top-down process, we only need to use the accumulated data in the previous layer, and do not revisit the previous number of elements
According to. The graph is as follows:
The optimized code looks like this:
func minimumTotal(triangle [][]int) int {
l := len(triangle)
if l < 1 {
return 0
}
if l == 1 {
return triangle[0] [0]
}
result := 1<<31 - 1
triangle[0] [0] = triangle[0] [0]
triangle[1] [1] = triangle[1] [1] + triangle[0] [0]
triangle[1] [0] = triangle[1] [0] + triangle[0] [0]
for i := 2; i < l; i++ {
for j := 0; j < len(triangle[i]); j++ {
if j == 0 {
triangle[i][j] = triangle[i- 1][j] + triangle[i][j]
} else if j == (len(triangle[i]) - 1) {
triangle[i][j] = triangle[i- 1][j- 1] + triangle[i][j]
} else {
triangle[i][j] = min(triangle[i- 1][j- 1], triangle[i- 1][j]) + triangle[i][j]
}
}
}
for _,k := range triangle[l- 1] {
result = min(result, k)
}
return result
}
func min(a, b int) int {
if a > b {
return b
}
return a
}
Copy the code
Running results:
I’ve compiled all the problems I’ve written into an e-book, complete with illustrations for each problem. Click to download