Valid Boomerang
EasyPrompt
Given an array points where points[i] = [xi, yi] represents a point on the X-Y plane, return true if these points are a boomerang.
A boomerang is a set of three points that are all distinct and not in a straight line.
Example 1:
Input: points = [[1,1],[2,3],[3,2]]
Output: trueExample 2:
Input: points = [[1,1],[2,2],[3,3]]
Output: false
Constraints:
points.length == 3points[i].length == 20 <= xi, yi <= 100
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly translates the geometric definition of a boomerang. It first checks for the distinctness of the three points. Then, it determines if they are collinear by calculating and comparing the slopes of the lines formed by pairs of points. This method is intuitive but suffers from the practical complexities of floating-point arithmetic and the need to handle special cases like vertical lines (which have an infinite slope).
Algorithm
- Let the three points be
p1 = (x1, y1),p2 = (x2, y2), andp3 = (x3, y3). - First, explicitly check if any two points are identical. If
p1=p2orp1=p3orp2=p3, they cannot form a boomerang, so returnfalse. - Handle the case of vertical lines to avoid division by zero. If
x1,x2, andx3are all equal, the points are on a vertical line and thus collinear. Returnfalse. - If only two points share an x-coordinate (e.g.,
x1 == x2butx1 != x3), they cannot all be collinear, so returntrue. - If no vertical lines are involved, calculate the slopes using floating-point division:
slope12 = (double)(y2 - y1) / (x2 - x1)slope13 = (double)(y3 - y1) / (x3 - x1)
- Compare the slopes. If
slope12is not equal toslope13, the points are not collinear, so returntrue. Otherwise, returnfalse.
Walkthrough
The core idea is to verify the two conditions for a boomerang separately: distinctness and non-collinearity.
- Distinctness Check: We start by comparing each pair of points. If any two points have the same coordinates, the first condition is violated, and we can immediately return
false. - Collinearity Check using Slopes: If the points are distinct, we check if they lie on a single straight line. The standard way to do this is by comparing slopes. The slope of the line between
p1andp2must be different from the slope of the line betweenp1andp3. A major issue here is that a vertical line has an undefined slope, leading to a division-by-zero error. Therefore, we must add special logic to handle cases wherex1 == x2orx1 == x3before performing any division. This leads to a multi-branch conditional structure that, while correct, is cumbersome.
class Solution { public boolean isBoomerang(int[][] points) { int[] p1 = points[0]; int[] p2 = points[1]; int[] p3 = points[2]; // 1. Check for distinctness if ((p1[0] == p2[0] && p1[1] == p2[1]) || (p1[0] == p3[0] && p1[1] == p3[1]) || (p2[0] == p3[0] && p2[1] == p3[1])) { return false; } // 2. Check for collinearity using slopes // Handle vertical line case for p1-p2 if (p1[0] == p2[0]) { // If p1-p2 is a vertical line, for all 3 to be collinear, // p1-p3 must also be a vertical line. return p1[0] != p3[0]; } // Handle vertical line case for p1-p3 if (p1[0] == p3[0]) { // This case is symmetric to the one above. Since we already checked // p1[0] == p2[0], we know they are different, so they can't be collinear. return true; } // General case: calculate and compare slopes double slope12 = (double)(p2[1] - p1[1]) / (p2[0] - p1[0]); double slope13 = (double)(p3[1] - p1[1]) / (p3[0] - p1[0]); return slope12 != slope13; }}Complexity
Time
O(1), because the input size is fixed to 3 points. We perform a constant number of comparisons and arithmetic operations.
Space
O(1), as we only use a few variables to store coordinates and slopes, regardless of the input values.
Trade-offs
Pros
The logic is a direct implementation of the slope formula, which can be easy to understand conceptually.
Cons
Requires complex conditional logic to handle vertical lines (division by zero).
The use of floating-point numbers for equality comparison is generally discouraged due to potential precision errors.
The code is more verbose and prone to implementation errors compared to the cross-product method.
A more robust and efficient approach uses a mathematical property of collinear points. Three points are collinear if and only if the area of the triangle they form is zero. This can be checked using a formula derived from the cross-product of two vectors formed by the points, which cleverly avoids floating-point arithmetic and division altogether. This method is superior as it handles all edge cases (including non-distinct points and vertical lines) with a single, simple expression.
Algorithm
- Let the three points be
p1 = (x1, y1),p2 = (x2, y2), andp3 = (x3, y3). - Three points are collinear if the slope between
(p1, p2)is equal to the slope between(p1, p3).slope(p1, p2) == slope(p1, p3)(y2 - y1) / (x2 - x1) == (y3 - y1) / (x3 - x1) - To avoid division and floating-point issues, rearrange the equation using cross-multiplication:
(y2 - y1) * (x3 - x1) == (y3 - y1) * (x2 - x1) - A boomerang requires the points to be non-collinear, so we check for the inequality:
(y2 - y1) * (x3 - x1) != (y3 - y1) * (x2 - x1) - This single check is sufficient. It correctly identifies collinear points (returning
false) and also implicitly handles cases where points are not distinct. If two points are the same, both sides of the equality become zero, correctly identifying them as 'collinear' for the purpose of this problem.
Walkthrough
This method relies on the geometric insight that three points p1, p2, p3 are collinear if the vector p1->p2 is parallel to the vector p1->p3. In 2D, two vectors (dx1, dy1) and (dx2, dy2) are parallel if their cross-product is zero, which is calculated as dy1 * dx2 - dy2 * dx1 = 0.
Let's define the vectors based on our points:
- Vector
v1(fromp1top2):(p2[0] - p1[0], p2[1] - p1[1]) - Vector
v2(fromp1top3):(p3[0] - p1[0], p3[1] - p1[1])
The points are collinear if (p2[1] - p1[1]) * (p3[0] - p1[0]) == (p3[1] - p1[1]) * (p2[0] - p1[0]).
A boomerang is formed if the points are not collinear, so we simply check for the inequality.
This single check also covers the distinctness requirement. If any two points are identical (e.g., p1 and p2), then p2[0] - p1[0] and p2[1] - p1[1] will both be zero. This makes the left side of the equality (p3[1] - p1[1]) * 0 and the right side (p2[1] - p1[1]) * (p3[0] - p1[0]) which is 0 * .... The result is 0 == 0, so the equality holds, our != check fails, and the function correctly returns false.
class Solution { public boolean isBoomerang(int[][] points) { int[] p1 = points[0]; int[] p2 = points[1]; int[] p3 = points[2]; // The points are collinear if the cross-product of vectors p1->p2 and p1->p3 is zero. // (y2 - y1) * (x3 - x1) == (y3 - y1) * (x2 - x1) // A boomerang is formed if they are NOT collinear. // This single check handles both non-collinearity and distinctness. return (p2[1] - p1[1]) * (p3[0] - p1[0]) != (p3[1] - p1[1]) * (p2[0] - p1[0]); }}Complexity
Time
O(1), as it involves a fixed number of arithmetic operations.
Space
O(1), as no extra space proportional to the input is required.
Trade-offs
Pros
Extremely concise and efficient, requiring only a single line of logic.
Avoids division and floating-point arithmetic, eliminating potential precision errors and division-by-zero exceptions.
Robustly handles all edge cases, including vertical lines and non-distinct points, without extra conditional checks.
Cons
The underlying mathematical connection (cross-product or area of a triangle) might be less immediately obvious than direct slope calculation.
Solutions
Solution
class Solution {public boolean isBoomerang(int[][] points) { int x1 = points[0][0], y1 = points[0][1]; int x2 = points[1][0], y2 = points[1][1]; int x3 = points[2][0], y3 = points[2][1]; return (y2 - y1) * (x3 - x2) != (y3 - y2) * (x2 - x1); }}class Solution {public: bool isBoomerang(vector<vector<int>> &points) { int x1 = points[0][0], y1 = points[0][1]; int x2 = points[1][0], y2 = points[1][1]; int x3 = points[2][0], y3 = points[2][1]; return (y2 - y1) * (x3 - x2) != (y3 - y2) * (x2 - x1); }};class Solution: def isBoomerang(self, points: List[List[int]]) -> bool: (x1, y1), (x2, y2), (x3, y3) = points return (y2 - y1) * (x3 - x2) != (y3 - y2) * (x2 - x1)Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.