3899. Angles of a Triangle
Problem Description
You are given a positive integer array sides of length 3.
Your task is to determine whether these three values can serve as the side lengths of a triangle that has a positive area. In other words, the three numbers must form a real triangle (not a degenerate one where all points lie on a straight line).
The rule for checking this is the triangle inequality: for the three sides to form a valid triangle with positive area, the sum of any two sides must be strictly greater than the third side. If we sort the sides as a <= b <= c, it is enough to check the condition a + b > c, since this is the only inequality that could fail when the values are sorted.
- If such a triangle exists, you must return an array of three floating-point numbers representing the triangle's three internal angles, measured in degrees. These angles must be sorted in non-decreasing order (from smallest to largest).
- If such a triangle does not exist, you must return an empty array.
Because the answer involves floating-point computation, any returned value that is within 10^-5 of the correct answer will be accepted.
How We Pick the Algorithm
Why Math / Bit Manipulation?
This problem maps to Math / Bit Manipulation through a short path in the full flowchart.
Mathematical reasoning or direct calculation produces the answer.
Open in FlowchartIntuition
The problem naturally splits into two parts: first deciding whether a valid triangle exists, and second computing its three internal angles.
For the existence check, the key observation is the triangle inequality. The condition we need is that the sum of any two sides is strictly greater than the third. If we sort the sides so that a <= b <= c, then the largest side is c, and the only inequality that can possibly fail is a + b > c (the other two inequalities a + c > b and b + c > a are automatically satisfied once the sides are sorted). So a single check a + b <= c tells us when the triangle is invalid, and we return an empty array in that case. Sorting also conveniently helps us produce the angles in non-decreasing order later, because a larger side is always opposite a larger angle.
For computing the angles, we already know all three side lengths, so the natural tool is the law of cosines. For any triangle with sides a, b, c and the angle A opposite to side a, the law of cosines gives:
By applying this twice, we can directly solve for two of the angles A and B using acos, then convert the results from radians to degrees. Since the angle opposite a smaller side is smaller, and we sorted a <= b <= c, the angles come out in the order A <= B <= C naturally.
Finally, instead of computing the third angle C with another law of cosines call, we use the simple fact that the internal angles of any triangle add up to 180 degrees. So we get C = 180 - A - B, which is both faster and avoids extra rounding error.
Solution Approach
Solution 1: Sorting + Math
We first sort the array sides in non-decreasing order, and denote the three side lengths as a, b, and c, where a <= b <= c.
According to the triangle inequality, if a + b <= c, then these three sides cannot form a triangle with positive area, so we return an empty array directly.
Otherwise, the three sides can form a valid triangle. By the law of cosines, we have:
Therefore, we can compute angles A and B separately. We use acos to get each angle in radians, then convert it to degrees using degrees. Finally, using the fact that the sum of the internal angles of a triangle is 180 degrees, we get:
Since the array is sorted as a <= b <= c, and a larger side is opposite a larger angle, the resulting angles satisfy A <= B <= C. So we can directly return [A, B, C] as the answer in non-decreasing order.
The time complexity is O(1) (sorting three elements is constant work), and the space complexity is O(1), ignoring the space for the output array.
Example Walkthrough
Let's trace through the solution approach with a concrete input: sides = [4, 5, 3].
Step 1: Sort the sides
We sort the array in non-decreasing order:
So we assign a = 3, b = 4, c = 5, which satisfies a <= b <= c.
Step 2: Check the triangle inequality
We only need to verify a + b > c:
The condition holds, so a valid triangle with positive area exists. We proceed to compute the angles. (If instead we had something like [1, 2, 3], then 1 + 2 = 3 is not strictly greater than 3, so we would return [].)
Step 3: Compute angle A (opposite side a = 3)
Using the law of cosines:
Step 4: Compute angle B (opposite side b = 4)
Step 5: Compute angle C using the angle-sum rule
Instead of another law of cosines call, we use the fact that the internal angles sum to 180°:
This makes sense: [3, 4, 5] is a classic right triangle, so the largest angle (opposite the largest side 5) is exactly 90°.
Step 6: Return the result
Because we sorted a <= b <= c and a larger side is always opposite a larger angle, the angles already come out in non-decreasing order:
This is our final answer, with A <= B <= C as required.
Solution Implementation
1import math
2from typing import List
3
4
5class Solution:
6 def internalAngles(self, sides: List[int]) -> List[float]:
7 # Sort the sides so that side_a <= side_b <= side_c
8 sides.sort()
9 side_a, side_b, side_c = sides
10
11 # Triangle inequality check: the sum of the two shorter sides
12 # must be strictly greater than the longest side.
13 # Otherwise, the three lengths cannot form a valid triangle.
14 if side_a + side_b <= side_c:
15 return []
16
17 # Law of Cosines to find angle A (opposite to side_a):
18 # a^2 = b^2 + c^2 - 2*b*c*cos(A)
19 # => cos(A) = (b^2 + c^2 - a^2) / (2*b*c)
20 angle_a = math.degrees(
21 math.acos((side_b ** 2 + side_c ** 2 - side_a ** 2) / (2 * side_b * side_c))
22 )
23
24 # Law of Cosines to find angle B (opposite to side_b):
25 # cos(B) = (a^2 + c^2 - b^2) / (2*a*c)
26 angle_b = math.degrees(
27 math.acos((side_a ** 2 + side_c ** 2 - side_b ** 2) / (2 * side_a * side_c))
28 )
29
30 # The interior angles of a triangle sum to 180 degrees,
31 # so angle C is simply the remainder.
32 angle_c = 180 - angle_a - angle_b
33
34 return [angle_a, angle_b, angle_c]
351import java.util.Arrays;
2
3class Solution {
4 /**
5 * Computes the three internal angles (in degrees) of a triangle
6 * given the lengths of its three sides.
7 *
8 * @param sides an array containing exactly three side lengths
9 * @return a double array with the three internal angles in degrees,
10 * or an empty array if the sides cannot form a valid triangle
11 */
12 public double[] internalAngles(int[] sides) {
13 // Sort the sides in ascending order so that sideC is the longest.
14 Arrays.sort(sides);
15 int sideA = sides[0];
16 int sideB = sides[1];
17 int sideC = sides[2];
18
19 // Triangle inequality check: the sum of the two shorter sides
20 // must be strictly greater than the longest side.
21 if (sideA + sideB <= sideC) {
22 return new double[0];
23 }
24
25 // Apply the Law of Cosines to find the angle opposite each side.
26 // angleA is opposite sideA, angleB is opposite sideB.
27 double angleA = Math.toDegrees(
28 Math.acos((sideB * sideB + sideC * sideC - sideA * sideA)
29 / (2.0 * sideB * sideC)));
30 double angleB = Math.toDegrees(
31 Math.acos((sideA * sideA + sideC * sideC - sideB * sideB)
32 / (2.0 * sideA * sideC)));
33
34 // The three angles of a triangle sum to 180 degrees,
35 // so the remaining angle can be derived by subtraction.
36 double angleC = 180.0 - angleA - angleB;
37
38 return new double[] {angleA, angleB, angleC};
39 }
40}
411class Solution {
2public:
3 // Computes the three internal angles (in degrees) of a triangle given its side lengths.
4 // Returns an empty vector if the sides cannot form a valid triangle.
5 vector<double> internalAngles(vector<int>& sides) {
6 // Sort the sides in ascending order so that side_a <= side_b <= side_c.
7 sort(sides.begin(), sides.end());
8 int side_a = sides[0];
9 int side_b = sides[1];
10 int side_c = sides[2];
11
12 // Triangle inequality check: the sum of the two shorter sides must
13 // exceed the longest side. Otherwise, no valid triangle exists.
14 if (side_a + side_b <= side_c) {
15 return {};
16 }
17
18 // Pi is obtained via acos(-1.0); used to convert radians to degrees.
19 const double pi = acos(-1.0);
20 const double radians_to_degrees = 180.0 / pi;
21
22 // Apply the Law of Cosines to find each angle (opposite to its same-named side).
23 // angle_a is opposite side_a, angle_b is opposite side_b.
24 double angle_a = acos((1.0 * side_b * side_b + 1.0 * side_c * side_c - 1.0 * side_a * side_a) /
25 (2.0 * side_b * side_c)) * radians_to_degrees;
26 double angle_b = acos((1.0 * side_a * side_a + 1.0 * side_c * side_c - 1.0 * side_b * side_b) /
27 (2.0 * side_a * side_c)) * radians_to_degrees;
28
29 // The angles of a triangle sum to 180 degrees, so derive the third directly.
30 double angle_c = 180.0 - angle_a - angle_b;
31
32 // Return the three angles in the order corresponding to the sorted sides.
33 return {angle_a, angle_b, angle_c};
34 }
35};
361/**
2 * Computes the three internal angles (in degrees) of a triangle given its side lengths.
3 *
4 * The function uses the Law of Cosines to derive each angle:
5 * cos(A) = (b² + c² - a²) / (2bc)
6 *
7 * @param sides - An array of three numbers representing the triangle's side lengths.
8 * @returns An array of three angles in degrees, or an empty array if the sides
9 * cannot form a valid triangle.
10 */
11function internalAngles(sides: number[]): number[] {
12 // Sort the sides in ascending order so that `sideC` is the longest.
13 sides.sort((a, b) => a - b);
14
15 // Destructure the sorted sides into clearly named variables.
16 const [sideA, sideB, sideC]: number[] = sides;
17
18 // Triangle inequality check: the sum of the two shorter sides must
19 // exceed the longest side. Otherwise, a valid triangle cannot exist.
20 if (sideA + sideB <= sideC) {
21 return [];
22 }
23
24 // Conversion factor from radians to degrees.
25 const radianToDegree: number = 180 / Math.PI;
26
27 // Law of Cosines: angle opposite to sideA.
28 const angleA: number =
29 Math.acos((sideB * sideB + sideC * sideC - sideA * sideA) / (2 * sideB * sideC)) *
30 radianToDegree;
31
32 // Law of Cosines: angle opposite to sideB.
33 const angleB: number =
34 Math.acos((sideA * sideA + sideC * sideC - sideB * sideB) / (2 * sideA * sideC)) *
35 radianToDegree;
36
37 // The angles of a triangle sum to 180 degrees, so derive the third angle.
38 const angleC: number = 180 - angleA - angleB;
39
40 // Return the three internal angles in degrees.
41 return [angleA, angleB, angleC];
42}
43Time and Space Complexity
-
Time Complexity:
O(1)The input
sidesalways contains exactly 3 elements, sosides.sort()operates on a fixed-size list and takes constant time. The subsequent arithmetic operations—computing anglesA,B, andCusingacosanddegrees—are all constant-time operations independent of any growing input size. Therefore, the overall time complexity isO(1). -
Space Complexity:
O(1)The algorithm uses only a fixed number of variables (
a,b,c,A,B,C), and the returned list always holds exactly 3 elements. No additional space scales with the input. Hence, the space complexity isO(1).
Common Pitfalls
Pitfall 1: Forgetting that acos may produce a slightly out-of-range argument due to floating-point error
The law of cosines computes cos(A) = (b^2 + c^2 - a^2) / (2*b*c). Mathematically this value always lies within [-1, 1], but because of floating-point rounding, it can occasionally end up as something like 1.0000000002 or -1.0000000001. When such a value is passed to math.acos, Python raises a ValueError: math domain error.
This is especially likely when the triangle is nearly degenerate (e.g., a + b is only marginally greater than c), where the cosine value approaches exactly 1 or -1.
Solution: Clamp the cosine value to the valid [-1, 1] range before calling acos.
import math
from typing import List
class Solution:
def internalAngles(self, sides: List[int]) -> List[float]:
sides.sort()
side_a, side_b, side_c = sides
if side_a + side_b <= side_c:
return []
def safe_acos(x: float) -> float:
# Clamp into [-1, 1] to avoid math domain errors from rounding.
return math.acos(max(-1.0, min(1.0, x)))
angle_a = math.degrees(
safe_acos((side_b ** 2 + side_c ** 2 - side_a ** 2) / (2 * side_b * side_c))
)
angle_b = math.degrees(
safe_acos((side_a ** 2 + side_c ** 2 - side_b ** 2) / (2 * side_a * side_c))
)
angle_c = 180 - angle_a - angle_b
return [angle_a, angle_b, angle_c]
Pitfall 2: Integer overflow / squaring before the inequality check (language dependent)
In Python this is not an issue because integers have arbitrary precision. However, when porting the solution to languages such as C++, Java, or Go, computing side_b ** 2 + side_c ** 2 with 32-bit integers can overflow when the side lengths are large. Additionally, doing the triangle inequality check as a + b <= c with fixed-width integers can overflow a + b.
Solution: Use a wide enough integer type (e.g., long long in C++ / long in Java) for the squared terms, or perform the inequality check in a way that avoids addition overflow, such as a > c - b. In Python, no special handling is required.
Pitfall 3: Misordering the returned angles
The approach relies on the geometric fact that a larger side is opposite a larger angle. After sorting a <= b <= c, the angles automatically satisfy A <= B <= C. A common mistake is to compute the angles from an unsorted array (or to compute C first and naively place it last without sorting the sides), which breaks the required non-decreasing order of the output.
Solution: Always sort sides first, then compute A (opposite a), B (opposite b), and C = 180 - A - B. This guarantees the output [A, B, C] is already in non-decreasing order without an extra sort.
Pitfall 4: Using > instead of >= (or vice versa) for the degenerate case
The problem requires a triangle with positive area, so a degenerate triangle where a + b == c (all points collinear) must be rejected. Using a + b < c instead of a + b <= c would incorrectly accept these flat "triangles," which have zero area.
Solution: Use the strict comparison if side_a + side_b <= side_c: return [] to reject both impossible and degenerate cases.
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapWhich of the following is a good use case for backtracking?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity describes how the time needed
Want a Structured Path to Master System Design Too? Don’t Miss This!