You have a convex n
-sided polygon where each vertex has an integer value. You are given an integer array values
where values[i]
is the value of the ith
vertex in clockwise order.
Polygon triangulation is a process where you divide a polygon into a set of triangles and the vertices of each triangle must also be vertices of the original polygon. Note that no other shapes other than triangles are allowed in the division. This process will result in n - 2
triangles.
You will triangulate the polygon. For each triangle, the weight of that triangle is the product of the values at its vertices. The total score of the triangulation is the sum of these weights over all n - 2
triangles.
Return the minimum possible score that you can achieve with some triangulation of the polygon.
Example 1:
Input: values = [1,2,3]
Output: 6
Explanation: The polygon is already triangulated, and the score of the only triangle is 6.
Example 2:
Input: values = [3,7,4,5]
Output: 144
Explanation: There are two triangulations, with possible scores: 3*7*5 + 4*5*7 = 245, or 3*4*5 + 3*4*7 = 144.
The minimum score is 144.
Example 3:
Input: values = [1,3,1,4,1,5]
Output: 13
Explanation: The minimum score triangulation is 1*1*3 + 1*1*4 + 1*1*5 + 1*1*1 = 13.
Constraints:
n == values.length
3 <= n <= 50
1 <= values[i] <= 100
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The problem is about dividing a polygon into triangles. The brute force approach tries every single way you can draw lines to form triangles inside the polygon and adds up some 'score' for each way.
Here's how the algorithm would work step-by-step:
def minimum_score_triangulation_brute_force(polygon):
number_of_vertices = len(polygon)
def calculate_score(triangle):
return polygon[triangle[0]] * polygon[triangle[1]] * polygon[triangle[2]]
def triangulate(current_polygon):
if len(current_polygon) == 3:
return calculate_score(current_polygon)
minimum_triangulation_score = float('inf')
# Iterate through all possible vertices to form triangles.
for first_vertex_index in range(1, len(current_polygon) - 1):
# Divide the polygon and recursively triangulate.
first_triangle = (current_polygon[0], current_polygon[first_vertex_index], current_polygon[-1])
first_triangle_score = calculate_score(first_triangle)
left_polygon = tuple([current_polygon[index] for index in range(0, first_vertex_index + 1)])
right_polygon = tuple([current_polygon[index] for index in range(first_vertex_index, len(current_polygon))])
if len(left_polygon) > 2 and len(right_polygon) > 2:
left_triangulation_score = triangulate(left_polygon)
right_triangulation_score = triangulate(right_polygon)
total_score = first_triangle_score + left_triangulation_score + right_triangulation_score
elif len(left_polygon) > 2:
left_triangulation_score = triangulate(left_polygon)
total_score = first_triangle_score + left_triangulation_score
elif len(right_polygon) > 2:
right_triangulation_score = triangulate(right_polygon)
total_score = first_triangle_score + right_triangulation_score
else:
total_score = first_triangle_score
minimum_triangulation_score = min(minimum_triangulation_score, total_score)
return minimum_triangulation_score
# Creates an index tuple that represents the initial polygon
initial_polygon_indices = tuple(range(number_of_vertices))
return triangulate(initial_polygon_indices)
The most efficient way to solve this polygon triangulation problem is to break it down into smaller, overlapping subproblems. We find the best way to triangulate each smaller piece of the polygon and combine those solutions to find the best solution for the whole thing. This avoids recomputing the same things over and over.
Here's how the algorithm would work step-by-step:
def minimum_score_triangulation(polygon):
number_of_points = len(polygon)
# DP table to store min score for sub-polygons
dp_table = [[0] * number_of_points for _ in range(number_of_points)]
for polygon_size in range(2, number_of_points):
for left_point in range(number_of_points - polygon_size):
right_point = left_point + polygon_size
dp_table[left_point][right_point] = float('inf')
# Iterate through each possible vertex to form a triangle
for current_point in range(left_point + 1, right_point):
# The cost of the current triangle we are testing.
cost_of_current_triangle = polygon[left_point] * polygon[current_point] * polygon[right_point]
# Calculate the score with the current triangle
total_score = dp_table[left_point][current_point] + dp_table[current_point][right_point] + cost_of_current_triangle
dp_table[left_point][right_point] = min(dp_table[left_point][right_point], total_score)
# The result is the minimum triangulation score for the entire polygon
return dp_table[0][number_of_points - 1]
Case | How to Handle |
---|---|
Null or empty input array | Return 0 as triangulation is impossible for an invalid polygon. |
Array with fewer than 3 vertices | Return 0 as triangulation requires at least 3 vertices to form a polygon. |
Array with exactly 3 vertices (a triangle) | Return 0 directly, as no further triangulation is needed and score is 0. |
Large input size (n > 100) | DP solution should handle large inputs efficiently within time constraints; memoization avoids exponential recursion. |
Integer overflow when calculating score products for large values | Use a data type that can store larger values (e.g., long) or implement checks to prevent overflow. |
All vertices have the same value | The DP algorithm correctly calculates the minimum triangulation score even with identical vertex values. |
Array is already sorted in increasing order. | The DP algorithm functions correctly regardless of the vertex order, by considering all possible triangulations. |
Vertices form a degenerate polygon (self-intersecting) | The problem statement assumes a convex polygon; ensure constraints or pre-processing step before applying DP. |