Leetcode 1039. Minimum Score Triangulation of Polygon
Problem Explanation
The problem is asking to find the minimum possible total score from a convex n-sided polygon. We are required to create triangles from the polygon, where each triangle's score is the product of all its vertices. The total score of the polygon is the sum of all triangles' scores.
The vertices of the polygon are defined as A[0]
, A[1]
, ..., A[N-1]
For example, let's say we have a quadilateral polygon which vertices are labeled as [3,7,4,5]. One way to triangulate this polygon can be (3,7,5) and (3,4,5) with possible scores 375 + 345 = 245, or we can triangulate another way (3,4,7) and (3,4,5) which has possible scores 347 + 345 = 144. The minimum score among the two is 144.
Approach Explanation
This problem can be solved using Dynamic Programming.
- Sub-problem breakdown: We can divide the original problem into smaller problems, where each sub-problem represents the minimum total score for the triangulation of a sub-polygon.
- Use 2D DP Array: To store the result for each sub-problem, a 2D array is used where dp[i][j] represents the minimum total score for the triangulation of the polygon represented by the vertices from i to j.
- Bottom-up Approach: We start from smaller polygons and gradually build up our solution for larger polygons using the results of the smaller polygons.
- State Transition: For each vertex pair
(i, j)
, we pick a third vertexk
that forms a triangle(i, k, j)
. The score for this triangle isvalues[i] * values[k] * values[j]
and we add this score to the scores of the triangles formed in the sub-polygons(i, k)
and(k, j)
. Our goal is to minimize this total score.
Now let's see the solution implementation for this problem.
PYTHON Solution
1 2python 3class Solution: 4 def minScoreTriangulation(self, values): 5 n = len(values) 6 dp = [[0] * n for _ in range(n)] 7 for j in range(2,n): 8 for i in range(j-2,-1,-1): 9 dp[i][j] = min(values[i]*values[k]*values[j] + dp[i][k] + dp[k][j] for k in range(i+1, j)) 10 return dp[0][n-1]
In this python solution, we create a dynamic 2D array dp and initialize it with 0. For every vertex pair (i, j), we pick a third vertex k and calculate the minimum score for the polygon.
JAVA Solution
1 2java 3class Solution { 4 public int minScoreTriangulation(int[] values) { 5 int n = values.length; 6 int[][] dp = new int[n][n]; 7 for (int j = 2; j < n; ++j) 8 for (int i = j - 2; i >= 0; --i) { 9 dp[i][j] = Integer.MAX_VALUE; 10 for (int k = i + 1; k < j; ++k) 11 dp[i][j] = Math.min(dp[i][j], dp[i][k] + values[i] * values[k] * values[j] + dp[k][j]); 12 } 13 14 return dp[0][n - 1]; 15 } 16}
JAVASCRIPT Solution
1 2javascript 3var minScoreTriangulation = function(values) { 4 let n = values.length; 5 let dp = Array(n).fill(0).map(() => Array(n).fill(0)); 6 for(let j=2; j<n; ++j) 7 for(let i=j-2; i>=0; --i) { 8 dp[i][j] = Number.MAX_SAFE_INTEGER; 9 for(let k=i+1; k<j; ++k) 10 dp[i][j] = Math.min(dp[i][j], dp[i][k] + values[i]*values[k]*values[j] + dp[k][j]); 11 } 12 13 return dp[0][n-1]; 14};
In JavaScript solution, we have the same logic as Python and Java, but to define matrix-like 2 Dimensional array in JavaScript it's a little bit different.
C++ Solution
1 2cpp 3class Solution { 4public: 5 int minScoreTriangulation(vector<int>& values) { 6 int n = values.size(); 7 vector<vector<int>> dp(n, vector<int>(n)); 8 for (int j = 2; j < n; ++j) 9 for (int i = j - 2; i >= 0; --i) { 10 dp[i][j] = INT_MAX; 11 for (int k = i + 1; k < j; ++k) 12 dp[i][j] = min(dp[i][j], dp[i][k] + values[i] * values[k] * values[j] + dp[k][j]); 13 } 14 15 return dp[0][n - 1]; 16 } 17};
C# Solution
1 2csharp 3public class Solution { 4 public int MinScoreTriangulation(int[] values) { 5 int n = values.Length; 6 int[,] dp = new int[n,n]; 7 for(int j=2; j<n; j++) 8 for(int i=j-2; i>=0; i--) { 9 dp[i,j] = int.MaxValue; 10 for(int k=i+1; k<j; k++) 11 dp[i,j] = Math.Min(dp[i,j], dp[i,k] + values[i]*values[k]*values[j] + dp[k,j]); 12 } 13 14 return dp[0, n - 1]; 15 } 16}
In C# solution, when declare matrix or 2 dimensional array, variable types must be defined and using comma as separating axis.
In all these solutions above, we iterate three pointers and track the minimum total score. For each pair (i, j), we calculate all possible triangulation scores and get the minimum. Finally, we return dp[0][n-1], which stores the minimum total score for the triangulation of the polygon represented by the vertices from index 0 to n-1.The solutions in python, Java, JavaScript, C++ and C# mentioned above use dynamic programming approach and follow the formulation mentioned in the explaination section above.
For certain vertices i and j, our goal is to find the minimum possible score to form a triangle with all the vertices from i to j (both included). This is done by choosing each vertex k between i and j and determining the score to build the triangles (i, k, j). We add the product of vertices i, j and k as well as the score for the triangulation of sub-polygon (i, k) and (k, j). We store the minimum score among all such triangles and finally, return the minimum total score for the complete polygon.
The time complexity of the solution is O(N^3) due to the triple nested for loop. Here N is the number of vertices of the polygon. The outer two loops iterate over all possible pairs of vertices and the inner most loop iterates over all possible vertices between them. The space complexity is O(N^2) for the space utilized by the 2D dynamic programming matrix where N is the total number of vertices of the polygon.
Despite the cubic time complexity, this algorithm works knowledgably for the problem constraints where the number of vertices is not larger than 50. One must understand that DP solutions tend to be slower but they guarantee a solution to the problem. Indeed, the goal of dynamic programming is not to be fast, but to be certain to find the optimal solution.
Conclusion
This problem is a classic dynamic programming problem that highlights the technique of transforming a complex problem into overlapping smaller sub-problems and utilizing previously computed solutions to aid in finding the optimal solution. Understanding how to identify these sub-problems and defining the state transition is critical to developing effective dynamic programming solutions.
The main principle involved is that of 'optimal substructure', where the optimal solution to the problem can be formed from the optimal solutions to its sub-problems. These sub-problems are often overlapping and thus we make use of a dynamic programming array to avoid repeated calculations. With careful observation, a clear state transition relationship can be found and thus the larger problem can be solved.
So by understanding how to breakdown problems into simpler sub-problems and how to manage and use previously solved sub-problems, we can solve complex problems more efficiently. This principle applies not only to this problem, but it's a common strategy in dynamic programming.
Remember, a key part of successful programming is problem solving. Itโs not necessary to have the most efficient solution right off the bat; itโs important to continuously refine your code that solves the problem. Hence, don't be disheartened if you can't find an optimal solution right away; keep refining and eliminating redundancy wherever possible.
Got a question?ย Ask the Teaching Assistantย anything you don't understand.
Still not clear? Ask in the Forum, ย Discordย orย Submitย the part you don't understand to our editors.