LeetCode Day 4 "120 Triangle Minimum Path Sum"

LeetCode120 Triangle minimum path sum

Title description

Given a triangle, find the minimum path sum from top to bottom. Each step can only move to the adjacent node in the next row.

"Adjacent nodes" here refers to two nodes whose subscript is the same as or equal to the subscript of the node of the previous layer + 1.

Explanation: If you can only use O(n) extra space (n is the total number of rows of the triangle) to solve this problem, then your algorithm will be a plus.

Tip: array, dynamic programming

Example

Input: [[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]]

Output: The minimum path sum from top to bottom is 11, that is, 2 + 3 + 5 + 1 = 11.

Problem analysis

According to the meaning of the title, the example can be transformed into the following triangle:

Example illustration

  After transforming the triangle into this form, according to the meaning of the title, every time you walk can only go straight down and the next square to the right . It is also worth noting that the test case gives an isosceles triangle, that is, the length of the two-dimensional array is the same as the length of the last array. Being clear about this may help us consider special circumstances.
  

Problem solving ideas

Top-down calculation    is mentioned in the title description , and it is to find the shortest path. This is an optimal solution problem. This kind of problem is commonly used in dynamic programming , and sometimes greedy algorithms are also OK. When I wrote it, I remembered that when I talked about dynamic programming in the "Introduction to Algorithms", there was a way of implementing dynamic programming called "top-down with memo". But this kind of realization is more realized through recursion . Here is another implementation method mentioned in the book: "bottom-up", that is, the problem is transformed into the solution of smaller sub-problems.

Bottom-up method: This method generally needs to define the concept of the "scale" of the sub-problem, so that the solution of any sub-problem depends only on the solution of the "smaller" sub-problem. Therefore, we can sort the sub-problems by scale and solve them in the order of small to large. When solving a sub-problem, the smaller sub-problems it depends on have been solved, and the results have been saved. Each sub-problem only needs to be solved once. When we solve it, all its sub-problems have been solved ahead of time.

   In this question, we can clearly find that the question is described in this way. Calculate the minimum path of the first row (that is, the value itself), and then calculate the second, third, fourth... The minimum path of each row is itself calculated from its smaller rows. Therefore, this problem can use this method to solve the minimum path sum (not to use the "top-down" method of describing the nouns with the title, oops, these nouns are ignored). But in the actual implementation, we do not know where you will go each step (here may use greedy thinking to write, this kind of thinking is incorrect, will be discussed later), so we need to change the The shortest path of each grid is calculated (obviously this time complexity should be O(n^2) ), and finally the minimum value is taken.

   The “bottom-up” dynamic programming method generally involves writing recurrence equations, such as

dp[i] = max(dp[i], dp[i - 1]);

The main recurrence equation for this question is as follows:

dp[i] = min(dp[i], dp[i - 1]) + currentElement;

   The dp array is used to store the shortest path of each cell in each row. At the beginning, a two-dimensional array may be used to store each value. But according to the hint given by the title, it is best to use the extra space of O(n), so we can use the concept of "rolling array" here, that is, repeatedly assign dp. This is possible because we don’t care what data is saved before the last row. What we care about is only the shortest path of each cell in the last row saved by the dp array, and then take out the minimum value of the data to be the solution of the answer. . Just the above recursive equation using one-dimensional array.

The specific problem-solving process is as follows:

  1. First calculate the shortest path of the two grids in the second row

   Because if only the first row is calculated, there is only one array in the dp array at this time, and the index of the next i-1 may cause the index to be out of bounds, so you can deal with it first.

  1. Use double loop traversal

   The first loop to traverse the entire input list, here only need to traverse from the third line, because the first and second lines have been processed. The second loop traverses each data item in the array, and the loop only needs to traverse from the second element to the penultimate element. The first element and the last element need special treatment, the recurrence equation described above is not suitable, as follows:

Calculate the first element:

dp[0] = dp[0] + triangle.get(i).get(0);

 因为第一元素只能由它上面那个元素走到。

Calculate the last element:

dp[itemLen-1] = dp[itemLen - 2] + triangle.get(i).get(itemLen - 1);

   Here itemmLen refers to the length of the array. Because the last element can only be reached by the element in its upper left corner (for example, 7 in the example can only be 4->7).

  1. Calculate the minimum value of the dp array and return the result
      

Program realization

public int minimumTotal(List<List<Integer>> triangle) {
    int len = triangle.size();
    //先处理0, 1  长度的情况
    if (len == 0) {
    	return 0;
    }
    if (len == 1) {
    	return triangle.get(0).get(0);
    }
    int[] dp =  new int[len];
    //1.提前计算 第二行的数据
    dp[0] = triangle.get(1).get(0) +triangle.get(0).get(0);
    dp[1] = triangle.get(1).get(1) + triangle.get(0).get(0);

    int[] temp = new int[len];		//创建一个临时数组
    for (int i = 2; i < len; i++) {
        int itemLen = triangle.get(i).size();
        for (int j = 1; j < itemLen - 1; j++) {
        	temp[j] = Math.min(dp[j], dp[j - 1]) + triangle.get(i).get(j);	//递推式
    	}
        dp[0] = dp[0] + triangle.get(i).get(0);	//计算第一个数组
        dp[itemLen - 1] = dp[itemLen - 2] + triangle.get(i).get(itemLen - 1);	//计算倒数一个数据
        for (int j = 1; j < itemLen - 1; j++) {	//将dp重复赋值
            dp[j] = temp[j];
        }
    }
	
    //计算最小值
    int minVal = dp[0];
    for (int i = 1; i < len; i++) {
        if (minVal > dp[i]) {
            minVal = dp[i];
        }
    }
    return minVal;
}

Program running results

Program running results

  The result is not very good, the reason should be that a temporary array is created, and the value of the array is assigned to the dp array with a loop, and the space complexity should be O(2n).

  

Wrong idea

   In fact, when I started writing, my thoughts naturally followed the path given by the title, and each step went to the minimum value of the two adjacent grids below to add up. This is actually a greedy idea, that is, take the minimum value every time Add up , but it is wrong in our question. You can see the following example:
Greedy algorithm wrong path

According to this idea, the result is 0 , but the correct path should be as follows:
Dynamically plan the correct path

The result of this method is -1, which is shorter than the path of greedy thinking.

Guess you like

Origin blog.csdn.net/weixin_44184990/article/details/108567237