Medium

题目描述

给你一个大小为 n x 2 的二维数组 coords,表示无限笛卡尔平面上 n 个点的坐标。

找到以 coords 中任意三个元素为顶点的三角形的最大面积的两倍,使得该三角形至少有一条边平行于 x 轴或 y 轴。形式上,如果这样的三角形的最大面积为 A,则返回 2 * A

如果不存在这样的三角形,返回 -1

注意三角形不能有零面积。

示例 1:

输入:coords = [[1,1],[1,2],[3,2],[3,3]]
输出:2
解释:图中显示的三角形底边为 1,高为 2。因此其面积为 1/2 * 底边 * 高 = 1。

示例 2:

输入:coords = [[1,1],[2,2],[3,3]]
输出:-1
解释:唯一可能的三角形顶点为 (1, 1), (2, 2), 和 (3, 3)。它的任何一边都不平行于 x 轴或 y 轴。

提示:

  • 1 <= n == coords.length <= 10^5
  • 1 <= coords[i][0], coords[i][1] <= 10^6
  • 所有 coords[i] 都是唯一的

提示:

  • 面积 * 2 = 底边 * 高
  • 让底边平行于 x 轴或 y 轴
  • 排序以找到每个固定 x(或 y)的最大底边,然后最大高度来自另一个坐标的极值

解题思路

解题思路

这道题要求找到至少有一条边平行于坐标轴的三角形的最大面积。我们可以分两种情况考虑:

情况1:有一条边平行于x轴

当三角形有一条边平行于x轴时,这条边的两个端点具有相同的y坐标。我们可以:

  1. 将所有点按y坐标分组
  2. 对于每个y坐标,找到该水平线上最远的两个点作为底边
  3. 对于每个这样的底边,找到距离该水平线最远的点作为第三个顶点

情况2:有一条边平行于y轴

类似地,当三角形有一条边平行于y轴时:

  1. 将所有点按x坐标分组
  2. 对于每个x坐标,找到该竖直线上最远的两个点作为底边
  3. 找到距离该竖直线最远的点作为第三个顶点

优化策略

为了高效计算:

  • 使用哈希表按坐标分组
  • 对于每条平行线,只需要考虑最远的两个点作为底边
  • 高度的计算只需要考虑距离该直线最远的点

推荐解法:使用哈希表分组 + 贪心算法,时间复杂度为O(n²)。

代码实现

class Solution {
public:
    long long maxArea(vector<vector<int>>& coords) {
        int n = coords.size();
        if (n < 3) return -1;
        
        long long maxArea = -1;
        
        // Case 1: Base parallel to x-axis
        unordered_map<int, vector<int>> yGroups;
        for (auto& coord : coords) {
            yGroups[coord[1]].push_back(coord[0]);
        }
        
        for (auto& [y, xList] : yGroups) {
            if (xList.size() < 2) continue;
            sort(xList.begin(), xList.end());
            long long base = xList.back() - xList[0];
            if (base == 0) continue;
            
            long long maxHeight = 0;
            for (auto& coord : coords) {
                if (coord[1] != y) {
                    maxHeight = max(maxHeight, (long long)abs(coord[1] - y));
                }
            }
            if (maxHeight > 0) {
                maxArea = max(maxArea, base * maxHeight);
            }
        }
        
        // Case 2: Base parallel to y-axis
        unordered_map<int, vector<int>> xGroups;
        for (auto& coord : coords) {
            xGroups[coord[0]].push_back(coord[1]);
        }
        
        for (auto& [x, yList] : xGroups) {
            if (yList.size() < 2) continue;
            sort(yList.begin(), yList.end());
            long long base = yList.back() - yList[0];
            if (base == 0) continue;
            
            long long maxHeight = 0;
            for (auto& coord : coords) {
                if (coord[0] != x) {
                    maxHeight = max(maxHeight, (long long)abs(coord[0] - x));
                }
            }
            if (maxHeight > 0) {
                maxArea = max(maxArea, base * maxHeight);
            }
        }
        
        return maxArea;
    }
};
class Solution:
    def maxArea(self, coords: List[List[int]]) -> int:
        n = len(coords)
        if n < 3:
            return -1
        
        max_area = -1
        
        # Case 1: Base parallel to x-axis
        y_groups = {}
        for x, y in coords:
            if y not in y_groups:
                y_groups[y] = []
            y_groups[y].append(x)
        
        for y, x_list in y_groups.items():
            if len(x_list) < 2:
                continue
            x_list.sort()
            base = x_list[-1] - x_list[0]
            if base == 0:
                continue
            
            max_height = 0
            for x, cy in coords:
                if cy != y:
                    max_height = max(max_height, abs(cy - y))
            
            if max_height > 0:
                max_area = max(max_area, base * max_height)
        
        # Case 2: Base parallel to y-axis
        x_groups = {}
        for x, y in coords:
            if x not in x_groups:
                x_groups[x] = []
            x_groups[x].append(y)
        
        for x, y_list in x_groups.items():
            if len(y_list) < 2:
                continue
            y_list.sort()
            base = y_list[-1] - y_list[0]
            if base == 0:
                continue
            
            max_height = 0
            for cx, y in coords:
                if cx != x:
                    max_height = max(max_height, abs(cx - x))
            
            if max_height > 0:
                max_area = max(max_area, base * max_height)
        
        return max_area
