题目描述

✅ 812. 最大三角形面积

image-20260928224902513

image-20260928224902515

题意分析

从给定平面点中选择三个不同的点,求它们能组成的最大三角形面积。边可以朝任意方向,不要求平行于坐标轴;共线的三点面积为零。

点数最多为 50,可以直接枚举所有三点组合。关键是用常数时间准确算出每个三角形的面积,不必额外求边长、高或角度。

解法:枚举三点 + 叉积

核心思路

[!blue]

选定三点 A、B、C,以 A 为共同起点,构造向量 AB = (x1, y1) 和 AC = (x2, y2)。二维叉积是 cross = x1 * y2 - x2 * y1,其绝对值等于这两个向量围成的平行四边形面积;三角形恰好占其中一半,所以面积为 abs(cross) / 2。

叉积的正负只反映两个向量的方向顺序。交换 B、C 会让符号反转,但三角形面积不变,因此要取绝对值;三点共线时,两向量成比例,叉积自然为零,不需要另作共线判断。

按 i < j < k 枚举下标,每个无序三点组合都有且只有一种这样的排列,所以所有候选三角形都会被检查一次。best 从零开始,每次与当前面积比较并保留较大值,枚举结束后就是最大面积。

坐标是整数,可以先在整数域计算叉积,最后才用 2.0 做浮点除法。叉积绝对值可能为奇数,若先进行整数除法再转浮点,就会丢掉半单位面积。Go 同样先把叉积转换为 float64,再除以 2.0。

解题步骤

  • 按 i<j<k 枚举不同三点。
  • 计算两向量叉积,取绝对值再除二。
  • 维护最大面积。

题目坐标范围为 [-50, 50],坐标差绝对值不超过 100,叉积的两项乘积及相减结果都能安全存入 int。只有三个点时只计算一次;全部点共线时所有候选面积为零,返回初始的零面积。

代码实现

class Solution {
    public double largestTriangleArea(int[][] points) {
        double best = 0.0;
        int n = points.length;

        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                for (int k = j + 1; k < n; k++) {
                    double area = area(points[i], points[j], points[k]);

                    if (area > best) {
                        best = area;
                    }
                }
            }
        }

        return best;
    }

    private double area(int[] a, int[] b, int[] c) {
        // 两个向量使用同一个基点,叉积绝对值为面积的两倍
        int x1 = b[0] - a[0];
        int y1 = b[1] - a[1];
        int x2 = c[0] - a[0];
        int y2 = c[1] - a[1];

        // 最后使用浮点除法,保留半单位面积
        return Math.abs(x1 * y2 - x2 * y1) / 2.0;
    }
}
func largestTriangleArea(points [][]int) float64 {
    best := 0.0
    n := len(points)

    for i := 0; i < n; i++ {
        for j := i + 1; j < n; j++ {
            for k := j + 1; k < n; k++ {
                area := triangleArea(points[i], points[j], points[k])
                if area > best {
                    best = area
                }
            }
        }
    }

    return best
}

func triangleArea(a []int, b []int, c []int) float64 {
    // 两个向量使用同一个基点,叉积绝对值为面积的两倍
    x1 := b[0] - a[0]
    y1 := b[1] - a[1]
    x2 := c[0] - a[0]
    y2 := c[1] - a[1]
    cross := x1*y2 - x2*y1
    if cross < 0 {
        cross = -cross
    }
    // 最后使用浮点除法,保留半单位面积
    return float64(cross) / 2.0
}

复杂度分析

  • 时间复杂度:$O(n^3)$,每组三点常数计算。
  • 空间复杂度:$O(1)$,不保存中间图形。

关键点总结

[!green]

  • 叉积符号表示方向,面积只取大小。
  • 枚举下标递增,避免同一三点组合重复处理。

易错点总结

[!yellow]

  • 整除二会丢掉0.5部分。
  • 不取绝对值,会让负方向面积无法更新最大值。
  • 把叉积两项相减写成相加,会改变面积公式。

相似题目

题目 难度 关联与区别
149. 直线上最多的点数 困难 叉积既能判断共线,也能给出三点组成三角形的两倍有向面积。
补充题 19. 判断一个点是否在三角形内 中等 三角形面积或叉积符号是点内外判断的基础,本题枚举三点并取面积最大值。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2024/10999078
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!