public class Solution {
    public long MaxArea(int[][] coords) {
        int n = coords.Length;
        if (n < 3) return -1;
        
        long maxArea = -1;
        
        // Case 1: Base parallel to x-axis
        var yGroups = new Dictionary<int, List<int>>();
        foreach (var coord in coords) {
            if (!yGroups.ContainsKey(coord[1])) {
                yGroups[coord[1]] = new List<int>();
            }
            yGroups[coord[1]].Add(coord[0]);
        }
        
        foreach (var kvp in yGroups) {
            int y = kvp.Key;
            var xList = kvp.Value;
            if (xList.Count < 2) continue;
            
            xList.Sort();
            long baseLength = xList[xList.Count - 1] - xList[0];
            if (baseLength == 0) continue;
            
            long maxHeight = 0;
            foreach (var coord in coords) {
                if (coord[1] != y) {
                    maxHeight = Math.Max(maxHeight, Math.Abs(coord[1] - y));
                }
            }
            
            if (maxHeight > 0) {
                maxArea = Math.Max(maxArea, baseLength * maxHeight);
            }
        }
        
        // Case 2: Base parallel to y-axis
        var xGroups = new Dictionary<int, List<int>>();
        foreach (var coord in coords) {
            if (!xGroups.ContainsKey(coord[0])) {
                xGroups[coord[0]] = new List<int>();
            }
            xGroups[coord[0]].Add(coord[1]);
        }
        
        foreach (var kvp in xGroups) {
            int x = kvp.Key;
            var yList = kvp.Value;
            if (yList.Count < 2) continue;
            
            yList.Sort();
            long baseLength = yList[yList.Count - 1] - yList[0];
            if (baseLength == 0) continue;
            
            long maxHeight = 0;
            foreach (var coord in coords) {
                if (coord[0] != x) {
                    maxHeight = Math.Max(maxHeight, Math.Abs(coord[0] - x));
                }
            }
            
            if (maxHeight > 0) {
                maxArea = Math.Max(maxArea, baseLength * maxHeight);
            }
        }
        
        return maxArea;
    }
}
var maxArea = function(coords) {
    const n = coords.length;
    if (n < 3) return -1;
    
    let maxArea = 0;
    
    // Group points by x-coordinate and y-coordinate
    const xGroups = new Map();
    const yGroups = new Map();
    
    for (const [x, y] of coords) {
        if (!xGroups.has(x)) xGroups.set(x, []);
        if (!yGroups.has(y)) yGroups.set(y, []);
        xGroups.get(x).push([x, y]);
        yGroups.get(y).push([x, y]);
    }
    
    // Case 1: Two points share same x-coordinate (vertical side)
    for (const points of xGroups.values()) {
        if (points.length >= 2) {
            for (let i = 0; i < points.length; i++) {
                for (let j = i + 1; j < points.length; j++) {
                    const [x1, y1] = points[i];
                    const [x2, y2] = points[j];
                    const height = Math.abs(y2 - y1);
                    
                    // Find third point with maximum distance from the vertical line
                    for (const [x3, y3] of coords) {
                        if (x3 !== x1) {
                            const base = Math.abs(x3 - x1);
                            const area = base * height;
                            maxArea = Math.max(maxArea, area);
                        }
                    }
                }
            }
        }
    }
    
    // Case 2: Two points share same y-coordinate (horizontal side)
    for (const points of yGroups.values()) {
        if (points.length >= 2) {
            for (let i = 0; i < points.length; i++) {
                for (let j = i + 1; j < points.length; j++) {
                    const [x1, y1] = points[i];
                    const [x2, y2] = points[j];
                    const base = Math.abs(x2 - x1);
                    
                    // Find third point with maximum distance from the horizontal line
                    for (const [x3, y3] of coords) {
                        if (y3 !== y1) {
                            const height = Math.abs(y3 - y1);
                            const area = base * height;
                            maxArea = Math.max(maxArea, area);
                        }
                    }
                }
            }
        }
    }
    
    return maxArea === 0 ? -1 : maxArea;
};

复杂度分析

解法时间复杂度空间复杂度
哈希表分组O(n²)O(n)

分析说明:

  • 时间复杂度:O(n²) - 外层遍历每个坐标分组,内层遍历所有点找最大高度
  • 空间复杂度:O(n) - 哈希表存储坐标分组信息